From 24681c81c09022f584a57006f2534b5f74723414 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期二, 30 六月 2026 09:27:31 +0800
Subject: [PATCH] 初始化项目
---
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java | 4
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java | 31
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/job/rtc/ImRtcParticipantTimeoutJob.java | 58
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FaceMessage.java | 39
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java | 24
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java | 8
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackItemDO.java | 61
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackPageReqVO.java | 31
yudao-module-infra/src/test/resources/codegen/vue2_master_inner/java/InfraStudentServiceImpl | 1
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/ImageMessage.java | 37
sql/highgo/quartz.sql | 208
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConnectionManager.java | 21
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentSaveReqVO | 49
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java | 18
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDeviceStateConditionMatcher.java | 7
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInDO.java | 6
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java | 8
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java | 51
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/java/InfraStudentServiceImpl | 1
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java | 41
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageSendReqVO.java | 48
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendMapper.java | 110
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java | 112
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/privates/ImPrivateMessageManagerRespVO.java | 48
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_inner.vue.vm | 4
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java | 12
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImGroupMessageMapper.java | 104
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcLiveKitController.java | 76
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendAddNotification.java | 13
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/java/InfraStudentServiceImpl | 1
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImplTest.java | 177
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapperTest.java | 196
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java | 8
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/java/InfraStudentServiceImpl | 1
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java | 1
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageSendReqVO.java | 53
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcCallMapper.java | 64
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java | 3
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java | 3
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/index.vue.vm | 347
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java | 46
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_inner.vue.vm | 2
sql/tools/convertor.py | 123
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java | 252
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java | 70
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupCancelMuteMemberReqVO.java | 19
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImCommonConstants.java | 17
pom.xml | 33
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/ImStatisticsManagerController.java | 160
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationReadService.java | 67
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java | 37
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java | 9
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java | 27
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java | 6
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestRejectedNotification.java | 22
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelSaveReqVO.java | 40
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java | 10
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImGroupMessageMapperTest.java | 195
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberNicknameUpdateNotification.java | 16
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GrokChatModelTests.java | 77
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/search-form | 140
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java | 9
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryMapper.java | 15
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java | 16
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImpl.java | 270
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImplTest.java | 164
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerRespVO.java | 54
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImplTest.java | 391
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceStateUpdateTriggerMatcher.java | 13
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesController.java | 5
sql/dm/ruoyi-vue-pro-dm8.sql | 651
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/minimax/MiniMaxChatModel.java | 52
yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java | 16
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java | 3
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java | 283
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestService.java | 105
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/config/ImProperties.java | 195
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml | 8
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageLineController.java | 5
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java | 22
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImplTest.java | 144
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberEnterNotification.java | 25
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceEventPostTriggerMatcher.java | 8
yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java | 5
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberService.java | 244
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/manager/AbstractIotModbusPollScheduler.java | 137
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/ErrorCodeConstants_手动操作 | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/TextMessage.java | 21
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/util/ImMessageUtilsTest.java | 184
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java | 50
yudao-module-iot/yudao-module-iot-core/pom.xml | 6
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallRespVO.java | 45
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImConversationTypeEnum.java | 56
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendAddSourceEnum.java | 41
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java | 36
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImPrivateMessageController.java | 85
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/job/rtc/ImRtcCallCleanupJob.java | 58
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueLineController.java | 5
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/QuoteMessage.java | 50
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/channel/ImChannelMaterialTypeEnum.java | 37
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesLineController.java | 5
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMemberMapper.java | 137
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java | 88
yudao-module-member/src/test/resources/sql/create_tables.sql | 1
yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java | 5
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java | 29
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java | 35
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupDissolveNotification.java | 7
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestRejectedNotification.java | 32
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmAttachmentTypeEnum.java | 27
yudao-module-ai/pom.xml | 40
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberSettingUpdateNotification.java | 22
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java | 4
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/package-info.java | 8
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/java/InfraStudentServiceImpl | 1
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackItemManagerController.java | 85
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java | 69
yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java | 18
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImpl.java | 20
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/sensitiveword/ImSensitiveWordMapper.java | 44
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImpl.java | 148
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestService.java | 76
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java | 1
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java | 6
yudao-module-mall/yudao-module-trade/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml | 27
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java | 3
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java | 6
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendBlockNotification.java | 13
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConfigCacheService.java | 24
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerGroupSizeRespVO.java | 16
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/vo/config/MesProAndonConfigRespVO.java | 3
sql/kingbase/ruoyi-vue-pro.sql | 9
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageListReqVO.java | 27
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/java/InfraStudentServiceImpl | 1
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java | 26
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelPageReqVO.java | 22
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java | 2
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java | 47
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImpl.java | 425
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/data.ts.vm | 616
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java | 251
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java | 12
sql/mysql/ruoyi-vue-pro.sql | 857
yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java | 31
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/config/ImWebConfiguration.java | 22
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallStartNotification.java | 61
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendStateEnum.java | 55
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentServiceImpl | 1
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImplTest.java | 256
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java | 37
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimerConditionIntegrationTest.java | 20
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java | 79
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcParticipantStatusEnum.java | 62
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java | 10
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java | 7
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupRequestManagerPageReqVO.java | 37
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_erp.vue.vm | 240
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java | 5
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImGroupMessageNotification.java | 77
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSimpleRespVO.java | 5
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendController.java | 143
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImMessageReceiptNotification.java | 52
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java | 11
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java | 17
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupNameUpdateNotification.java | 20
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/api/api.ts.vm | 179
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImplTest.java | 201
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java | 5
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupRequestDO.java | 91
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java | 92
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMessagePinReqVO.java | 22
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupMemberDO.java | 102
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImplTest.java | 177
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java | 18
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java | 16
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerMessageTypeRespVO.java | 16
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java | 4
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java | 13
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java | 10
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/channel/ImChannelMessagePullRespVO.java | 33
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java | 11
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendRequestHandleResultEnum.java | 46
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesDetailController.java | 5
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java | 12
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberCancelMutedNotification.java | 18
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupBannedNotification.java | 16
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java | 11
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupInfoUpdateNotification.java | 28
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImChannelMessageNotification.java | 54
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java | 11
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFacePackController.java | 59
yudao-module-ai/src/main/java/org/springframework/ai/model/tool/DefaultToolExecutionEligibilityPredicate.java | 29
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java | 6
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java | 18
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java | 21
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationReadMapperTest.java | 105
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessageRespVO.java | 43
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java | 5
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/sql/h2 | 17
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java | 8
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java | 11
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendManagerPageReqVO.java | 34
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java | 7
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMessageUnpinNotification.java | 16
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_inner.vue.vm | 4
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackRespVO.java | 30
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java | 6
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/ImChannelMaterialManagerController.java | 99
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FileMessage.java | 33
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ErrorCodeConstants.java | 108
yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm | 156
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/form/index | 187
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptLineController.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java | 60
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java | 58
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberMutedNotification.java | 24
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImplTest.java | 1184 +
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java | 21
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java | 3
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java | 1
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendDO.java | 90
yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm | 22
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/channel/ImChannelMaterialController.java | 37
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupAdminRemoveNotification.java | 7
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/form.vue.vm | 157
sql/highgo/ruoyi-vue-pro.sql | 6198 +++++++
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java | 11
yudao-module-im/pom.xml | 85
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelRespVO.java | 33
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendDeleteNotification.java | 18
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java | 127
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemSaveReqVO.java | 55
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendRespVO.java | 64
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupDO.java | 94
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberInviteNotification.java | 7
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java | 215
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupCreateNotification.java | 7
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImplTest.java | 349
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitWebhookEventDTO.java | 83
yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm | 72
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java | 1
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java | 11
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java | 6
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupMemberController.java | 140
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java | 18
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/yiyan/YiYanChatModel.java | 52
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java | 3
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/kafka/IotKafkaMessageBus.java | 127
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java | 4
yudao-dependencies/pom.xml | 69
yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java | 6
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImplTest.java | 445
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java | 4
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClient.java | 15
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/CardMessage.java | 44
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/app/package-info.java | 4
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/request/ImFriendRequestRespVO.java | 61
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendUnblockNotification.java | 13
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/privates/ImPrivateMessageManagerPageReqVO.java | 37
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupRequestManagerRespVO.java | 57
yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryPickUpStoreConvert.java | 3
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineUniappTest.java | 34
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerPageReqVO.java | 28
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageRespVO.java | 42
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/package-info.java | 4
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/channel/ImChannelMaterialMapper.java | 39
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberCreateReqVO.java | 19
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java | 6
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java | 26
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentMapper | 30
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java | 114
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImpl.java | 297
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketService.java | 46
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMessagePinNotification.java | 64
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java | 266
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImContentTypeEnum.java | 422
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerTrendRespVO.java | 21
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerBanReqVO.java | 22
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java | 5
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java | 70
yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java | 17
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java | 38
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_normal.vue.vm | 195
yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java | 3
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptController.java | 5
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java | 5
yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java | 2
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/assert.json | 55
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java | 11
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageListReqVO.java | 26
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java | 5
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java | 107
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java | 339
README.md | 82
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java | 16
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFaceUserItemManagerController.java | 67
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImplTest.java | 350
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/channel/ImChannelMapper.java | 39
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java | 10
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImChannelMessageMapper.java | 53
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defectrecord/MesQcDefectRecordController.java | 9
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/ImChannelManagerController.java | 82
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMutedNotification.java | 11
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java | 9
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusProperties.java | 4
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestNotification.java | 37
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImChannelMessageController.java | 75
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapper.java | 99
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java | 2
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java | 44
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java | 7
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/RecallMessage.java | 18
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImpl.java | 548
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java | 27
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java | 279
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java | 45
script/livekit-poc/livekit.yaml | 30
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDevicePropertyPostTriggerMatcher.java | 8
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java | 2
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java | 6
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java | 8
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java | 16
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java | 122
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupAddSourceEnum.java | 41
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImplTest.java | 355
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java | 3
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java | 10
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java | 10
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java | 39
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/VideoMessage.java | 41
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/dto/ImPrivateMessageSendDTO.java | 43
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 247
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/ImFriendRequestManagerController.java | 66
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java | 4
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupSaveReqVO.java | 27
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java | 7
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_erp.vue.vm | 89
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/zhipu/ZhiPuChatModel.java | 52
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java | 9
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/redis/rtc/ImRtcCallLockRedisDAO.java | 80
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRespVO.java | 56
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImplTest.java | 291
yudao-module-mall/yudao-module-trade/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java | 200
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java | 16
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerPageReqVO.java | 37
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java | 5
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/barcode/MesWmBarcodeMapper.java | 8
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java | 7
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java | 32
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java | 75
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageService.java | 75
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/convert/channel/PayChannelConvert.java | 12
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/moonshot/MoonshotChatModel.java | 54
sql/tools/README.md | 28
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentRespVO | 59
yudao-server/src/main/resources/application.yaml | 92
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java | 3
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisStreamMessageCleanupJob.java | 30
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentService | 62
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestApprovedNotification.java | 28
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapper.java | 191
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImpl.java | 228
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSimpleRespVO.java | 19
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImPrivateMessageDO.java | 79
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueController.java | 5
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java | 10
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java | 10
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java | 6
script/livekit-poc/docker-compose.yml | 20
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberKickNotification.java | 7
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordSaveReqVO.java | 28
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/config/ImRtcConfiguration.java | 24
yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImplTest.java | 40
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java | 5
yudao-module-iot/yudao-module-iot-gateway/pom.xml | 30
yudao-server/src/main/resources/application-dev.yaml | 16
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java | 79
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java | 1
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java | 45
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java | 29
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupRequestController.java | 174
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupRequestHandleResultEnum.java | 48
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallMediaTypeEnum.java | 46
yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java | 116
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcParticipantMapper.java | 75
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtilsTest.java | 32
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java | 10
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java | 37
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendManagerRespVO.java | 54
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/BaseFriendNotification.java | 24
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberUpdateReqVO.java | 26
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitClient.java | 244
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendRequestManagerRespVO.java | 48
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApi.java | 32
yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtilsTest.java | 167
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallInviteReqVO.java | 23
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/xml/InfraStudentMapper | 12
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelMaterialServiceImpl.java | 113
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerOverviewRespVO.java | 43
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestReceivedNotification.java | 51
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerTopSenderRespVO.java | 19
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java | 5
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentServiceImpl | 85
yudao-module-im/src/test/resources/sql/clean.sql | 15
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/MergeMessage.java | 64
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java | 20
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImMessageController.http | 18
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/ImSensitiveWordManagerController.java | 106
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationReadController.java | 51
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java | 37
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/weixin/package-info.java | 6
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/index.vue.vm | 511
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java | 26
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleActionTest.java | 9
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationReadRespVO.java | 32
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueDetailController.java | 5
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java | 5
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java | 11
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessagePageReqVO.java | 28
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallCreateReqVO.java | 44
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageService.java | 130
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApiImpl.java | 16
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendRequestManagerPageReqVO.java | 34
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupRequestManagerController.java | 75
yudao-module-mall/yudao-module-promotion/src/test/resources/sql/clean.sql | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapper.java | 110
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java | 107
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java | 5
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/user/AdminUserProducer.java | 33
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialPageReqVO.java | 31
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java | 2
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java | 85
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageController.java | 6
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/MesProAndonConfigController.java | 15
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java | 15
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupCreateReqVO.java | 25
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollScheduler.java | 219
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java | 50
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java | 40
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/dto/RoleRespDTO.java | 37
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/request/ImGroupRequestRespVO.java | 68
yudao-module-mes/pom.xml | 14
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java | 7
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupPageReqVO.java | 30
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestApprovedNotification.java | 18
script/livekit-poc/verify.sh | 105
.image/common/im-preview-home.png | 0
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java | 13
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerService.java | 92
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/api/api.ts.vm | 1
yudao-module-erp/pom.xml | 21
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/detail/index | 140
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rabbitmq/IotRabbitMQMessageBus.java | 104
sql/opengauss/ruoyi-vue-pro.sql | 9
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/request/ImGroupRequestApplyReqVO.java | 26
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/MaterialMessage.java | 51
yudao-module-mall/yudao-module-trade/src/test/resources/sql/create_tables.sql | 6
yudao-module-mp/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/sensitiveword/ImSensitiveWordDO.java | 41
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java | 16
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/StepFunChatModelTests.java | 82
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java | 6
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java | 8
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerPageReqVO.java | 34
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentServiceImplTest | 145
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/import.vue.vm | 82
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java | 26
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java | 51
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelMaterialService.java | 106
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_normal.vue.vm | 347
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java | 46
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java | 58
yudao-module-infra/src/test/resources/codegen/vue3_master_inner/java/InfraStudentServiceImpl | 1
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java | 437
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendUpdateReqVO.java | 26
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/SiliconFlowImageModelTests.java | 9
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java | 15
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordPageReqVO.java | 31
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupAdminAddNotification.java | 7
sql/oracle/ruoyi-vue-pro.sql | 9
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java | 83
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/sql/sql | 54
yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategyTest.java | 6
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java | 143
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java | 26
.gitignore | 3
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java | 12
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/group/ImGroupMessageManagerPageReqVO.java | 37
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java | 12
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/ts/index | 41
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java | 75
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java | 4
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/util/ImMessageUtils.java | 218
yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImplTest.java | 325
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberInviteReqVO.java | 22
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageRespVO.java | 52
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentDO | 68
yudao-module-im/src/test/resources/application-unit-test.yaml | 49
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java | 4
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressRespVO.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMapper.java | 34
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImpl.java | 323
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java | 3
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java | 99
sql/tools/docker-compose.yaml | 15
script/livekit-poc/README.md | 32
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImChannelMessageManagerController.java | 80
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java | 50
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java | 65
yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm | 140
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java | 8
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImChannelMessageDO.java | 74
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMuteAllReqVO.java | 19
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcParticipantDO.java | 80
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java | 18
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/MesWmSnController.java | 21
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentController | 104
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/BaseGroupNotification.java | 16
yudao-module-im/src/test/resources/sql/create_tables.sql | 349
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/IotModbusTcpServerProtocol.java | 18
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/channel/PayChannelMapper.java | 4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/BarcodeBizTypeEnum.java | 1
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMuteMemberReqVO.java | 25
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupRequestMapper.java | 116
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerRespVO.java | 37
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationReadDO.java | 68
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java | 12
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImpl.java | 113
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java | 15
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcParticipantConnectedNotification.java | 61
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java | 8
yudao-server/pom.xml | 24
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java | 12
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/import.vue.vm | 71
yudao-module-mall/yudao-module-promotion/src/test/resources/sql/create_tables.sql | 60
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/stepfun/StepFunChatModel.java | 54
yudao-module-infra/src/main/resources/codegen/java/service/serviceImpl.vm | 9
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/weixin/config/YudaoWxClientConfiguration.java | 111
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java | 9
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapperTest.java | 80
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java | 29
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java | 8
yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableFieldTest.java | 27
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/ImFriendManagerController.java | 65
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImplTest.java | 162
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcParticipantDisconnectedNotification.java | 51
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcCallDO.java | 93
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java | 13
yudao-module-ai/src/main/java/org/springframework/ai/model/tool/ToolExecutionEligibilityPredicate.java | 21
sql/postgresql/ruoyi-vue-pro.sql | 9
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeService.java | 10
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackItemMapper.java | 49
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java | 26
yudao-module-iot/yudao-module-iot-biz/pom.xml | 4
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/channel/ImChannelMaterialDO.java | 69
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelService.java | 99
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSimpleRespVO.java | 19
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupAdminAddReqVO.java | 22
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/package-info.java | 14
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java | 39
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java | 2
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/message/user/AdminUserProfileUpdateMessage.java | 31
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_erp.vue.vm | 213
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDevicePropertyConditionMatcher.java | 10
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/channel/ImChannelDO.java | 57
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupOwnerTransferNotification.java | 16
yudao-module-pay/src/test/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceTest.java | 91
yudao-module-wms/pom.xml | 7
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java | 16
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupManagerController.java | 102
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageService.java | 104
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberQuitNotification.java | 7
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupNoticeUpdateNotification.java | 20
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java | 5
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java | 28
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationReadServiceImpl.java | 86
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/request/ImFriendRequestApplyReqVO.java | 35
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java | 136
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/package-info.java | 6
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java | 12
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentServiceImpl | 1
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java | 28
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java | 104
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java | 4
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/QiniuSmsClient.java | 4
yudao-server/src/main/resources/application-local.yaml | 22
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackMapper.java | 36
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java | 26
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendRequestDO.java | 85
.image/common/im-preview-manager.png | 0
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupTransferOwnerReqVO.java | 19
.image/common/im-feature.png | 0
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java | 773
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FilePathUtils.java | 106
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupCancelMutedNotification.java | 13
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemRespVO.java | 40
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationReadMapper.java | 83
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java | 11
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java | 10
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java | 44
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java | 61
yudao-module-infra/src/test/resources/codegen/vue2_master_normal/java/InfraStudentServiceImpl | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java | 4
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImpl.java | 117
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendInfoUpdatedNotification.java | 16
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcParticipantManagerRespVO.java | 39
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_inner.vue.vm | 2
yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java | 3
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutDO.java | 6
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryService.java | 10
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java | 14
yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java | 8
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java | 38
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java | 36
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentPageReqVO | 32
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerRespVO.java | 54
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessagePageReqVO.java | 21
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapperTest.java | 278
yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java | 16
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java | 9
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java | 57
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImPrivateMessageManagerController.java | 72
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallService.java | 169
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImPrivateMessageNotification.java | 68
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/form.vue.vm | 325
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/template/MesQcTemplateMapper.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImpl.java | 116
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImMessageReadNotification.java | 58
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallEndNotification.java | 76
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcParticipantRoleEnum.java | 38
yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupMemberManagerController.java | 60
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallNotification.java | 165
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImGroupMessageDO.java | 107
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java | 129
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialRespVO.java | 42
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordServiceImpl.java | 5
yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtilsTest.java | 173
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/java/InfraStudentServiceImpl | 1
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupAdminRemoveReqVO.java | 22
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java | 22
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordService.java | 8
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java | 34
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/member/ImGroupMemberManagerRespVO.java | 45
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/ImNotificationWebSocketDTO.java | 33
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java | 1
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupMemberRoleEnum.java | 51
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/dto/ImGroupMessageSendDTO.java | 235
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_erp.vue.vm | 424
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java | 23
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackManagerController.java | 85
yudao-module-infra/src/test/resources/codegen/vue3_master_normal/java/InfraStudentServiceImpl | 1
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/PayChannelController.java | 9
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/package-info.java | 6
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java | 5
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java | 5
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordRespVO.java | 29
yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java | 5
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java | 16
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcGroupCallRespVO.java | 30
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupUpdateReqVO.java | 46
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/index | 169
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageReceiptStatusEnum.java | 39
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java | 20
yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/http/HttpUtilsTest.java | 30
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImpl.java | 126
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/ImRtcCallManagerController.java | 113
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotCurrentTimeConditionMatcher.java | 11
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml | 13
yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java | 3
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java | 125
yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java | 3
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/pack/ImFacePackUserRespVO.java | 46
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImGroupMessageManagerController.java | 92
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollSchedulerTest.java | 147
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java | 22
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialSaveReqVO.java | 44
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcCallController.java | 169
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/LocationMessage.java | 24
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallEndReasonEnum.java | 41
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java | 11
yudao-module-pay/src/test/resources/sql/create_tables.sql | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImGroupMessageController.java | 85
yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java | 2
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberListNotification.java | 20
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImplTest.java | 278
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java | 36
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java | 2
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java | 14
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java | 25
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java | 52
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImplTest.java | 1052 +
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/group/ImGroupMessageManagerRespVO.java | 54
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendUpdateNotification.java | 27
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRemoveReqVO.java | 22
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImplTest.java | 94
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessageSendReqVO.java | 20
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImpl.java | 1186 +
/dev/null | 284
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordService.java | 57
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallStatusEnum.java | 60
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelServiceImpl.java | 120
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java | 24
sql/sqlserver/ruoyi-vue-pro.sql | 11
yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelService.java | 8
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupRespVO.java | 62
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/redis/RedisKeyConstants.java | 48
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/AbstractFileClient.java | 3
721 files changed, 48,407 insertions(+), 4,330 deletions(-)
diff --git a/.gitignore b/.gitignore
index 49330ee..b9d947f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,4 +51,5 @@
application-my.yaml
/yudao-ui-app/unpackage/
-**/.DS_Store
+.DS_Store
+**/.DS_Store
\ No newline at end of file
diff --git a/.image/common/im-feature.png b/.image/common/im-feature.png
new file mode 100644
index 0000000..da3f012
--- /dev/null
+++ b/.image/common/im-feature.png
Binary files differ
diff --git a/.image/common/im-preview-home.png b/.image/common/im-preview-home.png
new file mode 100644
index 0000000..c4790a3
--- /dev/null
+++ b/.image/common/im-preview-home.png
Binary files differ
diff --git a/.image/common/im-preview-manager.png b/.image/common/im-preview-manager.png
new file mode 100644
index 0000000..b8bb057
--- /dev/null
+++ b/.image/common/im-preview-manager.png
Binary files differ
diff --git a/README.md b/README.md
index 6f036fa..c248424 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
<p align="center">
- <img src="https://img.shields.io/badge/Spring%20Boot-3.4.5-blue.svg" alt="Downloads">
+ <img src="https://img.shields.io/badge/Spring%20Boot-4.1.0-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/Vue-3.2-blue.svg" alt="Downloads">
<img src="https://img.shields.io/github/license/YunaiV/ruoyi-vue-pro" alt="Downloads" />
</p>
@@ -23,13 +23,13 @@
## 馃惏 鐗堟湰璇存槑
-| 鐗堟湰 | JDK 8 + Spring Boot 2.7 | JDK 17/21 + Spring Boot 3.2 |
-|---------------------------------------------------------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------|
-| 銆愬畬鏁寸増銆慬ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [`master`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/) 鍒嗘敮 | [`master-jdk17`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master-jdk17/) 鍒嗘敮 |
-| 銆愮簿绠�鐗堛�慬yudao-boot-mini](https://gitee.com/yudaocode/yudao-boot-mini) | [`master`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master/) 鍒嗘敮 | [`master-jdk17`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master-jdk17/) 鍒嗘敮 |
+| 鐗堟湰 | JDK 8 + Spring Boot 2.7 | JDK 17/21 + Spring Boot 3.5 | JDK 25 + Spring Boot 4.x |
+|---------------------------------------------------------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------|
+| 銆愬畬鏁寸増銆慬ruoyi-vue-pro](https://gitee.com/zhijiantianya/ruoyi-vue-pro) | [`master`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master/) 鍒嗘敮 | [`master-jdk17`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master-jdk17/) 鍒嗘敮 | [`master-jdk25`](https://gitee.com/zhijiantianya/ruoyi-vue-pro/tree/master-jdk25/) 鍒嗘敮 |
+| 銆愮簿绠�鐗堛�慬yudao-boot-mini](https://gitee.com/yudaocode/yudao-boot-mini) | [`master`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master/) 鍒嗘敮 | [`master-jdk17`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master-jdk17/) 鍒嗘敮 | [`master-jdk25`](https://gitee.com/yudaocode/yudao-boot-mini/tree/master-jdk25/) 鍒嗘敮 |
-* 銆愬畬鏁寸増銆戯細鍖呮嫭绯荤粺鍔熻兘銆佸熀纭�璁炬柦銆佷細鍛樹腑蹇冦�佹暟鎹姤琛ㄣ�佸伐浣滄祦绋嬨�佸晢鍩庣郴缁熴�佸井淇″叕浼楀彿銆丆RM銆丒RP銆乄MS銆丮ES銆丄I 澶фā鍨嬨�両oT 鐗╄仈缃� 绛夊姛鑳�
-* 銆愮簿绠�鐗堛�戯細鍙寘鎷郴缁熷姛鑳姐�佸熀纭�璁炬柦鍔熻兘锛屼笉鍖呮嫭浼氬憳涓績銆佹暟鎹姤琛ㄣ�佸伐浣滄祦绋嬨�佸晢鍩庣郴缁熴�佸井淇″叕浼楀彿銆丆RM銆丒RP銆乄MS銆丮ES銆丄I 澶фā鍨嬨�両oT 鐗╄仈缃� 绛夊姛鑳�
+* 銆愬畬鏁寸増銆戯細鍖呮嫭绯荤粺鍔熻兘銆佸熀纭�璁炬柦銆佷細鍛樹腑蹇冦�佹暟鎹姤琛ㄣ�佸伐浣滄祦绋嬨�佸晢鍩庣郴缁熴�佸井淇″叕浼楀彿銆丆RM銆丒RP銆乄MS銆丮ES銆両M 鍗虫椂閫氳銆丄I 澶фā鍨嬨�両oT 鐗╄仈缃戠瓑鍔熻兘
+* 銆愮簿绠�鐗堛�戯細鍙寘鎷郴缁熷姛鑳姐�佸熀纭�璁炬柦鍔熻兘锛屼笉鍖呮嫭浼氬憳涓績銆佹暟鎹姤琛ㄣ�佸伐浣滄祦绋嬨�佸晢鍩庣郴缁熴�佸井淇″叕浼楀彿銆丆RM銆丒RP銆乄MS銆丮ES銆両M 鍗虫椂閫氳銆丄I 澶фā鍨嬨�両oT 鐗╄仈缃戠瓑鍔熻兘
鍙弬鑰� [銆婅縼绉绘枃妗c�媇(https://doc.iocoder.cn/migrate-module/) 锛屽彧闇�瑕� 5-10 鍒嗛挓锛屽嵆鍙皢銆愬畬鏁寸増銆戞寜闇�杩佺Щ鍒般�愮簿绠�鐗堛��
@@ -43,7 +43,7 @@
 |  |
+
## 馃惃 鎶�鏈爤
### 妯″潡
@@ -327,6 +340,7 @@
| `yudao-module-crm` | CRM 绯荤粺鐨� Module 妯″潡 |
| `yudao-module-mes` | MES 绯荤粺鐨� Module 妯″潡 |
| `yudao-module-wms` | WMS 绯荤粺鐨� Module 妯″潡 |
+| `yudao-module-im` | IM 鍗虫椂閫氳鐨� Module 妯″潡 |
| `yudao-module-ai` | AI 澶фā鍨嬬殑 Module 妯″潡 |
| `yudao-module-iot` | IoT 鐗╄仈缃戠殑 Module 妯″潡 |
| `yudao-module-mp` | 寰俊鍏紬鍙风殑 Module 妯″潡 |
@@ -336,42 +350,42 @@
| 妗嗘灦 | 璇存槑 | 鐗堟湰 | 瀛︿範鎸囧崡 |
|---------------------------------------------------------------------------------------------|------------------|----------------|----------------------------------------------------------------|
-| [Spring Boot](https://spring.io/projects/spring-boot) | 搴旂敤寮�鍙戞鏋� | 3.5.5 | [鏂囨。](https://github.com/YunaiV/SpringBoot-Labs) |
+| [Spring Boot](https://spring.io/projects/spring-boot) | 搴旂敤寮�鍙戞鏋� | 4.1.0 | [鏂囨。](https://github.com/YunaiV/SpringBoot-Labs) |
| [MySQL](https://www.mysql.com/cn/) | 鏁版嵁搴撴湇鍔″櫒 | 5.7 / 8.0+ | |
-| [Druid](https://github.com/alibaba/druid) | JDBC 杩炴帴姹犮�佺洃鎺х粍浠� | 1.2.27 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
-| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 澧炲己宸ュ叿鍖� | 3.5.12 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
-| [Dynamic Datasource](https://dynamic-datasource.com/) | 鍔ㄦ�佹暟鎹簮 | 4.3.1 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
+| [Druid](https://github.com/alibaba/druid) | JDBC 杩炴帴姹犮�佺洃鎺х粍浠� | 1.2.28 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
+| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 澧炲己宸ュ叿鍖� | 3.5.16 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
+| [Dynamic Datasource](https://dynamic-datasource.com/) | 鍔ㄦ�佹暟鎹簮 | 4.5.0 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
| [Redis](https://redis.io/) | key-value 鏁版嵁搴� | 5.0 / 6.0 /7.0 | |
-| [Redisson](https://github.com/redisson/redisson) | Redis 瀹㈡埛绔� | 3.35.0 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
-| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 妗嗘灦 | 6.2.9 | [鏂囨。](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
-| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 瀹夊叏妗嗘灦 | 6.5.2 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
-| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 鍙傛暟鏍¢獙缁勪欢 | 8.0.2 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
-| [Flowable](https://github.com/flowable/flowable-engine) | 宸ヤ綔娴佸紩鎿� | 7.0.0 | [鏂囨。](https://doc.iocoder.cn/bpm/) |
-| [Quartz](https://github.com/quartz-scheduler) | 浠诲姟璋冨害缁勪欢 | 2.5.0 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
-| [Springdoc](https://springdoc.org/) | Swagger 鏂囨。 | 2.8.9 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
-| [SkyWalking](https://skywalking.apache.org/) | 鍒嗗竷寮忓簲鐢ㄨ拷韪郴缁� | 9.5.0 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
-| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 鐩戞帶骞冲彴 | 3.5.2 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
-| [Jackson](https://github.com/FasterXML/jackson) | JSON 宸ュ叿搴� | 2.30.14 | |
+| [Redisson](https://github.com/redisson/redisson) | Redis 瀹㈡埛绔� | 4.6.1 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
+| [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 妗嗘灦 | 7.0.8 | [鏂囨。](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
+| [Spring Security](https://github.com/spring-projects/spring-security) | Spring 瀹夊叏妗嗘灦 | 7.1.0 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
+| [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 鍙傛暟鏍¢獙缁勪欢 | 9.1.0 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
+| [Flowable](https://github.com/flowable/flowable-engine) | 宸ヤ綔娴佸紩鎿� | 8.0.0 | [鏂囨。](https://doc.iocoder.cn/bpm/) |
+| [Quartz](https://github.com/quartz-scheduler) | 浠诲姟璋冨害缁勪欢 | 2.5.2 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
+| [Springdoc](https://springdoc.org/) | Swagger 鏂囨。 | 3.0.3 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
+| [SkyWalking](https://skywalking.apache.org/) | 鍒嗗竷寮忓簲鐢ㄨ拷韪郴缁� | 9.6.0 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
+| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 鐩戞帶骞冲彴 | 4.0.4 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
+| [Jackson](https://github.com/FasterXML/jackson) | JSON 宸ュ叿搴� | 3.1.4 | |
| [MapStruct](https://mapstruct.org/) | Java Bean 杞崲 | 1.6.3 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
-| [Lombok](https://projectlombok.org/) | 娑堥櫎鍐楅暱鐨� Java 浠g爜 | 1.18.38 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
-| [JUnit](https://junit.org/junit5/) | Java 鍗曞厓娴嬭瘯妗嗘灦 | 5.12.2 | - |
-| [Mockito](https://github.com/mockito/mockito) | Java Mock 妗嗘灦 | 5.17.0 | - |
+| [Lombok](https://projectlombok.org/) | 娑堥櫎鍐楅暱鐨� Java 浠g爜 | 1.18.46 | [鏂囨。](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
+| [JUnit](https://junit.org/junit5/) | Java 鍗曞厓娴嬭瘯妗嗘灦 | 6.0.3 | - |
+| [Mockito](https://github.com/mockito/mockito) | Java Mock 妗嗘灦 | 5.23.0 | - |
## 馃惙 婕旂ず鍥�
### 绯荤粺鍔熻兘
-| 妯″潡 | biu | biu | biu |
-|----------|-----------------------------|---------------------------|--------------------------|
+| 妯″潡 | biu | biu | biu |
+|----------|-----------------------------|---------------------------|---------------------------|
| 鐧诲綍 & 棣栭〉 |  |  |  |
| 鐢ㄦ埛 & 搴旂敤 |  |  |  |
-| 绉熸埛 & 濂楅 |  |  | - |
-| 閮ㄩ棬 & 宀椾綅 |  |  | - |
-| 鑿滃崟 & 瑙掕壊 |  |  | - |
-| 瀹¤鏃ュ織 |  |  | - |
+| 绉熸埛 & 濂楅 |  |  | - |
+| 閮ㄩ棬 & 宀椾綅 |  |  | - |
+| 鑿滃崟 & 瑙掕壊 |  |  | - |
+| 瀹¤鏃ュ織 |  |  | - |
| 鐭俊 |  |  |  |
-| 瀛楀吀 & 鏁忔劅璇� |  |  |  | - |
+| 瀛楀吀 & 鏁忔劅璇� |  |  |  | - |
### 宸ヤ綔娴佺▼
diff --git a/docs/123.png b/docs/123.png
deleted file mode 100644
index 6af739e..0000000
--- a/docs/123.png
+++ /dev/null
Binary files differ
diff --git a/docs/batch1/database_changes.sql b/docs/batch1/database_changes.sql
deleted file mode 100644
index 985291c..0000000
--- a/docs/batch1/database_changes.sql
+++ /dev/null
@@ -1,166 +0,0 @@
--- =====================================================
--- Batch 1: WMS API 妯″潡寤鸿 - 鏁版嵁搴撳彉鏇磋剼鏈�
--- 鐗堟湰: v1.0
--- 鏃ユ湡: 2026-06-26
--- 璇存槑: 鏂板搴撳瓨棰勭暀鐩稿叧琛紝鎵╁睍搴撳瓨瀛楁
--- =====================================================
-
--- =====================================================
--- 1. 鏂板搴撳瓨棰勭暀琛�
--- =====================================================
-
--- 搴撳瓨棰勭暀琛紙鐢ㄤ簬閿�鍞鍗曠瓑涓氬姟棰勭暀搴撳瓨锛�
-CREATE TABLE IF NOT EXISTS `wms_inventory_reserve` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `reserve_no` VARCHAR(64) NOT NULL COMMENT '棰勭暀鍗曞彿',
- `biz_type` INT NOT NULL COMMENT '涓氬姟绫诲瀷锛�10=閿�鍞鐣� 20=鐢熶骇棰勭暀锛�',
- `biz_id` BIGINT NOT NULL COMMENT '涓氬姟鍗曟嵁ID',
- `biz_no` VARCHAR(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁鍙�',
- `sku_id` BIGINT NOT NULL COMMENT 'SKU缂栧彿',
- `warehouse_id` BIGINT NOT NULL COMMENT '浠撳簱缂栧彿',
- `reserve_quantity` DECIMAL(24,6) NOT NULL COMMENT '棰勭暀鏁伴噺',
- `used_quantity` DECIMAL(24,6) DEFAULT 0 COMMENT '宸蹭娇鐢ㄦ暟閲�',
- `status` INT NOT NULL DEFAULT 0 COMMENT '鐘舵�侊紙0=棰勭暀涓� 1=閮ㄥ垎浣跨敤 2=宸蹭娇鐢� 3=宸查噴鏀撅級',
- `expire_time` DATETIME DEFAULT NULL COMMENT '杩囨湡鏃堕棿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_reserve_no` (`reserve_no`),
- KEY `idx_biz` (`biz_type`, `biz_id`),
- KEY `idx_sku_warehouse` (`sku_id`, `warehouse_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='搴撳瓨棰勭暀琛�';
-
--- =====================================================
--- 2. 鏂板搴撳瓨浜嬪姟娴佹按琛�
--- =====================================================
-
-CREATE TABLE IF NOT EXISTS `wms_inventory_transaction` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `transaction_no` VARCHAR(64) NOT NULL COMMENT '浜嬪姟娴佹按鍙�',
- `transaction_type` INT NOT NULL COMMENT '浜嬪姟绫诲瀷锛�10=鍏ュ簱 20=鍑哄簱 30=棰勭暀 40=閲婃斁 50=鐩樼偣 60=璋冩嫧锛�',
- `biz_type` INT NOT NULL COMMENT '涓氬姟绫诲瀷',
- `biz_id` BIGINT NOT NULL COMMENT '涓氬姟鍗曟嵁ID',
- `biz_no` VARCHAR(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁鍙�',
- `sku_id` BIGINT NOT NULL COMMENT 'SKU缂栧彿',
- `warehouse_id` BIGINT NOT NULL COMMENT '浠撳簱缂栧彿',
- `quantity` DECIMAL(24,6) NOT NULL COMMENT '鍙樺姩鏁伴噺锛堟鏁板叆搴擄紝璐熸暟鍑哄簱锛�',
- `before_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍙樺姩鍓嶆暟閲�',
- `after_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍙樺姩鍚庢暟閲�',
- `reserve_id` BIGINT DEFAULT NULL COMMENT '鍏宠仈棰勭暀ID',
- `reserve_no` VARCHAR(64) DEFAULT NULL COMMENT '鍏宠仈棰勭暀鍗曞彿',
- `transaction_time` DATETIME NOT NULL COMMENT '浜嬪姟鏃堕棿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_transaction_no` (`transaction_no`),
- KEY `idx_biz` (`biz_type`, `biz_id`),
- KEY `idx_sku` (`sku_id`),
- KEY `idx_transaction_time` (`transaction_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='搴撳瓨浜嬪姟娴佹按琛�';
-
--- =====================================================
--- 3. 鏁版嵁瀛楀吀鏂板
--- =====================================================
-
--- 搴撳瓨棰勭暀涓氬姟绫诲瀷
-INSERT INTO `system_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES ('WMS 搴撳瓨棰勭暀涓氬姟绫诲瀷', 'wms_reserve_biz_type', 0, '搴撳瓨棰勭暀鐨勪笟鍔℃潵婧愮被鍨�', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `name` = 'WMS 搴撳瓨棰勭暀涓氬姟绫诲瀷';
-
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES
-(10, '閿�鍞鐣�', '10', 'wms_reserve_biz_type', 0, 'primary', '', '閿�鍞鍗曢鐣欏簱瀛�', '1', NOW(), '1', NOW(), b'0'),
-(20, '鐢熶骇棰勭暀', '20', 'wms_reserve_biz_type', 0, 'success', '', '鐢熶骇宸ュ崟棰勭暀搴撳瓨', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `label` = VALUES(`label`);
-
--- 搴撳瓨浜嬪姟绫诲瀷
-INSERT INTO `system_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES ('WMS 搴撳瓨浜嬪姟绫诲瀷', 'wms_transaction_type', 0, '搴撳瓨浜嬪姟娴佹按绫诲瀷', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `name` = 'WMS 搴撳瓨浜嬪姟绫诲瀷';
-
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES
-(10, '鍏ュ簱', '10', 'wms_transaction_type', 0, 'success', '', '搴撳瓨鍏ュ簱', '1', NOW(), '1', NOW(), b'0'),
-(20, '鍑哄簱', '20', 'wms_transaction_type', 0, 'warning', '', '搴撳瓨鍑哄簱', '1', NOW(), '1', NOW(), b'0'),
-(30, '棰勭暀', '30', 'wms_transaction_type', 0, 'primary', '', '搴撳瓨棰勭暀', '1', NOW(), '1', NOW(), b'0'),
-(40, '閲婃斁', '40', 'wms_transaction_type', 0, 'info', '', '棰勭暀閲婃斁', '1', NOW(), '1', NOW(), b'0'),
-(50, '鐩樼偣', '50', 'wms_transaction_type', 0, 'default', '', '搴撳瓨鐩樼偣', '1', NOW(), '1', NOW(), b'0'),
-(60, '璋冩嫧', '60', 'wms_transaction_type', 0, 'default', '', '搴撳瓨璋冩嫧', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `label` = VALUES(`label`);
-
--- 搴撳瓨棰勭暀鐘舵��
-INSERT INTO `system_dict_type` (`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES ('WMS 搴撳瓨棰勭暀鐘舵��', 'wms_reserve_status', 0, '搴撳瓨棰勭暀鐘舵��', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `name` = 'WMS 搴撳瓨棰勭暀鐘舵��';
-
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES
-(0, '棰勭暀涓�', '0', 'wms_reserve_status', 0, 'primary', '', '搴撳瓨棰勭暀涓�', '1', NOW(), '1', NOW(), b'0'),
-(1, '閮ㄥ垎浣跨敤', '1', 'wms_reserve_status', 0, 'warning', '', '閮ㄥ垎宸蹭娇鐢�', '1', NOW(), '1', NOW(), b'0'),
-(2, '宸蹭娇鐢�', '2', 'wms_reserve_status', 0, 'success', '', '宸插叏閮ㄤ娇鐢�', '1', NOW(), '1', NOW(), b'0'),
-(3, '宸查噴鏀�', '3', 'wms_reserve_status', 0, 'info', '', '棰勭暀宸查噴鏀�', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `label` = VALUES(`label`);
-
--- =====================================================
--- 4. 鑿滃崟鏂板锛堝簱瀛橀鐣欑鐞嗭級
--- =====================================================
-
--- 搴撳瓨棰勭暀鏀惧湪"搴撳瓨绠$悊"鑿滃崟涓嬶紙ID: 6440锛�
--- 濡傛灉搴撳瓨绠$悊鑿滃崟涓嶅瓨鍦紝鍒欐斁鍦� WMS 绯荤粺鑿滃崟涓嬶紙ID: 6400锛�
-
--- 鏂规涓�锛氫娇鐢ㄥ浐瀹氱殑搴撳瓨绠$悊鑿滃崟ID锛堟帹鑽愶紝濡傛灉鏁版嵁搴撶粨鏋勪竴鑷达級
--- SET @inventory_menu_id = 6440;
-
--- 鏂规浜岋細鍔ㄦ�佹煡璇㈠簱瀛樼鐞嗚彍鍗旾D锛堟洿瀹夊叏锛�
-SET @inventory_menu_id = (SELECT `id` FROM `system_menu` WHERE `name` = '搴撳瓨绠$悊' AND `parent_id` = 6400 AND `deleted` = b'0' LIMIT 1);
-
--- 濡傛灉搴撳瓨绠$悊鑿滃崟涓嶅瓨鍦紝浣跨敤 WMS 绯荤粺鑿滃崟ID
-SET @inventory_menu_id = IFNULL(@inventory_menu_id, 6400);
-
--- 鏂板搴撳瓨棰勭暀鑿滃崟
-INSERT INTO `system_menu` (`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES ('搴撳瓨棰勭暀', '', 2, 30, @inventory_menu_id, 'reserve', 'ep:lock', 'wms/inventory/reserve/index', 'WmsInventoryReserve', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `name` = '搴撳瓨棰勭暀';
-
--- 鑾峰彇鑿滃崟ID
-SET @reserve_menu_id = (SELECT `id` FROM `system_menu` WHERE `path` = 'reserve' AND `parent_id` = @inventory_menu_id AND `deleted` = b'0');
-
--- 鏌ヨ鎸夐挳
-INSERT INTO `system_menu` (`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES ('搴撳瓨棰勭暀鏌ヨ', 'wms:inventory-reserve:query', 3, 1, @reserve_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `permission` = 'wms:inventory-reserve:query';
-
--- 閲婃斁鎸夐挳
-INSERT INTO `system_menu` (`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES ('搴撳瓨棰勭暀閲婃斁', 'wms:inventory-reserve:release', 3, 2, @reserve_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `permission` = 'wms:inventory-reserve:release';
-
--- =====================================================
--- 鍥炴粴鑴氭湰锛堝闇�鍥炴粴锛屾墽琛屼互涓嬭鍙ワ級
--- =====================================================
-
-/*
--- 鍒犻櫎鏂板琛�
-DROP TABLE IF EXISTS `wms_inventory_reserve`;
-DROP TABLE IF EXISTS `wms_inventory_transaction`;
-
--- 鍒犻櫎瀛楀吀
-DELETE FROM `system_dict_type` WHERE `type` = 'wms_reserve_biz_type';
-DELETE FROM `system_dict_data` WHERE `dict_type` = 'wms_reserve_biz_type';
-DELETE FROM `system_dict_type` WHERE `type` = 'wms_transaction_type';
-DELETE FROM `system_dict_data` WHERE `dict_type` = 'wms_transaction_type';
-DELETE FROM `system_dict_type` WHERE `type` = 'wms_reserve_status';
-DELETE FROM `system_dict_data` WHERE `dict_type` = 'wms_reserve_status';
-
--- 鍒犻櫎鑿滃崟
-DELETE FROM `system_menu` WHERE `path` = 'reserve' AND `name` = '搴撳瓨棰勭暀';
-DELETE FROM `system_menu` WHERE `permission` LIKE 'wms:inventory-reserve:%';
-*/
\ No newline at end of file
diff --git a/docs/batch1/frontend_changes.md b/docs/batch1/frontend_changes.md
deleted file mode 100644
index 8afd949..0000000
--- a/docs/batch1/frontend_changes.md
+++ /dev/null
@@ -1,321 +0,0 @@
-# Batch 1: WMS API 妯″潡寤鸿 - 鍓嶇淇敼鏂囨。
-
-## 娑夊強椤甸潰
-
-- 鏂板椤甸潰锛氬簱瀛橀鐣欑鐞嗛〉闈�
-- 淇敼椤甸潰锛氬簱瀛樻煡璇㈤〉闈紙鏂板棰勭暀鏁伴噺鏄剧ず锛�
-
----
-
-## API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| GET | /wms/inventory-reserve/page | 搴撳瓨棰勭暀鍒嗛〉鏌ヨ |
-| POST | /wms/inventory-reserve/release | 閲婃斁搴撳瓨棰勭暀 |
-| GET | /wms/inventory-reserve/get | 鑾峰彇棰勭暀璇︽儏 |
-
-**璇锋眰鍙傛暟锛堝垎椤垫煡璇級锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| pageNo | Integer | 鏄� | 椤电爜 |
-| pageSize | Integer | 鏄� | 姣忛〉鏁伴噺 |
-| reserveNo | String | 鍚� | 棰勭暀鍗曞彿 |
-| bizType | Integer | 鍚� | 涓氬姟绫诲瀷 |
-| bizNo | String | 鍚� | 涓氬姟鍗曟嵁鍙� |
-| status | Integer | 鍚� | 鐘舵�� |
-
-**鍝嶅簲锛�**
-
-```json
-{
- "code": 0,
- "data": {
- "list": [
- {
- "id": 1,
- "reserveNo": "RES202606260001",
- "bizType": 10,
- "bizTypeName": "閿�鍞鐣�",
- "bizId": 100,
- "bizNo": "SO202606260001",
- "skuId": 1,
- "skuName": "鍟嗗搧A-绾㈣壊-L",
- "warehouseId": 1,
- "warehouseName": "涓讳粨搴�",
- "reserveQuantity": 100.00,
- "usedQuantity": 0.00,
- "status": 0,
- "statusName": "棰勭暀涓�",
- "expireTime": "2026-06-30 00:00:00",
- "createTime": "2026-06-26 10:00:00"
- }
- ],
- "total": 1
- }
-}
-```
-
----
-
-## 鍓嶇淇敼鐐�
-
-### 1. 鏂板搴撳瓨棰勭暀绠$悊椤甸潰
-
-**鏂囦欢璺緞锛�** `src/views/wms/inventory/reserve/index.vue`
-
-```vue
-<template>
- <ContentWrap>
- <!-- 鎼滅储 -->
- <el-form
- class="-mb-15px"
- :model="queryParams"
- :inline="true"
- label-width="68px"
- >
- <el-form-item label="棰勭暀鍗曞彿" prop="reserveNo">
- <el-input
- v-model="queryParams.reserveNo"
- placeholder="璇疯緭鍏ラ鐣欏崟鍙�"
- clearable
- @keyup.enter="handleQuery"
- class="!w-240px"
- />
- </el-form-item>
- <el-form-item label="涓氬姟绫诲瀷" prop="bizType">
- <el-select
- v-model="queryParams.bizType"
- placeholder="璇烽�夋嫨涓氬姟绫诲瀷"
- clearable
- class="!w-240px"
- >
- <el-option
- v-for="dict in getIntDictOptions(DICT_TYPE.WMS_RESERVE_BIZ_TYPE)"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="鐘舵��" prop="status">
- <el-select
- v-model="queryParams.status"
- placeholder="璇烽�夋嫨鐘舵��"
- clearable
- class="!w-240px"
- >
- <el-option
- v-for="dict in getIntDictOptions(DICT_TYPE.WMS_RESERVE_STATUS)"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" />鎼滅储</el-button>
- <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" />閲嶇疆</el-button>
- </el-form-item>
- </el-form>
- </ContentWrap>
-
- <!-- 鍒楄〃 -->
- <ContentWrap class="mt-10px">
- <el-table v-loading="loading" :data="list" :stripe="true">
- <el-table-column label="棰勭暀鍗曞彿" align="center" prop="reserveNo" width="180" />
- <el-table-column label="涓氬姟绫诲瀷" align="center" prop="bizTypeName" width="100" />
- <el-table-column label="涓氬姟鍗曟嵁鍙�" align="center" prop="bizNo" width="180" />
- <el-table-column label="鍟嗗搧SKU" align="center" prop="skuName" width="200" />
- <el-table-column label="浠撳簱" align="center" prop="warehouseName" width="120" />
- <el-table-column label="棰勭暀鏁伴噺" align="center" prop="reserveQuantity" width="100" />
- <el-table-column label="宸蹭娇鐢ㄦ暟閲�" align="center" prop="usedQuantity" width="100" />
- <el-table-column label="鐘舵��" align="center" prop="statusName" width="100">
- <template #default="scope">
- <dict-tag :type="DICT_TYPE.WMS_RESERVE_STATUS" :value="scope.row.status" />
- </template>
- </el-table-column>
- <el-table-column
- label="杩囨湡鏃堕棿"
- align="center"
- prop="expireTime"
- :formatter="dateFormatter"
- width="180"
- />
- <el-table-column label="鎿嶄綔" align="center" fixed="right" width="100">
- <template #default="scope">
- <el-button
- link
- type="primary"
- @click="handleRelease(scope.row)"
- v-hasPermi="['wms:inventory-reserve:release']"
- v-if="scope.row.status === 0 || scope.row.status === 1"
- >
- 閲婃斁
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- <!-- 鍒嗛〉 -->
- <Pagination
- :total="total"
- v-model:page="queryParams.pageNo"
- v-model:limit="queryParams.pageSize"
- @pagination="getList"
- />
- </ContentWrap>
-</template>
-
-<script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import * as ReserveApi from '@/api/wms/inventory/reserve'
-
-defineOptions({ name: 'WmsInventoryReserve' })
-
-const loading = ref(true)
-const list = ref([])
-const total = ref(0)
-const queryParams = reactive({
- pageNo: 1,
- pageSize: 10,
- reserveNo: undefined,
- bizType: undefined,
- bizNo: undefined,
- status: undefined
-})
-
-/** 鏌ヨ鍒楄〃 */
-const getList = async () => {
- loading.value = true
- try {
- const data = await ReserveApi.getInventoryReservePage(queryParams)
- list.value = data.list
- total.value = data.total
- } finally {
- loading.value = false
- }
-}
-
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
- queryParams.pageNo = 1
- getList()
-}
-
-/** 閲嶇疆鎸夐挳鎿嶄綔 */
-const resetQuery = () => {
- queryParams.reserveNo = undefined
- queryParams.bizType = undefined
- queryParams.bizNo = undefined
- queryParams.status = undefined
- handleQuery()
-}
-
-/** 閲婃斁棰勭暀 */
-const handleRelease = async (row: any) => {
- try {
- await message.delConfirm(`纭閲婃斁棰勭暀鍗曞彿銆�${row.reserveNo}銆戠殑搴撳瓨棰勭暀锛焋)
- await ReserveApi.releaseInventoryReserve(row.id)
- message.success('閲婃斁鎴愬姛')
- await getList()
- } catch {}
-}
-
-/** 鍒濆鍖� */
-onMounted(() => {
- getList()
-})
-</script>
-```
-
-### 2. 鏂板 API 鎺ュ彛鏂囦欢
-
-**鏂囦欢璺緞锛�** `src/api/wms/inventory/reserve/index.ts`
-
-```typescript
-import request from '@/config/axios'
-
-// 搴撳瓨棰勭暀鍒嗛〉鏌ヨ
-export const getInventoryReservePage = async (params: any) => {
- return await request.get({ url: '/wms/inventory-reserve/page', params })
-}
-
-// 鑾峰彇搴撳瓨棰勭暀璇︽儏
-export const getInventoryReserve = async (id: number) => {
- return await request.get({ url: '/wms/inventory-reserve/get?id=' + id })
-}
-
-// 閲婃斁搴撳瓨棰勭暀
-export const releaseInventoryReserve = async (id: number) => {
- return await request.post({ url: '/wms/inventory-reserve/release?id=' + id })
-}
-```
-
-### 3. 瀛楀吀绫诲瀷鏂板
-
-**鏂囦欢璺緞锛�** `src/utils/dict.ts`
-
-鍦� `DICT_TYPE` 涓柊澧烇細
-
-```typescript
-WMS_RESERVE_BIZ_TYPE = 'wms_reserve_biz_type',
-WMS_RESERVE_STATUS = 'wms_reserve_status',
-WMS_TRANSACTION_TYPE = 'wms_transaction_type'
-```
-
----
-
-## 娉ㄦ剰浜嬮」
-
-1. 鏈壒娆′富瑕佹柊澧炲簱瀛橀鐣欏姛鑳斤紝鍓嶇鏀瑰姩杈冨皬
-2. 搴撳瓨棰勭暀椤甸潰鎻愪緵棰勭暀鏌ヨ鍜屾墜鍔ㄩ噴鏀惧姛鑳�
-3. 鍚庣画鎵规锛圗RP/MES 闆嗘垚锛変細鑷姩璋冪敤棰勭暀 API锛屾棤闇�鍓嶇骞查
-4. 寤鸿鍏堟墽琛屾暟鎹簱鑴氭湰锛屽啀閮ㄧ讲鍚庣浠g爜锛屾渶鍚庢洿鏂板墠绔�
-
----
-
-## 鍚庣鏂板鏂囦欢娓呭崟
-
-```
-yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/
-鈹溾攢鈹� api/inventory/
-鈹� 鈹溾攢鈹� WmsInventoryApi.java
-鈹� 鈹溾攢鈹� WmsInventoryApiImpl.java
-鈹� 鈹斺攢鈹� dto/
-鈹� 鈹溾攢鈹� WmsInventoryQueryReqDTO.java
-鈹� 鈹溾攢鈹� WmsInventoryRespDTO.java
-鈹� 鈹溾攢鈹� WmsReceiptReqDTO.java
-鈹� 鈹溾攢鈹� WmsReceiptResultDTO.java
-鈹� 鈹溾攢鈹� WmsReserveReqDTO.java
-鈹� 鈹溾攢鈹� WmsShipmentReqDTO.java
-鈹� 鈹溾攢鈹� WmsShipmentResultDTO.java
-鈹� 鈹斺攢鈹� WmsUseReserveReqDTO.java
-鈹溾攢鈹� controller/admin/inventory/
-鈹� 鈹溾攢鈹� WmsInventoryReserveController.java
-鈹� 鈹斺攢鈹� vo/
-鈹� 鈹溾攢鈹� WmsInventoryReservePageReqVO.java
-鈹� 鈹斺攢鈹� WmsInventoryReserveRespVO.java
-鈹溾攢鈹� dal/dataobject/inventory/
-鈹� 鈹溾攢鈹� WmsInventoryReserveDO.java
-鈹� 鈹斺攢鈹� WmsInventoryTransactionDO.java
-鈹溾攢鈹� dal/mysql/inventory/
-鈹� 鈹溾攢鈹� WmsInventoryReserveMapper.java
-鈹� 鈹斺攢鈹� WmsInventoryTransactionMapper.java
-鈹溾攢鈹� enums/inventory/
-鈹� 鈹溾攢鈹� WmsInventoryBizTypeEnum.java
-鈹� 鈹溾攢鈹� WmsReserveBizTypeEnum.java
-鈹� 鈹溾攢鈹� WmsReserveStatusEnum.java
-鈹� 鈹斺攢鈹� WmsTransactionTypeEnum.java
-鈹斺攢鈹� service/inventory/
- 鈹溾攢鈹� WmsInventoryReserveService.java
- 鈹溾攢鈹� WmsInventoryReserveServiceImpl.java
- 鈹溾攢鈹� WmsInventoryTransactionService.java
- 鈹斺攢鈹� WmsInventoryTransactionServiceImpl.java
-```
-
----
-
-**鏂囨。鐗堟湰**: v1.0
-**鍒涘缓鏃ユ湡**: 2026-06-26
diff --git a/docs/batch2/database_changes.sql b/docs/batch2/database_changes.sql
deleted file mode 100644
index 3b687c2..0000000
--- a/docs/batch2/database_changes.sql
+++ /dev/null
@@ -1,92 +0,0 @@
--- =====================================================
--- Batch 2: ERP 閲囪喘璁㈠崟瀹℃壒闆嗘垚 - 鏁版嵁搴撳彉鏇磋剼鏈�
--- 鐗堟湰: v1.0
--- 鏃ユ湡: 2026-06-26
--- 璇存槑: 涓� ERP 閲囪喘璁㈠崟娣诲姞 BPM 娴佺▼瀹℃壒闆嗘垚
--- =====================================================
-
--- =====================================================
--- 1. 淇敼閲囪喘璁㈠崟琛紝鏂板娴佺▼瀹炰緥瀛楁
--- =====================================================
-
--- 鏂板娴佺▼瀹炰緥缂栧彿瀛楁
-ALTER TABLE `erp_purchase_order`
-ADD COLUMN `process_instance_id` VARCHAR(64) DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿' AFTER `remark`;
-
--- =====================================================
--- 2. 鏁版嵁瀛楀吀淇敼锛堝鏍哥姸鎬侊級
--- =====================================================
-
--- 娉ㄦ剰锛欵RP 瀹℃牳鐘舵�佸凡鏈夊瓧鍏告暟鎹紝杩欓噷浠呰ˉ鍏呮柊澧炵姸鎬�
--- 鍘� PROCESS(10) 浠�"鏈鏍�"鏀逛负"瀹℃壒涓�"
--- 鍘� APPROVE(20) 浠�"宸插鏍�"鏀逛负"瀹℃壒閫氳繃"
--- 鏂板 DRAFT(0) 鑽夌鐘舵��
--- 鏂板 REJECT(30) 瀹℃壒涓嶉�氳繃鐘舵��
-
--- 鏇存柊鐜版湁瀛楀吀鏁版嵁鐨勬爣绛�
-UPDATE `system_dict_data`
-SET `label` = '瀹℃壒涓�'
-WHERE `dict_type` = 'erp_audit_status' AND `value` = '10';
-
-UPDATE `system_dict_data`
-SET `label` = '瀹℃壒閫氳繃'
-WHERE `dict_type` = 'erp_audit_status' AND `value` = '20';
-
--- 鏂板鑽夌鐘舵�侊紙濡傛灉涓嶅瓨鍦級
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT 0, '鑽夌', '0', 'erp_audit_status', 0, 'info', '', '璁㈠崟鑽夌鐘舵��', '1', NOW(), '1', NOW(), b'0'
-FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `system_dict_data` WHERE `dict_type` = 'erp_audit_status' AND `value` = '0');
-
--- 鏂板瀹℃壒涓嶉�氳繃鐘舵�侊紙濡傛灉涓嶅瓨鍦級
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT 30, '瀹℃壒涓嶉�氳繃', '30', 'erp_audit_status', 0, 'danger', '', '瀹℃壒涓嶉�氳繃', '1', NOW(), '1', NOW(), b'0'
-FROM DUAL
-WHERE NOT EXISTS (SELECT 1 FROM `system_dict_data` WHERE `dict_type` = 'erp_audit_status' AND `value` = '30');
-
--- =====================================================
--- 3. 鑿滃崟鏂板锛堟彁浜ゅ鎵规寜閽級
--- =====================================================
-
--- 鑾峰彇閲囪喘璁㈠崟鑿滃崟ID
-SET @purchase_order_menu_id = (SELECT `id` FROM `system_menu` WHERE `path` = 'purchase-order' AND `deleted` = b'0' LIMIT 1);
-
--- 濡傛灉閲囪喘璁㈠崟鑿滃崟涓嶅瓨鍦紝灏濊瘯閫氳繃鍚嶇О鏌ユ壘
-SET @purchase_order_menu_id = IFNULL(@purchase_order_menu_id,
- (SELECT `id` FROM `system_menu` WHERE `name` = '閲囪喘璁㈠崟' AND `deleted` = b'0' LIMIT 1));
-
--- 鏂板鎻愪氦瀹℃壒鎸夐挳
-INSERT INTO `system_menu` (`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT '閲囪喘璁㈠崟鎻愪氦瀹℃壒', 'erp:purchase-order:submit', 3, 10, @purchase_order_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM DUAL
-WHERE @purchase_order_menu_id IS NOT NULL
-ON DUPLICATE KEY UPDATE `permission` = 'erp:purchase-order:submit';
-
--- =====================================================
--- 4. BPM 娴佺▼瀹氫箟锛堥渶瑕佸湪鍓嶇鍒涘缓娴佺▼妯″瀷锛�
--- =====================================================
-
--- 鎻愮ず锛氳鍦� BPM 绠$悊鍚庡彴鍒涘缓娴佺▼妯″瀷
--- 娴佺▼鏍囪瘑锛圞ey锛夛細erp-purchase-order-audit
--- 娴佺▼鍚嶇О锛欵RP 閲囪喘璁㈠崟瀹℃壒娴佺▼
--- 涓氬姟鍏宠仈锛氶噰璐鍗� ID
-
--- =====================================================
--- 鍥炴粴鑴氭湰锛堝闇�鍥炴粴锛屾墽琛屼互涓嬭鍙ワ級
--- =====================================================
-
-/*
--- 鍒犻櫎鏂板瀛楁
-ALTER TABLE `erp_purchase_order` DROP COLUMN `process_instance_id`;
-
--- 鎭㈠瀛楀吀鏁版嵁鏍囩
-UPDATE `system_dict_data` SET `label` = '鏈鏍�' WHERE `dict_type` = 'erp_audit_status' AND `value` = '10';
-UPDATE `system_dict_data` SET `label` = '宸插鏍�' WHERE `dict_type` = 'erp_audit_status' AND `value` = '20';
-
--- 鍒犻櫎鏂板瀛楀吀鏁版嵁
-DELETE FROM `system_dict_data` WHERE `dict_type` = 'erp_audit_status' AND `value` = '0';
-DELETE FROM `system_dict_data` WHERE `dict_type` = 'erp_audit_status' AND `value` = '30';
-
--- 鍒犻櫎鏂板鑿滃崟
-DELETE FROM `system_menu` WHERE `permission` = 'erp:purchase-order:submit';
-*/
\ No newline at end of file
diff --git a/docs/batch2/frontend_changes.md b/docs/batch2/frontend_changes.md
deleted file mode 100644
index a5370b8..0000000
--- a/docs/batch2/frontend_changes.md
+++ /dev/null
@@ -1,229 +0,0 @@
-# Batch 2: ERP 閲囪喘璁㈠崟瀹℃壒闆嗘垚 - 鍓嶇淇敼鏂囨。
-
-## 姒傝堪
-
-鏈壒娆′负 ERP 閲囪喘璁㈠崟妯″潡闆嗘垚 BPM 娴佺▼瀹℃壒鍔熻兘锛屽疄鐜伴噰璐鍗曠殑瀹℃壒娴佺▼鍖栫鐞嗐��
-
-## 娑夊強椤甸潰
-
-- 淇敼椤甸潰锛氶噰璐鍗曠鐞嗛〉闈紙鏂板鎻愪氦瀹℃壒銆佸鎵圭姸鎬佸睍绀猴級
-- 鏂板閰嶇疆锛欱PM 娴佺▼妯″瀷閰嶇疆
-
----
-
-## API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /erp/purchase-order/submit | 鎻愪氦閲囪喘璁㈠崟瀹℃壒 |
-
-**璇锋眰鍙傛暟锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| id | Long | 鏄� | 閲囪喘璁㈠崟缂栧彿 |
-
-**鍝嶅簲锛�**
-
-```json
-{
- "code": 0,
- "data": true,
- "msg": "鎿嶄綔鎴愬姛"
-}
-```
-
----
-
-## 鍓嶇淇敼鐐�
-
-### 1. 閲囪喘璁㈠崟鍒楄〃椤甸潰淇敼
-
-**鏂囦欢璺緞锛�** `src/views/erp/purchase/order/index.vue`
-
-#### 1.1 鏂板鎻愪氦瀹℃壒鎸夐挳
-
-鍦ㄦ搷浣滃垪鏂板"鎻愪氦瀹℃壒"鎸夐挳锛屼粎鑽夌鐘舵�佸彲瑙侊細
-
-```vue
-<el-table-column label="鎿嶄綔" align="center" fixed="right" width="200">
- <template #default="scope">
- <el-button
- link
- type="primary"
- @click="handleUpdate(scope.row.id)"
- v-hasPermi="['erp:purchase-order:update']"
- v-if="scope.row.status === 0"
- >
- 缂栬緫
- </el-button>
- <el-button
- link
- type="primary"
- @click="handleSubmit(scope.row.id)"
- v-hasPermi="['erp:purchase-order:update']"
- v-if="scope.row.status === 0"
- >
- 鎻愪氦瀹℃壒
- </el-button>
- <el-button
- link
- type="primary"
- @click="handleApprove(scope.row.id)"
- v-hasPermi="['erp:purchase-order:update-status']"
- v-if="scope.row.status === 10"
- >
- 瀹℃壒閫氳繃
- </el-button>
- <el-button
- link
- type="danger"
- @click="handleDelete(scope.row.id)"
- v-hasPermi="['erp:purchase-order:delete']"
- v-if="scope.row.status === 0 || scope.row.status === 30"
- >
- 鍒犻櫎
- </el-button>
- </template>
-</el-table-column>
-```
-
-#### 1.2 鏂板鎻愪氦瀹℃壒鏂规硶
-
-```typescript
-/** 鎻愪氦瀹℃壒 */
-const handleSubmit = async (id: number) => {
- try {
- await message.confirm('纭鎻愪氦璇ラ噰璐鍗曡繘琛屽鎵癸紵')
- await PurchaseOrderApi.submitPurchaseOrder(id)
- message.success('鎻愪氦鎴愬姛')
- await getList()
- } catch {}
-}
-```
-
-#### 1.3 淇敼鐘舵�佸垪鏄剧ず
-
-```vue
-<el-table-column label="鐘舵��" align="center" prop="status" width="100">
- <template #default="scope">
- <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" />
- </template>
-</el-table-column>
-```
-
-### 2. API 鎺ュ彛鏂囦欢淇敼
-
-**鏂囦欢璺緞锛�** `src/api/erp/purchase/order/index.ts`
-
-鏂板鎻愪氦瀹℃壒鎺ュ彛锛�
-
-```typescript
-// 鎻愪氦閲囪喘璁㈠崟瀹℃壒
-export const submitPurchaseOrder = async (id: number) => {
- return await request.post({ url: '/erp/purchase-order/submit?id=' + id })
-}
-```
-
-### 3. 瀛楀吀绫诲瀷纭
-
-**鏂囦欢璺緞锛�** `src/utils/dict.ts`
-
-纭繚 `DICT_TYPE` 涓凡鍖呭惈锛�
-
-```typescript
-ERP_AUDIT_STATUS = 'erp_audit_status'
-```
-
-瀛楀吀鏁版嵁闇�瑕佸寘鍚互涓嬪�硷細
-- 0: 鑽夌锛坕nfo 棰滆壊锛�
-- 10: 瀹℃壒涓紙warning 棰滆壊锛�
-- 20: 瀹℃壒閫氳繃锛坰uccess 棰滆壊锛�
-- 30: 瀹℃壒涓嶉�氳繃锛坉anger 棰滆壊锛�
-
----
-
-## BPM 娴佺▼妯″瀷閰嶇疆
-
-### 娴佺▼妯″瀷淇℃伅
-
-鍦� BPM 绠$悊鍚庡彴鍒涘缓娴佺▼妯″瀷锛�
-
-| 閰嶇疆椤� | 鍊� |
-|--------|-----|
-| 娴佺▼鏍囪瘑锛圞ey锛� | erp-purchase-order-audit |
-| 娴佺▼鍚嶇О | ERP 閲囪喘璁㈠崟瀹℃壒娴佺▼ |
-| 娴佺▼鍒嗙被 | 涓氬姟娴佺▼ |
-
-### 娴佺▼璁捐寤鸿
-
-```
-寮�濮嬭妭鐐� 鈫� 閮ㄩ棬涓荤瀹℃壒 鈫� 閲囪喘缁忕悊瀹℃壒 鈫� 缁撴潫鑺傜偣
-```
-
-瀹℃壒缁撴灉锛�
-- 閫氳繃锛氱姸鎬佸彉涓� 20锛堝鎵归�氳繃锛�
-- 涓嶉�氳繃锛氱姸鎬佸彉涓� 30锛堝鎵逛笉閫氳繃锛�
-- 鍙栨秷锛氱姸鎬佸彉涓� 0锛堣崏绋匡級
-
----
-
-## 娉ㄦ剰浜嬮」
-
-1. 鍒涘缓閲囪喘璁㈠崟鏃讹紝榛樿鐘舵�佷粠"鏈鏍�"鏀逛负"鑽夌"
-2. 鍙湁鑽夌鐘舵�佺殑璁㈠崟鎵嶈兘鎻愪氦瀹℃壒
-3. 瀹℃壒涓殑璁㈠崟涓嶈兘缂栬緫鍜屽垹闄�
-4. 瀹℃壒涓嶉�氳繃鐨勮鍗曞彲浠ラ噸鏂扮紪杈戝悗鍐嶆鎻愪氦
-5. 闇�瑕佸厛鎵ц鏁版嵁搴撹剼鏈紝鍐嶉儴缃插悗绔唬鐮�
-6. 闇�瑕佸湪 BPM 绠$悊鍚庡彴鍒涘缓娴佺▼妯″瀷锛圞ey: erp-purchase-order-audit锛�
-
----
-
-## 鍚庣鏂板/淇敼鏂囦欢娓呭崟
-
-```
-yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/
-鈹溾攢鈹� enums/
-鈹� 鈹溾攢鈹� ErpAuditStatus.java (淇敼锛氭柊澧� DRAFT銆丷EJECT 鐘舵��)
-鈹� 鈹斺攢鈹� ErrorCodeConstants.java (淇敼锛氭柊澧為敊璇爜)
-鈹溾攢鈹� dal/dataobject/purchase/
-鈹� 鈹� ErpPurchaseOrderDO.java (淇敼锛氭柊澧� processInstanceId 瀛楁)
-鈹溾攢鈹� service/purchase/
-鈹� 鈹溾攢鈹� ErpPurchaseOrderService.java (淇敼锛氭柊澧炴帴鍙f柟娉�)
-鈹� 鈹溾攢鈹� ErpPurchaseOrderServiceImpl.java (淇敼锛氬疄鐜� BPM 闆嗘垚)
-鈹� 鈹斺攢鈹� listener/
-鈹� 鈹斺攢鈹� ErpPurchaseOrderStatusListener.java (鏂板锛氬鎵圭姸鎬佺洃鍚櫒)
-鈹斺攢鈹� controller/admin/purchase/
- 鈹� ErpPurchaseOrderController.java (淇敼锛氭柊澧炴彁浜ゅ鎵规帴鍙�)
-```
-
----
-
-## 鐘舵�佹祦杞浘
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鑽夌 鈹�
-鈹� (status=0)鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鎻愪氦瀹℃壒
- 鈫�
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 瀹℃壒涓� 鈹�
-鈹� (status=10)鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 瀹℃壒缁撴灉
- 鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈫� 鈫� 鈫�
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 瀹℃壒閫氳繃 鈹� 鈹� 瀹℃壒涓嶉�氳繃 鈹� 鈹� 鍙栨秷 鈹�
-鈹� (status=20) 鈹� 鈹� (status=30) 鈹� 鈹� (status=0) 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 閲嶆柊缂栬緫
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
----
-
-**鏂囨。鐗堟湰**: v1.0
-**鍒涘缓鏃ユ湡**: 2026-06-26
\ No newline at end of file
diff --git a/docs/batch3/database_changes.sql b/docs/batch3/database_changes.sql
deleted file mode 100644
index 2c111cf..0000000
--- a/docs/batch3/database_changes.sql
+++ /dev/null
@@ -1,53 +0,0 @@
--- =====================================================
--- Batch 3: ERP 閿�鍞鍗曞鎵归泦鎴� - 鏁版嵁搴撳彉鏇磋剼鏈�
--- 鐗堟湰: v1.0
--- 鏃ユ湡: 2026-06-26
--- 璇存槑: 涓� ERP 閿�鍞鍗曟坊鍔� BPM 娴佺▼瀹℃壒闆嗘垚
--- =====================================================
-
--- =====================================================
--- 1. 淇敼閿�鍞鍗曡〃锛屾柊澧炴祦绋嬪疄渚嬪瓧娈�
--- =====================================================
-
--- 鏂板娴佺▼瀹炰緥缂栧彿瀛楁
-ALTER TABLE `erp_sale_order`
-ADD COLUMN `process_instance_id` VARCHAR(64) DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿' AFTER `remark`;
-
--- =====================================================
--- 2. 鑿滃崟鏂板锛堟彁浜ゅ鎵规寜閽級
--- =====================================================
-
--- 鑾峰彇閿�鍞鍗曡彍鍗旾D
-SET @sale_order_menu_id = (SELECT `id` FROM `system_menu` WHERE `path` = 'sale-order' AND `deleted` = b'0' LIMIT 1);
-
--- 濡傛灉閿�鍞鍗曡彍鍗曚笉瀛樺湪锛屽皾璇曢�氳繃鍚嶇О鏌ユ壘
-SET @sale_order_menu_id = IFNULL(@sale_order_menu_id,
- (SELECT `id` FROM `system_menu` WHERE `name` = '閿�鍞鍗�' AND `deleted` = b'0' LIMIT 1));
-
--- 鏂板鎻愪氦瀹℃壒鎸夐挳
-INSERT INTO `system_menu` (`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT '閿�鍞鍗曟彁浜ゅ鎵�', 'erp:sale-order:submit', 3, 10, @sale_order_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM DUAL
-WHERE @sale_order_menu_id IS NOT NULL
-ON DUPLICATE KEY UPDATE `permission` = 'erp:sale-order:submit';
-
--- =====================================================
--- 3. BPM 娴佺▼瀹氫箟锛堥渶瑕佸湪鍓嶇鍒涘缓娴佺▼妯″瀷锛�
--- =====================================================
-
--- 鎻愮ず锛氳鍦� BPM 绠$悊鍚庡彴鍒涘缓娴佺▼妯″瀷
--- 娴佺▼鏍囪瘑锛圞ey锛夛細erp-sale-order-audit
--- 娴佺▼鍚嶇О锛欵RP 閿�鍞鍗曞鎵规祦绋�
--- 涓氬姟鍏宠仈锛氶攢鍞鍗� ID
-
--- =====================================================
--- 鍥炴粴鑴氭湰锛堝闇�鍥炴粴锛屾墽琛屼互涓嬭鍙ワ級
--- =====================================================
-
-/*
--- 鍒犻櫎鏂板瀛楁
-ALTER TABLE `erp_sale_order` DROP COLUMN `process_instance_id`;
-
--- 鍒犻櫎鏂板鑿滃崟
-DELETE FROM `system_menu` WHERE `permission` = 'erp:sale-order:submit';
-*/
\ No newline at end of file
diff --git a/docs/batch3/frontend_changes.md b/docs/batch3/frontend_changes.md
deleted file mode 100644
index d94f483..0000000
--- a/docs/batch3/frontend_changes.md
+++ /dev/null
@@ -1,181 +0,0 @@
-# Batch 3: ERP 閿�鍞鍗曞鎵归泦鎴� - 鍓嶇淇敼鏂囨。
-
-## 姒傝堪
-
-鏈壒娆′负 ERP 閿�鍞鍗曟ā鍧楅泦鎴� BPM 娴佺▼瀹℃壒鍔熻兘锛屽疄鐜伴攢鍞鍗曠殑瀹℃壒娴佺▼鍖栫鐞嗐�備笌 Batch 2 閲囪喘璁㈠崟瀹℃壒闆嗘垚绫讳技銆�
-
-## 娑夊強椤甸潰
-
-- 淇敼椤甸潰锛氶攢鍞鍗曠鐞嗛〉闈紙鏂板鎻愪氦瀹℃壒銆佸鎵圭姸鎬佸睍绀猴級
-- 鏂板閰嶇疆锛欱PM 娴佺▼妯″瀷閰嶇疆
-
----
-
-## API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /erp/sale-order/submit | 鎻愪氦閿�鍞鍗曞鎵� |
-
-**璇锋眰鍙傛暟锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| id | Long | 鏄� | 閿�鍞鍗曠紪鍙� |
-
-**鍝嶅簲锛�**
-
-```json
-{
- "code": 0,
- "data": true,
- "msg": "鎿嶄綔鎴愬姛"
-}
-```
-
----
-
-## 鍓嶇淇敼鐐�
-
-### 1. 閿�鍞鍗曞垪琛ㄩ〉闈慨鏀�
-
-**鏂囦欢璺緞锛�** `src/views/erp/sale/order/index.vue`
-
-#### 1.1 鏂板鎻愪氦瀹℃壒鎸夐挳
-
-鍦ㄦ搷浣滃垪鏂板"鎻愪氦瀹℃壒"鎸夐挳锛屼粎鑽夌鐘舵�佸彲瑙侊細
-
-```vue
-<el-table-column label="鎿嶄綔" align="center" fixed="right" width="200">
- <template #default="scope">
- <el-button
- link
- type="primary"
- @click="handleUpdate(scope.row.id)"
- v-hasPermi="['erp:sale-order:update']"
- v-if="scope.row.status === 0"
- >
- 缂栬緫
- </el-button>
- <el-button
- link
- type="primary"
- @click="handleSubmit(scope.row.id)"
- v-hasPermi="['erp:sale-order:update']"
- v-if="scope.row.status === 0"
- >
- 鎻愪氦瀹℃壒
- </el-button>
- <el-button
- link
- type="primary"
- @click="handleApprove(scope.row.id)"
- v-hasPermi="['erp:sale-order:update-status']"
- v-if="scope.row.status === 10"
- >
- 瀹℃壒閫氳繃
- </el-button>
- <el-button
- link
- type="danger"
- @click="handleDelete(scope.row.id)"
- v-hasPermi="['erp:sale-order:delete']"
- v-if="scope.row.status === 0 || scope.row.status === 30"
- >
- 鍒犻櫎
- </el-button>
- </template>
-</el-table-column>
-```
-
-#### 1.2 鏂板鎻愪氦瀹℃壒鏂规硶
-
-```typescript
-/** 鎻愪氦瀹℃壒 */
-const handleSubmit = async (id: number) => {
- try {
- await message.confirm('纭鎻愪氦璇ラ攢鍞鍗曡繘琛屽鎵癸紵')
- await SaleOrderApi.submitSaleOrder(id)
- message.success('鎻愪氦鎴愬姛')
- await getList()
- } catch {}
-}
-```
-
-#### 1.3 淇敼鐘舵�佸垪鏄剧ず
-
-```vue
-<el-table-column label="鐘舵��" align="center" prop="status" width="100">
- <template #default="scope">
- <dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" />
- </template>
-</el-table-column>
-```
-
-### 2. API 鎺ュ彛鏂囦欢淇敼
-
-**鏂囦欢璺緞锛�** `src/api/erp/sale/order/index.ts`
-
-鏂板鎻愪氦瀹℃壒鎺ュ彛锛�
-
-```typescript
-// 鎻愪氦閿�鍞鍗曞鎵�
-export const submitSaleOrder = async (id: number) => {
- return await request.post({ url: '/erp/sale-order/submit?id=' + id })
-}
-```
-
----
-
-## BPM 娴佺▼妯″瀷閰嶇疆
-
-### 娴佺▼妯″瀷淇℃伅
-
-鍦� BPM 绠$悊鍚庡彴鍒涘缓娴佺▼妯″瀷锛�
-
-| 閰嶇疆椤� | 鍊� |
-|--------|-----|
-| 娴佺▼鏍囪瘑锛圞ey锛� | erp-sale-order-audit |
-| 娴佺▼鍚嶇О | ERP 閿�鍞鍗曞鎵规祦绋� |
-| 娴佺▼鍒嗙被 | 涓氬姟娴佺▼ |
-
-### 娴佺▼璁捐寤鸿
-
-```
-寮�濮嬭妭鐐� 鈫� 閿�鍞富绠″鎵� 鈫� 璐㈠姟瀹℃壒 鈫� 缁撴潫鑺傜偣
-```
-
----
-
-## 娉ㄦ剰浜嬮」
-
-1. 鍒涘缓閿�鍞鍗曟椂锛岄粯璁ょ姸鎬佷粠"鏈鏍�"鏀逛负"鑽夌"
-2. 鍙湁鑽夌鐘舵�佺殑璁㈠崟鎵嶈兘鎻愪氦瀹℃壒
-3. 瀹℃壒涓殑璁㈠崟涓嶈兘缂栬緫鍜屽垹闄�
-4. 瀹℃壒涓嶉�氳繃鐨勮鍗曞彲浠ラ噸鏂扮紪杈戝悗鍐嶆鎻愪氦
-5. 闇�瑕佸厛鎵ц鏁版嵁搴撹剼鏈紝鍐嶉儴缃插悗绔唬鐮�
-6. 闇�瑕佸湪 BPM 绠$悊鍚庡彴鍒涘缓娴佺▼妯″瀷锛圞ey: erp-sale-order-audit锛�
-
----
-
-## 鍚庣鏂板/淇敼鏂囦欢娓呭崟
-
-```
-yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/
-鈹溾攢鈹� enums/
-鈹� 鈹斺攢鈹� ErrorCodeConstants.java (淇敼锛氭柊澧為敊璇爜)
-鈹溾攢鈹� dal/dataobject/sale/
-鈹� 鈹斺攢鈹� ErpSaleOrderDO.java (淇敼锛氭柊澧� processInstanceId 瀛楁)
-鈹溾攢鈹� service/sale/
-鈹� 鈹溾攢鈹� ErpSaleOrderService.java (淇敼锛氭柊澧炴帴鍙f柟娉�)
-鈹� 鈹溾攢鈹� ErpSaleOrderServiceImpl.java (淇敼锛氬疄鐜� BPM 闆嗘垚)
-鈹� 鈹斺攢鈹� listener/
-鈹� 鈹斺攢鈹� ErpSaleOrderStatusListener.java (鏂板锛氬鎵圭姸鎬佺洃鍚櫒)
-鈹斺攢鈹� controller/admin/sale/
- 鈹斺攢鈹� ErpSaleOrderController.java (淇敼锛氭柊澧炴彁浜ゅ鎵规帴鍙�)
-```
-
----
-
-**鏂囨。鐗堟湰**: v1.0
-**鍒涘缓鏃ユ湡**: 2026-06-26
\ No newline at end of file
diff --git a/docs/batch4/database_changes.sql b/docs/batch4/database_changes.sql
deleted file mode 100644
index 304e895..0000000
--- a/docs/batch4/database_changes.sql
+++ /dev/null
@@ -1,53 +0,0 @@
--- =====================================================
--- Batch 4: ERP 閲囪喘鍏ュ簱鍗曞鎵归泦鎴� - 鏁版嵁搴撳彉鏇磋剼鏈�
--- 鐗堟湰: v1.0
--- 鏃ユ湡: 2026-06-26
--- 璇存槑: 涓� ERP 閲囪喘鍏ュ簱鍗曟坊鍔� BPM 娴佺▼瀹℃壒闆嗘垚
--- =====================================================
-
--- =====================================================
--- 1. 淇敼閲囪喘鍏ュ簱琛紝鏂板娴佺▼瀹炰緥瀛楁
--- =====================================================
-
--- 鏂板娴佺▼瀹炰緥缂栧彿瀛楁
-ALTER TABLE `erp_purchase_in`
-ADD COLUMN `process_instance_id` VARCHAR(64) DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿' AFTER `remark`;
-
--- =====================================================
--- 2. 鑿滃崟鏂板锛堟彁浜ゅ鎵规寜閽級
--- =====================================================
-
--- 鑾峰彇閲囪喘鍏ュ簱鑿滃崟ID
-SET @purchase_in_menu_id = (SELECT `id` FROM `system_menu` WHERE `path` = 'purchase-in' AND `deleted` = b'0' LIMIT 1);
-
--- 濡傛灉閲囪喘鍏ュ簱鑿滃崟涓嶅瓨鍦紝灏濊瘯閫氳繃鍚嶇О鏌ユ壘
-SET @purchase_in_menu_id = IFNULL(@purchase_in_menu_id,
- (SELECT `id` FROM `system_menu` WHERE `name` = '閲囪喘鍏ュ簱' AND `deleted` = b'0' LIMIT 1));
-
--- 鏂板鎻愪氦瀹℃壒鎸夐挳
-INSERT INTO `system_menu` (`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT '閲囪喘鍏ュ簱鎻愪氦瀹℃壒', 'erp:purchase-in:submit', 3, 10, @purchase_in_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM DUAL
-WHERE @purchase_in_menu_id IS NOT NULL
-ON DUPLICATE KEY UPDATE `permission` = 'erp:purchase-in:submit';
-
--- =====================================================
--- 3. BPM 娴佺▼瀹氫箟锛堥渶瑕佸湪鍓嶇鍒涘缓娴佺▼妯″瀷锛�
--- =====================================================
-
--- 鎻愮ず锛氳鍦� BPM 绠$悊鍚庡彴鍒涘缓娴佺▼妯″瀷
--- 娴佺▼鏍囪瘑锛圞ey锛夛細erp-purchase-in-audit
--- 娴佺▼鍚嶇О锛欵RP 閲囪喘鍏ュ簱瀹℃壒娴佺▼
--- 涓氬姟鍏宠仈锛氶噰璐叆搴撳崟 ID
-
--- =====================================================
--- 鍥炴粴鑴氭湰锛堝闇�鍥炴粴锛屾墽琛屼互涓嬭鍙ワ級
--- =====================================================
-
-/*
--- 鍒犻櫎鏂板瀛楁
-ALTER TABLE `erp_purchase_in` DROP COLUMN `process_instance_id`;
-
--- 鍒犻櫎鏂板鑿滃崟
-DELETE FROM `system_menu` WHERE `permission` = 'erp:purchase-in:submit';
-*/
\ No newline at end of file
diff --git a/docs/batch4/frontend_changes.md b/docs/batch4/frontend_changes.md
deleted file mode 100644
index 98a04f5..0000000
--- a/docs/batch4/frontend_changes.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# Batch 4: ERP 閲囪喘鍏ュ簱鍗曞鎵归泦鎴� - 鍓嶇淇敼鏂囨。
-
-## 姒傝堪
-
-鏈壒娆′负 ERP 閲囪喘鍏ュ簱鍗曟ā鍧楅泦鎴� BPM 娴佺▼瀹℃壒鍔熻兘銆傞噰璐叆搴撳崟瀹℃壒閫氳繃鍚庝細鑷姩澧炲姞搴撳瓨銆�
-
-## 娑夊強椤甸潰
-
-- 淇敼椤甸潰锛氶噰璐叆搴撶鐞嗛〉闈紙鏂板鎻愪氦瀹℃壒銆佸鎵圭姸鎬佸睍绀猴級
-
----
-
-## API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /erp/purchase-in/submit | 鎻愪氦閲囪喘鍏ュ簱瀹℃壒 |
-
-**璇锋眰鍙傛暟锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| id | Long | 鏄� | 閲囪喘鍏ュ簱鍗曠紪鍙� |
-
-**鍝嶅簲锛�**
-
-```json
-{
- "code": 0,
- "data": true,
- "msg": "鎿嶄綔鎴愬姛"
-}
-```
-
----
-
-## 鍓嶇淇敼鐐�
-
-### 1. 閲囪喘鍏ュ簱鍒楄〃椤甸潰淇敼
-
-**鏂囦欢璺緞锛�** `src/views/erp/purchase/in/index.vue`
-
-#### 1.1 鏂板鎻愪氦瀹℃壒鎸夐挳
-
-```vue
-<el-button
- link
- type="primary"
- @click="handleSubmit(scope.row.id)"
- v-hasPermi="['erp:purchase-in:update']"
- v-if="scope.row.status === 0"
->
- 鎻愪氦瀹℃壒
-</el-button>
-```
-
-#### 1.2 鏂板鎻愪氦瀹℃壒鏂规硶
-
-```typescript
-/** 鎻愪氦瀹℃壒 */
-const handleSubmit = async (id: number) => {
- try {
- await message.confirm('纭鎻愪氦璇ラ噰璐叆搴撳崟杩涜瀹℃壒锛熷鎵归�氳繃鍚庡皢澧炲姞搴撳瓨')
- await PurchaseInApi.submitPurchaseIn(id)
- message.success('鎻愪氦鎴愬姛')
- await getList()
- } catch {}
-}
-```
-
-### 2. API 鎺ュ彛鏂囦欢淇敼
-
-**鏂囦欢璺緞锛�** `src/api/erp/purchase/in/index.ts`
-
-```typescript
-// 鎻愪氦閲囪喘鍏ュ簱瀹℃壒
-export const submitPurchaseIn = async (id: number) => {
- return await request.post({ url: '/erp/purchase-in/submit?id=' + id })
-}
-```
-
----
-
-## 娉ㄦ剰浜嬮」
-
-1. 閲囪喘鍏ュ簱鍗曞鎵归�氳繃鍚庝細鑷姩澧炲姞搴撳瓨
-2. 瀹℃壒涓嶉�氳繃鎴栧彇娑堜笉浼氬彉鏇村簱瀛�
-3. BPM 娴佺▼ Key锛歚erp-purchase-in-audit`
-
----
-
-**鏂囨。鐗堟湰**: v1.0
-**鍒涘缓鏃ユ湡**: 2026-06-26
\ No newline at end of file
diff --git a/docs/batch5/database_changes.sql b/docs/batch5/database_changes.sql
deleted file mode 100644
index 364e2b5..0000000
--- a/docs/batch5/database_changes.sql
+++ /dev/null
@@ -1,53 +0,0 @@
--- =====================================================
--- Batch 5: ERP 閿�鍞嚭搴撳崟瀹℃壒闆嗘垚 - 鏁版嵁搴撳彉鏇磋剼鏈�
--- 鐗堟湰: v1.0
--- 鏃ユ湡: 2026-06-26
--- 璇存槑: 涓� ERP 閿�鍞嚭搴撳崟娣诲姞 BPM 娴佺▼瀹℃壒闆嗘垚
--- =====================================================
-
--- =====================================================
--- 1. 淇敼閿�鍞嚭搴撹〃锛屾柊澧炴祦绋嬪疄渚嬪瓧娈�
--- =====================================================
-
--- 鏂板娴佺▼瀹炰緥缂栧彿瀛楁
-ALTER TABLE `erp_sale_out`
-ADD COLUMN `process_instance_id` VARCHAR(64) DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿' AFTER `remark`;
-
--- =====================================================
--- 2. 鑿滃崟鏂板锛堟彁浜ゅ鎵规寜閽級
--- =====================================================
-
--- 鑾峰彇閿�鍞嚭搴撹彍鍗旾D
-SET @sale_out_menu_id = (SELECT `id` FROM `system_menu` WHERE `path` = 'sale-out' AND `deleted` = b'0' LIMIT 1);
-
--- 濡傛灉閿�鍞嚭搴撹彍鍗曚笉瀛樺湪锛屽皾璇曢�氳繃鍚嶇О鏌ユ壘
-SET @sale_out_menu_id = IFNULL(@sale_out_menu_id,
- (SELECT `id` FROM `system_menu` WHERE `name` = '閿�鍞嚭搴�' AND `deleted` = b'0' LIMIT 1));
-
--- 鏂板鎻愪氦瀹℃壒鎸夐挳
-INSERT INTO `system_menu` (`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT '閿�鍞嚭搴撴彁浜ゅ鎵�', 'erp:sale-out:submit', 3, 10, @sale_out_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM DUAL
-WHERE @sale_out_menu_id IS NOT NULL
-ON DUPLICATE KEY UPDATE `permission` = 'erp:sale-out:submit';
-
--- =====================================================
--- 3. BPM 娴佺▼瀹氫箟锛堥渶瑕佸湪鍓嶇鍒涘缓娴佺▼妯″瀷锛�
--- =====================================================
-
--- 鎻愮ず锛氳鍦� BPM 绠$悊鍚庡彴鍒涘缓娴佺▼妯″瀷
--- 娴佺▼鏍囪瘑锛圞ey锛夛細erp-sale-out-audit
--- 娴佺▼鍚嶇О锛欵RP 閿�鍞嚭搴撳鎵规祦绋�
--- 涓氬姟鍏宠仈锛氶攢鍞嚭搴撳崟 ID
-
--- =====================================================
--- 鍥炴粴鑴氭湰锛堝闇�鍥炴粴锛屾墽琛屼互涓嬭鍙ワ級
--- =====================================================
-
-/*
--- 鍒犻櫎鏂板瀛楁
-ALTER TABLE `erp_sale_out` DROP COLUMN `process_instance_id`;
-
--- 鍒犻櫎鏂板鑿滃崟
-DELETE FROM `system_menu` WHERE `permission` = 'erp:sale-out:submit';
-*/
\ No newline at end of file
diff --git a/docs/batch5/frontend_changes.md b/docs/batch5/frontend_changes.md
deleted file mode 100644
index cba1796..0000000
--- a/docs/batch5/frontend_changes.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Batch 5: ERP 閿�鍞嚭搴撳崟瀹℃壒闆嗘垚 - 鍓嶇淇敼鏂囨。
-
-## 姒傝堪
-
-鏈壒娆′负 ERP 閿�鍞嚭搴撳崟妯″潡闆嗘垚 BPM 娴佺▼瀹℃壒鍔熻兘銆傞攢鍞嚭搴撳崟瀹℃壒閫氳繃鍚庝細鑷姩鍑忓皯搴撳瓨銆�
-
-## 娑夊強椤甸潰
-
-- 淇敼椤甸潰锛氶攢鍞嚭搴撶鐞嗛〉闈紙鏂板鎻愪氦瀹℃壒銆佸鎵圭姸鎬佸睍绀猴級
-
----
-
-## API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /erp/sale-out/submit | 鎻愪氦閿�鍞嚭搴撳鎵� |
-
-**璇锋眰鍙傛暟锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| id | Long | 鏄� | 閿�鍞嚭搴撳崟缂栧彿 |
-
----
-
-## 鍓嶇淇敼鐐�
-
-### 1. 閿�鍞嚭搴撳垪琛ㄩ〉闈慨鏀�
-
-**鏂囦欢璺緞锛�** `src/views/erp/sale/out/index.vue`
-
-#### 1.1 鏂板鎻愪氦瀹℃壒鎸夐挳
-
-```vue
-<el-button
- link
- type="primary"
- @click="handleSubmit(scope.row.id)"
- v-hasPermi="['erp:sale-out:update']"
- v-if="scope.row.status === 0"
->
- 鎻愪氦瀹℃壒
-</el-button>
-```
-
-#### 1.2 鏂板鎻愪氦瀹℃壒鏂规硶
-
-```typescript
-/** 鎻愪氦瀹℃壒 */
-const handleSubmit = async (id: number) => {
- try {
- await message.confirm('纭鎻愪氦璇ラ攢鍞嚭搴撳崟杩涜瀹℃壒锛熷鎵归�氳繃鍚庡皢鍑忓皯搴撳瓨')
- await SaleOutApi.submitSaleOut(id)
- message.success('鎻愪氦鎴愬姛')
- await getList()
- } catch {}
-}
-```
-
-### 2. API 鎺ュ彛鏂囦欢淇敼
-
-**鏂囦欢璺緞锛�** `src/api/erp/sale/out/index.ts`
-
-```typescript
-// 鎻愪氦閿�鍞嚭搴撳鎵�
-export const submitSaleOut = async (id: number) => {
- return await request.post({ url: '/erp/sale-out/submit?id=' + id })
-}
-```
-
----
-
-## 娉ㄦ剰浜嬮」
-
-1. 閿�鍞嚭搴撳崟瀹℃壒閫氳繃鍚庝細鑷姩鍑忓皯搴撳瓨锛堣礋鏁板彉鏇达級
-2. 瀹℃壒涓嶉�氳繃鎴栧彇娑堜笉浼氬彉鏇村簱瀛�
-3. BPM 娴佺▼ Key锛歚erp-sale-out-audit`
-
----
-
-**鏂囨。鐗堟湰**: v1.0
-**鍒涘缓鏃ユ湡**: 2026-06-26
\ No newline at end of file
diff --git a/docs/batch6/database_changes.sql b/docs/batch6/database_changes.sql
deleted file mode 100644
index 2b80ab2..0000000
--- a/docs/batch6/database_changes.sql
+++ /dev/null
@@ -1,42 +0,0 @@
--- =============================================
--- 鎵规鍏細MES 鐢熶骇宸ュ崟 BPM 瀹℃壒闆嗘垚
--- 鎵ц椤哄簭锛�1
--- =============================================
-
--- 1. 涓� MES 鐢熶骇宸ュ崟琛ㄦ坊鍔犳祦绋嬪疄渚嬬紪鍙峰瓧娈�
-ALTER TABLE `mes_pro_work_order` ADD COLUMN `process_instance_id` VARCHAR(64) NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿' AFTER `status`;
-
--- 2. 涓烘祦绋嬪疄渚嬬紪鍙峰垱寤虹储寮曪紙鍙�夛紝鐢ㄤ簬鎸夋祦绋嬪疄渚嬫煡璇級
--- ALTER TABLE `mes_pro_work_order` ADD INDEX `idx_process_instance_id` (`process_instance_id`);
-
--- 3. 鏇存柊宸ュ崟鐘舵�佸瓧鍏告暟鎹紙娣诲姞瀹℃壒涓�佸鎵逛笉閫氳繃鐘舵�侊級
--- 娉ㄦ剰锛氬鏋滃瓧鍏告暟鎹凡瀛樺湪鍒欏拷鐣�
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES
- (1, '瀹℃壒涓�', '1', 'mes_pro_work_order_status', 0, 'warning', '', 'MES鐢熶骇宸ュ崟鐘舵��-瀹℃壒涓�', '1', NOW(), '1', NOW(), b'0'),
- (5, '瀹℃壒涓嶉�氳繃', '5', 'mes_pro_work_order_status', 0, 'danger', '', 'MES鐢熶骇宸ュ崟鐘舵��-瀹℃壒涓嶉�氳繃', '1', NOW(), '1', NOW(), b'0')
-ON DUPLICATE KEY UPDATE `updater` = '1', `update_time` = NOW();
-
--- 4. 娣诲姞鑿滃崟鎸夐挳锛堟彁浜ゅ鎵癸級
--- 鍏堟煡璇㈢敓浜у伐鍗曡彍鍗旾D锛堝亣璁捐彍鍗曡矾寰勪负 MES绠$悊 > 鐢熶骇绠$悊 > 鐢熶骇宸ュ崟锛�
-SET @workorder_menu_id = (SELECT `id` FROM `system_menu` WHERE `name` = '鐢熶骇宸ュ崟' AND `parent_id` IN (SELECT `id` FROM `system_menu` WHERE `name` = '鐢熶骇绠$悊') LIMIT 1);
-
-INSERT INTO `system_menu` (`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT '鐢熶骇宸ュ崟鎻愪氦瀹℃壒', 'mes:pro-work-order:update', 3, 6, @workorder_menu_id, '', '', '', '', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'
-FROM DUAL
-WHERE @workorder_menu_id IS NOT NULL
- AND NOT EXISTS (SELECT 1 FROM `system_menu` WHERE `name` = '鐢熶骇宸ュ崟鎻愪氦瀹℃壒' AND `parent_id` = @workorder_menu_id);
-
--- 5. 涓鸿鑹插垎閰嶆彁浜ゅ鎵规寜閽潈闄愶紙鏍规嵁瀹為檯闇�瑕佽皟鏁达級
--- 绀轰緥锛氫负 MES 绠$悊鍛樿鑹插垎閰嶆潈闄�
--- INSERT INTO `system_role_menu` (`role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`)
--- SELECT r.id, m.id, '1', NOW(), '1', NOW(), b'0', 1
--- FROM `system_role` r, `system_menu` m
--- WHERE r.name = 'MES绠$悊鍛�' AND m.name = '鐢熶骇宸ュ崟鎻愪氦瀹℃壒';
-
--- =============================================
--- 鍥炴粴鑴氭湰锛堝闇�鍥炴粴鎵ц浠ヤ笅璇彞锛�
--- =============================================
--- ALTER TABLE `mes_pro_work_order` DROP COLUMN `process_instance_id`;
--- DELETE FROM `system_dict_data` WHERE `dict_type` = 'mes_pro_work_order_status' AND `value` IN ('1', '5');
--- DELETE FROM `system_menu` WHERE `name` = '鐢熶骇宸ュ崟鎻愪氦瀹℃壒';
diff --git a/docs/batch6/frontend_changes.md b/docs/batch6/frontend_changes.md
deleted file mode 100644
index 7f22dbc..0000000
--- a/docs/batch6/frontend_changes.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# MES 鐢熶骇宸ュ崟瀹℃壒闆嗘垚
-
-## 娑夊強椤甸潰
-
-- 鐢熶骇宸ュ崟鍒楄〃椤甸潰 (`views/mes/pro/workorder/index.vue`)
-- 鐢熶骇宸ュ崟璇︽儏/缂栬緫椤甸潰 (`views/mes/pro/workorder/WorkOrderForm.vue`)
-
-## API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| PUT | /mes/pro/work-order/submit | 鎻愪氦宸ュ崟瀹℃壒 |
-
-**璇锋眰鍙傛暟锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| id | Long | 鏄� | 宸ュ崟缂栧彿锛圦uery 鍙傛暟锛� |
-
-**鍝嶅簲锛�** `{ "code": 200, "msg": "鎿嶄綔鎴愬姛", "data": true }`
-
-## 宸ュ崟鐘舵�佸彉鏇磋鏄�
-
-| 鍘熺姸鎬� | 鏂扮姸鎬� | 瑙﹀彂鏉′欢 |
-|--------|--------|----------|
-| 鑽夌(0) | 瀹℃壒涓�(1) | 鎻愪氦瀹℃壒 |
-| 瀹℃壒涓�(1) | 宸茬‘璁�(2) | 瀹℃壒閫氳繃 |
-| 瀹℃壒涓�(1) | 瀹℃壒涓嶉�氳繃(5) | 瀹℃壒涓嶉�氳繃 |
-| 瀹℃壒涓�(1) | 鑽夌(0) | 瀹℃壒鍙栨秷 |
-
-## 鍓嶇淇敼鐐�
-
-### 1. 鍒楄〃椤甸潰 - 娣诲姞"鎻愪氦瀹℃壒"鎸夐挳
-
-**浣嶇疆锛�** `views/mes/pro/workorder/index.vue`
-
-```html
-<!-- 鍦ㄦ搷浣滃垪涓坊鍔犳彁浜ゅ鎵规寜閽� -->
-<el-table-column label="鎿嶄綔" align="center" width="200">
- <template #default="scope">
- <el-button
- v-if="scope.row.status === 0"
- link
- type="primary"
- @click="handleSubmit(scope.row.id)"
- v-hasPermi="['mes:pro-work-order:update']"
- >
- 鎻愪氦瀹℃壒
- </el-button>
- <el-button
- v-if="scope.row.status === 0"
- link
- type="primary"
- @click="handleUpdate(scope.row.id)"
- v-hasPermi="['mes:pro-work-order:update']"
- >
- 缂栬緫
- </el-button>
- <el-button
- v-if="scope.row.status === 0"
- link
- type="danger"
- @click="handleDelete(scope.row.id)"
- v-hasPermi="['mes:pro-work-order:delete']"
- >
- 鍒犻櫎
- </el-button>
- <!-- 宸茬‘璁ょ姸鎬佹樉绀哄畬鎴愩�佸彇娑堟寜閽� -->
- <el-button
- v-if="scope.row.status === 2"
- link
- type="success"
- @click="handleFinish(scope.row.id)"
- v-hasPermi="['mes:pro-work-order:update']"
- >
- 瀹屾垚
- </el-button>
- <el-button
- v-if="scope.row.status === 2"
- link
- type="warning"
- @click="handleCancel(scope.row.id)"
- v-hasPermi="['mes:pro-work-order:update']"
- >
- 鍙栨秷
- </el-button>
- </template>
-</el-table-column>
-```
-
-### 2. data 鏁版嵁
-
-```js
-// 鐘舵�佸瓧鍏�
-const statusDict = ref([
- { label: '鑽夌', value: 0, tagType: 'info' },
- { label: '瀹℃壒涓�', value: 1, tagType: 'warning' },
- { label: '宸茬‘璁�', value: 2, tagType: 'success' },
- { label: '宸插畬鎴�', value: 3, tagType: 'primary' },
- { label: '宸插彇娑�', value: 4, tagType: 'danger' },
- { label: '瀹℃壒涓嶉�氳繃', value: 5, tagType: 'danger' }
-])
-```
-
-### 3. 鏂规硶
-
-```js
-import { submitWorkOrder } from '@/api/mes/pro/workorder'
-
-// 鎻愪氦瀹℃壒
-const handleSubmit = async (id: number) => {
- try {
- await message.confirm('纭鎻愪氦璇ュ伐鍗曡繘琛屽鎵癸紵')
- await submitWorkOrder(id)
- message.success('鎻愪氦鎴愬姛')
- await getList()
- } catch (error) {
- console.error(error)
- }
-}
-```
-
-### 4. API 鏂规硶
-
-**鏂囦欢锛�** `api/mes/pro/workorder/index.ts`
-
-```ts
-// 鎻愪氦宸ュ崟瀹℃壒
-export const submitWorkOrder = (id: number) => {
- return request.put({ url: '/mes/pro/work-order/submit', params: { id } })
-}
-```
-
-### 5. 鐘舵�佹爣绛炬樉绀�
-
-```html
-<dict-tag :type="DICT_TYPE.MES_PRO_WORK_ORDER_STATUS" :value="scope.row.status" />
-```
-
-### 6. 琛ㄥ崟鐘舵�佺鐢ㄩ�昏緫
-
-**缂栬緫琛ㄥ崟锛�** 鍙湁鑽夌鐘舵��(0)鍜屽鎵逛笉閫氳繃鐘舵��(5)鎵嶈兘缂栬緫
-
-```js
-// 鍒ゆ柇鏄惁鍙紪杈�
-const isEditable = computed(() => {
- return formData.value.status === 0 || formData.value.status === 5
-})
-```
-
-```html
-<el-form-item label="宸ュ崟缂栫爜" prop="code">
- <el-input v-model="formData.code" :disabled="!isEditable" />
-</el-form-item>
-```
-
-## 娉ㄦ剰浜嬮」
-
-1. **鐘舵�佹祦杞�**锛氳崏绋� 鈫� 鎻愪氦瀹℃壒 鈫� 瀹℃壒涓� 鈫� 瀹℃壒閫氳繃(宸茬‘璁�) / 瀹℃壒涓嶉�氳繃
-2. **瀹℃壒涓嶉�氳繃鍚�**锛氬伐鍗曠姸鎬佸彉涓�"瀹℃壒涓嶉�氳繃"(5)锛屽彲浠ラ噸鏂扮紪杈戝悗鍐嶆鎻愪氦瀹℃壒
-3. **鏉冮檺鎺у埗**锛氭彁浜ゅ鎵逛娇鐢� `mes:pro-work-order:update` 鏉冮檺锛屼笌缂栬緫鏉冮檺涓�鑷�
-4. **鎸夐挳鏄剧ず**锛氭牴鎹伐鍗曠姸鎬佸姩鎬佹樉绀烘搷浣滄寜閽紝閬垮厤璇搷浣�
-5. **瀛楀吀鏁版嵁**锛氱‘淇濈郴缁熷瓧鍏� `mes_pro_work_order_status` 宸叉坊鍔犲鎵逛腑(1)鍜屽鎵逛笉閫氳繃(5)鐘舵��
diff --git a/docs/cross_module_integration_plan.md b/docs/cross_module_integration_plan.md
deleted file mode 100644
index 30e10c0..0000000
--- a/docs/cross_module_integration_plan.md
+++ /dev/null
@@ -1,531 +0,0 @@
-# MES/ERP/WMS/CRM 璺ㄦā鍧楅泦鎴愭柟妗�
-
-## 涓�銆佹暣浣撴灦鏋勬杩�
-
-### 1.1 妯″潡瀹氫綅
-
-| 妯″潡 | 鏍稿績鑱岃矗 | 涓氬姟杈圭晫 |
-|------|---------|---------|
-| **ERP** | 璐㈠姟鏍哥畻銆侀噰璐攢鍞鍗曠鐞� | 瀵瑰涓氬姟寰�鏉ャ�佹垚鏈牳绠� |
-| **MES** | 鐢熶骇鎵ц銆佸伐鑹虹鐞嗐�佽川閲忔帶鍒� | 鐢熶骇杩囩▼绠$悊 |
-| **WMS** | 浠撳偍绠$悊銆佸簱瀛樻帶鍒� | 瀹炵墿搴撳瓨绠$悊 |
-| **CRM** | 瀹㈡埛鍏崇郴銆侀攢鍞満浼氥�佸悎鍚岀鐞� | 瀹㈡埛渚т笟鍔$鐞� |
-
-### 1.2 缁熶竴鍩虹鏁版嵁鏋舵瀯
-
-閲囩敤 **鍗曚竴浜у搧涓绘暟鎹�** 妯″紡锛屾墦鐮存ā鍧楀鍨掞細
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍩虹鏁版嵁灞傦紙鍏变韩锛� 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 浜у搧鐗╂枡涓绘暟鎹紙MD_ITEM锛� 鈫� 鎵�鏈夋ā鍧楀叡鐢ㄥ敮涓�浜у搧缂栫爜 鈹�
-鈹� 瀹㈡埛涓绘暟鎹紙MD_CLIENT锛� 鈫� ERP/CRM 鍏辩敤 鈹�
-鈹� 渚涘簲鍟嗕富鏁版嵁锛圡D_VENDOR锛� 鈫� ERP/MES 鍏辩敤 鈹�
-鈹� 浠撳簱涓绘暟鎹紙MD Warehouse锛� 鈫� ERP/WMS/MES 鍏辩敤 鈹�
-鈹� 璁¢噺鍗曚綅涓绘暟鎹紙MD Unit锛� 鈫� 鍏ㄥ眬鍏辩敤 鈹�
-鈹� BOM 涓绘暟鎹紙MD BOM锛� 鈫� MES/ERP 鍏辩敤 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈫� 鈫� 鈫� 鈫�
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� ERP 鈹� 鈹� MES 鈹� 鈹� WMS 鈹� 鈹� CRM 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-### 1.3 鏍稿績璁捐鍘熷垯
-
-1. **鏁版嵁鍞竴鎬�**锛氫骇鍝佺墿鏂欑紪鐮佸叏灞�鍞竴锛屽悇妯″潡閫氳繃浜у搧ID鍏宠仈
-2. **娴佺▼椹卞姩**锛氭墍鏈夎法妯″潡鎿嶄綔閫氳繃 BPM 瀹℃壒娴佺▼瑙﹀彂
-3. **浜嬩欢瑙h��**锛氭ā鍧楅棿閫氳繃浜嬩欢鐩戝惉鏈哄埗瀹炵幇鑱斿姩锛岄伩鍏嶇洿鎺ヨ皟鐢�
-4. **搴撳瓨涓績鍖�**锛歐MS 浣滀负鍞竴搴撳瓨绠$悊鑰咃紝鎵�鏈夊簱瀛樺彉鍔ㄩ渶缁忚繃 WMS
-
----
-
-## 浜屻�佺粺涓�鍩虹鏁版嵁璁捐
-
-### 2.1 浜у搧鐗╂枡涓绘暟鎹紙鏍稿績锛�
-
-**琛ㄧ粨鏋勶細** `md_item`
-
-| 瀛楁 | 绫诲瀷 | 璇存槑 | 浣跨敤妯″潡 |
-|------|------|------|---------|
-| id | BIGINT | 浜у搧ID锛堝叏灞�鍞竴锛� | 鍏ㄩ儴 |
-| code | VARCHAR(64) | 浜у搧缂栫爜锛堝叏灞�鍞竴锛� | 鍏ㄩ儴 |
-| name | VARCHAR(255) | 浜у搧鍚嶇О | 鍏ㄩ儴 |
-| specification | VARCHAR(255) | 瑙勬牸鍨嬪彿 | 鍏ㄩ儴 |
-| unit_measure_id | BIGINT | 涓昏閲忓崟浣� | 鍏ㄩ儴 |
-| category_id | BIGINT | 浜у搧鍒嗙被 | 鍏ㄩ儴 |
-| item_type | INT | 鐗╂枡绫诲瀷锛堝師鏂�/鍗婃垚鍝�/鎴愬搧/杈呮枡锛� | MES/ERP |
-| is_batch_managed | BOOLEAN | 鏄惁鎵规绠$悊 | WMS/MES |
-| is_serial_managed | BOOLEAN | 鏄惁搴忓垪鍙风鐞� | WMS/MES |
-| barcode_rule_id | BIGINT | 鏉$爜瑙勫垯 | WMS/MES |
-| safety_stock | DECIMAL | 瀹夊叏搴撳瓨 | WMS |
-| min_order_qty | DECIMAL | 鏈�灏忚璐ч噺 | ERP |
-| lead_time | INT | 閲囪喘鎻愬墠鏈燂紙澶╋級 | ERP/MES |
-| purchase_price | DECIMAL | 閲囪喘浠� | ERP |
-| sales_price | DECIMAL | 閿�鍞环 | ERP/CRM |
-| cost_price | DECIMAL | 鎴愭湰浠� | ERP |
-| status | INT | 鐘舵�侊紙鍚敤/绂佺敤锛� | 鍏ㄩ儴 |
-
-### 2.2 妯″潡鏁版嵁褰掑睘鍒掑垎
-
-| 鏁版嵁绫诲瀷 | 鎵�灞炴ā鍧� | 鍏变韩鑼冨洿 |
-|---------|---------|---------|
-| 浜у搧鐗╂枡 | MES锛堜富锛夋垨鐙珛妯″潡 | ERP/WMS/CRM/MES 鍏ㄩ儴鍏变韩 |
-| 瀹㈡埛淇℃伅 | CRM锛堜富锛夋垨鐙珛妯″潡 | ERP/MES 鍏变韩锛堣鍗�/鍙戣揣锛� |
-| 渚涘簲鍟嗕俊鎭� | ERP锛堜富锛夋垨鐙珛妯″潡 | MES 鍏变韩锛堝鍗忓姞宸ワ級 |
-| 浠撳簱淇℃伅 | WMS锛堜富锛夋垨鐙珛妯″潡 | ERP/MES 鍏变韩锛堝嚭鍏ュ簱锛� |
-| BOM 淇℃伅 | MES锛堜富锛夋垨鐙珛妯″潡 | ERP 鍏变韩锛堟垚鏈牳绠楋級 |
-| 宸ヨ壓璺嚎 | MES 鐙湁 | 涓嶅叡浜� |
-| 閿�鍞満浼� | CRM 鐙湁 | 涓嶅叡浜� |
-| 璐ㄦ鏍囧噯 | MES 鐙湁 | WMS 鍙傝�� |
-
-### 2.3 鏁版嵁鍚屾绛栫暐
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� API/浜嬩欢 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 涓绘暟鎹ā鍧� 鈹� 鈫愨攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈫� 鈹� 涓氬姟妯″潡 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈫� 鈫�
- 鏁版嵁鍙樻洿浜嬩欢 鏈湴缂撳瓨鏇存柊
- 鈫� 鈫�
- 鍙戝竷 DomainEvent 鐩戝惉骞跺悓姝�
-```
-
-**鍚屾鏂瑰紡锛�**
-1. **瀹炴椂鍚屾**锛氬叧閿暟鎹彉鏇撮�氳繃 Spring Event 瀹炴椂閫氱煡
-2. **API 鏌ヨ**锛氫笟鍔℃ā鍧楅渶瑕佽鎯呮椂璋冪敤涓绘暟鎹ā鍧� API
-3. **鏈湴缂撳瓨**锛氶珮棰戣闂暟鎹湪涓氬姟妯″潡寤虹珛缂撳瓨琛紙浠呭瓨 ID+鍚嶇О+缂栫爜锛�
-
----
-
-## 涓夈�佽法妯″潡涓氬姟娴佺▼闆嗘垚
-
-### 3.1 閲囪喘涓氬姟娴佺▼锛圗RP 鈫� WMS 鈫� MES锛�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 閲囪喘涓氬姟瀹屾暣娴佺▼ 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-
-ERP閲囪喘璁㈠崟 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫� 鍙垱寤洪噰璐叆搴撳崟
- 鈫� 鈫�
- 鐘舵�佸彉鏇� ERP閲囪喘鍏ュ簱
- 鈫� 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫�
-鏇存柊璁㈠崟鐘舵�� 鈫�
- WMS搴撳瓨澧炲姞
- 鈫�
- MES鍘熸枡鍙敤
- 鈫�
- 鍙垱寤虹敓浜ч鏂欏崟
-```
-
-**鑱斿姩鐐硅璁★細**
-
-| 瑙﹀彂鐐� | 鑱斿姩鎿嶄綔 | 瀹炵幇鏂瑰紡 |
-|--------|---------|---------|
-| ERP閲囪喘璁㈠崟瀹℃壒閫氳繃 | 璁㈠崟鐘舵��=宸插鎵癸紝鍏佽鍒涘缓鍏ュ簱鍗� | 鐘舵�佹牎楠� |
-| ERP閲囪喘鍏ュ簱瀹℃壒閫氳繃 | WMS搴撳瓨澧炲姞銆佹洿鏂伴噰璐鍗曞凡鍏ュ簱鏁伴噺 | 浜嬩欢鐩戝惉 |
-| ERP閲囪喘鍏ュ簱鍏ㄩ儴瀹屾垚 | 閲囪喘璁㈠崟鐘舵��=宸插畬鎴� | 鏁伴噺鍒ゆ柇 |
-| MES鐢熶骇棰嗘枡瀹℃壒閫氳繃 | WMS鍘熸枡搴撳瓨鍑忓皯 | 浜嬩欢鐩戝惉 |
-
-### 3.2 閿�鍞笟鍔℃祦绋嬶紙CRM 鈫� ERP 鈫� WMS锛�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 閿�鍞笟鍔″畬鏁存祦绋� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-
-CRM閿�鍞悎鍚� 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫� 鍙垱寤篍RP閿�鍞鍗�
- 鈫� 鈫�
- 鐘舵�佸彉鏇� ERP閿�鍞鍗�
- 鈫� 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫�
-鍚堝悓灞ヨ寮�濮� 鈫�
- 鍙垱寤洪攢鍞嚭搴撳崟
- 鈫�
- ERP閿�鍞嚭搴�
- 鈫�
- 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫�
- 鈫�
- WMS搴撳瓨鍑忓皯
- 鈫�
- ERP鎴愭湰鏍哥畻
- 鈫�
- CRM鍚堝悓灞ヨ鏇存柊
-```
-
-**鑱斿姩鐐硅璁★細**
-
-| 瑙﹀彂鐐� | 鑱斿姩鎿嶄綔 | 瀹炵幇鏂瑰紡 |
-|--------|---------|---------|
-| CRM鍚堝悓瀹℃壒閫氳繃 | 鍙垱寤篍RP閿�鍞鍗曪紝鍏宠仈鍚堝悓ID | 鐘舵�佹牎楠� |
-| ERP閿�鍞鍗曞鎵归�氳繃 | 璁㈠崟鐘舵��=宸插鎵癸紝鍏佽鍒涘缓鍑哄簱鍗� | 鐘舵�佹牎楠� |
-| ERP閿�鍞嚭搴撳鎵归�氳繃 | WMS搴撳瓨鍑忓皯銆佹洿鏂伴攢鍞鍗曞凡鍑哄簱鏁伴噺 | 浜嬩欢鐩戝惉 |
-| ERP閿�鍞嚭搴撳鎵归�氳繃 | 鏇存柊CRM鍚堝悓灞ヨ杩涘害 | 浜嬩欢鐩戝惉 |
-| ERP閿�鍞嚭搴撳叏閮ㄥ畬鎴� | 閿�鍞鍗曠姸鎬�=宸插畬鎴� | 鏁伴噺鍒ゆ柇 |
-
-### 3.3 鐢熶骇涓氬姟娴佺▼锛圡ES 鈫� WMS 鈫� ERP锛�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鐢熶骇涓氬姟瀹屾暣娴佺▼ 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-
-MES鐢熶骇宸ュ崟 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫� 鐘舵��=宸茬‘璁�
- 鈫� 鈫�
- 鑷姩鐢熸垚BOM 鍙垱寤虹敓浜т换鍔�
- 鈫� 鈫�
- 鍙垱寤洪鏂欏崟 MES鐢熶骇浠诲姟鎵ц
- 鈫� 鈹�鈹�(浠诲姟寮�濮�)鈹�鈹�鈫�
-MES鐢熶骇棰嗘枡 鈫�
- 鈫� 鍘熸枡娑堣�楄褰�
- 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫� 鈫�
- 鈫� 鈹�鈹�(浠诲姟瀹屾垚)鈹�鈹�鈫�
-WMS鍘熸枡搴撳瓨鍑忓皯 鈫�
- MES鐢熶骇鍏ュ簱
- 鈫�
- 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫�
- 鈫�
- WMS鎴愬搧搴撳瓨澧炲姞
- 鈫�
- ERP鎴愭湰鏍哥畻
- 鈫�
- MES宸ュ崟瀹屾垚
-```
-
-**鑱斿姩鐐硅璁★細**
-
-| 瑙﹀彂鐐� | 鑱斿姩鎿嶄綔 | 瀹炵幇鏂瑰紡 |
-|--------|---------|---------|
-| MES鐢熶骇宸ュ崟瀹℃壒閫氳繃 | 宸ュ崟鐘舵��=宸茬‘璁わ紝鍙垱寤轰换鍔�/棰嗘枡鍗� | 鐘舵�佹牎楠� |
-| MES鐢熶骇棰嗘枡瀹℃壒閫氳繃 | WMS鍘熸枡搴撳瓨鍑忓皯 | 浜嬩欢鐩戝惉 |
-| MES鐢熶骇浠诲姟瀹屾垚 | 绱鐢熶骇鏁伴噺銆佸彲鍒涘缓鍏ュ簱鍗� | 鐘舵�佹牎楠� |
-| MES鐢熶骇鍏ュ簱瀹℃壒閫氳繃 | WMS鎴愬搧搴撳瓨澧炲姞銆佸伐鍗曠敓浜ф暟閲忕疮鍔� | 浜嬩欢鐩戝惉 |
-| MES鐢熶骇鍏ュ簱瀹℃壒閫氳繃 | ERP鎴愭湰鏍哥畻锛堝彲閫夛級 | 浜嬩欢鐩戝惉 |
-| MES宸ュ崟鍏ㄩ儴瀹屾垚 | 宸ュ崟鐘舵��=宸插畬鎴� | 鏁伴噺鍒ゆ柇 |
-
-### 3.4 閫�璐т笟鍔℃祦绋�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 閫�璐т笟鍔℃祦绋� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-
-ERP閲囪喘閫�璐� 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫� WMS搴撳瓨鍑忓皯
- 鈫�
- 鏇存柊閲囪喘璁㈠崟閫�璐ф暟閲�
-
-ERP閿�鍞��璐� 鈹�鈹�(瀹℃壒閫氳繃)鈹�鈹�鈫� WMS搴撳瓨澧炲姞
- 鈫�
- 鏇存柊閿�鍞鍗曢��璐ф暟閲�
-```
-
----
-
-## 鍥涖�佸簱瀛樼鐞嗙粺涓�璁捐
-
-### 4.1 搴撳瓨鏁版嵁妯″瀷
-
-**鏍稿績琛細** `wms_stock`
-
-| 瀛楁 | 绫诲瀷 | 璇存槑 |
-|------|------|------|
-| id | BIGINT | 涓婚敭 |
-| item_id | BIGINT | 浜у搧ID锛堝叧鑱� md_item锛� |
-| warehouse_id | BIGINT | 浠撳簱ID |
-| location_id | BIGINT | 搴撲綅ID |
-| batch_code | VARCHAR(64) | 鎵规鍙� |
-| quantity | DECIMAL | 褰撳墠搴撳瓨鏁伴噺 |
-| quantity_locked | DECIMAL | 閿佸畾鏁伴噺 |
-| quantity_available | DECIMAL | 鍙敤鏁伴噺 = quantity - quantity_locked |
-| unit_measure_id | BIGINT | 璁¢噺鍗曚綅 |
-
-### 4.2 搴撳瓨鍙樺姩鏉ユ簮
-
-| 鍙樺姩绫诲瀷 | 澧炲噺鏂瑰悜 | 鏉ユ簮妯″潡 | 瑙﹀彂鏉′欢 |
-|---------|---------|---------|---------|
-| 閲囪喘鍏ュ簱 | + | ERP | 閲囪喘鍏ュ簱鍗曞鎵归�氳繃 |
-| 閿�鍞嚭搴� | - | ERP | 閿�鍞嚭搴撳崟瀹℃壒閫氳繃 |
-| 鐢熶骇鍏ュ簱 | + | MES | 鐢熶骇鍏ュ簱鍗曞鎵归�氳繃 |
-| 鐢熶骇棰嗘枡 | - | MES | 鐢熶骇棰嗘枡鍗曞鎵归�氳繃 |
-| 鐢熶骇閫�鏂� | + | MES | 鐢熶骇閫�鏂欏崟瀹℃壒閫氳繃 |
-| 閲囪喘閫�璐� | - | ERP | 閲囪喘閫�璐у崟瀹℃壒閫氳繃 |
-| 閿�鍞��璐� | + | ERP | 閿�鍞��璐у崟瀹℃壒閫氳繃 |
-| 璋冩嫧鍏ュ簱 | + | WMS | 璋冩嫧鍗曞鎵归�氳繃锛堢洰鏍囦粨锛� |
-| 璋冩嫧鍑哄簱 | - | WMS | 璋冩嫧鍗曞鎵归�氳繃锛堟簮浠擄級 |
-| 鐩樼泩 | + | WMS | 鐩樼偣鍗曞鎵归�氳繃 |
-| 鐩樹簭 | - | WMS | 鐩樼偣鍗曞鎵归�氳繃 |
-
-### 4.3 搴撳瓨鏈嶅姟 API 璁捐
-
-```java
-/**
- * 搴撳瓨鏈嶅姟鎺ュ彛 - WMS 妯″潡鎻愪緵锛屽叾浠栨ā鍧楄皟鐢�
- */
-public interface WmsStockApi {
-
- /**
- * 鍒涘缓搴撳瓨璁板綍锛堝叆搴擄級
- */
- Long createStockRecord(StockRecordCreateDTO dto);
-
- /**
- * 閿佸畾搴撳瓨
- */
- void lockStock(Long itemId, Long warehouseId, BigDecimal quantity);
-
- /**
- * 瑙i攣搴撳瓨
- */
- void unlockStock(Long itemId, Long warehouseId, BigDecimal quantity);
-
- /**
- * 鏌ヨ鍙敤搴撳瓨
- */
- BigDecimal getAvailableStock(Long itemId, Long warehouseId);
-
- /**
- * 鎵归噺鏌ヨ搴撳瓨
- */
- Map<Long, BigDecimal> getAvailableStockMap(List<Long> itemIds, Long warehouseId);
-
- /**
- * 鏍¢獙搴撳瓨鍏呰冻
- */
- void validateStockEnough(Long itemId, Long warehouseId, BigDecimal quantity);
-}
-```
-
-### 4.4 搴撳瓨棰勮鏈哄埗
-
-| 棰勮绫诲瀷 | 瑙﹀彂鏉′欢 | 閫氱煡瀵硅薄 |
-|---------|---------|---------|
-| 搴撳瓨涓嶈冻 | 鍙敤搴撳瓨 < 瀹夊叏搴撳瓨 | ERP閲囪喘銆丮ES璁″垝 |
-| 搴撳瓨绉帇 | 搴撳瓨 > 鏈�楂樺簱瀛橀槇鍊� | ERP閿�鍞� |
-| 鏁堟湡棰勮 | 鎵规鏁堟湡 < 30澶� | WMS銆丮ES璐ㄩ噺 |
-| 閿佸畾瓒呮椂 | 閿佸畾鏃堕棿 > 閰嶇疆闃堝�� | 鐩稿叧涓氬姟浜哄憳 |
-
----
-
-## 浜斻�丅PM 瀹℃壒娴佺▼缁熶竴璁捐
-
-### 5.1 瀹℃壒娴佺▼鏍囪瘑瑙勮寖
-
-| 妯″潡 | 涓氬姟鍗曟嵁 | 娴佺▼ KEY |
-|------|---------|---------|
-| ERP | 閲囪喘璁㈠崟 | `erp-purchase-order-audit` |
-| ERP | 閿�鍞鍗� | `erp-sale-order-audit` |
-| ERP | 閲囪喘鍏ュ簱 | `erp-purchase-in-audit` |
-| ERP | 閿�鍞嚭搴� | `erp-sale-out-audit` |
-| ERP | 閲囪喘閫�璐� | `erp-purchase-return-audit` |
-| ERP | 閿�鍞��璐� | `erp-sale-return-audit` |
-| MES | 鐢熶骇宸ュ崟 | `mes-pro-work-order-audit` |
-| MES | 鐢熶骇棰嗘枡 | `mes-material-issue-audit` |
-| MES | 鐢熶骇鍏ュ簱 | `mes-material-receive-audit` |
-| WMS | 搴撳瓨璋冩嫧 | `wms-stock-transfer-audit` |
-| WMS | 搴撳瓨鐩樼偣 | `wms-stock-check-audit` |
-| CRM | 閿�鍞悎鍚� | `crm-sale-contract-audit` |
-| CRM | 閿�鍞姤浠� | `crm-sale-quotation-audit` |
-
-### 5.2 瀹℃壒鐘舵�佹灇涓剧粺涓�
-
-```java
-/**
- * 缁熶竴瀹℃壒鐘舵�佹灇涓�
- */
-public enum AuditStatusEnum {
- DRAFT(0, "鑽夌"), // 鏂板缓鐘舵��
- AUDITING(1, "瀹℃壒涓�"), // 宸叉彁浜ゅ鎵�
- APPROVED(20, "宸插鎵�"), // 瀹℃壒閫氳繃
- REJECTED(30, "宸叉嫆缁�"), // 瀹℃壒涓嶉�氳繃
- CANCELLED(40, "宸插彇娑�"); // 瀹℃壒鍙栨秷
-
- // BPM 娴佺▼鐘舵�佸搴旓細
- // BPM_RESULT_PASS = 2 鈫� APPROVED
- // BPM_RESULT_REJECT = 3 鈫� REJECTED
- // BPM_RESULT_CANCEL = 4 鈫� DRAFT锛堥��鍥炶崏绋匡級
-}
-```
-
-### 5.3 瀹℃壒鐩戝惉鍣ㄧ粺涓�妯℃澘
-
-```java
-/**
- * 璺ㄦā鍧楀鎵圭粨鏋滅洃鍚櫒鍩虹被
- */
-public abstract class CrossModuleAuditListener extends BpmProcessInstanceStatusEventListener {
-
- @Override
- protected void onEvent(BpmProcessInstanceStatusEvent event) {
- // 1. 鏇存柊鏈ā鍧楀崟鎹姸鎬�
- updateAuditStatus(event.getBusinessKey(), event.getStatus());
-
- // 2. 瑙﹀彂璺ㄦā鍧楄仈鍔紙閫氳繃浜嬩欢鍙戝竷锛�
- if (event.getStatus() == 2) { // 瀹℃壒閫氳繃
- publishCrossModuleEvent(event.getBusinessKey());
- }
- }
-
- /**
- * 鍙戝竷璺ㄦā鍧楄仈鍔ㄤ簨浠�
- */
- protected abstract void publishCrossModuleEvent(String businessKey);
-}
-```
-
----
-
-## 鍏�佽法妯″潡浜嬩欢鏈哄埗璁捐
-
-### 6.1 浜嬩欢绫诲瀷瀹氫箟
-
-| 浜嬩欢绫诲瀷 | 鍙戝竷妯″潡 | 鐩戝惉妯″潡 | 璇存槑 |
-|---------|---------|---------|---------|
-| `PurchaseInApprovedEvent` | ERP | WMS, ERP-PO | 閲囪喘鍏ュ簱瀹℃壒閫氳繃 |
-| `SaleOutApprovedEvent` | ERP | WMS, ERP-SO, CRM | 閿�鍞嚭搴撳鎵归�氳繃 |
-| `MaterialIssueApprovedEvent` | MES | WMS | 鐢熶骇棰嗘枡瀹℃壒閫氳繃 |
-| `MaterialReceiveApprovedEvent` | MES | WMS, MES-WO | 鐢熶骇鍏ュ簱瀹℃壒閫氳繃 |
-| `WorkOrderApprovedEvent` | MES | MES-Task | 鐢熶骇宸ュ崟瀹℃壒閫氳繃 |
-| `ContractApprovedEvent` | CRM | ERP | 閿�鍞悎鍚屽鎵归�氳繃 |
-
-### 6.2 浜嬩欢鏁版嵁缁撴瀯
-
-```java
-/**
- * 璺ㄦā鍧椾簨浠跺熀绫�
- */
-@Data
-public abstract class CrossModuleEvent {
- /** 涓氬姟鍗曟嵁ID */
- private Long businessId;
- /** 涓氬姟鍗曟嵁缂栫爜 */
- private String businessCode;
- /** 浜у搧ID鍒楄〃 */
- private List<Long> itemIds;
- /** 浠撳簱ID */
- private Long warehouseId;
- /** 鎿嶄綔鏃堕棿 */
- private LocalDateTime eventTime;
- /** 鎿嶄綔鐢ㄦ埛ID */
- private Long userId;
- /** 绉熸埛ID */
- private Long tenantId;
-}
-
-/**
- * 閲囪喘鍏ュ簱瀹℃壒閫氳繃浜嬩欢
- */
-@Data
-@EqualsAndHashCode(callSuper = true)
-public class PurchaseInApprovedEvent extends CrossModuleEvent {
- /** 鍏ュ簱鏁伴噺锛堟寜浜у搧锛� */
- private Map<Long, BigDecimal> quantityMap;
- /** 鍏宠仈閲囪喘璁㈠崟ID */
- private Long purchaseOrderId;
-}
-```
-
-### 6.3 浜嬩欢鍙戝竷涓庣洃鍚�
-
-```java
-// ERP 妯″潡鍙戝竷浜嬩欢
-@Component
-public class ErpPurchaseInStatusListener extends CrossModuleAuditListener {
-
- @Resource
- private ApplicationEventPublisher eventPublisher;
-
- @Override
- protected void publishCrossModuleEvent(String businessKey) {
- ErpPurchaseInDO purchaseIn = purchaseInService.getPurchaseIn(Long.parseLong(businessKey));
-
- // 鍙戝竷浜嬩欢渚涘叾浠栨ā鍧楃洃鍚�
- eventPublisher.publishEvent(new PurchaseInApprovedEvent()
- .setBusinessId(purchaseIn.getId())
- .setItemIds(extractItemIds(purchaseIn))
- .setQuantityMap(extractQuantityMap(purchaseIn))
- .setWarehouseId(purchaseIn.getWarehouseId()));
- }
-}
-
-// WMS 妯″潡鐩戝惉浜嬩欢
-@Component
-public class WmsStockEventListener {
-
- @EventListener
- public void onPurchaseInApproved(PurchaseInApprovedEvent event) {
- // 澧炲姞搴撳瓨
- event.getQuantityMap().forEach((itemId, quantity) -> {
- stockService.createStockRecord(new StockRecordCreateDTO()
- .setItemId(itemId)
- .setWarehouseId(event.getWarehouseId())
- .setQuantity(quantity)
- .setBizType(StockBizTypeEnum.PURCHASE_IN));
- });
- }
-}
-
-// ERP 閲囪喘璁㈠崟妯″潡鐩戝惉浜嬩欢
-@Component
-public class ErpPurchaseOrderEventListener {
-
- @EventListener
- public void onPurchaseInApproved(PurchaseInApprovedEvent event) {
- // 鏇存柊閲囪喘璁㈠崟宸插叆搴撴暟閲�
- purchaseOrderService.updateInQuantity(event.getPurchaseOrderId(), event.getQuantityMap());
- }
-}
-```
-
----
-
-## 涓冦�佸疄鏂借鍒�
-
-### 7.1 鍒嗘壒娆″疄鏂介『搴�
-
-| 鎵规 | 鍐呭 | 妯″潡 | 棰勪及宸ヤ綔閲� |
-|------|------|------|-----------|
-| 1 | 鍩虹鏁版嵁缁熶竴 | 鍏ㄩ儴 | 3澶� |
-| 2 | 搴撳瓨鏈嶅姟 API | WMS | 2澶� |
-| 3 | 閲囪喘涓氬姟鑱斿姩 | ERP/WMS | 2澶� |
-| 4 | 閿�鍞笟鍔¤仈鍔� | ERP/WMS/CRM | 2澶� |
-| 5 | 鐢熶骇涓氬姟鑱斿姩 | MES/WMS | 3澶� |
-| 6 | 閫�璐т笟鍔¤仈鍔� | ERP/WMS | 1澶� |
-| 7 | 浜嬩欢鏈哄埗瀹屽杽 | 鍏ㄩ儴 | 2澶� |
-| 8 | 娴佺▼瀹氫箟閰嶇疆 | BPM | 2澶� |
-| 9 | 鍓嶇椤甸潰璋冩暣 | 鍏ㄩ儴 | 3澶� |
-| 10 | 鑱旇皟娴嬭瘯 | 鍏ㄩ儴 | 3澶� |
-
-### 7.2 鎶�鏈鐐�
-
-1. **Spring Event 寮傛澶勭悊**锛氳法妯″潡浜嬩欢浣跨敤 `@Async` 寮傛鎵ц锛岄伩鍏嶄簨鍔″祵濂�
-2. **鍒嗗竷寮忎簨鍔�**锛氬叧閿搷浣滆�冭檻浣跨敤 Seata 鎴栨湰鍦版秷鎭〃淇濊瘉涓�鑷存��
-3. **骞傜瓑璁捐**锛氫簨浠剁洃鍚櫒闇�鏀寔骞傜瓑锛岄槻姝㈤噸澶嶆墽琛�
-4. **绉熸埛闅旂**锛氫簨浠舵暟鎹惡甯� tenantId锛岀洃鍚椂杩囨护
-
----
-
-## 鍏�侀闄╀笌瀵圭瓥
-
-| 椋庨櫓鐐� | 褰卞搷 | 瀵圭瓥 |
-|--------|------|------|
-| 鏁版嵁涓嶄竴鑷� | 搴撳瓨涓庡疄闄呬笉绗� | 浜嬩欢骞傜瓑+琛ュ伩鏈哄埗+瀹氭湡鐩樼偣 |
-| 娴佺▼姝婚攣 | 瀹℃壒鍗′綇 | 璁剧疆瀹℃壒瓒呮椂鑷姩澶勭悊 |
-| 鎬ц兘鐡堕 | 浜嬩欢闃熷垪闃诲 | 寮傛闃熷垪+鎵归噺澶勭悊 |
-| 璺ㄧ鎴锋暟鎹硠闇� | 瀹夊叏椋庨櫓 | 浜嬩欢鎼哄甫绉熸埛ID+涓ユ牸鏍¢獙 |
-
----
-
-## 涔濄�佹�荤粨
-
-鏈柟妗堥�氳繃浠ヤ笅鏈哄埗瀹炵幇妯″潡闂存墦閫氾細
-
-1. **缁熶竴鍩虹鏁版嵁**锛氫骇鍝�/瀹㈡埛/渚涘簲鍟�/浠撳簱绛変富鏁版嵁鍏ㄥ眬鍏变韩
-2. **浜嬩欢椹卞姩鑱斿姩**锛氬鎵归�氳繃瑙﹀彂璺ㄦā鍧椾簨浠讹紝瑙h�︽ā鍧椾緷璧�
-3. **搴撳瓨涓績鍖�**锛歐MS 浣滀负鍞竴搴撳瓨绠$悊鑰咃紝鎵�鏈夊彉鍔ㄩ�氳繃 API/浜嬩欢
-4. **娴佺▼鏍囧噯鍖�**锛氱粺涓�鐨� BPM 娴佺▼ KEY銆佺姸鎬佹灇涓俱�佺洃鍚櫒妯℃澘
-
-涓嬩竴姝ラ渶纭锛�
-- 涓绘暟鎹ā鍧楀綊灞烇紙鏄惁鏂板缓鐙珛妯″潡锛�
-- 鍒嗗竷寮忎簨鍔℃柟妗堥�夋嫨
-- 鍏蜂綋瀹炴柦浼樺厛绾ф帓搴�
\ No newline at end of file
diff --git a/docs/database_schema.sql b/docs/database_schema.sql
deleted file mode 100644
index e5b76dd..0000000
--- a/docs/database_schema.sql
+++ /dev/null
@@ -1,5152 +0,0 @@
--- =====================================================
--- 鑺嬮亾 ruoyi-vue-pro 椤圭洰鏁版嵁搴撹〃缁撴瀯
--- 鐢熸垚鏃ユ湡: 2026-06-23
--- 鍩轰簬 yudao-server/pom.xml 涓凡瑙i攣妯″潡鐨勫疄浣撶被鐢熸垚
--- =====================================================
-
--- 宸茶В閿佹ā鍧楋細
--- 1. yudao-module-system (32 寮犺〃)
--- 2. yudao-module-infra (11 寮犺〃)
--- 3. yudao-module-bpm (8 寮犺〃)
--- 4. yudao-module-crm (19 寮犺〃)
--- 5. yudao-module-erp (33 寮犺〃)
--- 6. yudao-module-mes (133 寮犺〃锛屽惈 wm 瀛愭ā鍧� 62 寮犺〃)
--- 7. yudao-module-wms (16 寮犺〃)
--- 鍚堣: 252 寮犺〃
-
--- =====================================================
--- 绗竴閮ㄥ垎: yudao-module-system 绯荤粺绠$悊妯″潡 (32 寮犺〃)
--- =====================================================
-
--- 1.1 绠$悊鍚庡彴鐢ㄦ埛琛�
--- CREATE TABLE `system_users` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢ㄦ埛ID',
--- `username` varchar(100) DEFAULT NULL COMMENT '鐢ㄦ埛璐﹀彿',
--- `password` varchar(100) DEFAULT NULL COMMENT '鍔犲瘑鍚庣殑瀵嗙爜',
--- `nickname` varchar(100) DEFAULT NULL COMMENT '鐢ㄦ埛鏄电О',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
--- `post_ids` json DEFAULT NULL COMMENT '宀椾綅缂栧彿鏁扮粍',
--- `email` varchar(100) DEFAULT NULL COMMENT '鐢ㄦ埛閭',
--- `mobile` varchar(100) DEFAULT NULL COMMENT '鎵嬫満鍙风爜',
--- `sex` tinyint DEFAULT NULL COMMENT '鐢ㄦ埛鎬у埆',
--- `avatar` varchar(255) DEFAULT NULL COMMENT '鐢ㄦ埛澶村儚',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `login_ip` varchar(50) DEFAULT NULL COMMENT '鏈�鍚庣櫥褰旾P',
--- `login_date` datetime DEFAULT NULL COMMENT '鏈�鍚庣櫥褰曟椂闂�',
--- `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '澶氱鎴风紪鍙�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='绠$悊鍚庡彴鐢ㄦ埛琛�';
---
--- -- 1.2 閮ㄩ棬琛�
--- CREATE TABLE `system_dept` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '閮ㄩ棬ID',
--- `name` varchar(100) DEFAULT NULL COMMENT '閮ㄩ棬鍚嶇О',
--- `parent_id` bigint NOT NULL DEFAULT '0' COMMENT '鐖堕儴闂↖D',
--- `sort` int NOT NULL DEFAULT '0' COMMENT '鏄剧ず椤哄簭',
--- `leader_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜�',
--- `phone` varchar(50) DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
--- `email` varchar(100) DEFAULT NULL COMMENT '閭',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '澶氱鎴风紪鍙�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='閮ㄩ棬琛�';
---
--- -- 1.3 宀椾綅琛�
--- CREATE TABLE `system_post` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '宀椾綅搴忓彿',
--- `name` varchar(100) DEFAULT NULL COMMENT '宀椾綅鍚嶇О',
--- `code` varchar(100) DEFAULT NULL COMMENT '宀椾綅缂栫爜',
--- `sort` int NOT NULL DEFAULT '0' COMMENT '宀椾綅鎺掑簭',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='宀椾綅琛�';
---
--- -- 1.4 鐢ㄦ埛宀椾綅鍏宠仈琛�
--- CREATE TABLE `system_user_post` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑷涓婚敭',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
--- `post_id` bigint NOT NULL COMMENT '宀椾綅ID',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='鐢ㄦ埛宀椾綅鍏宠仈琛�';
---
--- -- 1.5 瀛楀吀绫诲瀷琛�
--- CREATE TABLE `system_dict_type` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀛楀吀涓婚敭',
--- `name` varchar(100) DEFAULT NULL COMMENT '瀛楀吀鍚嶇О',
--- `type` varchar(100) DEFAULT NULL COMMENT '瀛楀吀绫诲瀷',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `deleted_time` datetime DEFAULT NULL COMMENT '鍒犻櫎鏃堕棿',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='瀛楀吀绫诲瀷琛�';
---
--- -- 1.6 瀛楀吀鏁版嵁琛�
--- CREATE TABLE `system_dict_data` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀛楀吀鏁版嵁缂栧彿',
--- `sort` int NOT NULL DEFAULT '0' COMMENT '瀛楀吀鎺掑簭',
--- `label` varchar(100) DEFAULT NULL COMMENT '瀛楀吀鏍囩',
--- `value` varchar(100) DEFAULT NULL COMMENT '瀛楀吀鍊�',
--- `dict_type` varchar(100) DEFAULT NULL COMMENT '瀛楀吀绫诲瀷',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `color_type` varchar(50) DEFAULT NULL COMMENT '棰滆壊绫诲瀷',
--- `css_class` varchar(100) DEFAULT NULL COMMENT 'css鏍峰紡',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='瀛楀吀鏁版嵁琛�';
---
--- -- 1.7 鐧诲綍鏃ュ織琛�
--- CREATE TABLE `system_login_log` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織涓婚敭',
--- `log_type` tinyint NOT NULL COMMENT '鏃ュ織绫诲瀷',
--- `trace_id` varchar(64) DEFAULT NULL COMMENT '閾捐矾杩借釜缂栧彿',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `username` varchar(100) DEFAULT NULL COMMENT '鐢ㄦ埛璐﹀彿',
--- `result` tinyint NOT NULL COMMENT '鐧诲綍缁撴灉',
--- `user_ip` varchar(50) DEFAULT NULL COMMENT '鐢ㄦ埛IP',
--- `user_agent` varchar(512) DEFAULT NULL COMMENT '娴忚鍣║A',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='鐧诲綍鏃ュ織琛�';
---
--- -- 1.8 鎿嶄綔鏃ュ織琛�
--- CREATE TABLE `system_operate_log` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織涓婚敭',
--- `trace_id` varchar(64) DEFAULT NULL COMMENT '閾捐矾杩借釜缂栧彿',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `type` varchar(100) DEFAULT NULL COMMENT '鎿嶄綔妯″潡绫诲瀷',
--- `sub_type` varchar(100) DEFAULT NULL COMMENT '鎿嶄綔鍚�',
--- `biz_id` bigint DEFAULT NULL COMMENT '鎿嶄綔妯″潡涓氬姟缂栧彿',
--- `action` varchar(2000) DEFAULT NULL COMMENT '鏃ュ織鍐呭',
--- `extra` varchar(2000) DEFAULT NULL COMMENT '鎷撳睍瀛楁',
--- `request_method` varchar(50) DEFAULT NULL COMMENT '璇锋眰鏂规硶鍚�',
--- `request_url` varchar(255) DEFAULT NULL COMMENT '璇锋眰鍦板潃',
--- `user_ip` varchar(50) DEFAULT NULL COMMENT '鐢ㄦ埛IP',
--- `user_agent` varchar(512) DEFAULT NULL COMMENT '娴忚鍣║A',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='鎿嶄綔鏃ュ織琛�';
---
--- -- 1.9 閫氱煡鍏憡琛�
--- CREATE TABLE `system_notice` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍏憡ID',
--- `title` varchar(200) DEFAULT NULL COMMENT '鍏憡鏍囬',
--- `type` tinyint NOT NULL COMMENT '鍏憡绫诲瀷',
--- `content` text COMMENT '鍏憡鍐呭',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='閫氱煡鍏憡琛�';
---
--- -- 1.10 鑿滃崟琛�
--- CREATE TABLE `system_menu` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑿滃崟缂栧彿',
--- `name` varchar(100) DEFAULT NULL COMMENT '鑿滃崟鍚嶇О',
--- `permission` varchar(100) DEFAULT NULL COMMENT '鏉冮檺鏍囪瘑',
--- `type` tinyint NOT NULL COMMENT '鑿滃崟绫诲瀷',
--- `sort` int NOT NULL DEFAULT '0' COMMENT '鏄剧ず椤哄簭',
--- `parent_id` bigint NOT NULL DEFAULT '0' COMMENT '鐖惰彍鍗旾D',
--- `path` varchar(255) DEFAULT NULL COMMENT '璺敱鍦板潃',
--- `icon` varchar(100) DEFAULT NULL COMMENT '鑿滃崟鍥炬爣',
--- `component` varchar(255) DEFAULT NULL COMMENT '缁勪欢璺緞',
--- `component_name` varchar(100) DEFAULT NULL COMMENT '缁勪欢鍚�',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `visible` bit(1) DEFAULT b'1' COMMENT '鏄惁鍙',
--- `keep_alive` bit(1) DEFAULT b'1' COMMENT '鏄惁缂撳瓨',
--- `always_show` bit(1) DEFAULT b'1' COMMENT '鏄惁鎬绘槸鏄剧ず',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='鑿滃崟琛�';
---
--- -- 1.11 瑙掕壊琛�
--- CREATE TABLE `system_role` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瑙掕壊ID',
--- `name` varchar(100) DEFAULT NULL COMMENT '瑙掕壊鍚嶇О',
--- `code` varchar(100) DEFAULT NULL COMMENT '瑙掕壊鏍囪瘑',
--- `sort` int NOT NULL DEFAULT '0' COMMENT '瑙掕壊鎺掑簭',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `type` tinyint NOT NULL COMMENT '瑙掕壊绫诲瀷',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `data_scope` tinyint DEFAULT NULL COMMENT '鏁版嵁鑼冨洿',
--- `data_scope_dept_ids` json DEFAULT NULL COMMENT '鏁版嵁鑼冨洿(鎸囧畾閮ㄩ棬鏁扮粍)',
--- `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '澶氱鎴风紪鍙�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='瑙掕壊琛�';
---
--- -- 1.12 瑙掕壊鑿滃崟鍏宠仈琛�
--- CREATE TABLE `system_role_menu` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑷涓婚敭',
--- `role_id` bigint NOT NULL COMMENT '瑙掕壊ID',
--- `menu_id` bigint NOT NULL COMMENT '鑿滃崟ID',
--- `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '澶氱鎴风紪鍙�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='瑙掕壊鑿滃崟鍏宠仈琛�';
---
--- -- 1.13 鐢ㄦ埛瑙掕壊鍏宠仈琛�
--- CREATE TABLE `system_user_role` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑷涓婚敭',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
--- `role_id` bigint NOT NULL COMMENT '瑙掕壊ID',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='鐢ㄦ埛瑙掕壊鍏宠仈琛�';
---
--- -- 1.14 鐭俊娓犻亾琛�
--- CREATE TABLE `system_sms_channel` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '娓犻亾缂栧彿',
--- `signature` varchar(100) DEFAULT NULL COMMENT '鐭俊绛惧悕',
--- `code` varchar(100) DEFAULT NULL COMMENT '娓犻亾缂栫爜',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鍚敤鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `api_key` varchar(255) DEFAULT NULL COMMENT '鐭俊API鐨勮处鍙�',
--- `api_secret` varchar(255) DEFAULT NULL COMMENT '鐭俊API鐨勫瘑閽�',
--- `callback_url` varchar(255) DEFAULT NULL COMMENT '鐭俊鍙戦�佸洖璋僓RL',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='鐭俊娓犻亾琛�';
---
--- -- 1.15 鎵嬫満楠岃瘉鐮佽〃
--- CREATE TABLE `system_sms_code` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `mobile` varchar(20) DEFAULT NULL COMMENT '鎵嬫満鍙�',
--- `code` varchar(20) DEFAULT NULL COMMENT '楠岃瘉鐮�',
--- `scene` tinyint NOT NULL COMMENT '鍙戦�佸満鏅�',
--- `create_ip` varchar(50) DEFAULT NULL COMMENT '鍒涘缓IP',
--- `today_index` int DEFAULT NULL COMMENT '浠婃棩鍙戦�佺殑绗嚑鏉�',
--- `used` bit(1) DEFAULT b'0' COMMENT '鏄惁浣跨敤',
--- `used_time` datetime DEFAULT NULL COMMENT '浣跨敤鏃堕棿',
--- `used_ip` varchar(50) DEFAULT NULL COMMENT '浣跨敤IP',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`),
--- KEY `idx_mobile` (`mobile`)
--- ) ENGINE=InnoDB COMMENT='鎵嬫満楠岃瘉鐮佽〃';
---
--- -- 1.16 鐭俊妯℃澘琛�
--- CREATE TABLE `system_sms_template` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑷缂栧彿',
--- `type` tinyint NOT NULL COMMENT '鐭俊绫诲瀷',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鍚敤鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `code` varchar(100) DEFAULT NULL COMMENT '妯℃澘缂栫爜',
--- `name` varchar(100) DEFAULT NULL COMMENT '妯℃澘鍚嶇О',
--- `content` varchar(500) DEFAULT NULL COMMENT '妯℃澘鍐呭',
--- `params` json DEFAULT NULL COMMENT '鍙傛暟鏁扮粍',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `api_template_id` varchar(100) DEFAULT NULL COMMENT '鐭俊API鐨勬ā鏉跨紪鍙�',
--- `channel_id` bigint DEFAULT NULL COMMENT '鐭俊娓犻亾缂栧彿',
--- `channel_code` varchar(100) DEFAULT NULL COMMENT '鐭俊娓犻亾缂栫爜',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='鐭俊妯℃澘琛�';
---
--- -- 1.17 鐭俊鏃ュ織琛�
--- CREATE TABLE `system_sms_log` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑷缂栧彿',
--- `channel_id` bigint DEFAULT NULL COMMENT '鐭俊娓犻亾缂栧彿',
--- `channel_code` varchar(100) DEFAULT NULL COMMENT '鐭俊娓犻亾缂栫爜',
--- `template_id` bigint DEFAULT NULL COMMENT '妯℃澘缂栧彿',
--- `template_code` varchar(100) DEFAULT NULL COMMENT '妯℃澘缂栫爜',
--- `template_type` tinyint DEFAULT NULL COMMENT '鐭俊绫诲瀷',
--- `template_content` varchar(500) DEFAULT NULL COMMENT '妯℃澘鍐呭',
--- `template_params` json DEFAULT NULL COMMENT '妯℃澘鍙傛暟',
--- `api_template_id` varchar(100) DEFAULT NULL COMMENT '鐭俊API鐨勬ā鏉跨紪鍙�',
--- `mobile` varchar(20) DEFAULT NULL COMMENT '鎵嬫満鍙�',
--- `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` tinyint DEFAULT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `send_status` tinyint NOT NULL DEFAULT '0' COMMENT '鍙戦�佺姸鎬�',
--- `send_time` datetime DEFAULT NULL COMMENT '鍙戦�佹椂闂�',
--- `api_send_code` varchar(100) DEFAULT NULL COMMENT '鐭俊API鍙戦�佺粨鏋滅殑缂栫爜',
--- `api_send_msg` varchar(500) DEFAULT NULL COMMENT '鐭俊API鍙戦�佸け璐ョ殑鎻愮ず',
--- `api_request_id` varchar(100) DEFAULT NULL COMMENT '鐭俊API鍙戦�佽繑鍥炵殑鍞竴璇锋眰ID',
--- `api_serial_no` varchar(100) DEFAULT NULL COMMENT '鐭俊API鍙戦�佽繑鍥炵殑搴忓彿',
--- `receive_status` tinyint NOT NULL DEFAULT '0' COMMENT '鎺ユ敹鐘舵��',
--- `receive_time` datetime DEFAULT NULL COMMENT '鎺ユ敹鏃堕棿',
--- `api_receive_code` varchar(100) DEFAULT NULL COMMENT '鐭俊API鎺ユ敹缁撴灉鐨勭紪鐮�',
--- `api_receive_msg` varchar(500) DEFAULT NULL COMMENT '鐭俊API鎺ユ敹缁撴灉鐨勬彁绀�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='鐭俊鏃ュ織琛�';
---
--- -- 1.18 绀句氦瀹㈡埛绔〃
--- CREATE TABLE `system_social_client` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `name` varchar(100) DEFAULT NULL COMMENT '搴旂敤鍚�',
--- `social_type` tinyint NOT NULL COMMENT '绀句氦绫诲瀷',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `client_id` varchar(255) DEFAULT NULL COMMENT '瀹㈡埛绔痠d',
--- `client_secret` varchar(255) DEFAULT NULL COMMENT '瀹㈡埛绔疭ecret',
--- `agent_id` varchar(100) DEFAULT NULL COMMENT '浠g悊缂栧彿',
--- `public_key` varchar(512) DEFAULT NULL COMMENT 'publicKey鍏挜',
--- `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '澶氱鎴风紪鍙�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='绀句氦瀹㈡埛绔〃';
---
--- -- 1.19 绀句氦鐢ㄦ埛琛�
--- CREATE TABLE `system_social_user` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑷涓婚敭',
--- `type` tinyint NOT NULL COMMENT '绀句氦骞冲彴鐨勭被鍨�',
--- `openid` varchar(100) DEFAULT NULL COMMENT '绀句氦openid',
--- `token` varchar(255) DEFAULT NULL COMMENT '绀句氦token',
--- `raw_token_info` text COMMENT '鍘熷Token鏁版嵁',
--- `nickname` varchar(100) DEFAULT NULL COMMENT '鐢ㄦ埛鏄电О',
--- `avatar` varchar(255) DEFAULT NULL COMMENT '鐢ㄦ埛澶村儚',
--- `raw_user_info` text COMMENT '鍘熷鐢ㄦ埛鏁版嵁',
--- `code` varchar(100) DEFAULT NULL COMMENT '鏈�鍚庝竴娆$殑璁よ瘉code',
--- `state` varchar(100) DEFAULT NULL COMMENT '鏈�鍚庝竴娆$殑璁よ瘉state',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='绀句氦鐢ㄦ埛琛�';
---
--- -- 1.20 绀句氦鐢ㄦ埛缁戝畾琛�
--- CREATE TABLE `system_social_user_bind` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `user_id` bigint NOT NULL COMMENT '鍏宠仈鐨勭敤鎴风紪鍙�',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `social_user_id` bigint NOT NULL COMMENT '绀句氦骞冲彴鐨勭敤鎴风紪鍙�',
--- `social_type` tinyint NOT NULL COMMENT '绀句氦骞冲彴鐨勭被鍨�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='绀句氦鐢ㄦ埛缁戝畾琛�';
---
--- -- 1.21 绉熸埛琛�
--- CREATE TABLE `system_tenant` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '绉熸埛缂栧彿',
--- `name` varchar(100) DEFAULT NULL COMMENT '绉熸埛鍚�',
--- `contact_user_id` bigint DEFAULT NULL COMMENT '鑱旂郴浜虹殑鐢ㄦ埛缂栧彿',
--- `contact_name` varchar(100) DEFAULT NULL COMMENT '鑱旂郴浜�',
--- `contact_mobile` varchar(50) DEFAULT NULL COMMENT '鑱旂郴鎵嬫満',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `websites` json DEFAULT NULL COMMENT '缁戝畾鍩熷悕鍒楄〃',
--- `package_id` bigint DEFAULT NULL COMMENT '绉熸埛濂楅缂栧彿',
--- `expire_time` datetime DEFAULT NULL COMMENT '杩囨湡鏃堕棿',
--- `account_count` int DEFAULT NULL COMMENT '璐﹀彿鏁伴噺',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='绉熸埛琛�';
---
--- -- 1.22 绉熸埛濂楅琛�
--- CREATE TABLE `system_tenant_package` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '濂楅缂栧彿',
--- `name` varchar(100) DEFAULT NULL COMMENT '濂楅鍚�',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '绉熸埛濂楅鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `menu_ids` json DEFAULT NULL COMMENT '鍏宠仈鐨勮彍鍗曠紪鍙�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='绉熸埛濂楅琛�';
---
--- -- 1.23 閭璐﹀彿琛�
--- CREATE TABLE `system_mail_account` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
--- `mail` varchar(100) DEFAULT NULL COMMENT '閭',
--- `username` varchar(100) DEFAULT NULL COMMENT '鐢ㄦ埛鍚�',
--- `password` varchar(100) DEFAULT NULL COMMENT '瀵嗙爜',
--- `host` varchar(100) DEFAULT NULL COMMENT 'SMTP鏈嶅姟鍣ㄥ煙鍚�',
--- `port` int DEFAULT NULL COMMENT 'SMTP鏈嶅姟鍣ㄧ鍙�',
--- `ssl_enable` bit(1) DEFAULT b'0' COMMENT '鏄惁寮�鍚疭SL',
--- `starttls_enable` bit(1) DEFAULT b'0' COMMENT '鏄惁寮�鍚疭TARTTLS',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='閭璐﹀彿琛�';
---
--- -- 1.24 閭欢妯$増琛�
--- CREATE TABLE `system_mail_template` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
--- `name` varchar(100) DEFAULT NULL COMMENT '妯$増鍚嶇О',
--- `code` varchar(100) DEFAULT NULL COMMENT '妯$増缂栧彿',
--- `account_id` bigint DEFAULT NULL COMMENT '鍙戦�佺殑閭璐﹀彿缂栧彿',
--- `nickname` varchar(100) DEFAULT NULL COMMENT '鍙戦�佷汉鍚嶇О',
--- `title` varchar(255) DEFAULT NULL COMMENT '鏍囬',
--- `content` text COMMENT '鍐呭',
--- `params` json DEFAULT NULL COMMENT '鍙傛暟鏁扮粍',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='閭欢妯$増琛�';
---
--- -- 1.25 閭鏃ュ織琛�
--- CREATE TABLE `system_mail_log` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織缂栧彿',
--- `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栫爜',
--- `user_type` tinyint DEFAULT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `to_mails` json DEFAULT NULL COMMENT '鎺ユ敹閭鍦板潃',
--- `cc_mails` json DEFAULT NULL COMMENT '鎶勯�侀偖绠卞湴鍧�',
--- `bcc_mails` json DEFAULT NULL COMMENT '瀵嗛�侀偖绠卞湴鍧�',
--- `account_id` bigint DEFAULT NULL COMMENT '閭璐﹀彿缂栧彿',
--- `from_mail` varchar(100) DEFAULT NULL COMMENT '鍙戦�侀偖绠卞湴鍧�',
--- `template_id` bigint DEFAULT NULL COMMENT '妯$増缂栧彿',
--- `template_code` varchar(100) DEFAULT NULL COMMENT '妯$増缂栫爜',
--- `template_nickname` varchar(100) DEFAULT NULL COMMENT '妯$増鍙戦�佷汉鍚嶇О',
--- `template_title` varchar(255) DEFAULT NULL COMMENT '妯$増鏍囬',
--- `template_content` text COMMENT '妯$増鍐呭',
--- `template_params` json DEFAULT NULL COMMENT '妯$増鍙傛暟',
--- `send_status` tinyint NOT NULL DEFAULT '0' COMMENT '鍙戦�佺姸鎬�',
--- `send_time` datetime DEFAULT NULL COMMENT '鍙戦�佹椂闂�',
--- `send_message_id` varchar(255) DEFAULT NULL COMMENT '鍙戦�佽繑鍥炵殑娑堟伅ID',
--- `send_exception` varchar(500) DEFAULT NULL COMMENT '鍙戦�佸紓甯�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='閭鏃ュ織琛�';
---
--- -- 1.26 绔欏唴淇℃ā鐗堣〃
--- CREATE TABLE `system_notify_template` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
--- `name` varchar(100) DEFAULT NULL COMMENT '妯$増鍚嶇О',
--- `code` varchar(100) DEFAULT NULL COMMENT '妯$増缂栫爜',
--- `type` tinyint NOT NULL COMMENT '妯$増绫诲瀷',
--- `nickname` varchar(100) DEFAULT NULL COMMENT '鍙戦�佷汉鍚嶇О',
--- `content` varchar(500) DEFAULT NULL COMMENT '妯$増鍐呭',
--- `params` json DEFAULT NULL COMMENT '鍙傛暟鏁扮粍',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='绔欏唴淇℃ā鐗堣〃';
---
--- -- 1.27 绔欏唴淇¤〃
--- CREATE TABLE `system_notify_message` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '绔欏唴淇$紪鍙�',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `template_id` bigint DEFAULT NULL COMMENT '妯$増缂栧彿',
--- `template_code` varchar(100) DEFAULT NULL COMMENT '妯$増缂栫爜',
--- `template_type` tinyint DEFAULT NULL COMMENT '妯$増绫诲瀷',
--- `template_nickname` varchar(100) DEFAULT NULL COMMENT '妯$増鍙戦�佷汉鍚嶇О',
--- `template_content` varchar(500) DEFAULT NULL COMMENT '妯$増鍐呭',
--- `template_params` json DEFAULT NULL COMMENT '妯$増鍙傛暟',
--- `read_status` bit(1) DEFAULT b'0' COMMENT '鏄惁宸茶',
--- `read_time` datetime DEFAULT NULL COMMENT '闃呰鏃堕棿',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='绔欏唴淇¤〃';
---
--- -- 1.28 OAuth2瀹㈡埛绔〃
--- CREATE TABLE `system_oauth2_client` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `client_id` varchar(100) DEFAULT NULL COMMENT '瀹㈡埛绔紪鍙�',
--- `secret` varchar(255) DEFAULT NULL COMMENT '瀹㈡埛绔瘑閽�',
--- `name` varchar(100) DEFAULT NULL COMMENT '搴旂敤鍚�',
--- `logo` varchar(255) DEFAULT NULL COMMENT '搴旂敤鍥炬爣',
--- `description` varchar(500) DEFAULT NULL COMMENT '搴旂敤鎻忚堪',
--- `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
--- `access_token_validity_seconds` int DEFAULT NULL COMMENT '璁块棶浠ょ墝鐨勬湁鏁堟湡',
--- `refresh_token_validity_seconds` int DEFAULT NULL COMMENT '鍒锋柊浠ょ墝鐨勬湁鏁堟湡',
--- `redirect_uris` json DEFAULT NULL COMMENT '鍙噸瀹氬悜鐨刄RI鍦板潃',
--- `authorized_grant_types` json DEFAULT NULL COMMENT '鎺堟潈绫诲瀷',
--- `scopes` json DEFAULT NULL COMMENT '鎺堟潈鑼冨洿',
--- `auto_approve_scopes` json DEFAULT NULL COMMENT '鑷姩鎺堟潈鐨凷cope',
--- `authorities` json DEFAULT NULL COMMENT '鏉冮檺',
--- `resource_ids` json DEFAULT NULL COMMENT '璧勬簮',
--- `additional_information` varchar(2000) DEFAULT NULL COMMENT '闄勫姞淇℃伅',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='OAuth2瀹㈡埛绔〃';
---
--- -- 1.29 OAuth2鎺堟潈鐮佽〃
--- CREATE TABLE `system_oauth2_code` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `code` varchar(255) DEFAULT NULL COMMENT '鎺堟潈鐮�',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `client_id` varchar(100) DEFAULT NULL COMMENT '瀹㈡埛绔紪鍙�',
--- `scopes` json DEFAULT NULL COMMENT '鎺堟潈鑼冨洿',
--- `redirect_uri` varchar(255) DEFAULT NULL COMMENT '閲嶅畾鍚戝湴鍧�',
--- `state` varchar(100) DEFAULT NULL COMMENT '鐘舵��',
--- `expires_time` datetime DEFAULT NULL COMMENT '杩囨湡鏃堕棿',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='OAuth2鎺堟潈鐮佽〃';
---
--- -- 1.30 OAuth2璁块棶浠ょ墝琛�
--- CREATE TABLE `system_oauth2_access_token` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `access_token` varchar(255) DEFAULT NULL COMMENT '璁块棶浠ょ墝',
--- `refresh_token` varchar(255) DEFAULT NULL COMMENT '鍒锋柊浠ょ墝',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `user_info` json DEFAULT NULL COMMENT '鐢ㄦ埛淇℃伅',
--- `client_id` varchar(100) DEFAULT NULL COMMENT '瀹㈡埛绔紪鍙�',
--- `scopes` json DEFAULT NULL COMMENT '鎺堟潈鑼冨洿',
--- `expires_time` datetime DEFAULT NULL COMMENT '杩囨湡鏃堕棿',
--- `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '澶氱鎴风紪鍙�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='OAuth2璁块棶浠ょ墝琛�';
---
--- -- 1.31 OAuth2鍒锋柊浠ょ墝琛�
--- CREATE TABLE `system_oauth2_refresh_token` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `refresh_token` varchar(255) DEFAULT NULL COMMENT '鍒锋柊浠ょ墝',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `client_id` varchar(100) DEFAULT NULL COMMENT '瀹㈡埛绔紪鍙�',
--- `scopes` json DEFAULT NULL COMMENT '鎺堟潈鑼冨洿',
--- `expires_time` datetime DEFAULT NULL COMMENT '杩囨湡鏃堕棿',
--- `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '澶氱鎴风紪鍙�',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='OAuth2鍒锋柊浠ょ墝琛�';
---
--- -- 1.32 OAuth2鎵瑰噯琛�
--- CREATE TABLE `system_oauth2_approve` (
--- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `client_id` varchar(100) DEFAULT NULL COMMENT '瀹㈡埛绔紪鍙�',
--- `scope` varchar(255) DEFAULT NULL COMMENT '鎺堟潈鑼冨洿',
--- `approved` bit(1) DEFAULT b'0' COMMENT '鏄惁鎺ュ彈',
--- `expires_time` datetime DEFAULT NULL COMMENT '杩囨湡鏃堕棿',
--- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
--- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB COMMENT='OAuth2鎵瑰噯琛�';
---
---
--- -- =====================================================
--- -- 绗簩閮ㄥ垎: yudao-module-infra 鍩虹璁炬柦妯″潡 (11 寮犺〃)
--- -- =====================================================
---
--- -- 2.1 浠g爜鐢熸垚瀛楁瀹氫箟琛�
--- CREATE TABLE `infra_codegen_column` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ID 缂栧彿',
--- `table_id` BIGINT NOT NULL COMMENT '琛ㄧ紪鍙�',
--- `column_name` VARCHAR(200) NOT NULL COMMENT '瀛楁鍚�',
--- `data_type` VARCHAR(200) NOT NULL COMMENT '鏁版嵁搴撳瓧娈电被鍨�',
--- `column_comment` VARCHAR(500) DEFAULT NULL COMMENT '瀛楁鎻忚堪',
--- `nullable` TINYINT(1) NOT NULL COMMENT '鏄惁鍏佽涓虹┖',
--- `primary_key` TINYINT(1) NOT NULL COMMENT '鏄惁涓婚敭',
--- `ordinal_position` INT NOT NULL COMMENT '鎺掑簭',
--- `java_type` VARCHAR(200) NOT NULL COMMENT 'Java 灞炴�х被鍨�',
--- `java_field` VARCHAR(200) NOT NULL COMMENT 'Java 灞炴�у悕',
--- `dict_type` VARCHAR(200) DEFAULT NULL COMMENT '瀛楀吀绫诲瀷',
--- `example` VARCHAR(500) DEFAULT NULL COMMENT '鏁版嵁绀轰緥',
--- `create_operation` TINYINT(1) NOT NULL COMMENT '鏄惁涓� Create 鍒涘缓鎿嶄綔鐨勫瓧娈�',
--- `update_operation` TINYINT(1) NOT NULL COMMENT '鏄惁涓� Update 鏇存柊鎿嶄綔鐨勫瓧娈�',
--- `list_operation` TINYINT(1) NOT NULL COMMENT '鏄惁涓� List 鏌ヨ鎿嶄綔鐨勫瓧娈�',
--- `list_operation_condition` VARCHAR(200) NOT NULL COMMENT 'List 鏌ヨ鎿嶄綔鐨勬潯浠剁被鍨�',
--- `list_operation_result` TINYINT(1) NOT NULL COMMENT '鏄惁涓� List 鏌ヨ鎿嶄綔鐨勮繑鍥炲瓧娈�',
--- `html_type` VARCHAR(200) NOT NULL COMMENT '鏄剧ず绫诲瀷',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='浠g爜鐢熸垚瀛楁瀹氫箟琛�';
---
--- -- 2.2 浠g爜鐢熸垚琛ㄥ畾涔夎〃
--- CREATE TABLE `infra_codegen_table` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ID 缂栧彿',
--- `data_source_config_id` BIGINT NOT NULL COMMENT '鏁版嵁婧愮紪鍙�',
--- `scene` INT NOT NULL COMMENT '鐢熸垚鍦烘櫙',
--- `table_name` VARCHAR(200) NOT NULL COMMENT '琛ㄥ悕绉�',
--- `table_comment` VARCHAR(500) DEFAULT NULL COMMENT '琛ㄦ弿杩�',
--- `remark` VARCHAR(500) DEFAULT NULL COMMENT '澶囨敞',
--- `module_name` VARCHAR(100) NOT NULL COMMENT '妯″潡鍚嶏紝鍗充竴绾х洰褰�',
--- `business_name` VARCHAR(100) NOT NULL COMMENT '涓氬姟鍚嶏紝鍗充簩绾х洰褰�',
--- `class_name` VARCHAR(100) NOT NULL COMMENT '绫诲悕绉帮紙棣栧瓧姣嶅ぇ鍐欙級',
--- `class_comment` VARCHAR(500) DEFAULT NULL COMMENT '绫绘弿杩�',
--- `author` VARCHAR(100) DEFAULT NULL COMMENT '浣滆��',
--- `template_type` INT NOT NULL COMMENT '妯℃澘绫诲瀷',
--- `front_type` INT NOT NULL COMMENT '浠g爜鐢熸垚鐨勫墠绔被鍨�',
--- `parent_menu_id` BIGINT DEFAULT NULL COMMENT '鐖惰彍鍗曠紪鍙�',
--- `master_table_id` BIGINT DEFAULT NULL COMMENT '涓昏〃鐨勭紪鍙�',
--- `sub_join_column_id` BIGINT DEFAULT NULL COMMENT '瀛愯〃鍏宠仈涓昏〃鐨勫瓧娈电紪鍙�',
--- `sub_join_many` TINYINT(1) DEFAULT NULL COMMENT '涓昏〃涓庡瓙琛ㄦ槸鍚︿竴瀵瑰',
--- `tree_parent_column_id` BIGINT DEFAULT NULL COMMENT '鏍戣〃鐨勭埗瀛楁缂栧彿',
--- `tree_name_column_id` BIGINT DEFAULT NULL COMMENT '鏍戣〃鐨勫悕瀛楀瓧娈电紪鍙�',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='浠g爜鐢熸垚琛ㄥ畾涔夎〃';
---
--- -- 2.3 鍙傛暟閰嶇疆琛�
--- CREATE TABLE `infra_config` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍙傛暟涓婚敭',
--- `category` VARCHAR(100) NOT NULL COMMENT '鍙傛暟鍒嗙被',
--- `name` VARCHAR(100) NOT NULL COMMENT '鍙傛暟鍚嶇О',
--- `config_key` VARCHAR(100) NOT NULL COMMENT '鍙傛暟閿悕',
--- `value` VARCHAR(500) NOT NULL COMMENT '鍙傛暟閿��',
--- `type` INT NOT NULL COMMENT '鍙傛暟绫诲瀷',
--- `visible` TINYINT(1) NOT NULL COMMENT '鏄惁鍙',
--- `remark` VARCHAR(500) DEFAULT NULL COMMENT '澶囨敞',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鍙傛暟閰嶇疆琛�';
---
--- -- 2.4 鏁版嵁婧愰厤缃〃
--- CREATE TABLE `infra_data_source_config` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭缂栧彿',
--- `name` VARCHAR(100) NOT NULL COMMENT '杩炴帴鍚�',
--- `url` VARCHAR(1024) NOT NULL COMMENT '鏁版嵁婧愯繛鎺�',
--- `username` VARCHAR(255) NOT NULL COMMENT '鐢ㄦ埛鍚�',
--- `password` VARCHAR(255) NOT NULL COMMENT '瀵嗙爜',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鏁版嵁婧愰厤缃〃';
---
--- -- 2.5 鏂囦欢鍐呭琛�
--- CREATE TABLE `infra_file_content` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿锛屾暟鎹簱鑷',
--- `config_id` BIGINT NOT NULL COMMENT '閰嶇疆缂栧彿',
--- `path` VARCHAR(512) NOT NULL COMMENT '璺緞锛屽嵆鏂囦欢鍚�',
--- `content` LONGBLOB NOT NULL COMMENT '鏂囦欢鍐呭',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鏂囦欢鍐呭琛�';
---
--- -- 2.6 鏂囦欢琛�
--- CREATE TABLE `infra_file` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿锛屾暟鎹簱鑷',
--- `config_id` BIGINT NOT NULL COMMENT '閰嶇疆缂栧彿',
--- `name` VARCHAR(256) DEFAULT NULL COMMENT '鍘熸枃浠跺悕',
--- `path` VARCHAR(512) NOT NULL COMMENT '璺緞锛屽嵆鏂囦欢鍚�',
--- `url` VARCHAR(1024) NOT NULL COMMENT '璁块棶鍦板潃',
--- `type` VARCHAR(128) DEFAULT NULL COMMENT '鏂囦欢鐨� MIME 绫诲瀷',
--- `size` BIGINT NOT NULL COMMENT '鏂囦欢澶у皬',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鏂囦欢琛�';
---
--- -- 2.7 鏂囦欢閰嶇疆琛�
--- CREATE TABLE `infra_file_config` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '閰嶇疆缂栧彿锛屾暟鎹簱鑷',
--- `name` VARCHAR(100) NOT NULL COMMENT '閰嶇疆鍚�',
--- `storage` INT NOT NULL COMMENT '瀛樺偍鍣�',
--- `remark` VARCHAR(500) DEFAULT NULL COMMENT '澶囨敞',
--- `master` TINYINT(1) NOT NULL COMMENT '鏄惁涓轰富閰嶇疆',
--- `config` VARCHAR(4000) NOT NULL COMMENT '鏂囦欢瀹㈡埛绔厤缃�',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鏂囦欢閰嶇疆琛�';
---
--- -- 2.8 瀹氭椂浠诲姟琛�
--- CREATE TABLE `infra_job` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '浠诲姟缂栧彿',
--- `name` VARCHAR(100) NOT NULL COMMENT '浠诲姟鍚嶇О',
--- `status` INT NOT NULL COMMENT '浠诲姟鐘舵��',
--- `handler_name` VARCHAR(100) NOT NULL COMMENT '澶勭悊鍣ㄧ殑鍚嶅瓧',
--- `handler_param` VARCHAR(500) DEFAULT NULL COMMENT '澶勭悊鍣ㄧ殑鍙傛暟',
--- `cron_expression` VARCHAR(100) NOT NULL COMMENT 'CRON 琛ㄨ揪寮�',
--- `retry_count` INT NOT NULL DEFAULT 0 COMMENT '閲嶈瘯娆℃暟',
--- `retry_interval` INT NOT NULL DEFAULT 0 COMMENT '閲嶈瘯闂撮殧锛屽崟浣嶏細姣',
--- `monitor_timeout` INT DEFAULT NULL COMMENT '鐩戞帶瓒呮椂鏃堕棿锛屽崟浣嶏細姣',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='瀹氭椂浠诲姟琛�';
---
--- -- 2.9 瀹氭椂浠诲姟鎵ц鏃ュ織琛�
--- CREATE TABLE `infra_job_log` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織缂栧彿',
--- `job_id` BIGINT NOT NULL COMMENT '浠诲姟缂栧彿',
--- `handler_name` VARCHAR(100) NOT NULL COMMENT '澶勭悊鍣ㄧ殑鍚嶅瓧',
--- `handler_param` VARCHAR(500) DEFAULT NULL COMMENT '澶勭悊鍣ㄧ殑鍙傛暟',
--- `execute_index` INT NOT NULL COMMENT '绗嚑娆℃墽琛�',
--- `begin_time` DATETIME NOT NULL COMMENT '寮�濮嬫墽琛屾椂闂�',
--- `end_time` DATETIME DEFAULT NULL COMMENT '缁撴潫鎵ц鏃堕棿',
--- `duration` INT DEFAULT NULL COMMENT '鎵ц鏃堕暱锛屽崟浣嶏細姣',
--- `status` INT NOT NULL COMMENT '鐘舵��',
--- `result` VARCHAR(4000) DEFAULT NULL COMMENT '缁撴灉鏁版嵁',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='瀹氭椂浠诲姟鎵ц鏃ュ織琛�';
---
--- -- 2.10 API 璁块棶鏃ュ織琛�
--- CREATE TABLE `infra_api_access_log` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `trace_id` VARCHAR(64) DEFAULT NULL COMMENT '閾捐矾杩借釜缂栧彿',
--- `user_id` BIGINT DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `user_type` INT DEFAULT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `application_name` VARCHAR(100) NOT NULL COMMENT '搴旂敤鍚�',
--- `request_method` VARCHAR(16) NOT NULL COMMENT '璇锋眰鏂规硶鍚�',
--- `request_url` VARCHAR(512) NOT NULL COMMENT '璁块棶鍦板潃',
--- `request_params` TEXT COMMENT '璇锋眰鍙傛暟',
--- `response_body` TEXT COMMENT '鍝嶅簲缁撴灉',
--- `user_ip` VARCHAR(64) NOT NULL COMMENT '鐢ㄦ埛 IP',
--- `user_agent` VARCHAR(512) DEFAULT NULL COMMENT '娴忚鍣� UA',
--- `operate_module` VARCHAR(100) DEFAULT NULL COMMENT '鎿嶄綔妯″潡',
--- `operate_name` VARCHAR(100) DEFAULT NULL COMMENT '鎿嶄綔鍚�',
--- `operate_type` INT DEFAULT NULL COMMENT '鎿嶄綔鍒嗙被',
--- `begin_time` DATETIME NOT NULL COMMENT '寮�濮嬭姹傛椂闂�',
--- `end_time` DATETIME NOT NULL COMMENT '缁撴潫璇锋眰鏃堕棿',
--- `duration` INT NOT NULL COMMENT '鎵ц鏃堕暱锛屽崟浣嶏細姣',
--- `result_code` INT NOT NULL COMMENT '缁撴灉鐮�',
--- `result_msg` VARCHAR(512) DEFAULT NULL COMMENT '缁撴灉鎻愮ず',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='API 璁块棶鏃ュ織琛�';
---
--- -- 2.11 API 寮傚父鏃ュ織琛�
--- CREATE TABLE `infra_api_error_log` (
--- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
--- `user_id` BIGINT DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
--- `trace_id` VARCHAR(64) DEFAULT NULL COMMENT '閾捐矾杩借釜缂栧彿',
--- `user_type` INT DEFAULT NULL COMMENT '鐢ㄦ埛绫诲瀷',
--- `application_name` VARCHAR(100) NOT NULL COMMENT '搴旂敤鍚�',
--- `request_method` VARCHAR(16) NOT NULL COMMENT '璇锋眰鏂规硶鍚�',
--- `request_url` VARCHAR(512) NOT NULL COMMENT '璁块棶鍦板潃',
--- `request_params` TEXT COMMENT '璇锋眰鍙傛暟',
--- `user_ip` VARCHAR(64) NOT NULL COMMENT '鐢ㄦ埛 IP',
--- `user_agent` VARCHAR(512) DEFAULT NULL COMMENT '娴忚鍣� UA',
--- `exception_time` DATETIME NOT NULL COMMENT '寮傚父鍙戠敓鏃堕棿',
--- `exception_name` VARCHAR(256) DEFAULT NULL COMMENT '寮傚父鍚�',
--- `exception_message` TEXT COMMENT '寮傚父瀵艰嚧鐨勬秷鎭�',
--- `exception_root_cause_message` TEXT COMMENT '寮傚父瀵艰嚧鐨勬牴娑堟伅',
--- `exception_stack_trace` TEXT COMMENT '寮傚父鐨勬爤杞ㄨ抗',
--- `exception_class_name` VARCHAR(512) DEFAULT NULL COMMENT '寮傚父鍙戠敓鐨勭被鍏ㄥ悕',
--- `exception_file_name` VARCHAR(256) DEFAULT NULL COMMENT '寮傚父鍙戠敓鐨勭被鏂囦欢',
--- `exception_method_name` VARCHAR(128) DEFAULT NULL COMMENT '寮傚父鍙戠敓鐨勬柟娉曞悕',
--- `exception_line_number` INT DEFAULT NULL COMMENT '寮傚父鍙戠敓鐨勬柟娉曟墍鍦ㄨ',
--- `process_status` INT NOT NULL COMMENT '澶勭悊鐘舵��',
--- `process_time` DATETIME DEFAULT NULL COMMENT '澶勭悊鏃堕棿',
--- `process_user_id` BIGINT DEFAULT NULL COMMENT '澶勭悊鐢ㄦ埛缂栧彿',
--- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
--- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
--- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
--- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
--- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
--- PRIMARY KEY (`id`)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='API 寮傚父鏃ュ織琛�';
-
-
--- =====================================================
--- 绗笁閮ㄥ垎: yudao-module-bpm 宸ヤ綔娴佹ā鍧� (8 寮犺〃)
--- =====================================================
-
--- 3.1 BPM 娴佺▼鍒嗙被琛�
-CREATE TABLE `bpm_category` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍒嗙被缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '鍒嗙被鍚�',
- `code` VARCHAR(255) NOT NULL COMMENT '鍒嗙被鏍囧織',
- `description` VARCHAR(500) DEFAULT NULL COMMENT '鍒嗙被鎻忚堪',
- `status` TINYINT NOT NULL DEFAULT 0 COMMENT '鍒嗙被鐘舵�侊紙0姝e父 1鍋滅敤锛�',
- `sort` INT NOT NULL DEFAULT 0 COMMENT '鍒嗙被鎺掑簭',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BPM 娴佺▼鍒嗙被琛�';
-
--- 3.2 BPM 娴佺▼琛ㄨ揪寮忚〃
-CREATE TABLE `bpm_process_expression` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '琛ㄨ揪寮忓悕瀛�',
- `status` TINYINT NOT NULL DEFAULT 0 COMMENT '琛ㄨ揪寮忕姸鎬侊紙0姝e父 1鍋滅敤锛�',
- `expression` VARCHAR(1024) NOT NULL COMMENT '琛ㄨ揪寮�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BPM 娴佺▼琛ㄨ揪寮忚〃';
-
--- 3.3 BPM 娴佺▼鐩戝惉鍣ㄨ〃
-CREATE TABLE `bpm_process_listener` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭 ID',
- `name` VARCHAR(255) NOT NULL COMMENT '鐩戝惉鍣ㄥ悕瀛�',
- `status` TINYINT NOT NULL DEFAULT 0 COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
- `type` VARCHAR(50) NOT NULL COMMENT '鐩戝惉绫诲瀷锛坋xecution鎵ц鐩戝惉鍣ㄣ�乼ask浠诲姟鐩戝惉鍣級',
- `event` VARCHAR(50) NOT NULL COMMENT '鐩戝惉浜嬩欢',
- `value_type` VARCHAR(50) NOT NULL COMMENT '鍊肩被鍨嬶紙class绫汇�乨elegateExpression濮旀墭琛ㄨ揪寮忋�乪xpression琛ㄨ揪寮忥級',
- `value` VARCHAR(1024) NOT NULL COMMENT '鍊�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BPM 娴佺▼鐩戝惉鍣ㄨ〃';
-
--- 3.4 OA 璇峰亣鐢宠琛�
-CREATE TABLE `bpm_oa_leave` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '璇峰亣琛ㄥ崟涓婚敭',
- `user_id` BIGINT NOT NULL COMMENT '鐢宠浜虹殑鐢ㄦ埛缂栧彿',
- `type` TINYINT NOT NULL COMMENT '璇峰亣绫诲瀷',
- `reason` VARCHAR(500) DEFAULT NULL COMMENT '鍘熷洜',
- `start_time` DATETIME NOT NULL COMMENT '寮�濮嬫椂闂�',
- `end_time` DATETIME NOT NULL COMMENT '缁撴潫鏃堕棿',
- `day` BIGINT NOT NULL COMMENT '璇峰亣澶╂暟',
- `status` TINYINT NOT NULL DEFAULT 0 COMMENT '瀹℃壒缁撴灉',
- `process_instance_id` VARCHAR(64) DEFAULT NULL COMMENT '瀵瑰簲鐨勬祦绋嬬紪鍙�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='OA 璇峰亣鐢宠琛�';
-
--- 3.5 娴佺▼鎶勯�佽〃
-CREATE TABLE `bpm_process_instance_copy` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `start_user_id` BIGINT NOT NULL COMMENT '鍙戣捣浜� Id',
- `process_instance_name` VARCHAR(255) NOT NULL COMMENT '娴佺▼鍚�',
- `process_instance_id` VARCHAR(64) NOT NULL COMMENT '娴佺▼瀹炰緥鐨勭紪鍙�',
- `process_definition_id` VARCHAR(64) NOT NULL COMMENT '娴佺▼瀹炰緥鐨勬祦绋嬪畾涔夌紪鍙�',
- `category` VARCHAR(64) DEFAULT NULL COMMENT '娴佺▼鍒嗙被',
- `activity_id` VARCHAR(64) DEFAULT NULL COMMENT '娴佺▼娲诲姩鐨勭紪鍙�',
- `activity_name` VARCHAR(255) DEFAULT NULL COMMENT '娴佺▼娲诲姩鐨勫悕瀛�',
- `task_id` VARCHAR(64) DEFAULT NULL COMMENT '娴佺▼浠诲姟鐨勭紪鍙�',
- `user_id` BIGINT NOT NULL COMMENT '鐢ㄦ埛缂栧彿锛堣鎶勯�佺殑鐢ㄦ埛缂栧彿锛�',
- `reason` VARCHAR(500) DEFAULT NULL COMMENT '鎶勯�佹剰瑙�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='娴佺▼鎶勯�佽〃';
-
--- 3.6 BPM 宸ヤ綔娴佽〃鍗曞畾涔夎〃
-CREATE TABLE `bpm_form` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '琛ㄥ崟鍚�',
- `status` TINYINT NOT NULL DEFAULT 0 COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
- `conf` TEXT NOT NULL COMMENT '琛ㄥ崟鐨勯厤缃�',
- `fields` JSON NOT NULL COMMENT '琛ㄥ崟椤圭殑鏁扮粍',
- `remark` VARCHAR(500) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BPM 宸ヤ綔娴佽〃鍗曞畾涔夎〃';
-
--- 3.7 BPM 娴佺▼瀹氫箟鎷撳睍淇℃伅琛�
-CREATE TABLE `bpm_process_definition_info` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `process_definition_id` VARCHAR(64) NOT NULL COMMENT '娴佺▼瀹氫箟鐨勭紪鍙�',
- `model_id` VARCHAR(64) NOT NULL COMMENT '娴佺▼妯″瀷鐨勭紪鍙�',
- `model_type` TINYINT NOT NULL DEFAULT 10 COMMENT '娴佺▼妯″瀷鐨勭被鍨�',
- `category` VARCHAR(64) DEFAULT NULL COMMENT '娴佺▼鍒嗙被鐨勭紪鐮�',
- `icon` VARCHAR(255) DEFAULT NULL COMMENT '鍥炬爣',
- `description` VARCHAR(500) DEFAULT NULL COMMENT '鎻忚堪',
- `form_type` TINYINT NOT NULL DEFAULT 10 COMMENT '琛ㄥ崟绫诲瀷锛�10鏅�氳〃鍗� 20鑷畾涔夎〃鍗曪級',
- `form_id` BIGINT DEFAULT NULL COMMENT '鍔ㄦ�佽〃鍗曠紪鍙�',
- `form_conf` TEXT DEFAULT NULL COMMENT '琛ㄥ崟鐨勯厤缃�',
- `form_fields` JSON DEFAULT NULL COMMENT '琛ㄥ崟椤圭殑鏁扮粍',
- `form_custom_create_path` VARCHAR(255) DEFAULT NULL COMMENT '鑷畾涔夎〃鍗曠殑鎻愪氦璺緞',
- `form_custom_view_path` VARCHAR(255) DEFAULT NULL COMMENT '鑷畾涔夎〃鍗曠殑鏌ョ湅璺緞',
- `simple_model` TEXT DEFAULT NULL COMMENT 'SIMPLE 璁捐鍣ㄦā鍨嬫暟鎹�',
- `visible` BIT(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍙',
- `sort` BIGINT NOT NULL DEFAULT 0 COMMENT '鎺掑簭鍊�',
- `start_user_ids` VARCHAR(1024) DEFAULT NULL COMMENT '鍙彂璧风敤鎴风紪鍙锋暟缁�',
- `start_dept_ids` VARCHAR(1024) DEFAULT NULL COMMENT '鍙彂璧烽儴闂ㄧ紪鍙锋暟缁�',
- `manager_user_ids` VARCHAR(1024) DEFAULT NULL COMMENT '鍙鐞嗙敤鎴风紪鍙锋暟缁�',
- `allow_cancel_running_process` BIT(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏佽鎾ら攢瀹℃壒涓殑鐢宠',
- `allow_withdraw_task` BIT(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏佽瀹℃壒浜烘挙鍥炰换鍔�',
- `process_id_rule` JSON DEFAULT NULL COMMENT '娴佺▼ ID 瑙勫垯',
- `auto_approval_type` TINYINT DEFAULT NULL COMMENT '鑷姩鍘婚噸绫诲瀷',
- `title_setting` JSON DEFAULT NULL COMMENT '鏍囬璁剧疆',
- `summary_setting` JSON DEFAULT NULL COMMENT '鎽樿璁剧疆',
- `process_before_trigger_setting` JSON DEFAULT NULL COMMENT '娴佺▼鍓嶇疆閫氱煡璁剧疆',
- `process_after_trigger_setting` JSON DEFAULT NULL COMMENT '娴佺▼鍚庣疆閫氱煡璁剧疆',
- `task_before_trigger_setting` JSON DEFAULT NULL COMMENT '浠诲姟鍓嶇疆閫氱煡璁剧疆',
- `task_after_trigger_setting` JSON DEFAULT NULL COMMENT '浠诲姟鍚庣疆閫氱煡璁剧疆',
- `print_template_setting` JSON DEFAULT NULL COMMENT '鑷畾涔夋墦鍗版ā鏉胯缃�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BPM 娴佺▼瀹氫箟鎷撳睍淇℃伅琛�';
-
--- 3.8 BPM 鐢ㄦ埛缁勮〃
-CREATE TABLE `bpm_user_group` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '缁勫悕',
- `description` VARCHAR(500) DEFAULT NULL COMMENT '鎻忚堪',
- `status` TINYINT NOT NULL DEFAULT 0 COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
- `user_ids` JSON NOT NULL COMMENT '鎴愬憳鐢ㄦ埛缂栧彿鏁扮粍',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='BPM 鐢ㄦ埛缁勮〃';
-
-
--- =====================================================
--- 绗洓閮ㄥ垎: yudao-module-crm 瀹㈡埛鍏崇郴绠$悊妯″潡 (19 寮犺〃)
--- =====================================================
-
--- 4.1 CRM 鍟嗘満琛�
-CREATE TABLE `crm_business` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '鍟嗘満鍚嶇О',
- `customer_id` BIGINT NOT NULL COMMENT '瀹㈡埛缂栧彿',
- `follow_up_status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '璺熻繘鐘舵��',
- `contact_last_time` DATETIME NULL DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
- `contact_next_time` DATETIME NULL DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
- `owner_user_id` BIGINT NULL DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
- `status_type_id` BIGINT NOT NULL COMMENT '鍟嗘満鐘舵�佺粍缂栧彿',
- `status_id` BIGINT NOT NULL COMMENT '鍟嗘満鐘舵�佺紪鍙�',
- `end_status` INT NULL DEFAULT NULL COMMENT '缁撴潫鐘舵��',
- `end_remark` VARCHAR(500) NULL DEFAULT NULL COMMENT '缁撴潫鏃剁殑澶囨敞',
- `deal_time` DATETIME NULL DEFAULT NULL COMMENT '棰勮鎴愪氦鏃ユ湡',
- `total_product_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '浜у搧鎬婚噾棰濓紝鍗曚綅锛氬厓',
- `discount_percent` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鏁村崟鎶樻墸锛岀櫨鍒嗘瘮',
- `total_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鍟嗘満鎬婚噾棰濓紝鍗曚綅锛氬厓',
- `remark` VARCHAR(500) NULL DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍟嗘満琛�';
-
--- 4.2 CRM 鍟嗘満浜у搧鍏宠仈琛�
-CREATE TABLE `crm_business_product` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `business_id` BIGINT NOT NULL COMMENT '鍟嗘満缂栧彿',
- `product_id` BIGINT NOT NULL COMMENT '浜у搧缂栧彿',
- `product_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '浜у搧鍗曚环锛屽崟浣嶏細鍏�',
- `business_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鍟嗘満浠锋牸锛屽崟浣嶏細鍏�',
- `count` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鏁伴噺',
- `total_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鎬昏浠锋牸锛屽崟浣嶏細鍏�',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍟嗘満浜у搧鍏宠仈琛�';
-
--- 4.3 CRM 鍟嗘満鐘舵�佽〃
-CREATE TABLE `crm_business_status` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `type_id` BIGINT NOT NULL COMMENT '鐘舵�佺被鍨嬬紪鍙�',
- `name` VARCHAR(255) NOT NULL COMMENT '鐘舵�佸悕',
- `percent` INT NULL DEFAULT NULL COMMENT '璧㈠崟鐜囷紝鐧惧垎姣�',
- `sort` INT NULL DEFAULT NULL COMMENT '鎺掑簭',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍟嗘満鐘舵�佽〃';
-
--- 4.4 CRM 鍟嗘満鐘舵�佺粍琛�
-CREATE TABLE `crm_business_status_type` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `name` VARCHAR(255) NOT NULL COMMENT '鐘舵�佺被鍨嬪悕',
- `dept_ids` VARCHAR(2048) NULL DEFAULT NULL COMMENT '浣跨敤鐨勯儴闂ㄧ紪鍙�',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍟嗘満鐘舵�佺粍琛�';
-
--- 4.5 CRM 绾跨储琛�
-CREATE TABLE `crm_clue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿锛屼富閿嚜澧�',
- `name` VARCHAR(255) NOT NULL COMMENT '绾跨储鍚嶇О',
- `follow_up_status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '璺熻繘鐘舵��',
- `contact_last_time` DATETIME NULL DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
- `contact_last_content` VARCHAR(500) NULL DEFAULT NULL COMMENT '鏈�鍚庤窡杩涘唴瀹�',
- `contact_next_time` DATETIME NULL DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
- `owner_user_id` BIGINT NULL DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
- `transform_status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '杞寲鐘舵��',
- `customer_id` BIGINT NULL DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `mobile` VARCHAR(20) NULL DEFAULT NULL COMMENT '鎵嬫満鍙�',
- `telephone` VARCHAR(20) NULL DEFAULT NULL COMMENT '鐢佃瘽',
- `qq` VARCHAR(20) NULL DEFAULT NULL COMMENT 'QQ',
- `wechat` VARCHAR(50) NULL DEFAULT NULL COMMENT '寰俊',
- `email` VARCHAR(100) NULL DEFAULT NULL COMMENT '閭',
- `area_id` INT NULL DEFAULT NULL COMMENT '鎵�鍦ㄥ湴',
- `detail_address` VARCHAR(255) NULL DEFAULT NULL COMMENT '璇︾粏鍦板潃',
- `industry_id` INT NULL DEFAULT NULL COMMENT '鎵�灞炶涓�',
- `level` INT NULL DEFAULT NULL COMMENT '瀹㈡埛绛夌骇',
- `source` INT NULL DEFAULT NULL COMMENT '瀹㈡埛鏉ユ簮',
- `remark` VARCHAR(500) NULL DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 绾跨储琛�';
-
--- 4.6 CRM 鑱旂郴浜轰笌鍟嗘満鍏宠仈琛�
-CREATE TABLE `crm_contact_business` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `contact_id` BIGINT NOT NULL COMMENT '鑱旂郴浜虹紪鍙�',
- `business_id` BIGINT NOT NULL COMMENT '鍟嗘満缂栧彿',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鑱旂郴浜轰笌鍟嗘満鍏宠仈琛�';
-
--- 4.7 CRM 鑱旂郴浜鸿〃
-CREATE TABLE `crm_contact` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `name` VARCHAR(255) NOT NULL COMMENT '鑱旂郴浜哄鍚�',
- `customer_id` BIGINT NOT NULL COMMENT '瀹㈡埛缂栧彿',
- `contact_last_time` DATETIME NULL DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
- `contact_last_content` VARCHAR(500) NULL DEFAULT NULL COMMENT '鏈�鍚庤窡杩涘唴瀹�',
- `contact_next_time` DATETIME NULL DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
- `owner_user_id` BIGINT NULL DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴风紪鍙�',
- `mobile` VARCHAR(20) NULL DEFAULT NULL COMMENT '鎵嬫満鍙�',
- `telephone` VARCHAR(20) NULL DEFAULT NULL COMMENT '鐢佃瘽',
- `email` VARCHAR(100) NULL DEFAULT NULL COMMENT '鐢靛瓙閭',
- `qq` BIGINT NULL DEFAULT NULL COMMENT 'QQ',
- `wechat` VARCHAR(50) NULL DEFAULT NULL COMMENT '寰俊',
- `area_id` INT NULL DEFAULT NULL COMMENT '鎵�鍦ㄥ湴',
- `detail_address` VARCHAR(255) NULL DEFAULT NULL COMMENT '璇︾粏鍦板潃',
- `sex` INT NULL DEFAULT NULL COMMENT '鎬у埆',
- `master` TINYINT(1) NULL DEFAULT NULL COMMENT '鏄惁鍏抽敭鍐崇瓥浜�',
- `post` VARCHAR(100) NULL DEFAULT NULL COMMENT '鑱屼綅',
- `parent_id` BIGINT NULL DEFAULT NULL COMMENT '鐩村睘涓婄骇',
- `remark` VARCHAR(500) NULL DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鑱旂郴浜鸿〃';
-
--- 4.8 CRM 鍚堝悓閰嶇疆琛�
-CREATE TABLE `crm_contract_config` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `notify_enabled` TINYINT(1) NULL DEFAULT NULL COMMENT '鏄惁寮�鍚彁鍓嶆彁閱�',
- `notify_days` INT NULL DEFAULT NULL COMMENT '鎻愬墠鎻愰啋澶╂暟',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍚堝悓閰嶇疆琛�';
-
--- 4.9 CRM 鍚堝悓琛�
-CREATE TABLE `crm_contract` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍚堝悓缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '鍚堝悓鍚嶇О',
- `no` VARCHAR(100) NOT NULL COMMENT '鍚堝悓缂栧彿',
- `customer_id` BIGINT NOT NULL COMMENT '瀹㈡埛缂栧彿',
- `business_id` BIGINT NULL DEFAULT NULL COMMENT '鍟嗘満缂栧彿',
- `contact_last_time` DATETIME NULL DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
- `owner_user_id` BIGINT NULL DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
- `process_instance_id` VARCHAR(64) NULL DEFAULT NULL COMMENT '宸ヤ綔娴佺紪鍙�',
- `audit_status` INT NULL DEFAULT NULL COMMENT '瀹℃壒鐘舵��',
- `order_date` DATETIME NULL DEFAULT NULL COMMENT '涓嬪崟鏃ユ湡',
- `start_time` DATETIME NULL DEFAULT NULL COMMENT '寮�濮嬫椂闂�',
- `end_time` DATETIME NULL DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
- `total_product_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '浜у搧鎬婚噾棰濓紝鍗曚綅锛氬厓',
- `discount_percent` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鏁村崟鎶樻墸',
- `total_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鍚堝悓鎬婚噾棰濓紝鍗曚綅锛氬垎',
- `sign_contact_id` BIGINT NULL DEFAULT NULL COMMENT '瀹㈡埛绛剧害浜�',
- `sign_user_id` BIGINT NULL DEFAULT NULL COMMENT '鍏徃绛剧害浜�',
- `remark` VARCHAR(500) NULL DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍚堝悓琛�';
-
--- 4.10 CRM 鍚堝悓浜у搧鍏宠仈琛�
-CREATE TABLE `crm_contract_product` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `contract_id` BIGINT NOT NULL COMMENT '鍚堝悓缂栧彿',
- `product_id` BIGINT NOT NULL COMMENT '浜у搧缂栧彿',
- `product_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '浜у搧鍗曚环锛屽崟浣嶏細鍏�',
- `contract_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鍚堝悓浠锋牸锛屽崟浣嶏細鍏�',
- `count` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鏁伴噺',
- `total_price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '鎬昏浠锋牸锛屽崟浣嶏細鍏�',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍚堝悓浜у搧鍏宠仈琛�';
-
--- 4.11 CRM 瀹㈡埛琛�
-CREATE TABLE `crm_customer` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '瀹㈡埛鍚嶇О',
- `follow_up_status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '璺熻繘鐘舵��',
- `contact_last_time` DATETIME NULL DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
- `contact_last_content` VARCHAR(500) NULL DEFAULT NULL COMMENT '鏈�鍚庤窡杩涘唴瀹�',
- `contact_next_time` DATETIME NULL DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
- `owner_user_id` BIGINT NULL DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
- `owner_time` DATETIME NULL DEFAULT NULL COMMENT '鎴愪负璐熻矗浜虹殑鏃堕棿',
- `lock_status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '閿佸畾鐘舵��',
- `deal_status` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鎴愪氦鐘舵��',
- `mobile` VARCHAR(20) NULL DEFAULT NULL COMMENT '鎵嬫満',
- `telephone` VARCHAR(20) NULL DEFAULT NULL COMMENT '鐢佃瘽',
- `qq` VARCHAR(20) NULL DEFAULT NULL COMMENT 'QQ',
- `wechat` VARCHAR(50) NULL DEFAULT NULL COMMENT '寰俊',
- `email` VARCHAR(100) NULL DEFAULT NULL COMMENT '閭',
- `area_id` INT NULL DEFAULT NULL COMMENT '鎵�鍦ㄥ湴',
- `detail_address` VARCHAR(255) NULL DEFAULT NULL COMMENT '璇︾粏鍦板潃',
- `industry_id` INT NULL DEFAULT NULL COMMENT '鎵�灞炶涓�',
- `level` INT NULL DEFAULT NULL COMMENT '瀹㈡埛绛夌骇',
- `source` INT NULL DEFAULT NULL COMMENT '瀹㈡埛鏉ユ簮',
- `remark` VARCHAR(500) NULL DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 瀹㈡埛琛�';
-
--- 4.12 CRM 瀹㈡埛闄愬埗閰嶇疆琛�
-CREATE TABLE `crm_customer_limit_config` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `type` INT NOT NULL COMMENT '瑙勫垯绫诲瀷',
- `user_ids` VARCHAR(2048) NULL DEFAULT NULL COMMENT '瑙勫垯閫傜敤浜虹兢',
- `dept_ids` VARCHAR(2048) NULL DEFAULT NULL COMMENT '瑙勫垯閫傜敤閮ㄩ棬',
- `max_count` INT NULL DEFAULT NULL COMMENT '鏁伴噺涓婇檺',
- `deal_count_enabled` TINYINT(1) NULL DEFAULT NULL COMMENT '鎴愪氦瀹㈡埛鏄惁鍗犳湁鎷ユ湁瀹㈡埛鏁�',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 瀹㈡埛闄愬埗閰嶇疆琛�';
-
--- 4.13 CRM 瀹㈡埛鍏捣閰嶇疆琛�
-CREATE TABLE `crm_customer_pool_config` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `enabled` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍚敤瀹㈡埛鍏捣',
- `contact_expire_days` INT NULL DEFAULT NULL COMMENT '鏈窡杩涙斁鍏ュ叕娴峰ぉ鏁�',
- `deal_expire_days` INT NULL DEFAULT NULL COMMENT '鏈垚浜ゆ斁鍏ュ叕娴峰ぉ鏁�',
- `notify_enabled` TINYINT(1) NULL DEFAULT NULL COMMENT '鏄惁寮�鍚彁鍓嶆彁閱�',
- `notify_days` INT NULL DEFAULT NULL COMMENT '鎻愬墠鎻愰啋澶╂暟',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 瀹㈡埛鍏捣閰嶇疆琛�';
-
--- 4.14 CRM 璺熻繘璁板綍琛�
-CREATE TABLE `crm_follow_up_record` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `biz_type` INT NOT NULL COMMENT '鏁版嵁绫诲瀷',
- `biz_id` BIGINT NOT NULL COMMENT '鏁版嵁缂栧彿',
- `type` INT NULL DEFAULT NULL COMMENT '璺熻繘绫诲瀷',
- `content` VARCHAR(2000) NULL DEFAULT NULL COMMENT '璺熻繘鍐呭',
- `next_time` DATETIME NULL DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
- `pic_urls` VARCHAR(2048) NULL DEFAULT NULL COMMENT '鍥剧墖',
- `file_urls` VARCHAR(2048) NULL DEFAULT NULL COMMENT '闄勪欢',
- `business_ids` VARCHAR(2048) NULL DEFAULT NULL COMMENT '鍏宠仈鐨勫晢鏈虹紪鍙锋暟缁�',
- `contact_ids` VARCHAR(2048) NULL DEFAULT NULL COMMENT '鍏宠仈鐨勮仈绯讳汉缂栧彿鏁扮粍',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 璺熻繘璁板綍琛�';
-
--- 4.15 CRM 鏁版嵁鏉冮檺琛�
-CREATE TABLE `crm_permission` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿锛屼富閿嚜澧�',
- `biz_type` INT NOT NULL COMMENT '鏁版嵁绫诲瀷',
- `biz_id` BIGINT NOT NULL COMMENT '鏁版嵁缂栧彿',
- `user_id` BIGINT NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `level` INT NOT NULL COMMENT '鏉冮檺绾у埆',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鏁版嵁鏉冮檺琛�';
-
--- 4.16 CRM 浜у搧鍒嗙被琛�
-CREATE TABLE `crm_product_category` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍒嗙被缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '鍒嗙被鍚嶇О',
- `parent_id` BIGINT NOT NULL DEFAULT 0 COMMENT '鐖剁骇缂栧彿',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 浜у搧鍒嗙被琛�';
-
--- 4.17 CRM 浜у搧琛�
-CREATE TABLE `crm_product` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '浜у搧鍚嶇О',
- `no` VARCHAR(100) NOT NULL COMMENT '浜у搧缂栫爜',
- `unit` INT NULL DEFAULT NULL COMMENT '鍗曚綅',
- `price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '浠锋牸锛屽崟浣嶏細鍏�',
- `status` INT NULL DEFAULT NULL COMMENT '鐘舵��',
- `category_id` BIGINT NULL DEFAULT NULL COMMENT '浜у搧鍒嗙被 ID',
- `description` VARCHAR(500) NULL DEFAULT NULL COMMENT '浜у搧鎻忚堪',
- `owner_user_id` BIGINT NULL DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 浜у搧琛�';
-
--- 4.18 CRM 鍥炴琛�
-CREATE TABLE `crm_receivable` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ID',
- `no` VARCHAR(100) NOT NULL COMMENT '鍥炴缂栧彿',
- `plan_id` BIGINT NULL DEFAULT NULL COMMENT '鍥炴璁″垝缂栧彿',
- `customer_id` BIGINT NOT NULL COMMENT '瀹㈡埛缂栧彿',
- `contract_id` BIGINT NOT NULL COMMENT '鍚堝悓缂栧彿',
- `owner_user_id` BIGINT NULL DEFAULT NULL COMMENT '璐熻矗浜虹紪鍙�',
- `return_time` DATETIME NULL DEFAULT NULL COMMENT '鍥炴鏃ユ湡',
- `return_type` INT NULL DEFAULT NULL COMMENT '鍥炴鏂瑰紡',
- `price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '璁″垝鍥炴閲戦锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(500) NULL DEFAULT NULL COMMENT '澶囨敞',
- `process_instance_id` VARCHAR(64) NULL DEFAULT NULL COMMENT '宸ヤ綔娴佺紪鍙�',
- `audit_status` INT NULL DEFAULT NULL COMMENT '瀹℃壒鐘舵��',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍥炴琛�';
-
--- 4.19 CRM 鍥炴璁″垝琛�
-CREATE TABLE `crm_receivable_plan` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `period` INT NULL DEFAULT NULL COMMENT '鏈熸暟',
- `customer_id` BIGINT NOT NULL COMMENT '瀹㈡埛缂栧彿',
- `contract_id` BIGINT NOT NULL COMMENT '鍚堝悓缂栧彿',
- `owner_user_id` BIGINT NULL DEFAULT NULL COMMENT '璐熻矗浜虹紪鍙�',
- `return_time` DATETIME NULL DEFAULT NULL COMMENT '璁″垝鍥炴鏃ユ湡',
- `return_type` INT NULL DEFAULT NULL COMMENT '璁″垝鍥炴绫诲瀷',
- `price` DECIMAL(24, 6) NULL DEFAULT NULL COMMENT '璁″垝鍥炴閲戦锛屽崟浣嶏細鍏�',
- `receivable_id` BIGINT NULL DEFAULT NULL COMMENT '鍥炴缂栧彿',
- `remind_days` INT NULL DEFAULT NULL COMMENT '鎻愬墠鍑犲ぉ鎻愰啋',
- `remind_time` DATETIME NULL DEFAULT NULL COMMENT '鎻愰啋鏃ユ湡',
- `remark` VARCHAR(500) NULL DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) NULL DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
- `deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='CRM 鍥炴璁″垝琛�';
-
-
--- =====================================================
--- 绗簲閮ㄥ垎: yudao-module-erp 浼佷笟璧勬簮璁″垝妯″潡 (33 寮犺〃)
--- =====================================================
-
--- 5.1 缁撶畻璐︽埛琛�
-CREATE TABLE `erp_account` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缁撶畻璐︽埛缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '璐︽埛鍚嶇О',
- `no` VARCHAR(255) NOT NULL COMMENT '璐︽埛缂栫爜',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `status` INT NOT NULL COMMENT '寮�鍚姸鎬�',
- `sort` INT NOT NULL COMMENT '鎺掑簭',
- `default_status` TINYINT(1) NOT NULL COMMENT '鏄惁榛樿',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 缁撶畻璐︽埛';
-
--- 5.2 浠樻鍗曡〃
-CREATE TABLE `erp_finance_payment` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '浠樻鍗曞彿',
- `status` INT NOT NULL COMMENT '浠樻鐘舵��',
- `payment_time` DATETIME NOT NULL COMMENT '浠樻鏃堕棿',
- `finance_user_id` BIGINT DEFAULT NULL COMMENT '璐㈠姟浜哄憳缂栧彿',
- `supplier_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
- `account_id` BIGINT DEFAULT NULL COMMENT '浠樻璐︽埛缂栧彿',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣浠锋牸锛屽崟浣嶏細鍏�',
- `discount_price` DECIMAL(24,6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
- `payment_price` DECIMAL(24,6) NOT NULL COMMENT '瀹炰粯閲戦锛屽崟浣嶏細鍒�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 浠樻鍗�';
-
--- 5.3 浠樻鍗曢」琛�
-CREATE TABLE `erp_finance_payment_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍏ュ簱椤圭紪鍙�',
- `payment_id` BIGINT DEFAULT NULL COMMENT '浠樻鍗曠紪鍙�',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `biz_id` BIGINT DEFAULT NULL COMMENT '涓氬姟缂栧彿',
- `biz_no` VARCHAR(255) DEFAULT NULL COMMENT '涓氬姟鍗曞彿',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '搴斾粯閲戦锛屽崟浣嶏細鍒�',
- `paid_price` DECIMAL(24,6) NOT NULL COMMENT '宸蹭粯閲戦锛屽崟浣嶏細鍒�',
- `payment_price` DECIMAL(24,6) NOT NULL COMMENT '鏈浠樻锛屽崟浣嶏細鍒�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 浠樻椤�';
-
--- 5.4 鏀舵鍗曡〃
-CREATE TABLE `erp_finance_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '鏀舵鍗曞彿',
- `status` INT NOT NULL COMMENT '鏀舵鐘舵��',
- `receipt_time` DATETIME NOT NULL COMMENT '鏀舵鏃堕棿',
- `finance_user_id` BIGINT DEFAULT NULL COMMENT '璐㈠姟浜哄憳缂栧彿',
- `customer_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `account_id` BIGINT DEFAULT NULL COMMENT '鏀舵璐︽埛缂栧彿',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣浠锋牸锛屽崟浣嶏細鍏�',
- `discount_price` DECIMAL(24,6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
- `receipt_price` DECIMAL(24,6) NOT NULL COMMENT '瀹炴敹閲戦锛屽崟浣嶏細鍒�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 鏀舵鍗�';
-
--- 5.5 鏀舵椤硅〃
-CREATE TABLE `erp_finance_receipt_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍏ュ簱椤圭紪鍙�',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鏀舵鍗曠紪鍙�',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `biz_id` BIGINT DEFAULT NULL COMMENT '涓氬姟缂栧彿',
- `biz_no` VARCHAR(255) DEFAULT NULL COMMENT '涓氬姟鍗曞彿',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '搴旀敹閲戦锛屽崟浣嶏細鍒�',
- `receipted_price` DECIMAL(24,6) NOT NULL COMMENT '宸叉敹閲戦锛屽崟浣嶏細鍒�',
- `receipt_price` DECIMAL(24,6) NOT NULL COMMENT '鏈鏀舵锛屽崟浣嶏細鍒�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 鏀舵椤�';
-
--- 5.6 浜у搧鍒嗙被琛�
-CREATE TABLE `erp_product_category` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍒嗙被缂栧彿',
- `parent_id` BIGINT NOT NULL COMMENT '鐖跺垎绫荤紪鍙�',
- `name` VARCHAR(255) NOT NULL COMMENT '鍒嗙被鍚嶇О',
- `code` VARCHAR(255) NOT NULL COMMENT '鍒嗙被缂栫爜',
- `sort` INT NOT NULL COMMENT '鍒嗙被鎺掑簭',
- `status` INT NOT NULL COMMENT '寮�鍚姸鎬�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 浜у搧鍒嗙被';
-
--- 5.7 浜у搧琛�
-CREATE TABLE `erp_product` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '浜у搧缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '浜у搧鍚嶇О',
- `bar_code` VARCHAR(255) NOT NULL COMMENT '浜у搧鏉$爜',
- `category_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍒嗙被缂栧彿',
- `unit_id` BIGINT DEFAULT NULL COMMENT '鍗曚綅缂栧彿',
- `status` INT NOT NULL COMMENT '浜у搧鐘舵��',
- `standard` VARCHAR(255) DEFAULT NULL COMMENT '浜у搧瑙勬牸',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '浜у搧澶囨敞',
- `expiry_day` INT DEFAULT NULL COMMENT '淇濊川鏈熷ぉ鏁�',
- `weight` DECIMAL(24,6) DEFAULT NULL COMMENT '鍩虹閲嶉噺锛坘g锛�',
- `purchase_price` DECIMAL(24,6) DEFAULT NULL COMMENT '閲囪喘浠锋牸锛屽崟浣嶏細鍏�',
- `sale_price` DECIMAL(24,6) DEFAULT NULL COMMENT '閿�鍞环鏍硷紝鍗曚綅锛氬厓',
- `min_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈�浣庝环鏍硷紝鍗曚綅锛氬厓',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 浜у搧';
-
--- 5.8 浜у搧鍗曚綅琛�
-CREATE TABLE `erp_product_unit` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍗曚綅缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '鍗曚綅鍚嶅瓧',
- `status` INT NOT NULL COMMENT '鍗曚綅鐘舵��',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 浜у搧鍗曚綅';
-
--- 5.9 渚涘簲鍟嗚〃
-CREATE TABLE `erp_supplier` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '渚涘簲鍟嗙紪鍙�',
- `name` VARCHAR(255) NOT NULL COMMENT '渚涘簲鍟嗗悕绉�',
- `contact` VARCHAR(255) DEFAULT NULL COMMENT '鑱旂郴浜�',
- `mobile` VARCHAR(255) DEFAULT NULL COMMENT '鎵嬫満鍙风爜',
- `telephone` VARCHAR(255) DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
- `email` VARCHAR(255) DEFAULT NULL COMMENT '鐢靛瓙閭',
- `fax` VARCHAR(255) DEFAULT NULL COMMENT '浼犵湡',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `status` INT NOT NULL COMMENT '寮�鍚姸鎬�',
- `sort` INT NOT NULL COMMENT '鎺掑簭',
- `tax_no` VARCHAR(255) DEFAULT NULL COMMENT '绾崇◣浜鸿瘑鍒彿',
- `tax_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庣巼',
- `bank_name` VARCHAR(255) DEFAULT NULL COMMENT '寮�鎴疯',
- `bank_account` VARCHAR(255) DEFAULT NULL COMMENT '寮�鎴疯处鍙�',
- `bank_address` VARCHAR(255) DEFAULT NULL COMMENT '寮�鎴峰湴鍧�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 渚涘簲鍟�';
-
--- 5.10 瀹㈡埛琛�
-CREATE TABLE `erp_customer` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '瀹㈡埛缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '瀹㈡埛鍚嶇О',
- `contact` VARCHAR(255) DEFAULT NULL COMMENT '鑱旂郴浜�',
- `mobile` VARCHAR(255) DEFAULT NULL COMMENT '鎵嬫満鍙风爜',
- `telephone` VARCHAR(255) DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
- `email` VARCHAR(255) DEFAULT NULL COMMENT '鐢靛瓙閭',
- `fax` VARCHAR(255) DEFAULT NULL COMMENT '浼犵湡',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `status` INT NOT NULL COMMENT '寮�鍚姸鎬�',
- `sort` INT NOT NULL COMMENT '鎺掑簭',
- `tax_no` VARCHAR(255) DEFAULT NULL COMMENT '绾崇◣浜鸿瘑鍒彿',
- `tax_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庣巼',
- `bank_name` VARCHAR(255) DEFAULT NULL COMMENT '寮�鎴疯',
- `bank_account` VARCHAR(255) DEFAULT NULL COMMENT '寮�鎴疯处鍙�',
- `bank_address` VARCHAR(255) DEFAULT NULL COMMENT '寮�鎴峰湴鍧�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 瀹㈡埛';
-
--- 5.11 閲囪喘璁㈠崟琛�
-CREATE TABLE `erp_purchase_order` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '閲囪喘璁㈠崟鍙�',
- `status` INT NOT NULL COMMENT '閲囪喘鐘舵��',
- `supplier_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
- `account_id` BIGINT DEFAULT NULL COMMENT '缁撶畻璐︽埛缂栧彿',
- `order_time` DATETIME NOT NULL COMMENT '涓嬪崟鏃堕棿',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鏈�缁堝悎璁′环鏍硷紝鍗曚綅锛氬厓',
- `total_product_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣浜у搧浠锋牸锛屽崟浣嶏細鍏�',
- `total_tax_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
- `discount_percent` DECIMAL(24,6) NOT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
- `discount_price` DECIMAL(24,6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
- `deposit_price` DECIMAL(24,6) NOT NULL COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢鍦板潃',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `in_count` DECIMAL(24,6) DEFAULT NULL COMMENT '閲囪喘鍏ュ簱鏁伴噺',
- `return_count` DECIMAL(24,6) DEFAULT NULL COMMENT '閲囪喘閫�璐ф暟閲�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閲囪喘璁㈠崟';
-
--- 5.12 閲囪喘璁㈠崟椤硅〃
-CREATE TABLE `erp_purchase_order_items` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `order_id` BIGINT DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) NOT NULL COMMENT '浜у搧鍗曚綅鍗曚环锛屽崟浣嶏細鍏�',
- `count` DECIMAL(24,6) NOT NULL COMMENT '鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鎬讳环锛屽崟浣嶏細鍏�',
- `tax_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
- `tax_price` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庨锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `in_count` DECIMAL(24,6) DEFAULT NULL COMMENT '閲囪喘鍏ュ簱鏁伴噺',
- `return_count` DECIMAL(24,6) DEFAULT NULL COMMENT '閲囪喘閫�璐ф暟閲�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閲囪喘璁㈠崟椤�';
-
--- 5.13 閲囪喘鍏ュ簱琛�
-CREATE TABLE `erp_purchase_in` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '閲囪喘鍏ュ簱鍗曞彿',
- `status` INT NOT NULL COMMENT '鍏ュ簱鐘舵��',
- `supplier_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
- `account_id` BIGINT DEFAULT NULL COMMENT '缁撶畻璐︽埛缂栧彿',
- `in_time` DATETIME NOT NULL COMMENT '鍏ュ簱鏃堕棿',
- `order_id` BIGINT DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
- `order_no` VARCHAR(255) DEFAULT NULL COMMENT '閲囪喘璁㈠崟鍙�',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鏈�缁堝悎璁′环鏍硷紝鍗曚綅锛氬厓',
- `payment_price` DECIMAL(24,6) DEFAULT NULL COMMENT '宸叉敮浠橀噾棰濓紝鍗曚綅锛氬厓',
- `total_product_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣浜у搧浠锋牸锛屽崟浣嶏細鍏�',
- `total_tax_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
- `discount_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
- `discount_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
- `other_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍏跺畠閲戦锛屽崟浣嶏細鍏�',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢鍦板潃',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閲囪喘鍏ュ簱';
-
--- 5.14 閲囪喘鍏ュ簱椤硅〃
-CREATE TABLE `erp_purchase_in_items` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `in_id` BIGINT DEFAULT NULL COMMENT '閲囪喘鍏ュ簱缂栧彿',
- `order_item_id` BIGINT DEFAULT NULL COMMENT '閲囪喘璁㈠崟椤圭紪鍙�',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) NOT NULL COMMENT '浜у搧鍗曚綅鍗曚环锛屽崟浣嶏細鍏�',
- `count` DECIMAL(24,6) NOT NULL COMMENT '鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鎬讳环锛屽崟浣嶏細鍏�',
- `tax_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
- `tax_price` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庨锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閲囪喘鍏ュ簱椤�';
-
--- 5.15 閲囪喘閫�璐ц〃
-CREATE TABLE `erp_purchase_return` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '閲囪喘閫�璐у崟鍙�',
- `status` INT NOT NULL COMMENT '閫�璐х姸鎬�',
- `supplier_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
- `account_id` BIGINT DEFAULT NULL COMMENT '缁撶畻璐︽埛缂栧彿',
- `return_time` DATETIME NOT NULL COMMENT '閫�璐ф椂闂�',
- `order_id` BIGINT DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
- `order_no` VARCHAR(255) DEFAULT NULL COMMENT '閲囪喘璁㈠崟鍙�',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鏈�缁堝悎璁′环鏍硷紝鍗曚綅锛氬厓',
- `refund_price` DECIMAL(24,6) DEFAULT NULL COMMENT '宸查��娆鹃噾棰濓紝鍗曚綅锛氬厓',
- `total_product_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣浜у搧浠锋牸锛屽崟浣嶏細鍏�',
- `total_tax_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
- `discount_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
- `discount_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
- `other_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍏跺畠閲戦锛屽崟浣嶏細鍏�',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢鍦板潃',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閲囪喘閫�璐�';
-
--- 5.16 閲囪喘閫�璐ч」琛�
-CREATE TABLE `erp_purchase_return_items` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `return_id` BIGINT DEFAULT NULL COMMENT '閲囪喘閫�璐х紪鍙�',
- `order_item_id` BIGINT DEFAULT NULL COMMENT '閲囪喘璁㈠崟椤圭紪鍙�',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) NOT NULL COMMENT '浜у搧鍗曚綅鍗曚环锛屽崟浣嶏細鍏�',
- `count` DECIMAL(24,6) NOT NULL COMMENT '鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鎬讳环锛屽崟浣嶏細鍏�',
- `tax_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
- `tax_price` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庨锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閲囪喘閫�璐ч」';
-
--- 5.17 閿�鍞鍗曡〃
-CREATE TABLE `erp_sale_order` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '閿�鍞鍗曞彿',
- `status` INT NOT NULL COMMENT '閿�鍞姸鎬�',
- `customer_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `account_id` BIGINT DEFAULT NULL COMMENT '缁撶畻璐︽埛缂栧彿',
- `sale_user_id` BIGINT DEFAULT NULL COMMENT '閿�鍞憳缂栧彿',
- `order_time` DATETIME NOT NULL COMMENT '涓嬪崟鏃堕棿',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鏈�缁堝悎璁′环鏍硷紝鍗曚綅锛氬厓',
- `total_product_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣浜у搧浠锋牸锛屽崟浣嶏細鍏�',
- `total_tax_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
- `discount_percent` DECIMAL(24,6) NOT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
- `discount_price` DECIMAL(24,6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
- `deposit_price` DECIMAL(24,6) NOT NULL COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢鍦板潃',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `out_count` DECIMAL(24,6) DEFAULT NULL COMMENT '閿�鍞嚭搴撴暟閲�',
- `return_count` DECIMAL(24,6) DEFAULT NULL COMMENT '閿�鍞��璐ф暟閲�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閿�鍞鍗�';
-
--- 5.18 閿�鍞鍗曢」琛�
-CREATE TABLE `erp_sale_order_items` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `order_id` BIGINT DEFAULT NULL COMMENT '閿�鍞鍗曠紪鍙�',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) NOT NULL COMMENT '浜у搧鍗曚綅鍗曚环锛屽崟浣嶏細鍏�',
- `count` DECIMAL(24,6) NOT NULL COMMENT '鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鎬讳环锛屽崟浣嶏細鍏�',
- `tax_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
- `tax_price` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庨锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `out_count` DECIMAL(24,6) DEFAULT NULL COMMENT '閿�鍞嚭搴撴暟閲�',
- `return_count` DECIMAL(24,6) DEFAULT NULL COMMENT '閿�鍞��璐ф暟閲�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閿�鍞鍗曢」';
-
--- 5.19 閿�鍞嚭搴撹〃
-CREATE TABLE `erp_sale_out` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '閿�鍞嚭搴撳崟鍙�',
- `status` INT NOT NULL COMMENT '鍑哄簱鐘舵��',
- `customer_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `account_id` BIGINT DEFAULT NULL COMMENT '缁撶畻璐︽埛缂栧彿',
- `sale_user_id` BIGINT DEFAULT NULL COMMENT '閿�鍞憳缂栧彿',
- `out_time` DATETIME NOT NULL COMMENT '鍑哄簱鏃堕棿',
- `order_id` BIGINT DEFAULT NULL COMMENT '閿�鍞鍗曠紪鍙�',
- `order_no` VARCHAR(255) DEFAULT NULL COMMENT '閿�鍞鍗曞彿',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鏈�缁堝悎璁′环鏍硷紝鍗曚綅锛氬厓',
- `receipt_price` DECIMAL(24,6) DEFAULT NULL COMMENT '宸叉敹娆鹃噾棰濓紝鍗曚綅锛氬厓',
- `total_product_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣浜у搧浠锋牸锛屽崟浣嶏細鍏�',
- `total_tax_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
- `discount_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
- `discount_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
- `other_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍏跺畠閲戦锛屽崟浣嶏細鍏�',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢鍦板潃',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閿�鍞嚭搴�';
-
--- 5.20 閿�鍞嚭搴撻」琛�
-CREATE TABLE `erp_sale_out_items` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `out_id` BIGINT DEFAULT NULL COMMENT '閿�鍞嚭搴撶紪鍙�',
- `order_item_id` BIGINT DEFAULT NULL COMMENT '閿�鍞鍗曢」缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) NOT NULL COMMENT '浜у搧鍗曚綅鍗曚环锛屽崟浣嶏細鍏�',
- `count` DECIMAL(24,6) NOT NULL COMMENT '鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鎬讳环锛屽崟浣嶏細鍏�',
- `tax_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
- `tax_price` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庨锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閿�鍞嚭搴撻」';
-
--- 5.21 閿�鍞��璐ц〃
-CREATE TABLE `erp_sale_return` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '閿�鍞��璐у崟鍙�',
- `status` INT NOT NULL COMMENT '閫�璐х姸鎬�',
- `customer_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `account_id` BIGINT DEFAULT NULL COMMENT '缁撶畻璐︽埛缂栧彿',
- `sale_user_id` BIGINT DEFAULT NULL COMMENT '閿�鍞憳缂栧彿',
- `return_time` DATETIME NOT NULL COMMENT '閫�璐ф椂闂�',
- `order_id` BIGINT DEFAULT NULL COMMENT '閿�鍞鍗曠紪鍙�',
- `order_no` VARCHAR(255) DEFAULT NULL COMMENT '閿�鍞鍗曞彿',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鏈�缁堝悎璁′环鏍硷紝鍗曚綅锛氬厓',
- `refund_price` DECIMAL(24,6) DEFAULT NULL COMMENT '宸查��娆鹃噾棰濓紝鍗曚綅锛氬厓',
- `total_product_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣浜у搧浠锋牸锛屽崟浣嶏細鍏�',
- `total_tax_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
- `discount_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
- `discount_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
- `other_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍏跺畠閲戦锛屽崟浣嶏細鍏�',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢鍦板潃',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閿�鍞��璐�';
-
--- 5.22 閿�鍞��璐ч」琛�
-CREATE TABLE `erp_sale_return_items` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `return_id` BIGINT DEFAULT NULL COMMENT '閿�鍞��璐х紪鍙�',
- `order_item_id` BIGINT DEFAULT NULL COMMENT '閿�鍞鍗曢」缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) NOT NULL COMMENT '浜у搧鍗曚綅鍗曚环锛屽崟浣嶏細鍏�',
- `count` DECIMAL(24,6) NOT NULL COMMENT '鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鎬讳环锛屽崟浣嶏細鍏�',
- `tax_percent` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
- `tax_price` DECIMAL(24,6) DEFAULT NULL COMMENT '绋庨锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 閿�鍞��璐ч」';
-
--- 5.23 浠撳簱琛�
-CREATE TABLE `erp_warehouse` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '浠撳簱缂栧彿',
- `name` VARCHAR(255) NOT NULL COMMENT '浠撳簱鍚嶇О',
- `address` VARCHAR(255) DEFAULT NULL COMMENT '浠撳簱鍦板潃',
- `sort` BIGINT NOT NULL COMMENT '鎺掑簭',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `principal` VARCHAR(255) DEFAULT NULL COMMENT '璐熻矗浜�',
- `warehouse_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浠撳偍璐癸紝鍗曚綅锛氬厓',
- `truckage_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鎼繍璐癸紝鍗曚綅锛氬厓',
- `status` INT NOT NULL COMMENT '寮�鍚姸鎬�',
- `default_status` TINYINT(1) NOT NULL COMMENT '鏄惁榛樿',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 浠撳簱';
-
--- 5.24 浜у搧搴撳瓨琛�
-CREATE TABLE `erp_stock` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `count` DECIMAL(24,6) NOT NULL COMMENT '搴撳瓨鏁伴噺',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 浜у搧搴撳瓨';
-
--- 5.25 浜у搧搴撳瓨鏄庣粏琛�
-CREATE TABLE `erp_stock_record` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `count` DECIMAL(24,6) NOT NULL COMMENT '鍑哄叆搴撴暟閲�',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鎬诲簱瀛橀噺',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `biz_id` BIGINT DEFAULT NULL COMMENT '涓氬姟缂栧彿',
- `biz_item_id` BIGINT DEFAULT NULL COMMENT '涓氬姟椤圭紪鍙�',
- `biz_no` VARCHAR(255) DEFAULT NULL COMMENT '涓氬姟鍗曞彿',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 浜у搧搴撳瓨鏄庣粏';
-
--- 5.26 鍏跺畠鍏ュ簱鍗曡〃
-CREATE TABLE `erp_stock_in` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍏ュ簱缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '鍏ュ簱鍗曞彿',
- `supplier_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
- `in_time` DATETIME NOT NULL COMMENT '鍏ュ簱鏃堕棿',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣閲戦锛屽崟浣嶏細鍏�',
- `status` INT NOT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢 URL',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 鍏跺畠鍏ュ簱鍗�';
-
--- 5.27 鍏跺畠鍏ュ簱鍗曢」琛�
-CREATE TABLE `erp_stock_in_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍏ュ簱椤圭紪鍙�',
- `in_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浜у搧鍗曚环',
- `count` DECIMAL(24,6) DEFAULT NULL COMMENT '浜у搧鏁伴噺',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堣閲戦锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 鍏跺畠鍏ュ簱鍗曢」';
-
--- 5.28 鍏跺畠鍑哄簱鍗曡〃
-CREATE TABLE `erp_stock_out` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍑哄簱缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '鍑哄簱鍗曞彿',
- `customer_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `out_time` DATETIME NOT NULL COMMENT '鍑哄簱鏃堕棿',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣閲戦锛屽崟浣嶏細鍏�',
- `status` INT NOT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢 URL',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 鍏跺畠鍑哄簱鍗�';
-
--- 5.29 鍏跺畠鍑哄簱鍗曢」琛�
-CREATE TABLE `erp_stock_out_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鍑哄簱椤圭紪鍙�',
- `out_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浜у搧鍗曚环',
- `count` DECIMAL(24,6) DEFAULT NULL COMMENT '浜у搧鏁伴噺',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堣閲戦锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 鍏跺畠鍑哄簱鍗曢」';
-
--- 5.30 搴撳瓨璋冩嫧鍗曡〃
-CREATE TABLE `erp_stock_move` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '璋冩嫧缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '璋冩嫧鍗曞彿',
- `move_time` DATETIME NOT NULL COMMENT '璋冩嫧鏃堕棿',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣閲戦锛屽崟浣嶏細鍏�',
- `status` INT NOT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢 URL',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 搴撳瓨璋冩嫧鍗�';
-
--- 5.31 搴撳瓨璋冩嫧鍗曢」琛�
-CREATE TABLE `erp_stock_move_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '璋冩嫧椤圭紪鍙�',
- `move_id` BIGINT DEFAULT NULL COMMENT '璋冩嫧缂栧彿',
- `from_warehouse_id` BIGINT DEFAULT NULL COMMENT '璋冨嚭浠撳簱缂栧彿',
- `to_warehouse_id` BIGINT DEFAULT NULL COMMENT '璋冨叆浠撳簱缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浜у搧鍗曚环',
- `count` DECIMAL(24,6) DEFAULT NULL COMMENT '浜у搧鏁伴噺',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堣閲戦锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 搴撳瓨璋冩嫧鍗曢」';
-
--- 5.32 搴撳瓨鐩樼偣鍗曡〃
-CREATE TABLE `erp_stock_check` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鐩樼偣缂栧彿',
- `no` VARCHAR(255) NOT NULL COMMENT '鐩樼偣鍗曞彿',
- `check_time` DATETIME NOT NULL COMMENT '鐩樼偣鏃堕棿',
- `total_count` DECIMAL(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
- `total_price` DECIMAL(24,6) NOT NULL COMMENT '鍚堣閲戦锛屽崟浣嶏細鍏�',
- `status` INT NOT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `file_url` VARCHAR(255) DEFAULT NULL COMMENT '闄勪欢 URL',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 搴撳瓨鐩樼偣鍗�';
-
--- 5.33 搴撳瓨鐩樼偣鍗曢」琛�
-CREATE TABLE `erp_stock_check_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鐩樼偣椤圭紪鍙�',
- `check_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `product_unit_id` BIGINT DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
- `product_price` DECIMAL(24,6) DEFAULT NULL COMMENT '浜у搧鍗曚环',
- `stock_count` DECIMAL(24,6) DEFAULT NULL COMMENT '璐﹂潰鏁伴噺锛堝綋鍓嶅簱瀛橈級',
- `actual_count` DECIMAL(24,6) DEFAULT NULL COMMENT '瀹為檯鏁伴噺锛堝疄闄呭簱瀛橈級',
- `count` DECIMAL(24,6) DEFAULT NULL COMMENT '鐩堜簭鏁伴噺',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堣閲戦锛屽崟浣嶏細鍏�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='ERP 搴撳瓨鐩樼偣鍗曢」';
-
-
--- =====================================================
--- 绗叚閮ㄥ垎: yudao-module-mes 鍒堕�犳墽琛岀郴缁熸ā鍧� (绾� 133 寮犺〃)
--- =====================================================
-
--- 6.1 MES 鍋囨湡璁剧疆琛�
-CREATE TABLE `mes_cal_holiday` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `day` DATETIME DEFAULT NULL COMMENT '鏃ユ湡',
- `type` INT DEFAULT NULL COMMENT '鏃ユ湡绫诲瀷',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍋囨湡璁剧疆';
-
--- 6.2 MES 鎺掔彮璁″垝琛�
-CREATE TABLE `mes_cal_plan` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '璁″垝缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '璁″垝缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '璁″垝鍚嶇О',
- `calendar_type` INT DEFAULT NULL COMMENT '鐝粍绫诲瀷',
- `start_date` DATETIME DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
- `end_date` DATETIME DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
- `shift_type` INT DEFAULT NULL COMMENT '杞彮鏂瑰紡',
- `shift_method` INT DEFAULT NULL COMMENT '鍊掔彮鏂瑰紡',
- `shift_count` INT DEFAULT NULL COMMENT '鍊掔彮澶╂暟',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鎺掔彮璁″垝';
-
--- 6.3 MES 璁″垝鐝琛�
-CREATE TABLE `mes_cal_plan_shift` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鐝缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鎺掔彮璁″垝缂栧彿',
- `sort` INT DEFAULT NULL COMMENT '鏄剧ず椤哄簭',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鐝鍚嶇О',
- `start_time` VARCHAR(20) DEFAULT NULL COMMENT '寮�濮嬫椂闂达紙HH:mm 鏍煎紡锛�',
- `end_time` VARCHAR(20) DEFAULT NULL COMMENT '缁撴潫鏃堕棿锛圚H:mm 鏍煎紡锛�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁″垝鐝';
-
--- 6.4 MES 璁″垝鐝粍鍏宠仈琛�
-CREATE TABLE `mes_cal_plan_team` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鎺掔彮璁″垝缂栧彿',
- `team_id` BIGINT DEFAULT NULL COMMENT '鐝粍缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁″垝鐝粍鍏宠仈';
-
--- 6.5 MES 鐝粍琛�
-CREATE TABLE `mes_cal_team` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鐝粍缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鐝粍缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鐝粍鍚嶇О',
- `calendar_type` INT DEFAULT NULL COMMENT '鐝粍绫诲瀷',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐝粍';
-
--- 6.6 MES 鐝粍鎴愬憳琛�
-CREATE TABLE `mes_cal_team_member` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鐝粍鎴愬憳缂栧彿',
- `team_id` BIGINT DEFAULT NULL COMMENT '鐝粍缂栧彿',
- `user_id` BIGINT DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐝粍鎴愬憳';
-
--- 6.7 MES 鐝粍鎺掔彮琛�
-CREATE TABLE `mes_cal_team_shift` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鎺掔彮璁″垝缂栧彿',
- `team_id` BIGINT DEFAULT NULL COMMENT '鐝粍缂栧彿',
- `shift_id` BIGINT DEFAULT NULL COMMENT '鐝缂栧彿',
- `day` DATETIME DEFAULT NULL COMMENT '鏃ユ湡',
- `sort` INT DEFAULT NULL COMMENT '鎺掑簭',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐝粍鎺掔彮';
-
-
--- =====================================================
--- MES 宸ュ叿绠$悊妯″潡 (tm)
--- =====================================================
-
--- 6.8 MES 宸ュ叿绫诲瀷琛�
-CREATE TABLE `mes_tm_tool_type` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '绫诲瀷缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '绫诲瀷鍚嶇О',
- `code_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁缂栫爜绠$悊',
- `mainten_type` INT DEFAULT NULL COMMENT '淇濆吇缁存姢绫诲瀷',
- `mainten_period` INT DEFAULT NULL COMMENT '淇濆吇鍛ㄦ湡',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ュ叿绫诲瀷';
-
--- 6.9 MES 宸ュ叿鍙拌处琛�
-CREATE TABLE `mes_tm_tool` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '宸ュ叿缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '宸ュ叿鍚嶇О',
- `brand` VARCHAR(100) DEFAULT NULL COMMENT '鍝佺墝',
- `specification` VARCHAR(100) DEFAULT NULL COMMENT '鍨嬪彿瑙勬牸',
- `tool_type_id` BIGINT DEFAULT NULL COMMENT '宸ュ叿绫诲瀷缂栧彿',
- `quantity` INT DEFAULT NULL COMMENT '鏁伴噺',
- `available_quantity` INT DEFAULT NULL COMMENT '鍙敤鏁伴噺',
- `mainten_type` INT DEFAULT NULL COMMENT '淇濆吇缁存姢绫诲瀷',
- `next_mainten_period` INT DEFAULT NULL COMMENT '涓嬫淇濆吇鍛ㄦ湡锛堟鏁帮級',
- `next_mainten_date` DATETIME DEFAULT NULL COMMENT '涓嬫淇濆吇鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ュ叿鍙拌处';
-
-
--- =====================================================
--- MES 璁惧绠$悊妯″潡 (dv)
--- =====================================================
-
--- 6.10 MES 璁惧绫诲瀷琛�
-CREATE TABLE `mes_dv_machinery_type` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '绫诲瀷缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '绫诲瀷鍚嶇О',
- `parent_id` BIGINT DEFAULT NULL COMMENT '鐖剁被鍨嬬紪鍙�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `sort` INT DEFAULT NULL COMMENT '鏄剧ず鎺掑簭',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁惧绫诲瀷';
-
--- 6.11 MES 璁惧鍙拌处琛�
-CREATE TABLE `mes_dv_machinery` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '璁惧缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '璁惧鍚嶇О',
- `brand` VARCHAR(100) DEFAULT NULL COMMENT '鍝佺墝',
- `specification` VARCHAR(100) DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
- `machinery_type_id` BIGINT DEFAULT NULL COMMENT '璁惧绫诲瀷缂栧彿',
- `workshop_id` BIGINT DEFAULT NULL COMMENT '鎵�灞炶溅闂寸紪鍙�',
- `status` INT DEFAULT NULL COMMENT '璁惧鐘舵��',
- `last_mainten_time` DATETIME DEFAULT NULL COMMENT '鏈�杩戜繚鍏绘椂闂�',
- `last_check_time` DATETIME DEFAULT NULL COMMENT '鏈�杩戠偣妫�鏃堕棿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁惧鍙拌处';
-
--- 6.12 MES 鐐规淇濆吇椤圭洰琛�
-CREATE TABLE `mes_dv_subject` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '椤圭洰缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '椤圭洰鍚嶇О',
- `type` INT DEFAULT NULL COMMENT '椤圭洰绫诲瀷',
- `content` VARCHAR(500) DEFAULT NULL COMMENT '椤圭洰鍐呭',
- `standard` VARCHAR(500) DEFAULT NULL COMMENT '鏍囧噯',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐐规淇濆吇椤圭洰';
-
--- 6.13 MES 鐐规淇濆吇鏂规琛�
-CREATE TABLE `mes_dv_check_plan` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鏂规缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鏂规鍚嶇О',
- `type` INT DEFAULT NULL COMMENT '鏂规绫诲瀷',
- `start_date` DATETIME DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
- `end_date` DATETIME DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
- `cycle_type` INT DEFAULT NULL COMMENT '鍛ㄦ湡绫诲瀷',
- `cycle_count` INT DEFAULT NULL COMMENT '鍛ㄦ湡鏁伴噺',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐐规淇濆吇鏂规';
-
--- 6.14 MES 鐐规淇濆吇鏂规璁惧琛�
-CREATE TABLE `mes_dv_check_plan_machinery` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鏂规缂栧彿',
- `machinery_id` BIGINT DEFAULT NULL COMMENT '璁惧缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐐规淇濆吇鏂规璁惧';
-
--- 6.15 MES 鐐规淇濆吇鏂规椤圭洰琛�
-CREATE TABLE `mes_dv_check_plan_subject` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鏂规缂栧彿',
- `subject_id` BIGINT DEFAULT NULL COMMENT '椤圭洰缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐐规淇濆吇鏂规椤圭洰';
-
--- 6.16 MES 璁惧鐐规璁板綍琛�
-CREATE TABLE `mes_dv_check_record` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鐐规璁″垝缂栧彿',
- `machinery_id` BIGINT DEFAULT NULL COMMENT '璁惧缂栧彿',
- `check_time` DATETIME DEFAULT NULL COMMENT '鐐规鏃堕棿',
- `user_id` BIGINT DEFAULT NULL COMMENT '鐐规浜虹紪鍙�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁惧鐐规璁板綍';
-
--- 6.17 MES 璁惧鐐规璁板綍鏄庣粏琛�
-CREATE TABLE `mes_dv_check_record_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `record_id` BIGINT DEFAULT NULL COMMENT '鐐规璁板綍缂栧彿',
- `subject_id` BIGINT DEFAULT NULL COMMENT '鐐规椤圭洰缂栧彿',
- `check_status` INT DEFAULT NULL COMMENT '鐐规缁撴灉',
- `check_result` VARCHAR(500) DEFAULT NULL COMMENT '寮傚父鎻忚堪',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁惧鐐规璁板綍鏄庣粏';
-
--- 6.18 MES 璁惧淇濆吇璁板綍琛�
-CREATE TABLE `mes_dv_mainten_record` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '璁″垝缂栧彿',
- `machinery_id` BIGINT DEFAULT NULL COMMENT '璁惧缂栧彿',
- `mainten_time` DATETIME DEFAULT NULL COMMENT '淇濆吇鏃堕棿',
- `user_id` BIGINT DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁惧淇濆吇璁板綍';
-
--- 6.19 MES 璁惧淇濆吇璁板綍鏄庣粏琛�
-CREATE TABLE `mes_dv_mainten_record_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `record_id` BIGINT DEFAULT NULL COMMENT '淇濆吇璁板綍缂栧彿',
- `subject_id` BIGINT DEFAULT NULL COMMENT '椤圭洰缂栧彿',
- `status` INT DEFAULT NULL COMMENT '淇濆吇缁撴灉',
- `result` VARCHAR(500) DEFAULT NULL COMMENT '寮傚父鎻忚堪',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁惧淇濆吇璁板綍鏄庣粏';
-
--- 6.20 MES 缁翠慨宸ュ崟琛�
-CREATE TABLE `mes_dv_repair` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '缁翠慨宸ュ崟缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '缁翠慨宸ュ崟鍚嶇О',
- `machinery_id` BIGINT DEFAULT NULL COMMENT '璁惧缂栧彿',
- `require_date` DATETIME DEFAULT NULL COMMENT '鎶ヤ慨鏃ユ湡',
- `finish_date` DATETIME DEFAULT NULL COMMENT '缁翠慨瀹屾垚鏃ユ湡',
- `confirm_date` DATETIME DEFAULT NULL COMMENT '楠屾敹鏃ユ湡',
- `result` INT DEFAULT NULL COMMENT '缁翠慨缁撴灉',
- `accepted_user_id` BIGINT DEFAULT NULL COMMENT '缁翠慨浜虹敤鎴风紪鍙�',
- `confirm_user_id` BIGINT DEFAULT NULL COMMENT '楠屾敹浜虹敤鎴风紪鍙�',
- `source_doc_type` INT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
- `source_doc_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `source_doc_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栫爜',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 缁翠慨宸ュ崟';
-
--- 6.21 MES 缁翠慨宸ュ崟琛岃〃
-CREATE TABLE `mes_dv_repair_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `repair_id` BIGINT DEFAULT NULL COMMENT '缁翠慨宸ュ崟缂栧彿',
- `subject_id` BIGINT DEFAULT NULL COMMENT '鐐规淇濆吇椤圭洰缂栧彿',
- `malfunction` VARCHAR(500) DEFAULT NULL COMMENT '鏁呴殰鎻忚堪',
- `malfunction_url` VARCHAR(500) DEFAULT NULL COMMENT '鏁呴殰鍥剧墖 URL',
- `description` VARCHAR(500) DEFAULT NULL COMMENT '缁翠慨鎻忚堪',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 缁翠慨宸ュ崟琛�';
-
-
--- =====================================================
--- MES 涓绘暟鎹ā鍧� (md)
--- =====================================================
-
--- 6.22 MES 缂栫爜瑙勫垯缁勬垚琛�
-CREATE TABLE `mes_md_auto_code_part` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `rule_id` BIGINT DEFAULT NULL COMMENT '瑙勫垯缂栧彿',
- `sort` INT DEFAULT NULL COMMENT '鍒嗘搴忓彿',
- `type` INT DEFAULT NULL COMMENT '鍒嗘绫诲瀷',
- `length` INT DEFAULT NULL COMMENT '鍒嗘闀垮害',
- `date_format` VARCHAR(100) DEFAULT NULL COMMENT '鏃ユ湡鏍煎紡',
- `fix_character` VARCHAR(255) DEFAULT NULL COMMENT '鍥哄畾瀛楃',
- `serial_start_no` INT DEFAULT NULL COMMENT '娴佹按鍙疯捣濮嬪��',
- `serial_step` INT DEFAULT NULL COMMENT '娴佹按鍙锋闀�',
- `cycle_flag` BIT(1) DEFAULT b'0' COMMENT '娴佹按鍙锋槸鍚﹀惊鐜�',
- `cycle_method` INT DEFAULT NULL COMMENT '寰幆鏂瑰紡',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 缂栫爜瑙勫垯缁勬垚';
-
--- 6.23 MES 缂栫爜鐢熸垚璁板綍琛�
-CREATE TABLE `mes_md_auto_code_record` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `rule_id` BIGINT DEFAULT NULL COMMENT '瑙勫垯缂栧彿',
- `result` VARCHAR(255) DEFAULT NULL COMMENT '鐢熸垚鐨勭紪鐮�',
- `serial_no` BIGINT DEFAULT NULL COMMENT '鐢熸垚鐨勬祦姘村彿',
- `input_char` VARCHAR(255) DEFAULT NULL COMMENT '浼犲叆鐨勫弬鏁�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 缂栫爜鐢熸垚璁板綍';
-
--- 6.24 MES 缂栫爜瑙勫垯琛�
-CREATE TABLE `mes_md_auto_code_rule` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '瑙勫垯缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '瑙勫垯鍚嶇О',
- `description` VARCHAR(255) DEFAULT NULL COMMENT '鎻忚堪',
- `max_length` INT DEFAULT NULL COMMENT '鏈�澶ч暱搴�',
- `padded` BIT(1) DEFAULT b'0' COMMENT '鏄惁琛ラ綈',
- `padded_char` VARCHAR(10) DEFAULT NULL COMMENT '琛ラ綈瀛楃',
- `padded_method` INT DEFAULT NULL COMMENT '琛ラ綈鏂瑰紡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 缂栫爜瑙勫垯';
-
--- 6.25 MES 瀹㈡埛琛�
-CREATE TABLE `mes_md_client` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '瀹㈡埛缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '瀹㈡埛鍚嶇О',
- `nickname` VARCHAR(100) DEFAULT NULL COMMENT '瀹㈡埛绠�绉�',
- `english_name` VARCHAR(100) DEFAULT NULL COMMENT '瀹㈡埛鑻辨枃鍚嶇О',
- `description` VARCHAR(255) DEFAULT NULL COMMENT '瀹㈡埛绠�浠�',
- `logo` VARCHAR(255) DEFAULT NULL COMMENT '瀹㈡埛LOGO鍦板潃',
- `type` INT DEFAULT NULL COMMENT '瀹㈡埛绫诲瀷',
- `address` VARCHAR(255) DEFAULT NULL COMMENT '瀹㈡埛鍦板潃',
- `website` VARCHAR(255) DEFAULT NULL COMMENT '瀹㈡埛瀹樼綉鍦板潃',
- `email` VARCHAR(100) DEFAULT NULL COMMENT '瀹㈡埛閭鍦板潃',
- `telephone` VARCHAR(100) DEFAULT NULL COMMENT '瀹㈡埛鐢佃瘽',
- `contact1_name` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�1',
- `contact1_telephone` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�1-鐢佃瘽',
- `contact1_email` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�1-閭',
- `contact2_name` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�2',
- `contact2_telephone` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�2-鐢佃瘽',
- `contact2_email` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�2-閭',
- `credit_code` VARCHAR(100) DEFAULT NULL COMMENT '缁熶竴绀句細淇$敤浠g爜',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 瀹㈡埛';
-
--- 6.26 MES 鐗╂枡鎵规灞炴�ч厤缃〃
-CREATE TABLE `mes_md_item_batch_config` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡缂栧彿',
- `produce_date_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鐢熶骇鏃ユ湡',
- `expire_date_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鏈夋晥鏈�',
- `receipt_date_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鍏ュ簱鏃ユ湡',
- `vendor_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-渚涘簲鍟�',
- `client_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-瀹㈡埛',
- `sales_order_code_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-閿�鍞鍗曠紪鍙�',
- `purchase_order_code_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-閲囪喘璁㈠崟缂栧彿',
- `work_order_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鐢熶骇宸ュ崟',
- `task_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鐢熶骇浠诲姟',
- `workstation_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-宸ヤ綔绔�',
- `tool_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-宸ュ叿',
- `mold_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-妯″叿',
- `lot_number_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鐢熶骇鎵瑰彿',
- `quality_status_flag` BIT(1) DEFAULT b'0' COMMENT '鎵规灞炴��-璐ㄩ噺鐘舵��',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡鎵规灞炴�ч厤缃�';
-
--- 6.27 MES 鐗╂枡浜у搧琛�
-CREATE TABLE `mes_md_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鐗╂枡缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鐗╂枡鍚嶇О',
- `specification` VARCHAR(255) DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
- `unit_measure_id` BIGINT DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
- `item_type_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡鍒嗙被缂栧彿',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `safe_stock_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍚敤瀹夊叏搴撳瓨',
- `min_stock` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈�浣庡簱瀛橀噺',
- `max_stock` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈�楂樺簱瀛橀噺',
- `high_value` BIT(1) DEFAULT b'0' COMMENT '鏄惁楂樺�肩墿鏂�',
- `batch_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍚敤鎵规绠$悊',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡浜у搧';
-
--- 6.28 MES 鐗╂枡浜у搧鍒嗙被琛�
-CREATE TABLE `mes_md_item_type` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍒嗙被缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍒嗙被鍚嶇О',
- `parent_id` BIGINT DEFAULT NULL COMMENT '鐖跺垎绫荤紪鍙�',
- `item_or_product` VARCHAR(100) DEFAULT NULL COMMENT '鐗╂枡/浜у搧鏍囪瘑',
- `sort` INT DEFAULT NULL COMMENT '鏄剧ず鎺掑簭',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡浜у搧鍒嗙被';
-
--- 6.29 MES 浜у搧 BOM 琛�
-CREATE TABLE `mes_md_product_bom` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡浜у搧缂栧彿',
- `bom_item_id` BIGINT DEFAULT NULL COMMENT 'BOM鐗╂枡缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鐗╂枡浣跨敤姣斾緥',
- `status` INT DEFAULT NULL COMMENT '鏄惁鍚敤',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 浜у搧 BOM';
-
--- 6.30 MES 浜у搧 SIP 琛�
-CREATE TABLE `mes_md_product_sip` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡浜у搧缂栧彿',
- `sort` INT DEFAULT NULL COMMENT '鎺掑垪椤哄簭',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `title` VARCHAR(100) DEFAULT NULL COMMENT '鏍囬',
- `description` VARCHAR(500) DEFAULT NULL COMMENT '璇︾粏鎻忚堪',
- `url` VARCHAR(255) DEFAULT NULL COMMENT '鍥剧墖鍦板潃',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 浜у搧 SIP';
-
--- 6.31 MES 浜у搧 SOP 琛�
-CREATE TABLE `mes_md_product_sop` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡浜у搧缂栧彿',
- `sort` INT DEFAULT NULL COMMENT '鎺掑垪椤哄簭',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `title` VARCHAR(100) DEFAULT NULL COMMENT '鏍囬',
- `description` VARCHAR(500) DEFAULT NULL COMMENT '璇︾粏鎻忚堪',
- `url` VARCHAR(255) DEFAULT NULL COMMENT '鍥剧墖鍦板潃',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 浜у搧 SOP';
-
--- 6.32 MES 璁¢噺鍗曚綅琛�
-CREATE TABLE `mes_md_unit_measure` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曚綅缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍗曚綅鍚嶇О',
- `primary_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁涓诲崟浣�',
- `primary_id` BIGINT DEFAULT NULL COMMENT '涓诲崟浣嶇紪鍙�',
- `change_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '涓庝富鍗曚綅鎹㈢畻姣斾緥',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璁¢噺鍗曚綅';
-
--- 6.33 MES 渚涘簲鍟嗚〃
-CREATE TABLE `mes_md_vendor` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鐮�',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
- `nickname` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗙畝绉�',
- `english_name` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗚嫳鏂囧悕绉�',
- `description` VARCHAR(255) DEFAULT NULL COMMENT '渚涘簲鍟嗙畝浠�',
- `logo` VARCHAR(255) DEFAULT NULL COMMENT '渚涘簲鍟哃OGO鍦板潃',
- `level` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗙瓑绾�',
- `score` INT DEFAULT NULL COMMENT '渚涘簲鍟嗚瘎鍒�',
- `address` VARCHAR(255) DEFAULT NULL COMMENT '渚涘簲鍟嗗湴鍧�',
- `website` VARCHAR(255) DEFAULT NULL COMMENT '渚涘簲鍟嗗畼缃戝湴鍧�',
- `email` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗛偖绠卞湴鍧�',
- `telephone` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗙數璇�',
- `contact1_name` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�1',
- `contact1_telephone` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�1-鐢佃瘽',
- `contact1_email` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�1-閭',
- `contact2_name` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�2',
- `contact2_telephone` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�2-鐢佃瘽',
- `contact2_email` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�2-閭',
- `credit_code` VARCHAR(100) DEFAULT NULL COMMENT '缁熶竴绀句細淇$敤浠g爜',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 渚涘簲鍟�';
-
--- 6.34 MES 杞﹂棿琛�
-CREATE TABLE `mes_md_workshop` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '杞﹂棿缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '杞﹂棿鍚嶇О',
- `area` DECIMAL(24,6) DEFAULT NULL COMMENT '闈㈢Н锛堝钩鏂圭背锛�',
- `charge_user_id` BIGINT DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴风紪鍙�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杞﹂棿';
-
--- 6.35 MES 宸ヤ綔绔欒〃
-CREATE TABLE `mes_md_workstation` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鐮�',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '宸ヤ綔绔欏悕绉�',
- `address` VARCHAR(255) DEFAULT NULL COMMENT '宸ヤ綔绔欏湴鐐�',
- `workshop_id` BIGINT DEFAULT NULL COMMENT '鎵�鍦ㄨ溅闂寸紪鍙�',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '绾胯竟搴撶紪鍙�',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯缂栧彿',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅缂栧彿',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ヤ綔绔�';
-
--- 6.36 MES 宸ヤ綔绔欒澶囪祫婧愯〃
-CREATE TABLE `mes_md_workstation_machine` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `machinery_id` BIGINT DEFAULT NULL COMMENT '璁惧缂栧彿',
- `quantity` INT DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ヤ綔绔欒澶囪祫婧�';
-
--- 6.37 MES 宸ヤ綔绔欏伐瑁呭す鍏疯祫婧愯〃
-CREATE TABLE `mes_md_workstation_tool` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `tool_type_id` BIGINT DEFAULT NULL COMMENT '宸ュ叿绫诲瀷缂栧彿',
- `quantity` INT DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ヤ綔绔欏伐瑁呭す鍏疯祫婧�';
-
--- 6.38 MES 宸ヤ綔绔欎汉鍔涜祫婧愯〃
-CREATE TABLE `mes_md_workstation_worker` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `post_id` BIGINT DEFAULT NULL COMMENT '宀椾綅缂栧彿',
- `quantity` INT DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ヤ綔绔欎汉鍔涜祫婧�';
-
-
--- =====================================================
--- MES 鐢熶骇妯″潡 (pro)
--- =====================================================
-
--- 6.39 MES 瀹夌伅鍛煎彨閰嶇疆琛�
-CREATE TABLE `mes_pro_andon_config` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `reason` VARCHAR(255) DEFAULT NULL COMMENT '鍛煎彨鍘熷洜',
- `level` INT DEFAULT NULL COMMENT '绾у埆',
- `handler_role_id` BIGINT DEFAULT NULL COMMENT '澶勭疆浜鸿鑹茬紪鍙�',
- `handler_user_id` BIGINT DEFAULT NULL COMMENT '澶勭疆浜虹紪鍙�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 瀹夌伅鍛煎彨閰嶇疆';
-
--- 6.40 MES 瀹夌伅鍛煎彨璁板綍琛�
-CREATE TABLE `mes_pro_andon_record` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `config_id` BIGINT DEFAULT NULL COMMENT '瀹夌伅閰嶇疆缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `user_id` BIGINT DEFAULT NULL COMMENT '鍙戣捣鐢ㄦ埛缂栧彿',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `reason` VARCHAR(255) DEFAULT NULL COMMENT '鍛煎彨鍘熷洜',
- `level` INT DEFAULT NULL COMMENT '绾у埆',
- `status` INT DEFAULT NULL COMMENT '澶勭疆鐘舵��',
- `handle_time` DATETIME DEFAULT NULL COMMENT '澶勭疆鏃堕棿',
- `handler_user_id` BIGINT DEFAULT NULL COMMENT '澶勭疆浜虹紪鍙�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 瀹夌伅鍛煎彨璁板綍';
-
--- 6.41 MES 鐢熶骇娴佽浆鍗¤〃
-CREATE TABLE `mes_pro_card` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '娴佽浆鍗$紪鐮�',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `batch_code` VARCHAR(100) DEFAULT NULL COMMENT '鎵规鍙�',
- `transfered_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '娴佽浆鏁伴噺',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇娴佽浆鍗�';
-
--- 6.42 MES 娴佽浆鍗″伐搴忚褰曡〃
-CREATE TABLE `mes_pro_card_process` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `card_id` BIGINT DEFAULT NULL COMMENT '娴佽浆鍗$紪鍙�',
- `sort` INT DEFAULT NULL COMMENT '搴忓彿',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `input_time` DATETIME DEFAULT NULL COMMENT '杩涘叆宸ュ簭鏃堕棿',
- `output_time` DATETIME DEFAULT NULL COMMENT '鍑哄伐搴忔椂闂�',
- `input_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鎶曞叆鏁伴噺',
- `output_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '浜у嚭鏁伴噺',
- `unqualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍煎搧鏁伴噺',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綅缂栧彿',
- `user_id` BIGINT DEFAULT NULL COMMENT '鎿嶄綔浜虹紪鍙�',
- `ipqc_id` BIGINT DEFAULT NULL COMMENT '杩囩▼妫�楠屽崟缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 娴佽浆鍗″伐搴忚褰�';
-
--- 6.43 MES 鐢熶骇宸ュ簭琛�
-CREATE TABLE `mes_pro_process` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '宸ュ簭缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '宸ュ簭鍚嶇О',
- `attention` VARCHAR(500) DEFAULT NULL COMMENT '宸ヨ壓瑕佹眰',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇宸ュ簭';
-
--- 6.44 MES 鐢熶骇宸ュ簭鍐呭琛�
-CREATE TABLE `mes_pro_process_content` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `sort` INT DEFAULT NULL COMMENT '椤哄簭缂栧彿',
- `content` VARCHAR(500) DEFAULT NULL COMMENT '姝ラ璇存槑',
- `device` VARCHAR(255) DEFAULT NULL COMMENT '杈呭姪璁惧',
- `material` VARCHAR(255) DEFAULT NULL COMMENT '杈呭姪鏉愭枡',
- `doc_url` VARCHAR(255) DEFAULT NULL COMMENT '鏉愭枡鏂囨。 URL',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇宸ュ簭鍐呭';
-
--- 6.45 MES 宸ヨ壓璺嚎琛�
-CREATE TABLE `mes_pro_route` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '宸ヨ壓璺嚎鍚嶇О',
- `description` VARCHAR(255) DEFAULT NULL COMMENT '宸ヨ壓璺嚎璇存槑',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ヨ壓璺嚎';
-
--- 6.46 MES 宸ヨ壓璺嚎宸ュ簭琛�
-CREATE TABLE `mes_pro_route_process` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `route_id` BIGINT DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `sort` INT DEFAULT NULL COMMENT '搴忓彿',
- `next_process_id` BIGINT DEFAULT NULL COMMENT '涓嬩竴閬撳伐搴忕紪鍙�',
- `link_type` INT DEFAULT NULL COMMENT '涓庝笅涓�閬撳伐搴忓叧绯�',
- `prepare_time` INT DEFAULT NULL COMMENT '鍑嗗鏃堕棿锛堝垎閽燂級',
- `wait_time` INT DEFAULT NULL COMMENT '绛夊緟鏃堕棿锛堝垎閽燂級',
- `color_code` VARCHAR(100) DEFAULT NULL COMMENT '鐢樼壒鍥炬樉绀洪鑹�',
- `key_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍏抽敭宸ュ簭',
- `check_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁璐ㄦ宸ュ簭',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ヨ壓璺嚎宸ュ簭';
-
--- 6.47 MES 宸ヨ壓璺嚎浜у搧 BOM 琛�
-CREATE TABLE `mes_pro_route_product_bom` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `route_id` BIGINT DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT 'BOM 鐗╂枡缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鐢ㄦ枡姣斾緥',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ヨ壓璺嚎浜у搧 BOM';
-
--- 6.48 MES 宸ヨ壓璺嚎浜у搧琛�
-CREATE TABLE `mes_pro_route_product` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `route_id` BIGINT DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `quantity` INT DEFAULT NULL COMMENT '鐢熶骇鏁伴噺',
- `production_time` DECIMAL(24,6) DEFAULT NULL COMMENT '鐢熶骇鐢ㄦ椂',
- `time_unit_type` VARCHAR(100) DEFAULT NULL COMMENT '鏃堕棿鍗曚綅',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 宸ヨ壓璺嚎浜у搧';
-
--- 6.49 MES 鐢熶骇浠诲姟琛�
-CREATE TABLE `mes_pro_task` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '浠诲姟缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '浠诲姟鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `route_id` BIGINT DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鎺掍骇鏁伴噺',
- `produced_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '宸茬敓浜ф暟閲�',
- `qualify_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
- `unqualify_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓嶈壇鍝佹暟閲�',
- `changed_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '璋冩暣鏁伴噺',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `start_time` DATETIME DEFAULT NULL COMMENT '寮�濮嬬敓浜ф椂闂�',
- `duration` INT DEFAULT NULL COMMENT '鐢熶骇鏃堕暱',
- `end_time` DATETIME DEFAULT NULL COMMENT '缁撴潫鐢熶骇鏃堕棿',
- `color_code` VARCHAR(100) DEFAULT NULL COMMENT '鐢樼壒鍥炬樉绀洪鑹�',
- `finish_date` DATETIME DEFAULT NULL COMMENT '瀹屾垚鏃ユ湡',
- `cancel_date` DATETIME DEFAULT NULL COMMENT '鍙栨秷鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '浠诲姟鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇浠诲姟';
-
--- 6.50 MES 鐢熶骇浠诲姟鎶曟枡琛�
-CREATE TABLE `mes_pro_task_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `task_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `source_doc_type` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
- `source_doc_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `source_line_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
- `source_doc_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栫爜',
- `batch_code` VARCHAR(100) DEFAULT NULL COMMENT '鎶曟枡鎵规',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `unit_measure_id` BIGINT DEFAULT NULL COMMENT '鍗曚綅缂栧彿',
- `issued_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鎬绘姇鏂欐暟閲�',
- `available_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '褰撳墠鍙敤鏁伴噺',
- `used_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '褰撳墠浣跨敤鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇浠诲姟鎶曟枡';
-
--- 6.51 MES 鐢熶骇宸ュ崟琛�
-CREATE TABLE `mes_pro_work_order` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '宸ュ崟缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '宸ュ崟鍚嶇О',
- `type` INT DEFAULT NULL COMMENT '宸ュ崟绫诲瀷',
- `order_source_type` INT DEFAULT NULL COMMENT '鏉ユ簮绫诲瀷',
- `order_source_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `product_id` BIGINT DEFAULT NULL COMMENT '浜у搧缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鐢熶骇鏁伴噺',
- `quantity_produced` DECIMAL(24,6) DEFAULT NULL COMMENT '宸茬敓浜ф暟閲�',
- `quantity_changed` DECIMAL(24,6) DEFAULT NULL COMMENT '璋冩暣鏁伴噺',
- `quantity_scheduled` DECIMAL(24,6) DEFAULT NULL COMMENT '宸叉帓浜ф暟閲�',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
- `batch_code` VARCHAR(100) DEFAULT NULL COMMENT '鎵规鍙�',
- `request_date` DATETIME DEFAULT NULL COMMENT '闇�姹傛棩鏈�',
- `parent_id` BIGINT DEFAULT NULL COMMENT '鐖跺伐鍗曠紪鍙�',
- `finish_date` DATETIME DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
- `cancel_date` DATETIME DEFAULT NULL COMMENT '鍙栨秷鏃堕棿',
- `status` INT DEFAULT NULL COMMENT '宸ュ崟鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇宸ュ崟';
-
--- 6.52 MES 鐢熶骇宸ュ崟 BOM 琛�
-CREATE TABLE `mes_pro_work_order_bom` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT 'BOM 鐗╂枡缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '棰勮浣跨敤閲�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇宸ュ崟 BOM';
-
--- 6.53 MES 鐢ㄦ埛宸ヤ綔绔欑粦瀹氬叧绯昏〃
-CREATE TABLE `mes_pro_work_record` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `user_id` BIGINT DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `type` INT DEFAULT NULL COMMENT '褰撳墠鐘舵��',
- `clock_in_time` DATETIME DEFAULT NULL COMMENT '涓婂伐鏃堕棿',
- `clock_out_time` DATETIME DEFAULT NULL COMMENT '涓嬪伐鏃堕棿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢ㄦ埛宸ヤ綔绔欑粦瀹氬叧绯�';
-
--- 6.54 MES 涓婁笅宸ヨ褰曟祦姘磋〃
-CREATE TABLE `mes_pro_work_record_log` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `user_id` BIGINT DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `type` INT DEFAULT NULL COMMENT '鎿嶄綔绫诲瀷',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 涓婁笅宸ヨ褰曟祦姘�';
-
--- 6.55 MES 鐢熶骇鎶ュ伐琛�
-CREATE TABLE `mes_pro_feedback` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鎶ュ伐鍗曠紪鍙�',
- `type` INT DEFAULT NULL COMMENT '鎶ュ伐绫诲瀷',
- `channel` VARCHAR(100) DEFAULT NULL COMMENT '鎶ュ伐閫斿緞',
- `feedback_time` DATETIME DEFAULT NULL COMMENT '鎶ュ伐鏃堕棿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
- `route_id` BIGINT DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
- `task_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `expire_date` DATETIME DEFAULT NULL COMMENT '杩囨湡鏃ユ湡',
- `lot_number` VARCHAR(100) DEFAULT NULL COMMENT '鐢熶骇鎵瑰彿',
- `scheduled_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鎺掍骇鏁伴噺',
- `feedback_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈鎶ュ伐鏁伴噺',
- `qualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
- `unqualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓嶈壇鍝佹暟閲�',
- `uncheck_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '寰呮娴嬫暟閲�',
- `labor_scrap_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '宸ュ簾鏁伴噺',
- `material_scrap_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏂欏簾鏁伴噺',
- `other_scrap_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍏朵粬搴熷搧鏁伴噺',
- `feedback_user_id` BIGINT DEFAULT NULL COMMENT '鎶ュ伐鐢ㄦ埛缂栧彿',
- `approve_user_id` BIGINT DEFAULT NULL COMMENT '瀹℃牳鐢ㄦ埛缂栧彿',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇鎶ュ伐';
-
-
--- =====================================================
--- MES 璐ㄦ妯″潡 (qc)
--- =====================================================
-
--- 6.56 MES 缂洪櫡绫诲瀷琛�
-CREATE TABLE `mes_qc_defect` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '缂洪櫡缂栫爜',
- `name` VARCHAR(255) DEFAULT NULL COMMENT '缂洪櫡鎻忚堪',
- `type` INT DEFAULT NULL COMMENT '妫�娴嬮」绫诲瀷',
- `level` INT DEFAULT NULL COMMENT '缂洪櫡绛夌骇',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 缂洪櫡绫诲瀷';
-
--- 6.57 MES 璐ㄦ缂洪櫡璁板綍琛�
-CREATE TABLE `mes_qc_defect_record` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `qc_type` INT DEFAULT NULL COMMENT '妫�楠岀被鍨�',
- `qc_id` BIGINT DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '妫�楠岃缂栧彿',
- `name` VARCHAR(255) DEFAULT NULL COMMENT '缂洪櫡鎻忚堪',
- `level` INT DEFAULT NULL COMMENT '缂洪櫡绛夌骇',
- `quantity` INT DEFAULT NULL COMMENT '缂洪櫡鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璐ㄦ缂洪櫡璁板綍';
-
--- 6.58 MES 璐ㄦ鎸囨爣琛�
-CREATE TABLE `mes_qc_indicator` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '妫�娴嬮」缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '妫�娴嬮」鍚嶇О',
- `type` INT DEFAULT NULL COMMENT '妫�娴嬮」绫诲瀷',
- `tool` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
- `result_type` INT DEFAULT NULL COMMENT '缁撴灉鍊肩被鍨�',
- `result_specification` VARCHAR(255) DEFAULT NULL COMMENT '缁撴灉鍊煎睘鎬�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璐ㄦ鎸囨爣';
-
--- 6.59 MES 妫�楠岀粨鏋滆褰曡〃
-CREATE TABLE `mes_qc_indicator_result` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鏍峰搧缂栧彿',
- `qc_id` BIGINT DEFAULT NULL COMMENT '鍏宠仈璐ㄦ鍗曠紪鍙�',
- `qc_type` INT DEFAULT NULL COMMENT '璐ㄦ绫诲瀷',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `sn` VARCHAR(100) DEFAULT NULL COMMENT '鐗╄祫 SN',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 妫�楠岀粨鏋滆褰�';
-
--- 6.60 MES 妫�楠岀粨鏋滄槑缁嗚褰曡〃
-CREATE TABLE `mes_qc_indicator_result_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `result_id` BIGINT DEFAULT NULL COMMENT '鍏宠仈妫�楠岀粨鏋滅紪鍙�',
- `indicator_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
- `value` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬪��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 妫�楠岀粨鏋滄槑缁嗚褰�';
-
--- 6.61 MES 杩囩▼妫�楠屽崟琛�
-CREATE TABLE `mes_qc_ipqc` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '妫�楠屽崟鍚嶇О',
- `type` INT DEFAULT NULL COMMENT 'IPQC 妫�楠岀被鍨�',
- `template_id` BIGINT DEFAULT NULL COMMENT '妫�楠屾ā鏉跨紪鍙�',
- `source_doc_type` INT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
- `source_doc_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `source_line_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
- `source_doc_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
- `task_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
- `workstation_id` BIGINT DEFAULT NULL COMMENT '宸ヤ綅缂栧彿',
- `process_id` BIGINT DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `check_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '妫�娴嬫暟閲�',
- `qualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
- `unqualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍煎搧鏁伴噺',
- `labor_scrap_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '宸ュ簾鏁伴噺',
- `material_scrap_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏂欏簾鏁伴噺',
- `other_scrap_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍏朵粬搴熷搧鏁伴噺',
- `critical_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '鑷村懡缂洪櫡鐜�',
- `major_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鐜�',
- `minor_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '杞诲井缂洪櫡鐜�',
- `critical_quantity` INT DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
- `major_quantity` INT DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
- `minor_quantity` INT DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
- `check_result` INT DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
- `inspect_date` DATETIME DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
- `inspector_user_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬩汉鍛樼敤鎴风紪鍙�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杩囩▼妫�楠屽崟';
-
--- 6.62 MES 杩囩▼妫�楠屽崟琛岃〃
-CREATE TABLE `mes_qc_ipqc_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `ipqc_id` BIGINT DEFAULT NULL COMMENT '杩囩▼妫�楠屽崟缂栧彿',
- `indicator_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
- `tool` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
- `check_method` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
- `standard_value` DECIMAL(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
- `unit_measure_id` BIGINT DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
- `max_threshold` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
- `min_threshold` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
- `critical_quantity` INT DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
- `major_quantity` INT DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
- `minor_quantity` INT DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杩囩▼妫�楠屽崟琛�';
-
--- 6.63 MES 鏉ユ枡妫�楠屽崟琛�
-CREATE TABLE `mes_qc_iqc` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '妫�楠屽崟鍚嶇О',
- `template_id` BIGINT DEFAULT NULL COMMENT '妫�楠屾ā鏉跨紪鍙�',
- `source_doc_type` INT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
- `source_doc_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `source_line_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
- `source_doc_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
- `vendor_batch` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗘壒娆″彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `received_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈鎺ユ敹鏁伴噺',
- `check_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈妫�娴嬫暟閲�',
- `qualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
- `unqualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍煎搧鏁伴噺',
- `critical_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '鑷村懡缂洪櫡鐜�',
- `major_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鐜�',
- `minor_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '杞诲井缂洪櫡鐜�',
- `critical_quantity` INT DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
- `major_quantity` INT DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
- `minor_quantity` INT DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
- `check_result` INT DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
- `receive_date` DATETIME DEFAULT NULL COMMENT '鏉ユ枡鏃ユ湡',
- `inspect_date` DATETIME DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
- `inspector_user_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬩汉鍛樼敤鎴风紪鍙�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鏉ユ枡妫�楠屽崟';
-
--- 6.64 MES 鏉ユ枡妫�楠屽崟琛岃〃
-CREATE TABLE `mes_qc_iqc_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `iqc_id` BIGINT DEFAULT NULL COMMENT '鏉ユ枡妫�楠屽崟缂栧彿',
- `indicator_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
- `tool` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
- `check_method` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
- `standard_value` DECIMAL(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
- `unit_measure_id` BIGINT DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
- `max_threshold` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
- `min_threshold` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
- `critical_quantity` INT DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
- `major_quantity` INT DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
- `minor_quantity` INT DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鏉ユ枡妫�楠屽崟琛�';
-
--- 6.65 MES 鍑鸿揣妫�楠屽崟琛�
-CREATE TABLE `mes_qc_oqc` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '妫�楠屽崟鍚嶇О',
- `template_id` BIGINT DEFAULT NULL COMMENT '妫�楠屾ā鏉跨紪鍙�',
- `source_doc_type` INT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
- `source_doc_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `source_line_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
- `source_doc_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `batch_code` VARCHAR(100) DEFAULT NULL COMMENT '鎵规鍙�',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `min_check_quantity` INT DEFAULT NULL COMMENT '鏈�浣庢娴嬫暟',
- `max_unqualified_quantity` INT DEFAULT NULL COMMENT '鏈�澶т笉鍚堟牸鏁�',
- `out_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈鍑鸿揣鏁伴噺',
- `check_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈妫�娴嬫暟閲�',
- `qualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
- `unqualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍煎搧鏁伴噺',
- `critical_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '鑷村懡缂洪櫡鐜�',
- `major_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鐜�',
- `minor_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '杞诲井缂洪櫡鐜�',
- `critical_quantity` INT DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
- `major_quantity` INT DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
- `minor_quantity` INT DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
- `check_result` INT DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
- `out_date` DATETIME DEFAULT NULL COMMENT '鍑鸿揣鏃ユ湡',
- `inspect_date` DATETIME DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
- `inspector_user_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬩汉鍛樼敤鎴风紪鍙�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍑鸿揣妫�楠屽崟';
-
--- 6.66 MES 鍑鸿揣妫�楠屽崟琛岃〃
-CREATE TABLE `mes_qc_oqc_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `oqc_id` BIGINT DEFAULT NULL COMMENT '鍑鸿揣妫�楠屽崟缂栧彿',
- `indicator_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
- `tool` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
- `check_method` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
- `standard_value` DECIMAL(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
- `unit_measure_id` BIGINT DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
- `max_threshold` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
- `min_threshold` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
- `critical_quantity` INT DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
- `major_quantity` INT DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
- `minor_quantity` INT DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍑鸿揣妫�楠屽崟琛�';
-
--- 6.67 MES 閫�璐ф楠屽崟琛�
-CREATE TABLE `mes_qc_rqc` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '妫�楠屽崟鍚嶇О',
- `template_id` BIGINT DEFAULT NULL COMMENT '妫�楠屾ā鏉跨紪鍙�',
- `source_doc_type` INT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
- `source_doc_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `source_line_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
- `source_doc_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
- `type` INT DEFAULT NULL COMMENT '妫�楠岀被鍨�',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `batch_code` VARCHAR(100) DEFAULT NULL COMMENT '鎵规鍙�',
- `check_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '妫�娴嬫暟閲�',
- `qualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
- `unqualified_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍兼暟閲�',
- `critical_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '鑷村懡缂洪櫡鐜�',
- `major_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鐜�',
- `minor_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '杞诲井缂洪櫡鐜�',
- `critical_quantity` INT DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
- `major_quantity` INT DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
- `minor_quantity` INT DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
- `check_result` INT DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
- `inspect_date` DATETIME DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
- `inspector_user_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬩汉鍛樼敤鎴风紪鍙�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閫�璐ф楠屽崟';
-
--- 6.68 MES 閫�璐ф楠岃琛�
-CREATE TABLE `mes_qc_rqc_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `rqc_id` BIGINT DEFAULT NULL COMMENT '閫�璐ф楠屽崟缂栧彿',
- `indicator_id` BIGINT DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
- `tool` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
- `check_method` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
- `standard_value` DECIMAL(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
- `unit_measure_id` BIGINT DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
- `max_threshold` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
- `min_threshold` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
- `critical_quantity` INT DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
- `major_quantity` INT DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
- `minor_quantity` INT DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閫�璐ф楠岃';
-
--- 6.69 MES 璐ㄦ鏂规琛�
-CREATE TABLE `mes_qc_template` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鏂规缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鏂规鍚嶇О',
- `types` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬬绫�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璐ㄦ鏂规';
-
--- 6.70 MES 璐ㄦ鏂规妫�娴嬫寚鏍囬」琛�
-CREATE TABLE `mes_qc_template_indicator` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `template_id` BIGINT DEFAULT NULL COMMENT '璐ㄦ鏂规缂栧彿',
- `indicator_id` BIGINT DEFAULT NULL COMMENT '璐ㄦ鎸囨爣缂栧彿',
- `check_method` VARCHAR(255) DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
- `standard_value` DECIMAL(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
- `unit_measure_id` BIGINT DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
- `threshold_max` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
- `threshold_min` DECIMAL(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
- `doc_url` VARCHAR(255) DEFAULT NULL COMMENT '璇存槑鍥� URL',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璐ㄦ鏂规妫�娴嬫寚鏍囬」';
-
--- 6.71 MES 璐ㄦ鏂规浜у搧鍏宠仈琛�
-CREATE TABLE `mes_qc_template_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `template_id` BIGINT DEFAULT NULL COMMENT '璐ㄦ鏂规缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
- `quantity_check` INT DEFAULT NULL COMMENT '鏈�浣庢娴嬫暟',
- `quantity_unqualified` INT DEFAULT NULL COMMENT '鏈�澶т笉鍚堟牸鏁�',
- `critical_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈�澶ц嚧鍛界己闄风巼',
- `major_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈�澶т弗閲嶇己闄风巼',
- `minor_rate` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈�澶ц交寰己闄风巼',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 璐ㄦ鏂规浜у搧鍏宠仈';
-
-
--- =====================================================
--- 绗竷閮ㄥ垎: yudao-module-wms 浠撳簱绠$悊绯荤粺妯″潡 (16 寮犺〃)
--- =====================================================
-
--- 7.1 WMS 搴撳瓨琛�
-CREATE TABLE `wms_inventory` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `sku_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧 SKU 缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '搴撳瓨鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 搴撳瓨';
-
--- 7.2 WMS 搴撳瓨娴佹按琛�
-CREATE TABLE `wms_inventory_history` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `sku_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧 SKU 缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '搴撳瓨鍙樺寲鏁伴噺',
- `before_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍙樺寲鍓嶅簱瀛樻暟閲�',
- `after_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍙樺寲鍚庡簱瀛樻暟閲�',
- `price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍗曚环',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '搴撳瓨鍙樺寲閲戦',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `order_id` BIGINT DEFAULT NULL COMMENT '鍗曟嵁缂栧彿',
- `order_no` VARCHAR(100) DEFAULT NULL COMMENT '鍗曟嵁鍙�',
- `order_type` INT DEFAULT NULL COMMENT '鍗曟嵁绫诲瀷',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 搴撳瓨娴佹按';
-
--- 7.3 WMS 鍟嗗搧鍝佺墝琛�
-CREATE TABLE `wms_item_brand` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍝佺墝缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍝佺墝鍚嶇О',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鍟嗗搧鍝佺墝';
-
--- 7.4 WMS 鍟嗗搧鍒嗙被琛�
-CREATE TABLE `wms_item_category` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `parent_id` BIGINT DEFAULT NULL COMMENT '鐖剁骇缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍒嗙被缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍒嗙被鍚嶇О',
- `sort` INT DEFAULT NULL COMMENT '鎺掑簭',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鍟嗗搧鍒嗙被';
-
--- 7.5 WMS 鍟嗗搧琛�
-CREATE TABLE `wms_item` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍟嗗搧缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍟嗗搧鍚嶇О',
- `unit` VARCHAR(100) DEFAULT NULL COMMENT '鍗曚綅',
- `category_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧鍒嗙被缂栧彿',
- `brand_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧鍝佺墝缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鍟嗗搧';
-
--- 7.6 WMS 鍟嗗搧 SKU 琛�
-CREATE TABLE `wms_item_sku` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '瑙勬牸鍚嶇О',
- `item_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧缂栧彿',
- `bar_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉$爜',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '瑙勬牸缂栧彿',
- `length` DECIMAL(24,6) DEFAULT NULL COMMENT '闀匡紝鍗曚綅 cm',
- `width` DECIMAL(24,6) DEFAULT NULL COMMENT '瀹斤紝鍗曚綅 cm',
- `height` DECIMAL(24,6) DEFAULT NULL COMMENT '楂橈紝鍗曚綅 cm',
- `gross_weight` DECIMAL(24,6) DEFAULT NULL COMMENT '姣涢噸锛屽崟浣� kg',
- `net_weight` DECIMAL(24,6) DEFAULT NULL COMMENT '鍑�閲嶏紝鍗曚綅 kg',
- `cost_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鎴愭湰浠凤紝鍗曚綅鍏�',
- `selling_price` DECIMAL(24,6) DEFAULT NULL COMMENT '閿�鍞环锛屽崟浣嶅厓',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鍟嗗搧 SKU';
-
--- 7.7 WMS 寰�鏉ヤ紒涓氳〃
-CREATE TABLE `wms_merchant` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '寰�鏉ヤ紒涓氱紪鍙�',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '寰�鏉ヤ紒涓氬悕绉�',
- `type` INT DEFAULT NULL COMMENT '寰�鏉ヤ紒涓氱被鍨�',
- `level` VARCHAR(100) DEFAULT NULL COMMENT '绾у埆',
- `bank_name` VARCHAR(100) DEFAULT NULL COMMENT '寮�鎴疯',
- `bank_account` VARCHAR(100) DEFAULT NULL COMMENT '閾惰璐︽埛',
- `address` VARCHAR(255) DEFAULT NULL COMMENT '鍦板潃',
- `mobile` VARCHAR(100) DEFAULT NULL COMMENT '鎵嬫満鍙�',
- `telephone` VARCHAR(100) DEFAULT NULL COMMENT '搴ф満鍙�',
- `contact` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴浜�',
- `email` VARCHAR(100) DEFAULT NULL COMMENT 'Email',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 寰�鏉ヤ紒涓�';
-
--- 7.8 WMS 浠撳簱琛�
-CREATE TABLE `wms_warehouse` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `sort` INT DEFAULT NULL COMMENT '鎺掑簭',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 浠撳簱';
-
--- 7.9 WMS 鐩樺簱鍗曡〃
-CREATE TABLE `wms_check_order` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(100) DEFAULT NULL COMMENT '鐩樺簱鍗曞彿',
- `order_time` DATETIME DEFAULT NULL COMMENT '鍗曟嵁鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐩樺簱鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `total_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鐩堜簭鏁伴噺',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鎬婚噾棰�',
- `actual_price` DECIMAL(24,6) DEFAULT NULL COMMENT '瀹為檯閲戦',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鐩樺簱鍗�';
-
--- 7.10 WMS 鐩樺簱鍗曟槑缁嗚〃
-CREATE TABLE `wms_check_order_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `order_id` BIGINT DEFAULT NULL COMMENT '鐩樺簱鍗曠紪鍙�',
- `sku_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧 SKU 缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `inventory_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨缂栧彿',
- `receipt_time` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃堕棿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '璐﹂潰鏁伴噺',
- `check_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '瀹炵洏鏁伴噺',
- `price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍗曚环',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鐩樺簱鍗曟槑缁�';
-
--- 7.11 WMS 绉诲簱鍗曡〃
-CREATE TABLE `wms_movement_order` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(100) DEFAULT NULL COMMENT '绉诲簱鍗曞彿',
- `order_time` DATETIME DEFAULT NULL COMMENT '鍗曟嵁鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '绉诲簱鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `source_warehouse_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮浠撳簱缂栧彿',
- `target_warehouse_id` BIGINT DEFAULT NULL COMMENT '鐩爣浠撳簱缂栧彿',
- `total_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鎬绘暟閲�',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鎬婚噾棰�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 绉诲簱鍗�';
-
--- 7.12 WMS 绉诲簱鍗曟槑缁嗚〃
-CREATE TABLE `wms_movement_order_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `order_id` BIGINT DEFAULT NULL COMMENT '绉诲簱鍗曠紪鍙�',
- `sku_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧 SKU 缂栧彿',
- `source_warehouse_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮浠撳簱缂栧彿',
- `target_warehouse_id` BIGINT DEFAULT NULL COMMENT '鐩爣浠撳簱缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '绉诲簱鏁伴噺',
- `price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍗曚环',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '琛岄噾棰�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 绉诲簱鍗曟槑缁�';
-
--- 7.13 WMS 鍏ュ簱鍗曡〃
-CREATE TABLE `wms_receipt_order` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(100) DEFAULT NULL COMMENT '鍏ュ簱鍗曞彿',
- `type` INT DEFAULT NULL COMMENT '鍏ュ簱绫诲瀷',
- `order_time` DATETIME DEFAULT NULL COMMENT '鍗曟嵁鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鍏ュ簱鐘舵��',
- `biz_order_no` VARCHAR(100) DEFAULT NULL COMMENT '涓氬姟璁㈠崟鍙�',
- `merchant_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `total_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鎬绘暟閲�',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鎬婚噾棰�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鍏ュ簱鍗�';
-
--- 7.14 WMS 鍏ュ簱鍗曟槑缁嗚〃
-CREATE TABLE `wms_receipt_order_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `order_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗曠紪鍙�',
- `sku_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧 SKU 缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍏ュ簱鏁伴噺',
- `price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍗曚环',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '琛岄噾棰�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鍏ュ簱鍗曟槑缁�';
-
--- 7.15 WMS 鍑哄簱鍗曡〃
-CREATE TABLE `wms_shipment_order` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `no` VARCHAR(100) DEFAULT NULL COMMENT '鍑哄簱鍗曞彿',
- `type` INT DEFAULT NULL COMMENT '鍑哄簱绫诲瀷',
- `order_time` DATETIME DEFAULT NULL COMMENT '鍗曟嵁鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鍑哄簱鐘舵��',
- `biz_order_no` VARCHAR(100) DEFAULT NULL COMMENT '涓氬姟璁㈠崟鍙�',
- `merchant_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `total_quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鎬绘暟閲�',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '鎬婚噾棰�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鍑哄簱鍗�';
-
--- 7.16 WMS 鍑哄簱鍗曟槑缁嗚〃
-CREATE TABLE `wms_shipment_order_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `order_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗曠紪鍙�',
- `sku_id` BIGINT DEFAULT NULL COMMENT '鍟嗗搧 SKU 缂栧彿',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鍑哄簱鏁伴噺',
- `price` DECIMAL(24,6) DEFAULT NULL COMMENT '鍗曚环',
- `total_price` DECIMAL(24,6) DEFAULT NULL COMMENT '琛岄噾棰�',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='WMS 鍑哄簱鍗曟槑缁�';
-
-
--- =====================================================
--- MES 浠撳簱鏉$爜绠$悊琛紙琛ュ厖锛�
--- =====================================================
-
--- MES 鏉$爜閰嶇疆琛�
-CREATE TABLE `mes_wm_barcode_config` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `format` INT DEFAULT NULL COMMENT '鏉$爜鏍煎紡',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `content_format` VARCHAR(255) DEFAULT NULL COMMENT '鍐呭鏍煎紡妯℃澘',
- `content_example` VARCHAR(255) DEFAULT NULL COMMENT '鍐呭鏍蜂緥',
- `auto_generate_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁鑷姩鐢熸垚',
- `default_template` VARCHAR(500) DEFAULT NULL COMMENT '榛樿鎵撳嵃妯℃澘',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鏉$爜閰嶇疆';
-
--- MES 鏉$爜娓呭崟琛�
-CREATE TABLE `mes_wm_barcode` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `config_id` BIGINT DEFAULT NULL COMMENT '鏉$爜閰嶇疆缂栧彿',
- `format` INT DEFAULT NULL COMMENT '鏉$爜鏍煎紡',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `content` VARCHAR(255) DEFAULT NULL COMMENT '鏉$爜鍐呭',
- `biz_id` BIGINT DEFAULT NULL COMMENT '涓氬姟缂栧彿',
- `biz_code` VARCHAR(100) DEFAULT NULL COMMENT '涓氬姟缂栫爜',
- `biz_name` VARCHAR(100) DEFAULT NULL COMMENT '涓氬姟鍚嶇О',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鏉$爜娓呭崟';
-
--- =====================================================
--- 6.73 MES 浠撳簱鍩虹璁剧疆
--- =====================================================
-
--- MES 浠撳簱琛�
-CREATE TABLE `mes_wm_warehouse` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '浠撳簱缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '浠撳簱鍚嶇О',
- `address` VARCHAR(255) DEFAULT NULL COMMENT '浠撳簱鍦板潃',
- `area` DECIMAL(24,6) DEFAULT NULL COMMENT '闈㈢Н',
- `charge_user_id` BIGINT DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴风紪鍙�',
- `frozen` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 浠撳簱';
-
--- MES 搴撳尯琛�
-CREATE TABLE `mes_wm_warehouse_location` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '搴撳尯缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '搴撳尯鍚嶇О',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `area` DECIMAL(24,6) DEFAULT NULL COMMENT '闈㈢Н',
- `frozen` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴撳尯';
-
--- MES 搴撲綅琛�
-CREATE TABLE `mes_wm_warehouse_area` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '搴撲綅缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '搴撲綅鍚嶇О',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯缂栧彿',
- `area` DECIMAL(24,6) DEFAULT NULL COMMENT '闈㈢Н',
- `max_load` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈�澶ц浇閲�',
- `position_x` INT DEFAULT NULL COMMENT '浣嶇疆 X',
- `position_y` INT DEFAULT NULL COMMENT '浣嶇疆 Y',
- `position_z` INT DEFAULT NULL COMMENT '浣嶇疆 Z',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `frozen` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
- `allow_item_mixing` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍏佽鐗╂枡娣锋斁',
- `allow_batch_mixing` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍏佽鎵规娣锋斁',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴撲綅';
-
--- =====================================================
--- 6.74 MES 搴撳瓨绠$悊
--- =====================================================
-
--- MES 搴撳瓨璁板綍琛�
-CREATE TABLE `mes_wm_material_stock` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '搴撳瓨鏁伴噺',
- `erp_time` DATETIME DEFAULT NULL COMMENT 'ERP 璐︽湡',
- `receipt_time` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃堕棿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴撳瓨璁板綍';
-
--- MES 搴撳瓨浜嬪姟娴佹按琛�
-CREATE TABLE `mes_wm_transaction` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `type` INT DEFAULT NULL COMMENT '浜嬪姟绫诲瀷',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `biz_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮涓氬姟涓诲崟 ID',
- `biz_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮涓氬姟鍗曞彿',
- `biz_line_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮涓氬姟琛� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨璁板綍 ID',
- `related_transaction_id` BIGINT DEFAULT NULL COMMENT '鍏宠仈鐨勪簨鍔� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈鍙樺姩鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `batch_code` VARCHAR(100) DEFAULT NULL COMMENT '鎵规鍙�',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `transaction_time` DATETIME DEFAULT NULL COMMENT '浜嬪姟鍙戠敓鏃堕棿',
- `erp_time` DATETIME DEFAULT NULL COMMENT 'ERP 璐︽湡',
- `receipt_time` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃堕棿',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴撳瓨浜嬪姟娴佹按';
-
--- MES 鎵规琛�
-CREATE TABLE `mes_wm_batch` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鎵规鍙�',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `produce_date` DATETIME DEFAULT NULL COMMENT '鐢熶骇鏃ユ湡',
- `expire_date` DATETIME DEFAULT NULL COMMENT '澶辨晥鏃ユ湡',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `vendor_code` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鐮�',
- `vendor_name` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鎵规';
-
--- MES 搴忓垪鍙疯〃
-CREATE TABLE `mes_wm_sn` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '搴忓垪鍙�',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴忓垪鍙�';
-
--- =====================================================
--- 6.75 MES 鍖呰绠$悊
--- =====================================================
-
--- MES 鍖呰鍗曡〃
-CREATE TABLE `mes_wm_package` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍖呰鍗曠紪鐮�',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍖呰鍗曞悕绉�',
- `barcode_id` BIGINT DEFAULT NULL COMMENT '鏉$爜 ID',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍖呰鍗�';
-
--- MES 鍖呰鍗曡琛�
-CREATE TABLE `mes_wm_package_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `package_id` BIGINT DEFAULT NULL COMMENT '鍖呰鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍖呰鍗曡';
-
--- =====================================================
--- 6.76 MES 鍒拌揣閫氱煡鍗�
--- =====================================================
-
--- MES 鍒拌揣閫氱煡鍗�
-CREATE TABLE `mes_wm_arrival_notice` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `arrival_date` DATETIME DEFAULT NULL COMMENT '棰勮鍒拌揣鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍒拌揣閫氱煡鍗�';
-
--- MES 鍒拌揣閫氱煡鍗曡
-CREATE TABLE `mes_wm_arrival_notice_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `notice_id` BIGINT DEFAULT NULL COMMENT '鍒拌揣閫氱煡鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍒拌揣閫氱煡鍗曡';
-
--- =====================================================
--- 6.77 MES 閿�鍞彂璐ч�氱煡鍗�
--- =====================================================
-
--- MES 閿�鍞彂璐ч�氱煡鍗�
-CREATE TABLE `mes_wm_sales_notice` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛 ID',
- `delivery_date` DATETIME DEFAULT NULL COMMENT '棰勮鍙戣揣鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞彂璐ч�氱煡鍗�';
-
--- MES 閿�鍞彂璐ч�氱煡鍗曡
-CREATE TABLE `mes_wm_sales_notice_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `notice_id` BIGINT DEFAULT NULL COMMENT '閿�鍞彂璐ч�氱煡鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞彂璐ч�氱煡鍗曡';
-
--- =====================================================
--- 6.78 MES 杞Щ鍗�
--- =====================================================
-
--- MES 杞Щ鍗�
-CREATE TABLE `mes_wm_transfer` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '杞Щ鍗曞悕绉�',
- `type` INT DEFAULT NULL COMMENT '杞Щ鍗曠被鍨�',
- `delivery_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁閰嶉��',
- `recipient_name` VARCHAR(100) DEFAULT NULL COMMENT '鏀惰揣浜�',
- `recipient_telephone` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴鏂瑰紡',
- `destination_address` VARCHAR(255) DEFAULT NULL COMMENT '鐩殑鍦�',
- `carrier` VARCHAR(100) DEFAULT NULL COMMENT '鎵胯繍鍟�',
- `shipping_number` VARCHAR(100) DEFAULT NULL COMMENT '杩愯緭鍗曞彿',
- `confirm_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁宸茬‘璁�',
- `transfer_date` DATETIME DEFAULT NULL COMMENT '杞Щ鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杞Щ鍗�';
-
--- MES 杞Щ鍗曡
-CREATE TABLE `mes_wm_transfer_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `transfer_id` BIGINT DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨璁板綍缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '杞Щ鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规缂栧彿',
- `from_warehouse_id` BIGINT DEFAULT NULL COMMENT '绉诲嚭浠撳簱缂栧彿',
- `from_location_id` BIGINT DEFAULT NULL COMMENT '绉诲嚭搴撳尯缂栧彿',
- `from_area_id` BIGINT DEFAULT NULL COMMENT '绉诲嚭搴撲綅缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杞Щ鍗曡';
-
--- MES 杞Щ鍗曟槑缁�
-CREATE TABLE `mes_wm_transfer_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '杞Щ鍗曡缂栧彿',
- `transfer_id` BIGINT DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓婃灦鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规缂栧彿',
- `to_warehouse_id` BIGINT DEFAULT NULL COMMENT '绉诲叆浠撳簱缂栧彿',
- `to_location_id` BIGINT DEFAULT NULL COMMENT '绉诲叆搴撳尯缂栧彿',
- `to_area_id` BIGINT DEFAULT NULL COMMENT '绉诲叆搴撲綅缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杞Щ鍗曟槑缁�';
-
--- =====================================================
--- 6.79 MES 鐗╂枡娑堣�楀崟
--- =====================================================
-
--- MES 鐗╂枡娑堣�楀崟
-CREATE TABLE `mes_wm_item_consume` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `return_date` DATETIME DEFAULT NULL COMMENT '娑堣�楁棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡娑堣�楀崟';
-
--- MES 鐗╂枡娑堣�楀崟琛�
-CREATE TABLE `mes_wm_item_consume_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `consume_id` BIGINT DEFAULT NULL COMMENT '娑堣�楀崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡娑堣�楀崟琛�';
-
--- MES 鐗╂枡娑堣�楀崟鏄庣粏
-CREATE TABLE `mes_wm_item_consume_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `consume_id` BIGINT DEFAULT NULL COMMENT '娑堣�楀崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡娑堣�楀崟鏄庣粏';
-
--- =====================================================
--- 6.80 MES 鐗╂枡閫�搴撳崟
--- =====================================================
-
--- MES 鐗╂枡閫�搴撳崟
-CREATE TABLE `mes_wm_item_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `receipt_date` DATETIME DEFAULT NULL COMMENT '閫�搴撴棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�搴撳崟';
-
--- MES 鐗╂枡閫�搴撳崟琛�
-CREATE TABLE `mes_wm_item_receipt_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '閫�搴撳崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�搴撳崟琛�';
-
--- MES 鐗╂枡閫�搴撳崟鏄庣粏
-CREATE TABLE `mes_wm_item_receipt_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '閫�搴撳崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�搴撳崟鏄庣粏';
-
--- =====================================================
--- 6.81 MES 鐢熶骇棰嗘枡鍗�
--- =====================================================
-
--- MES 鐢熶骇棰嗘枡鍗�
-CREATE TABLE `mes_wm_product_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `issue_date` DATETIME DEFAULT NULL COMMENT '棰嗘枡鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇棰嗘枡鍗�';
-
--- MES 鐢熶骇棰嗘枡鍗曡
-CREATE TABLE `mes_wm_product_issue_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `issue_id` BIGINT DEFAULT NULL COMMENT '棰嗘枡鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇棰嗘枡鍗曡';
-
--- MES 鐢熶骇棰嗘枡鍗曟槑缁�
-CREATE TABLE `mes_wm_product_issue_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `issue_id` BIGINT DEFAULT NULL COMMENT '棰嗘枡鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇棰嗘枡鍗曟槑缁�';
-
--- =====================================================
--- 6.82 MES 鐢熶骇鍏ュ簱鍗�
--- =====================================================
-
--- MES 鐢熶骇鍏ュ簱鍗�
-CREATE TABLE `mes_wm_product_produce` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `produce_date` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇鍏ュ簱鍗�';
-
--- MES 鐢熶骇鍏ュ簱鍗曡
-CREATE TABLE `mes_wm_product_produce_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `produce_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇鍏ュ簱鍗曡';
-
--- MES 鐢熶骇鍏ュ簱鍗曟槑缁�
-CREATE TABLE `mes_wm_product_produce_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `produce_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇鍏ュ簱鍗曟槑缁�';
-
--- =====================================================
--- 6.83 MES 鐢熶骇閫�鏂欏崟
--- =====================================================
-
--- MES 鐢熶骇閫�鏂欏崟
-CREATE TABLE `mes_wm_product_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `receipt_date` DATETIME DEFAULT NULL COMMENT '閫�鏂欐棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟';
-
--- MES 鐢熶骇閫�鏂欏崟琛�
-CREATE TABLE `mes_wm_product_receipt_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟琛�';
-
--- MES 鐢熶骇閫�鏂欏崟鏄庣粏
-CREATE TABLE `mes_wm_product_receipt_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟鏄庣粏';
-
--- =====================================================
--- 6.84 MES 閿�鍞嚭搴撳崟
--- =====================================================
-
--- MES 閿�鍞嚭搴撳崟
-CREATE TABLE `mes_wm_product_sales` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛 ID',
- `sales_date` DATETIME DEFAULT NULL COMMENT '鍑哄簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞嚭搴撳崟';
-
--- MES 閿�鍞嚭搴撳崟琛�
-CREATE TABLE `mes_wm_product_sales_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `sales_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞嚭搴撳崟琛�';
-
--- MES 閿�鍞嚭搴撳崟鏄庣粏
-CREATE TABLE `mes_wm_product_sales_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `sales_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞嚭搴撳崟鏄庣粏';
-
--- =====================================================
--- 6.85 MES 閿�鍞��璐у崟
--- =====================================================
-
--- MES 閿�鍞��璐у崟
-CREATE TABLE `mes_wm_return_sales` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛 ID',
- `return_date` DATETIME DEFAULT NULL COMMENT '閫�璐ф棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞��璐у崟';
-
--- MES 閿�鍞��璐у崟琛�
-CREATE TABLE `mes_wm_return_sales_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `return_id` BIGINT DEFAULT NULL COMMENT '閫�璐у崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞��璐у崟琛�';
-
--- MES 閿�鍞��璐у崟鏄庣粏
-CREATE TABLE `mes_wm_return_sales_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `return_id` BIGINT DEFAULT NULL COMMENT '閫�璐у崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞��璐у崟鏄庣粏';
-
--- =====================================================
--- 6.86 MES 閲囪喘閫�璐у崟
--- =====================================================
-
--- MES 閲囪喘閫�璐у崟
-CREATE TABLE `mes_wm_return_vendor` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `return_date` DATETIME DEFAULT NULL COMMENT '閫�璐ф棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閲囪喘閫�璐у崟';
-
--- MES 閲囪喘閫�璐у崟琛�
-CREATE TABLE `mes_wm_return_vendor_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `return_id` BIGINT DEFAULT NULL COMMENT '閫�璐у崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閲囪喘閫�璐у崟琛�';
-
--- MES 閲囪喘閫�璐у崟鏄庣粏
-CREATE TABLE `mes_wm_return_vendor_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `return_id` BIGINT DEFAULT NULL COMMENT '閫�璐у崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閲囪喘閫�璐у崟鏄庣粏';
-
--- =====================================================
--- 6.87 MES 鐢熶骇閫�鏂欏崟锛堝彂鏂欙級
--- =====================================================
-
--- MES 鐢熶骇閫�鏂欏崟锛堝彂鏂欙級
-CREATE TABLE `mes_wm_return_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `issue_date` DATETIME DEFAULT NULL COMMENT '閫�鏂欐棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟锛堝彂鏂欙級';
-
--- MES 鐢熶骇閫�鏂欏崟琛岋紙鍙戞枡锛�
-CREATE TABLE `mes_wm_return_issue_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `issue_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟琛岋紙鍙戞枡锛�';
-
--- MES 鐢熶骇閫�鏂欏崟鏄庣粏锛堝彂鏂欙級
-CREATE TABLE `mes_wm_return_issue_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `issue_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟鏄庣粏锛堝彂鏂欙級';
-
--- =====================================================
--- 6.88 MES 澶栧崗鍙戞枡鍗�
--- =====================================================
-
--- MES 澶栧崗鍙戞枡鍗�
-CREATE TABLE `mes_wm_outsource_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '澶栧崗宸ュ崟 ID',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `issue_date` DATETIME DEFAULT NULL COMMENT '鍙戞枡鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍙戞枡鍗�';
-
--- MES 澶栧崗鍙戞枡鍗曡
-CREATE TABLE `mes_wm_outsource_issue_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `issue_id` BIGINT DEFAULT NULL COMMENT '鍙戞枡鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍙戞枡鍗曡';
-
--- MES 澶栧崗鍙戞枡鍗曟槑缁�
-CREATE TABLE `mes_wm_outsource_issue_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `issue_id` BIGINT DEFAULT NULL COMMENT '鍙戞枡鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍙戞枡鍗曟槑缁�';
-
--- =====================================================
--- 6.89 MES 澶栧崗鍏ュ簱鍗�
--- =====================================================
-
--- MES 澶栧崗鍏ュ簱鍗�
-CREATE TABLE `mes_wm_outsource_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '澶栧崗宸ュ崟 ID',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `receipt_date` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍏ュ簱鍗�';
-
--- MES 澶栧崗鍏ュ簱鍗曡
-CREATE TABLE `mes_wm_outsource_receipt_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍏ュ簱鍗曡';
-
--- MES 澶栧崗鍏ュ簱鍗曟槑缁�
-CREATE TABLE `mes_wm_outsource_receipt_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍏ュ簱鍗曟槑缁�';
-
--- =====================================================
--- 6.90 MES 鍏朵粬鍏ュ簱鍗�
--- =====================================================
-
--- MES 鍏朵粬鍏ュ簱鍗�
-CREATE TABLE `mes_wm_misc_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `receipt_date` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍏ュ簱鍗�';
-
--- MES 鍏朵粬鍏ュ簱鍗曡
-CREATE TABLE `mes_wm_misc_receipt_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍏ュ簱鍗曡';
-
--- MES 鍏朵粬鍏ュ簱鍗曟槑缁�
-CREATE TABLE `mes_wm_misc_receipt_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍏ュ簱鍗曟槑缁�';
-
--- =====================================================
--- 6.91 MES 鍏朵粬鍑哄簱鍗�
--- =====================================================
-
--- MES 鍏朵粬鍑哄簱鍗�
-CREATE TABLE `mes_wm_misc_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `issue_date` DATETIME DEFAULT NULL COMMENT '鍑哄簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍑哄簱鍗�';
-
--- MES 鍏朵粬鍑哄簱鍗曡
-CREATE TABLE `mes_wm_misc_issue_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `issue_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍑哄簱鍗曡';
-
--- MES 鍏朵粬鍑哄簱鍗曟槑缁�
-CREATE TABLE `mes_wm_misc_issue_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `issue_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍑哄簱鍗曟槑缁�';
-
--- =====================================================
--- 6.92 MES 鐩樼偣璁″垝
--- =====================================================
-
--- MES 鐩樼偣璁″垝
-CREATE TABLE `mes_wm_stock_taking_plan` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鐩樼偣璁″垝缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鐩樼偣璁″垝鍚嶇О',
- `plan_date` DATETIME DEFAULT NULL COMMENT '鐩樼偣鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣璁″垝';
-
--- MES 鐩樼偣璁″垝鍙傛暟
-CREATE TABLE `mes_wm_stock_taking_plan_param` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣璁″垝 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `item_type_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡鍒嗙被 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣璁″垝鍙傛暟';
-
--- =====================================================
--- 6.93 MES 鐩樼偣浠诲姟
--- =====================================================
-
--- MES 鐩樼偣浠诲姟
-CREATE TABLE `mes_wm_stock_taking_task` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鐩樼偣浠诲姟缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鐩樼偣浠诲姟鍚嶇О',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣璁″垝 ID',
- `task_date` DATETIME DEFAULT NULL COMMENT '鐩樼偣鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣浠诲姟';
-
--- MES 鐩樼偣浠诲姟琛�
-CREATE TABLE `mes_wm_stock_taking_task_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `task_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣浠诲姟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '璐﹂潰鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣浠诲姟琛�';
-
--- MES 鐩樼偣浠诲姟缁撴灉
-CREATE TABLE `mes_wm_stock_taking_task_result` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `task_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣浠诲姟 ID',
- `line_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣浠诲姟琛� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '瀹炵洏鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣浠诲姟缁撴灉';
-
--- =====================================================
--- MES 妯″潡鏉$爜閰嶇疆鍒濆鍖栨暟鎹�
--- =====================================================
-
--- 鎻掑叆鐗╂枡鏉$爜閰嶇疆
-INSERT INTO `mes_wm_barcode_config` (`format`, `biz_type`, `content_format`, `content_example`, `auto_generate_flag`, `status`, `creator`, `updater`) VALUES
-(1, 600, '{BUSINESSCODE}', 'ITEM-001', b'1', 0, '1', '1');
-
--- 鎻掑叆浠撳簱鏉$爜閰嶇疆
-INSERT INTO `mes_wm_barcode_config` (`format`, `biz_type`, `content_format`, `content_example`, `auto_generate_flag`, `status`, `creator`, `updater`) VALUES
-(1, 102, 'WH-{BUSINESSCODE}', 'WH-001', b'1', 0, '1', '1');
-
--- 鎻掑叆搴撳尯鏉$爜閰嶇疆
-INSERT INTO `mes_wm_barcode_config` (`format`, `biz_type`, `content_format`, `content_example`, `auto_generate_flag`, `status`, `creator`, `updater`) VALUES
-(1, 103, 'LOC-{BUSINESSCODE}', 'LOC-001', b'1', 0, '1', '1');
-
--- 鎻掑叆搴撲綅鏉$爜閰嶇疆
-INSERT INTO `mes_wm_barcode_config` (`format`, `biz_type`, `content_format`, `content_example`, `auto_generate_flag`, `status`, `creator`, `updater`) VALUES
-(1, 104, 'AREA-{BUSINESSCODE}', 'AREA-001', b'1', 0, '1', '1');
-
--- 鎻掑叆渚涘簲鍟嗘潯鐮侀厤缃�
-INSERT INTO `mes_wm_barcode_config` (`format`, `biz_type`, `content_format`, `content_example`, `auto_generate_flag`, `status`, `creator`, `updater`) VALUES
-(1, 601, 'VENDOR-{BUSINESSCODE}', 'VENDOR-001', b'1', 0, '1', '1');
-
--- 鎻掑叆瀹㈡埛鏉$爜閰嶇疆
-INSERT INTO `mes_wm_barcode_config` (`format`, `biz_type`, `content_format`, `content_example`, `auto_generate_flag`, `status`, `creator`, `updater`) VALUES
-(1, 605, 'CLIENT-{BUSINESSCODE}', 'CLIENT-001', b'1', 0, '1', '1');
-
--- 鎻掑叆宸ヤ綔绔欐潯鐮侀厤缃�
-INSERT INTO `mes_wm_barcode_config` (`format`, `biz_type`, `content_format`, `content_example`, `auto_generate_flag`, `status`, `creator`, `updater`) VALUES
-(1, 602, 'WS-{BUSINESSCODE}', 'WS-001', b'1', 0, '1', '1');
-
--- 鎻掑叆杞﹂棿鏉$爜閰嶇疆
-INSERT INTO `mes_wm_barcode_config` (`format`, `biz_type`, `content_format`, `content_example`, `auto_generate_flag`, `status`, `creator`, `updater`) VALUES
-(1, 603, 'SHOP-{BUSINESSCODE}', 'SHOP-001', b'1', 0, '1', '1');
\ No newline at end of file
diff --git a/docs/im_module.sql b/docs/im_module.sql
deleted file mode 100644
index 875d5d1..0000000
--- a/docs/im_module.sql
+++ /dev/null
@@ -1,353 +0,0 @@
--- =====================================================
--- IM 鍗虫椂閫氳妯″潡鏁版嵁搴撹〃缁撴瀯
--- 鐢熸垚鏃ユ湡: 2026-06-29
--- 閫傜敤椤圭洰: mom-pro2-after
--- 鍖呭惈: 濂藉弸绠$悊銆佺兢鑱婄鐞嗐�佺鑱婃秷鎭�佺兢鑱婃秷鎭�
--- =====================================================
-
--- =====================================================
--- 绗竴閮ㄥ垎: 瀛楀吀绫诲瀷瀹氫箟
--- =====================================================
-
--- IM 绉佽亰娑堟伅鐘舵��
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (600, 'IM 绉佽亰娑堟伅鐘舵��', 'im_private_message_status', 0, '绉佽亰娑堟伅鐘舵��', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 缇よ亰娑堟伅鐘舵��
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (601, 'IM 缇よ亰娑堟伅鐘舵��', 'im_group_message_status', 0, '缇よ亰娑堟伅鐘舵��', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 缇よ亰娑堟伅鍥炴墽鐘舵��
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (602, 'IM 缇よ亰娑堟伅鍥炴墽鐘舵��', 'im_group_message_receipt_status', 0, '缇よ亰娑堟伅鍥炴墽鐘舵��', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 濂藉弸鐘舵��
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (603, 'IM 濂藉弸鐘舵��', 'im_friend_status', 0, '濂藉弸鐘舵��', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 缇ょ姸鎬�
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (604, 'IM 缇ょ姸鎬�', 'im_group_status', 0, '缇ょ姸鎬�', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 缇ゆ垚鍛樿鑹�
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (605, 'IM 缇ゆ垚鍛樿鑹�', 'im_group_member_role', 0, '缇ゆ垚鍛樿鑹�', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 濂藉弸娣诲姞鏉ユ簮
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (606, 'IM 濂藉弸娣诲姞鏉ユ簮', 'im_friend_add_source', 0, '濂藉弸娣诲姞鏉ユ簮', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 濂藉弸鐢宠澶勭悊缁撴灉
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (607, 'IM 濂藉弸鐢宠澶勭悊缁撴灉', 'im_friend_request_handle_result', 0, '濂藉弸鐢宠澶勭悊缁撴灉', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 娑堟伅绫诲瀷
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (608, 'IM 娑堟伅绫诲瀷', 'im_message_type', 0, '娑堟伅绫诲瀷', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- =====================================================
--- 绗簩閮ㄥ垎: 瀛楀吀鏁版嵁瀹氫箟
--- =====================================================
-
--- IM 绉佽亰娑堟伅鐘舵�佸瓧鍏告暟鎹�
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (1, '鏈', '0', 'im_private_message_status', 0, 'warning', '', '绉佽亰=鏈', 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2, '宸叉挙鍥�', '2', 'im_private_message_status', 0, 'danger', '', 'RECALL', 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (3, '宸茶', '3', 'im_private_message_status', 0, 'success', '', 'READ', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 缇よ亰娑堟伅鐘舵�佸瓧鍏告暟鎹�
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (1, '姝e父', '0', 'im_group_message_status', 0, 'success', '', '缇よ亰姝e父', 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2, '宸叉挙鍥�', '2', 'im_group_message_status', 0, 'danger', '', '缇よ亰宸叉挙鍥�', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 濂藉弸鐘舵�佸瓧鍏告暟鎹�
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (1, '姝e父', '0', 'im_friend_status', 0, 'success', '', '姝e父濂藉弸鍏崇郴', 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2, '宸插垹闄�', '1', 'im_friend_status', 0, 'danger', '', '宸插垹闄ゅソ鍙嬪叧绯�', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 缇ょ姸鎬佸瓧鍏告暟鎹�
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (1, '姝e父', '0', 'im_group_status', 0, 'success', '', '缇ゆ甯�', 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2, '宸茶В鏁�', '1', 'im_group_status', 0, 'info', '', '缇ゅ凡瑙f暎', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 缇ゆ垚鍛樿鑹插瓧鍏告暟鎹�
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (1, '缇や富', '1', 'im_group_member_role', 0, 'primary', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2, '绠$悊鍛�', '2', 'im_group_member_role', 0, 'warning', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (3, '鏅�氭垚鍛�', '3', 'im_group_member_role', 0, 'info', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 濂藉弸娣诲姞鏉ユ簮瀛楀吀鏁版嵁
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (1, '鎼滅储', '1', 'im_friend_add_source', 0, 'default', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2, '缇よ亰', '2', 'im_friend_add_source', 0, 'default', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (3, '鎵爜', '3', 'im_friend_add_source', 0, 'default', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (4, '鍚嶇墖', '4', 'im_friend_add_source', 0, 'default', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 濂藉弸鐢宠澶勭悊缁撴灉瀛楀吀鏁版嵁
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (1, '绛夊緟楠岃瘉', '0', 'im_friend_request_handle_result', 0, 'warning', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2, '宸叉坊鍔�', '1', 'im_friend_request_handle_result', 0, 'success', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (3, '宸叉嫆缁�', '2', 'im_friend_request_handle_result', 0, 'info', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 娑堟伅绫诲瀷瀛楀吀鏁版嵁
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (101, '鏂囨湰', '101', 'im_message_type', 0, '', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (102, '鍥剧墖', '102', 'im_message_type', 0, 'success', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (103, '璇煶', '103', 'im_message_type', 0, 'warning', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (104, '瑙嗛', '104', 'im_message_type', 0, 'warning', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (105, '鏂囦欢', '105', 'im_message_type', 0, 'info', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2101, '鎾ゅ洖', '2101', 'im_message_type', 0, 'danger', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2200, '鍥炴墽', '2200', 'im_message_type', 0, 'warning', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2201, '宸茶', '2201', 'im_message_type', 0, 'success', '', NULL, 'admin', NOW(), 'admin', NOW(), b'0');
-
--- IM 缇ゆ秷鎭洖鎵х姸鎬�
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (1, '涓嶉渶瑕佸洖鎵�', '0', 'im_group_message_receipt_status', 0, 'info', '', 'NO_RECEIPT', 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2, '寰呭畬鎴�', '1', 'im_group_message_receipt_status', 0, 'warning', '', 'PENDING', 'admin', NOW(), 'admin', NOW(), b'0');
-INSERT INTO `system_dict_data` (`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (3, '宸插畬鎴�', '2', 'im_group_message_receipt_status', 0, 'success', '', 'DONE', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- =====================================================
--- 绗笁閮ㄥ垎: IM 妯″潡鏍稿績琛ㄧ粨鏋� (11 寮犺〃)
--- =====================================================
-
--- 3.1 濂藉弸鍏崇郴琛�
-DROP TABLE IF EXISTS `im_friend`;
-CREATE TABLE `im_friend` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `friend_user_id` bigint NOT NULL COMMENT '濂藉弸鐢ㄦ埛缂栧彿',
- `remark` varchar(255) DEFAULT NULL COMMENT '濂藉弸澶囨敞',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '濂藉弸鐘舵�侊紙0姝e父 1宸插垹闄わ級',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_user_id` (`user_id`),
- KEY `idx_friend_user_id` (`friend_user_id`),
- UNIQUE KEY `uk_user_friend` (`user_id`, `friend_user_id`)
-) ENGINE=InnoDB COMMENT='濂藉弸鍏崇郴琛�';
-
--- 3.2 濂藉弸鐢宠琛�
-DROP TABLE IF EXISTS `im_friend_request`;
-CREATE TABLE `im_friend_request` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `user_id` bigint NOT NULL COMMENT '鐢宠浜虹紪鍙�',
- `target_user_id` bigint NOT NULL COMMENT '鐩爣鐢ㄦ埛缂栧彿',
- `content` varchar(500) DEFAULT NULL COMMENT '鐢宠鍐呭',
- `source` tinyint NOT NULL DEFAULT 1 COMMENT '娣诲姞鏉ユ簮锛�1鎼滅储 2缇よ亰 3鎵爜 4鍚嶇墖锛�',
- `handle_result` tinyint NOT NULL DEFAULT 0 COMMENT '澶勭悊缁撴灉锛�0绛夊緟 1宸叉坊鍔� 2宸叉嫆缁濓級',
- `handle_time` datetime DEFAULT NULL COMMENT '澶勭悊鏃堕棿',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_user_id` (`user_id`),
- KEY `idx_target_user_id` (`target_user_id`)
-) ENGINE=InnoDB COMMENT='濂藉弸鐢宠琛�';
-
--- 3.3 缇ょ粍琛�
-DROP TABLE IF EXISTS `im_group`;
-CREATE TABLE `im_group` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缇ょ紪鍙�',
- `name` varchar(100) NOT NULL COMMENT '缇ゅ悕绉�',
- `avatar` varchar(255) DEFAULT NULL COMMENT '缇ゅご鍍�',
- `owner_user_id` bigint NOT NULL COMMENT '缇や富鐢ㄦ埛缂栧彿',
- `notice` varchar(500) DEFAULT NULL COMMENT '缇ゅ叕鍛�',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '缇ょ姸鎬侊紙0姝e父 1宸茶В鏁o級',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_owner_user_id` (`owner_user_id`)
-) ENGINE=InnoDB COMMENT='缇ょ粍琛�';
-
--- 3.4 缇ゆ垚鍛樿〃
-DROP TABLE IF EXISTS `im_group_member`;
-CREATE TABLE `im_group_member` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `group_id` bigint NOT NULL COMMENT '缇ょ紪鍙�',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `nickname` varchar(100) DEFAULT NULL COMMENT '缇ゅ唴鏄电О',
- `role` tinyint NOT NULL DEFAULT 3 COMMENT '缇よ鑹诧紙1缇や富 2绠$悊鍛� 3鏅�氭垚鍛橈級',
- `mute_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁绂佽█',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_group_id` (`group_id`),
- KEY `idx_user_id` (`user_id`),
- UNIQUE KEY `uk_group_user` (`group_id`, `user_id`)
-) ENGINE=InnoDB COMMENT='缇ゆ垚鍛樿〃';
-
--- 3.5 绉佽亰娑堟伅琛�
-DROP TABLE IF EXISTS `im_private_message`;
-CREATE TABLE `im_private_message` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '娑堟伅缂栧彿',
- `from_user_id` bigint NOT NULL COMMENT '鍙戦�佷汉缂栧彿',
- `to_user_id` bigint NOT NULL COMMENT '鎺ユ敹浜虹紪鍙�',
- `content` text COMMENT '娑堟伅鍐呭',
- `message_type` int NOT NULL DEFAULT 101 COMMENT '娑堟伅绫诲瀷锛�101鏂囨湰 102鍥剧墖 103璇煶 104瑙嗛 105鏂囦欢锛�',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '娑堟伅鐘舵�侊紙0鏈 2宸叉挙鍥� 3宸茶锛�',
- `send_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍙戦�佹椂闂�',
- `read_time` datetime DEFAULT NULL COMMENT '宸茶鏃堕棿',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_from_user_id` (`from_user_id`),
- KEY `idx_to_user_id` (`to_user_id`)
-) ENGINE=InnoDB COMMENT='绉佽亰娑堟伅琛�';
-
--- 3.6 缇よ亰娑堟伅琛�
-DROP TABLE IF EXISTS `im_group_message`;
-CREATE TABLE `im_group_message` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '娑堟伅缂栧彿',
- `group_id` bigint NOT NULL COMMENT '缇ょ紪鍙�',
- `from_user_id` bigint NOT NULL COMMENT '鍙戦�佷汉缂栧彿',
- `content` text COMMENT '娑堟伅鍐呭',
- `message_type` int NOT NULL DEFAULT 101 COMMENT '娑堟伅绫诲瀷',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '娑堟伅鐘舵�侊紙0姝e父 2宸叉挙鍥烇級',
- `receipt_status` tinyint NOT NULL DEFAULT 0 COMMENT '鍥炴墽鐘舵�侊紙0涓嶉渶瑕� 1寰呭畬鎴� 2宸插畬鎴愶級',
- `send_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍙戦�佹椂闂�',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_group_id` (`group_id`),
- KEY `idx_from_user_id` (`from_user_id`)
-) ENGINE=InnoDB COMMENT='缇よ亰娑堟伅琛�';
-
--- 3.7 缇ゆ秷鎭洖鎵ц〃
-DROP TABLE IF EXISTS `im_group_message_receipt`;
-CREATE TABLE `im_group_message_receipt` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `message_id` bigint NOT NULL COMMENT '缇ゆ秷鎭紪鍙�',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `read_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '宸茶鏃堕棿',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_message_id` (`message_id`),
- KEY `idx_user_id` (`user_id`),
- UNIQUE KEY `uk_message_user` (`message_id`, `user_id`)
-) ENGINE=InnoDB COMMENT='缇ゆ秷鎭洖鎵ц〃';
-
--- 3.8 浼氳瘽琛紙绉佽亰+缇よ亰锛�
-DROP TABLE IF EXISTS `im_conversation`;
-CREATE TABLE `im_conversation` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浼氳瘽缂栧彿',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `conversation_type` tinyint NOT NULL COMMENT '浼氳瘽绫诲瀷锛�1绉佽亰 2缇よ亰锛�',
- `target_id` bigint NOT NULL COMMENT '鐩爣缂栧彿锛堢鑱婁负鐢ㄦ埛ID锛岀兢鑱婁负缇D锛�',
- `last_message_id` bigint DEFAULT NULL COMMENT '鏈�鍚庢秷鎭紪鍙�',
- `last_message_time` datetime DEFAULT NULL COMMENT '鏈�鍚庢秷鎭椂闂�',
- `unread_count` int NOT NULL DEFAULT 0 COMMENT '鏈娑堟伅鏁�',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_user_id` (`user_id`),
- UNIQUE KEY `uk_user_target_type` (`user_id`, `target_id`, `conversation_type`)
-) ENGINE=InnoDB COMMENT='浼氳瘽琛�';
-
--- 3.9 鐢ㄦ埛鍦ㄧ嚎鐘舵�佽〃
-DROP TABLE IF EXISTS `im_user_online`;
-CREATE TABLE `im_user_online` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `online_status` tinyint NOT NULL DEFAULT 0 COMMENT '鍦ㄧ嚎鐘舵�侊紙0绂荤嚎 1鍦ㄧ嚎锛�',
- `last_online_time` datetime DEFAULT NULL COMMENT '鏈�鍚庡湪绾挎椂闂�',
- `last_offline_time` datetime DEFAULT NULL COMMENT '鏈�鍚庣绾挎椂闂�',
- `device_type` tinyint DEFAULT NULL COMMENT '璁惧绫诲瀷锛�1Web 2Android 3iOS锛�',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_user_id` (`user_id`),
- UNIQUE KEY `uk_user_id` (`user_id`)
-) ENGINE=InnoDB COMMENT='鐢ㄦ埛鍦ㄧ嚎鐘舵�佽〃';
-
--- 3.10 缇ょ敵璇疯〃
-DROP TABLE IF EXISTS `im_group_request`;
-CREATE TABLE `im_group_request` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `group_id` bigint NOT NULL COMMENT '缇ょ紪鍙�',
- `user_id` bigint NOT NULL COMMENT '鐢宠浜虹紪鍙�',
- `content` varchar(500) DEFAULT NULL COMMENT '鐢宠鍐呭',
- `handle_result` tinyint NOT NULL DEFAULT 0 COMMENT '澶勭悊缁撴灉锛�0绛夊緟 1宸查�氳繃 2宸叉嫆缁濓級',
- `handle_user_id` bigint DEFAULT NULL COMMENT '澶勭悊浜虹紪鍙�',
- `handle_time` datetime DEFAULT NULL COMMENT '澶勭悊鏃堕棿',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_group_id` (`group_id`),
- KEY `idx_user_id` (`user_id`)
-) ENGINE=InnoDB COMMENT='缇ょ敵璇疯〃';
-
--- 3.11 娑堟伅鏂囦欢琛�
-DROP TABLE IF EXISTS `im_message_file`;
-CREATE TABLE `im_message_file` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
- `message_id` bigint NOT NULL COMMENT '娑堟伅缂栧彿',
- `message_type` tinyint NOT NULL COMMENT '娑堟伅绫诲瀷锛�102鍥剧墖 103璇煶 104瑙嗛 105鏂囦欢锛�',
- `file_url` varchar(500) NOT NULL COMMENT '鏂囦欢URL',
- `file_name` varchar(255) DEFAULT NULL COMMENT '鏂囦欢鍚�',
- `file_size` bigint DEFAULT NULL COMMENT '鏂囦欢澶у皬锛堝瓧鑺傦級',
- `file_duration` int DEFAULT NULL COMMENT '鏂囦欢鏃堕暱锛堢锛岃闊�/瑙嗛锛�',
- `width` int DEFAULT NULL COMMENT '瀹藉害锛堝浘鐗�/瑙嗛锛�',
- `height` int DEFAULT NULL COMMENT '楂樺害锛堝浘鐗�/瑙嗛锛�',
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`),
- KEY `idx_message_id` (`message_id`)
-) ENGINE=InnoDB COMMENT='娑堟伅鏂囦欢琛�';
-
--- =====================================================
--- IM 妯″潡琛ㄧ粺璁�: 11 寮犺〃
--- =====================================================
\ No newline at end of file
diff --git a/docs/im_module_unlock.md b/docs/im_module_unlock.md
deleted file mode 100644
index 8f6c422..0000000
--- a/docs/im_module_unlock.md
+++ /dev/null
@@ -1,399 +0,0 @@
-# IM 鍗虫椂閫氳妯″潡瑙i攣鎸囧崡
-
-## 涓�銆佹ā鍧楁杩�
-
-IM锛圛nstant Messaging锛夊嵆鏃堕�氳妯″潡鎻愪緵浼佷笟鍐呴儴鐨勫嵆鏃堕�氳鑳藉姏锛屾敮鎸佺鑱娿�佺兢鑱娿�佸ソ鍙嬬鐞嗙瓑鏍稿績鍔熻兘銆�
-
-### 1.1 鍔熻兘娓呭崟
-
-| 鍔熻兘 | 璇存槑 |
-|------|------|
-| 濂藉弸绠$悊 | 娣诲姞濂藉弸銆佸垹闄ゅソ鍙嬨�佸ソ鍙嬬敵璇峰鏍� |
-| 绉佽亰娑堟伅 | 涓�瀵逛竴鑱婂ぉ銆佹秷鎭挙鍥炪�佸凡璇诲洖鎵� |
-| 缇よ亰绠$悊 | 鍒涘缓缇ゃ�佽В鏁g兢銆佺兢鎴愬憳绠$悊銆佺兢鍏憡 |
-| 缇よ亰娑堟伅 | 缇ゅ唴鑱婂ぉ銆佹秷鎭挙鍥炪�佸洖鎵х‘璁� |
-| 浼氳瘽绠$悊 | 浼氳瘽鍒楄〃銆佹湭璇昏鏁般�佸巻鍙叉秷鎭� |
-| 鍦ㄧ嚎鐘舵�� | 鐢ㄦ埛鍦ㄧ嚎/绂荤嚎鐘舵�佹樉绀� |
-
-### 1.2 鏁版嵁搴撹〃娓呭崟
-
-| 琛ㄥ悕 | 璇存槑 |
-|------|------|
-| im_friend | 濂藉弸鍏崇郴琛� |
-| im_friend_request | 濂藉弸鐢宠琛� |
-| im_group | 缇ょ粍琛� |
-| im_group_member | 缇ゆ垚鍛樿〃 |
-| im_private_message | 绉佽亰娑堟伅琛� |
-| im_group_message | 缇よ亰娑堟伅琛� |
-| im_group_message_receipt | 缇ゆ秷鎭洖鎵ц〃 |
-| im_conversation | 浼氳瘽琛� |
-| im_user_online | 鐢ㄦ埛鍦ㄧ嚎鐘舵�佽〃 |
-| im_group_request | 缇ょ敵璇疯〃 |
-| im_message_file | 娑堟伅鏂囦欢琛� |
-
----
-
-## 浜屻�佽В閿佹楠�
-
-### 2.1 鍒涘缓妯″潡鐩綍缁撴瀯
-
-```bash
-mkdir -p yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/api
-mkdir -p yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/{controller,service,dal}
-mkdir -p yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/{friend,group,message}
-mkdir -p yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/{friend,group,message}
-mkdir -p yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/{dataobject,mysql}
-mkdir -p yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/{friend,group,message}
-mkdir -p yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/{friend,group,message}
-```
-
-### 2.2 鍒涘缓 pom.xml
-
-**yudao-module-im-api/pom.xml:**
-
-```xml
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-im</artifactId>
- <version>${revision}</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>yudao-module-im-api</artifactId>
- <packaging>jar</packaging>
-
- <name>${project.artifactId}</name>
- <description>IM 鍗虫椂閫氳妯″潡 API</description>
-
- <dependencies>
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-framework-common</artifactId>
- </dependency>
- </dependencies>
-</project>
-```
-
-**yudao-module-im-biz/pom.xml:**
-
-```xml
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-im</artifactId>
- <version>${revision}</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>yudao-module-im-biz</artifactId>
- <packaging>jar</packaging>
-
- <name>${project.artifactId}</name>
- <description>IM 鍗虫椂閫氳妯″潡涓氬姟瀹炵幇</description>
-
- <dependencies>
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-im-api</artifactId>
- <version>${revision}</version>
- </dependency>
-
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-system-api</artifactId>
- <version>${revision}</version>
- </dependency>
-
- <!-- Web 鐩稿叧 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-security</artifactId>
- </dependency>
-
- <!-- DB 鐩稿叧 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
- </dependency>
-
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-redis</artifactId>
- </dependency>
-
- <!-- WebSocket -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-websocket</artifactId>
- </dependency>
-
- <!-- Test 娴嬭瘯鐩稿叧 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-test</artifactId>
- </dependency>
- </dependencies>
-</project>
-```
-
-### 2.3 鎵ц鏁版嵁搴� SQL
-
-```bash
-# 鎵ц IM 妯″潡琛ㄧ粨鏋� SQL
-mysql -u root -p mom_pro < docs/im_module.sql
-```
-
-### 2.4 鍦� yudao-server/pom.xml 涓坊鍔犱緷璧�
-
-```xml
-<!-- IM 鍗虫椂閫氳妯″潡 -->
-<dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-im-biz</artifactId>
- <version>${revision}</version>
-</dependency>
-```
-
----
-
-## 涓夈�佹牳蹇冨疄浣撶被绀轰緥
-
-### 3.1 ImFriendDO.java
-
-```java
-package cn.iocoder.yudao.module.im.dal.dataobject.friend;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-/**
- * 濂藉弸鍏崇郴 DO
- */
-@TableName("im_friend")
-@KeySequence("im_friend_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class ImFriendDO extends BaseDO {
-
- @TableId
- private Long id;
-
- /** 鐢ㄦ埛缂栧彿 */
- private Long userId;
-
- /** 濂藉弸鐢ㄦ埛缂栧彿 */
- private Long friendUserId;
-
- /** 濂藉弸澶囨敞 */
- private String remark;
-
- /** 濂藉弸鐘舵�侊紙0姝e父 1宸插垹闄わ級 */
- private Integer status;
-
-}
-```
-
-### 3.2 ImGroupDO.java
-
-```java
-package cn.iocoder.yudao.module.im.dal.dataobject.group;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-/**
- * 缇ょ粍 DO
- */
-@TableName("im_group")
-@KeySequence("im_group_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class ImGroupDO extends BaseDO {
-
- @TableId
- private Long id;
-
- /** 缇ゅ悕绉� */
- private String name;
-
- /** 缇ゅご鍍� */
- private String avatar;
-
- /** 缇や富鐢ㄦ埛缂栧彿 */
- private Long ownerUserId;
-
- /** 缇ゅ叕鍛� */
- private String notice;
-
- /** 缇ょ姸鎬侊紙0姝e父 1宸茶В鏁o級 */
- private Integer status;
-
-}
-```
-
-### 3.3 ImPrivateMessageDO.java
-
-```java
-package cn.iocoder.yudao.module.im.dal.dataobject.message;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-import java.time.LocalDateTime;
-
-/**
- * 绉佽亰娑堟伅 DO
- */
-@TableName("im_private_message")
-@KeySequence("im_private_message_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class ImPrivateMessageDO extends BaseDO {
-
- @TableId
- private Long id;
-
- /** 鍙戦�佷汉缂栧彿 */
- private Long fromUserId;
-
- /** 鎺ユ敹浜虹紪鍙� */
- private Long toUserId;
-
- /** 娑堟伅鍐呭 */
- private String content;
-
- /** 娑堟伅绫诲瀷 */
- private Integer messageType;
-
- /** 娑堟伅鐘舵�侊紙0鏈 2宸叉挙鍥� 3宸茶锛� */
- private Integer status;
-
- /** 鍙戦�佹椂闂� */
- private LocalDateTime sendTime;
-
- /** 宸茶鏃堕棿 */
- private LocalDateTime readTime;
-
-}
-```
-
----
-
-## 鍥涖�佷笟鍔℃祦绋嬭鏄�
-
-### 4.1 濂藉弸娣诲姞娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍙戦�佸ソ鍙� 鈹� -> 鈹� 瀵规柟鏀跺埌 鈹� -> 鈹� 鍚屾剰/鎷掔粷 鈹� -> 鈹� 寤虹珛濂藉弸 鈹�
-鈹� 鐢宠 鈹� 鈹� 鐢宠閫氱煡 鈹� 鈹� 鐢宠 鈹� 鈹� 鍏崇郴 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹�
- v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� im_friend_ 鈹� 鈹� WebSocket 鈹� 鈹� im_friend 鈹�
-鈹� request 鈹� 鈹� 鎺ㄩ�侀�氱煡 鈹� 鈹� 琛ㄦ柊澧� 鈹�
-鈹� 琛ㄦ柊澧� 鈹� 鈹� 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-### 4.2 绉佽亰娑堟伅娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍙戦�佹秷鎭� 鈹� -> 鈹� WebSocket 鈹� -> 鈹� 鎺ユ敹娑堟伅 鈹� -> 鈹� 宸茶鍥炴墽 鈹�
-鈹� 鈹� 鈹� 鎺ㄩ�� 鈹� 鈹� 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹� 鈹�
- v v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� im_private_ 鈹� 鈹� 瀹炴椂鎺ㄩ�� 鈹� 鈹� 娑堟伅鍏ュ簱 鈹� 鈹� 鏇存柊宸茶 鈹�
-鈹� message 鈹� 鈹� 缁欐帴鏀朵汉 鈹� 鈹� 鐘舵�佹湭璇� 鈹� 鈹� 鐘舵�� 鈹�
-鈹� 鍏ュ簱 鈹� 鈹� 鈹� 鈹� 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-### 4.3 缇よ亰绠$悊娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍒涘缓缇よ亰 鈹� -> 鈹� 娣诲姞鎴愬憳 鈹� -> 鈹� 缇ゅ唴鑱婂ぉ 鈹� -> 鈹� 瑙f暎缇よ亰 鈹�
-鈹� 鈹� 鈹� 鈹� 鈹� 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹� 鈹�
- v v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� im_group 鈹� 鈹� im_group_ 鈹� 鈹� im_group_ 鈹� 鈹� 鏇存柊缇ょ姸鎬� 鈹�
-鈹� 琛ㄦ柊澧� 鈹� 鈹� member 鈹� 鈹� message 鈹� 鈹� 涓哄凡瑙f暎 鈹�
-鈹� 鈹� 鈹� 琛ㄦ柊澧� 鈹� 鈹� 鍏ュ簱 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
----
-
-## 浜斻�佽彍鍗曢厤缃�
-
-闇�瑕佸湪 system_menu 琛ㄤ腑娣诲姞 IM 妯″潡鐨勮彍鍗曪細
-
-```sql
--- IM 妯″潡涓�绾ц彍鍗�
-INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2100, '鍗虫椂閫氳', '', 1, 30, 0, '/im', 'message', NULL, 0, b'1', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- 濂藉弸绠$悊
-INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2101, '濂藉弸绠$悊', '', 2, 1, 2100, 'friend', '', 'im/friend/index', 0, b'1', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- 缇よ亰绠$悊
-INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2102, '缇よ亰绠$悊', '', 2, 2, 2100, 'group', '', 'im/group/index', 0, b'1', 'admin', NOW(), 'admin', NOW(), b'0');
-
--- 娑堟伅绠$悊
-INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-VALUES (2103, '娑堟伅绠$悊', '', 2, 3, 2100, 'message', '', 'im/message/index', 0, b'1', 'admin', NOW(), 'admin', NOW(), b'0');
-```
-
----
-
-## 鍏�佹敞鎰忎簨椤�
-
-1. **WebSocket 閰嶇疆**: IM 妯″潡渚濊禆 WebSocket 瀹炵幇瀹炴椂閫氳锛岄渶瑕侀厤缃� WebSocket 绔偣
-2. **Redis 娑堟伅闃熷垪**: 寤鸿浣跨敤 Redis Pub/Sub 瀹炵幇娑堟伅骞挎挱
-3. **绂荤嚎娑堟伅瀛樺偍**: 鐢ㄦ埛绂荤嚎鏃剁殑娑堟伅闇�瑕佹寔涔呭寲锛屼笂绾垮悗鎺ㄩ��
-4. **娑堟伅瀹夊叏**: 娑堟伅鍐呭闇�瑕佽�冭檻鏁忔劅璇嶈繃婊ゃ�� XSS 闃叉姢
-5. **鎬ц兘浼樺寲**: 楂樺苟鍙戝満鏅缓璁娇鐢ㄦ秷鎭槦鍒楀墛宄板~璋�
-
----
-
-**鏂囨。鐗堟湰**: v1.0
-**鍒涘缓鏃ユ湡**: 2026-06-29
-**閫傜敤椤圭洰**: mom-pro2-after
-**琛ㄦ暟閲�**: 11 寮�
\ No newline at end of file
diff --git a/docs/mdm_frontend_change.md b/docs/mdm_frontend_change.md
deleted file mode 100644
index bb8589b..0000000
--- a/docs/mdm_frontend_change.md
+++ /dev/null
@@ -1,241 +0,0 @@
-# MDM 鐗╂枡涓绘暟鎹ā鍧楁敼閫� - 鍓嶇鍙樻洿鏂囨。
-
-## 姒傝堪
-
-鏈鏀归�犲皢 ERP銆丮ES銆乄MS 涓変釜妯″潡鐨勭墿鏂�/浜у搧鏁版嵁缁熶竴鍒� MDM锛堜富鏁版嵁绠$悊锛夋ā鍧楋紝娑堥櫎鏁版嵁瀛ゅ矝銆�
-
-## 妯″潡鍙樻洿
-
-### 1. MDM 妯″潡锛堟柊澧烇級
-
-鏂板 MDM 鐗╂枡涓绘暟鎹鐞嗘ā鍧楋紝鍖呭惈浠ヤ笅椤甸潰锛�
-
-| 椤甸潰 | 璺緞 | 璇存槑 |
-|------|------|------|
-| 鐗╂枡绠$悊 | /mdm/item | 鐗╂枡涓绘暟鎹鐞� |
-| 鐗╂枡鍒嗙被 | /mdm/category | 鐗╂枡鍒嗙被绠$悊 |
-| 璁¢噺鍗曚綅 | /mdm/unit | 璁¢噺鍗曚綅绠$悊 |
-| 鍝佺墝绠$悊 | /mdm/brand | 鍝佺墝绠$悊 |
-| 浠撳簱绠$悊 | /mdm/warehouse | 浠撳簱涓绘暟鎹鐞� |
-
-### 2. ERP 妯″潡
-
-ERP 浜у搧鏁版嵁鏉ユ簮浜� MDM锛屽彉鏇村涓嬶細
-
-| 鍘熼〉闈� | 鍙樺寲 |
-|--------|------|
-| /erp/product | 浜у搧鏁版嵁浠� MDM 鑾峰彇锛岄〉闈繚鐣欎絾鏁版嵁婧愬彉鏇� |
-
-### 3. MES 妯″潡
-
-MES 鐗╂枡鏁版嵁鏉ユ簮浜� MDM锛屽彉鏇村涓嬶細
-
-| 鍘熼〉闈� | 鍙樺寲 |
-|--------|------|
-| /mes/md/item | 鐗╂枡鏁版嵁浠� MDM 鑾峰彇锛岄〉闈繚鐣欎絾鏁版嵁婧愬彉鏇� |
-
-### 4. WMS 妯″潡
-
-WMS 鍟嗗搧鍜� SKU 鏁版嵁鏉ユ簮浜� MDM锛屽彉鏇村涓嬶細
-
-| 鍘熼〉闈� | 鍙樺寲 |
-|--------|------|
-| /wms/item | 鍟嗗搧鏁版嵁浠� MDM 鑾峰彇锛岄〉闈繚鐣欎絾鏁版嵁婧愬彉鏇� |
-| /wms/item-sku | SKU 鏁版嵁浠� MDM 鑾峰彇锛岄〉闈繚鐣欎絾鏁版嵁婧愬彉鏇� |
-
----
-
-## API 鍙樻洿璇存槑
-
-### MDM 鐗╂枡 API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /mdm/item/create | 鍒涘缓鐗╂枡 |
-| PUT | /mdm/item/update | 鏇存柊鐗╂枡 |
-| PUT | /mdm/item/update-status | 鏇存柊鐗╂枡鐘舵�� |
-| DELETE | /mdm/item/delete | 鍒犻櫎鐗╂枡锛堝疄闄呬负绂佺敤锛� |
-| GET | /mdm/item/get | 鑾峰彇鐗╂枡 |
-| GET | /mdm/item/page | 鑾峰彇鐗╂枡鍒嗛〉 |
-| GET | /mdm/item/list-by-ids | 鑾峰彇鐗╂枡鍒楄〃 |
-
-**璇锋眰鍙傛暟锛堝垱寤猴級锛�**
-
-| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
-|------|------|------|------|
-| code | String | 鏄� | 鐗╂枡缂栫爜 |
-| name | String | 鏄� | 鐗╂枡鍚嶇О |
-| barCode | String | 鍚� | 鐗╂枡鏉$爜 |
-| specification | String | 鍚� | 瑙勬牸鍨嬪彿 |
-| categoryId | Long | 鏄� | 鐗╂枡鍒嗙被缂栧彿 |
-| unitMeasureId | Long | 鏄� | 璁¢噺鍗曚綅缂栧彿 |
-| brandId | Long | 鍚� | 鍝佺墝缂栧彿 |
-| itemType | Integer | 鏄� | 鐗╂枡绫诲瀷锛�1:鐗╂枡, 2:浜у搧, 3:鍗婃垚鍝侊級 |
-| status | Integer | 鍚� | 鐘舵�侊紙0:鍚敤, 1:绂佺敤锛� |
-| purchasePrice | BigDecimal | 鍚� | 閲囪喘浠锋牸 |
-| salesPrice | BigDecimal | 鍚� | 閿�鍞环鏍� |
-| costPrice | BigDecimal | 鍚� | 鎴愭湰浠锋牸 |
-| safetyStock | BigDecimal | 鍚� | 瀹夊叏搴撳瓨 |
-| expiryDays | Integer | 鍚� | 淇濊川鏈熷ぉ鏁� |
-| isBatchManaged | Boolean | 鍚� | 鏄惁鎵规绠$悊 |
-| remark | String | 鍚� | 澶囨敞 |
-
-**鍝嶅簲锛�**
-
-```json
-{
- "code": 0,
- "data": 1,
- "msg": "鎿嶄綔鎴愬姛"
-}
-```
-
-### MDM 鐗╂枡鍒嗙被 API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /mdm/category/create | 鍒涘缓鍒嗙被 |
-| PUT | /mdm/category/update | 鏇存柊鍒嗙被 |
-| DELETE | /mdm/category/delete | 鍒犻櫎鍒嗙被 |
-| GET | /mdm/category/get | 鑾峰彇鍒嗙被 |
-| GET | /mdm/category/list | 鑾峰彇鍒嗙被鍒楄〃 |
-| GET | /mdm/category/list-all-simple | 鑾峰彇鍚敤鐨勫垎绫诲垪琛� |
-
-### MDM 璁¢噺鍗曚綅 API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /mdm/unit/create | 鍒涘缓鍗曚綅 |
-| PUT | /mdm/unit/update | 鏇存柊鍗曚綅 |
-| DELETE | /mdm/unit/delete | 鍒犻櫎鍗曚綅 |
-| GET | /mdm/unit/get | 鑾峰彇鍗曚綅 |
-| GET | /mdm/unit/page | 鑾峰彇鍗曚綅鍒嗛〉 |
-| GET | /mdm/unit/list-by-ids | 鑾峰彇鍗曚綅鍒楄〃 |
-
-### MDM 鍝佺墝 API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /mdm/brand/create | 鍒涘缓鍝佺墝 |
-| PUT | /mdm/brand/update | 鏇存柊鍝佺墝 |
-| DELETE | /mdm/brand/delete | 鍒犻櫎鍝佺墝 |
-| GET | /mdm/brand/get | 鑾峰彇鍝佺墝 |
-| GET | /mdm/brand/page | 鑾峰彇鍝佺墝鍒嗛〉 |
-| GET | /mdm/brand/list-by-ids | 鑾峰彇鍝佺墝鍒楄〃 |
-
-### MDM 浠撳簱 API
-
-| 鏂规硶 | 璺緞 | 璇存槑 |
-|------|------|------|
-| POST | /mdm/warehouse/create | 鍒涘缓浠撳簱 |
-| PUT | /mdm/warehouse/update | 鏇存柊浠撳簱 |
-| PUT | /mdm/warehouse/update-status | 鏇存柊浠撳簱鐘舵�� |
-| DELETE | /mdm/warehouse/delete | 鍒犻櫎浠撳簱 |
-| GET | /mdm/warehouse/get | 鑾峰彇浠撳簱 |
-| GET | /mdm/warehouse/page | 鑾峰彇浠撳簱鍒嗛〉 |
-| GET | /mdm/warehouse/list-by-ids | 鑾峰彇浠撳簱鍒楄〃 |
-
----
-
-## 鍓嶇淇敼鐐�
-
-### 1. ERP 浜у搧椤甸潰
-
-ERP 浜у搧椤甸潰鏀逛负浠� MDM 鑾峰彇鏁版嵁锛屽墠绔渶瑕佷慨鏀癸細
-
-**API 璋冪敤鍙樻洿锛�**
-
-```js
-// 鍘熻皟鐢� ERP 浜у搧 API
-import { getProductPage, getProduct } from '@/api/erp/product'
-
-// 鏀逛负璋冪敤 MDM 鐗╂枡 API锛坕temType=2 浜у搧锛�
-import { getItemPage, getItem } from '@/api/mdm/item'
-
-// 鏌ヨ鏃堕渶瑕佷紶鍏� itemType=2锛堜骇鍝佺被鍨嬶級
-getItemPage({ itemType: 2, pageNo: 1, pageSize: 10 })
-```
-
-**瀛楁鏄犲皠锛�**
-
-| ERP 瀛楁 | MDM 瀛楁 | 璇存槑 |
-|----------|----------|------|
-| id | id | 缂栧彿 |
-| barCode | code | 缂栫爜锛堝師鏉$爜鏀逛负缂栫爜锛� |
-| name | name | 鍚嶇О |
-| spec | specification | 瑙勬牸鍨嬪彿 |
-| categoryId | categoryId | 鍒嗙被缂栧彿 |
-| unitId | unitMeasureId | 鍗曚綅缂栧彿 |
-| brandId | brandId | 鍝佺墝缂栧彿 |
-| status | status | 鐘舵�� |
-| purchasePrice | purchasePrice | 閲囪喘浠锋牸 |
-| salePrice | salesPrice | 閿�鍞环鏍� |
-| minPrice | costPrice | 鏈�浣庝环鏍兼敼涓烘垚鏈环 |
-
-### 2. MES 鐗╂枡椤甸潰
-
-MES 鐗╂枡椤甸潰鏀逛负浠� MDM 鑾峰彇鏁版嵁锛�
-
-**API 璋冪敤鍙樻洿锛�**
-
-```js
-// 鍘熻皟鐢� MES 鐗╂枡 API
-import { getItemPage, getItem } from '@/api/mes/md/item'
-
-// 鏀逛负璋冪敤 MDM 鐗╂枡 API锛坕temType=1 鐗╂枡锛�
-import { getItemPage, getItem } from '@/api/mdm/item'
-
-// 鏌ヨ鏃堕渶瑕佷紶鍏� itemType=1锛堢墿鏂欑被鍨嬶級
-getItemPage({ itemType: 1, pageNo: 1, pageSize: 10 })
-```
-
-**MES 鐗规湁鍔熻兘淇濈暀锛�**
-- 鎵规灞炴�ч厤缃細浠嶇敱 MES 妯″潡绠$悊
-- BOM 閰嶇疆锛氫粛鐢� MES 妯″潡绠$悊
-- SOP/SIP 閰嶇疆锛氫粛鐢� MES 妯″潡绠$悊
-
-### 3. WMS 鍟嗗搧/SKU 椤甸潰
-
-WMS 鍟嗗搧鍜� SKU 椤甸潰鏀逛负浠� MDM 鑾峰彇鏁版嵁锛�
-
-**API 璋冪敤鍙樻洿锛�**
-
-```js
-// 鍘熻皟鐢� WMS 鍟嗗搧 API
-import { getItemPage, getItem } from '@/api/wms/item'
-
-// 鏀逛负璋冪敤 MDM 鐗╂枡 API
-import { getItemPage, getItem } from '@/api/mdm/item'
-
-// SKU 鏁版嵁
-import { getItemSkuList } from '@/api/mdm/item-sku'
-```
-
----
-
-## 娉ㄦ剰浜嬮」
-
-1. **鐗╂枡绫诲瀷鍖哄垎**锛�
- - itemType=1锛氱墿鏂欙紙MES 浣跨敤锛�
- - itemType=2锛氫骇鍝侊紙ERP 浣跨敤锛�
- - itemType=3锛氬崐鎴愬搧
-
-2. **鍒犻櫎鎿嶄綔**锛歁DM 鐗╂枡鍒犻櫎瀹為檯涓虹鐢ㄦ搷浣滐紝涓嶅仛鐗╃悊鍒犻櫎
-
-3. **SKU 妯″紡**锛氭墍鏈夌墿鏂欏繀椤婚厤缃� SKU锛孍RP/MES 鏁版嵁杩佺Щ鏃惰嚜鍔ㄥ垱寤洪粯璁� SKU
-
-4. **鍚戝悗鍏煎**锛氬師妯″潡鐨� API 鎺ュ彛淇濈暀锛屽唴閮ㄨ皟鐢� MDM API
-
----
-
-## 鏁版嵁搴撹〃
-
-| 琛ㄥ悕 | 璇存槑 |
-|------|------|
-| mdm_item | 鐗╂枡涓绘暟鎹〃 |
-| mdm_item_sku | 鐗╂枡 SKU 琛� |
-| mdm_item_category | 鐗╂枡鍒嗙被琛� |
-| mdm_unit_measure | 璁¢噺鍗曚綅琛� |
-| mdm_brand | 鍝佺墝琛� |
-| mdm_warehouse | 浠撳簱琛� |
-| mdm_item_batch_config | 鎵规灞炴�ч厤缃〃 |
diff --git a/docs/mes_wm_schema.sql b/docs/mes_wm_schema.sql
deleted file mode 100644
index 3bed78a..0000000
--- a/docs/mes_wm_schema.sql
+++ /dev/null
@@ -1,1212 +0,0 @@
--- =====================================================
--- MES 浠撳簱绠$悊妯″潡 (wm) 琛ㄧ粨鏋�
--- 鐢熸垚鏃ユ湡: 2026-06-23
--- 鍏辫: 60 寮犺〃
--- =====================================================
-
--- =====================================================
--- 6.72 浠撳簱鍩虹璁剧疆
--- =====================================================
-
--- MES 浠撳簱琛�
-CREATE TABLE `mes_wm_warehouse` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '浠撳簱缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '浠撳簱鍚嶇О',
- `address` VARCHAR(255) DEFAULT NULL COMMENT '浠撳簱鍦板潃',
- `area` DECIMAL(24,6) DEFAULT NULL COMMENT '闈㈢Н',
- `charge_user_id` BIGINT DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴风紪鍙�',
- `frozen` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 浠撳簱';
-
--- MES 搴撳尯琛�
-CREATE TABLE `mes_wm_warehouse_location` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '搴撳尯缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '搴撳尯鍚嶇О',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱缂栧彿',
- `area` DECIMAL(24,6) DEFAULT NULL COMMENT '闈㈢Н',
- `frozen` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴撳尯';
-
--- MES 搴撲綅琛�
-CREATE TABLE `mes_wm_warehouse_area` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '搴撲綅缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '搴撲綅鍚嶇О',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯缂栧彿',
- `area` DECIMAL(24,6) DEFAULT NULL COMMENT '闈㈢Н',
- `max_load` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈�澶ц浇閲�',
- `position_x` INT DEFAULT NULL COMMENT '浣嶇疆 X',
- `position_y` INT DEFAULT NULL COMMENT '浣嶇疆 Y',
- `position_z` INT DEFAULT NULL COMMENT '浣嶇疆 Z',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `frozen` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
- `allow_item_mixing` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍏佽鐗╂枡娣锋斁',
- `allow_batch_mixing` BIT(1) DEFAULT b'0' COMMENT '鏄惁鍏佽鎵规娣锋斁',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴撲綅';
-
--- =====================================================
--- 6.73 搴撳瓨绠$悊
--- =====================================================
-
--- MES 搴撳瓨璁板綍琛�
-CREATE TABLE `mes_wm_material_stock` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '搴撳瓨鏁伴噺',
- `erp_time` DATETIME DEFAULT NULL COMMENT 'ERP 璐︽湡',
- `receipt_time` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃堕棿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴撳瓨璁板綍';
-
--- MES 搴撳瓨浜嬪姟娴佹按琛�
-CREATE TABLE `mes_wm_transaction` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `type` INT DEFAULT NULL COMMENT '浜嬪姟绫诲瀷',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `biz_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮涓氬姟涓诲崟 ID',
- `biz_code` VARCHAR(100) DEFAULT NULL COMMENT '鏉ユ簮涓氬姟鍗曞彿',
- `biz_line_id` BIGINT DEFAULT NULL COMMENT '鏉ユ簮涓氬姟琛� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨璁板綍 ID',
- `related_transaction_id` BIGINT DEFAULT NULL COMMENT '鍏宠仈鐨勪簨鍔� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏈鍙樺姩鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `batch_code` VARCHAR(100) DEFAULT NULL COMMENT '鎵规鍙�',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `transaction_time` DATETIME DEFAULT NULL COMMENT '浜嬪姟鍙戠敓鏃堕棿',
- `erp_time` DATETIME DEFAULT NULL COMMENT 'ERP 璐︽湡',
- `receipt_time` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃堕棿',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴撳瓨浜嬪姟娴佹按';
-
--- MES 鎵规琛�
-CREATE TABLE `mes_wm_batch` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鎵规鍙�',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `produce_date` DATETIME DEFAULT NULL COMMENT '鐢熶骇鏃ユ湡',
- `expire_date` DATETIME DEFAULT NULL COMMENT '澶辨晥鏃ユ湡',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `vendor_code` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鐮�',
- `vendor_name` VARCHAR(100) DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鎵规';
-
--- MES 搴忓垪鍙疯〃
-CREATE TABLE `mes_wm_sn` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '搴忓垪鍙�',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 搴忓垪鍙�';
-
--- =====================================================
--- 6.74 鏉$爜绠$悊
--- =====================================================
-
--- MES 鏉$爜閰嶇疆琛�
-CREATE TABLE `mes_wm_barcode_config` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `format` INT DEFAULT NULL COMMENT '鏉$爜鏍煎紡',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `content_format` VARCHAR(255) DEFAULT NULL COMMENT '鍐呭鏍煎紡妯℃澘',
- `content_example` VARCHAR(255) DEFAULT NULL COMMENT '鍐呭鏍蜂緥',
- `auto_generate_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁鑷姩鐢熸垚',
- `default_template` VARCHAR(500) DEFAULT NULL COMMENT '榛樿鎵撳嵃妯℃澘',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鏉$爜閰嶇疆';
-
--- MES 鏉$爜娓呭崟琛�
-CREATE TABLE `mes_wm_barcode` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `config_id` BIGINT DEFAULT NULL COMMENT '鏉$爜閰嶇疆缂栧彿',
- `format` INT DEFAULT NULL COMMENT '鏉$爜鏍煎紡',
- `biz_type` INT DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
- `content` VARCHAR(255) DEFAULT NULL COMMENT '鏉$爜鍐呭',
- `biz_id` BIGINT DEFAULT NULL COMMENT '涓氬姟缂栧彿',
- `biz_code` VARCHAR(100) DEFAULT NULL COMMENT '涓氬姟缂栫爜',
- `biz_name` VARCHAR(100) DEFAULT NULL COMMENT '涓氬姟鍚嶇О',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鏉$爜娓呭崟';
-
--- =====================================================
--- 6.75 鍖呰绠$悊
--- =====================================================
-
--- MES 鍖呰鍗曡〃
-CREATE TABLE `mes_wm_package` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍖呰鍗曠紪鐮�',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍖呰鍗曞悕绉�',
- `barcode_id` BIGINT DEFAULT NULL COMMENT '鏉$爜 ID',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍖呰鍗�';
-
--- MES 鍖呰鍗曡琛�
-CREATE TABLE `mes_wm_package_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `package_id` BIGINT DEFAULT NULL COMMENT '鍖呰鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍖呰鍗曡';
-
--- =====================================================
--- 6.76 鍒拌揣閫氱煡鍗�
--- =====================================================
-
--- MES 鍒拌揣閫氱煡鍗�
-CREATE TABLE `mes_wm_arrival_notice` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `arrival_date` DATETIME DEFAULT NULL COMMENT '棰勮鍒拌揣鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍒拌揣閫氱煡鍗�';
-
--- MES 鍒拌揣閫氱煡鍗曡
-CREATE TABLE `mes_wm_arrival_notice_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `notice_id` BIGINT DEFAULT NULL COMMENT '鍒拌揣閫氱煡鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍒拌揣閫氱煡鍗曡';
-
--- =====================================================
--- 6.77 閿�鍞彂璐ч�氱煡鍗�
--- =====================================================
-
--- MES 閿�鍞彂璐ч�氱煡鍗�
-CREATE TABLE `mes_wm_sales_notice` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛 ID',
- `delivery_date` DATETIME DEFAULT NULL COMMENT '棰勮鍙戣揣鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞彂璐ч�氱煡鍗�';
-
--- MES 閿�鍞彂璐ч�氱煡鍗曡
-CREATE TABLE `mes_wm_sales_notice_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `notice_id` BIGINT DEFAULT NULL COMMENT '閿�鍞彂璐ч�氱煡鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞彂璐ч�氱煡鍗曡';
-
--- =====================================================
--- 6.78 杞Щ鍗�
--- =====================================================
-
--- MES 杞Щ鍗�
-CREATE TABLE `mes_wm_transfer` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '杞Щ鍗曞悕绉�',
- `type` INT DEFAULT NULL COMMENT '杞Щ鍗曠被鍨�',
- `delivery_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁閰嶉��',
- `recipient_name` VARCHAR(100) DEFAULT NULL COMMENT '鏀惰揣浜�',
- `recipient_telephone` VARCHAR(100) DEFAULT NULL COMMENT '鑱旂郴鏂瑰紡',
- `destination_address` VARCHAR(255) DEFAULT NULL COMMENT '鐩殑鍦�',
- `carrier` VARCHAR(100) DEFAULT NULL COMMENT '鎵胯繍鍟�',
- `shipping_number` VARCHAR(100) DEFAULT NULL COMMENT '杩愯緭鍗曞彿',
- `confirm_flag` BIT(1) DEFAULT b'0' COMMENT '鏄惁宸茬‘璁�',
- `transfer_date` DATETIME DEFAULT NULL COMMENT '杞Щ鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杞Щ鍗�';
-
--- MES 杞Щ鍗曡
-CREATE TABLE `mes_wm_transfer_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `transfer_id` BIGINT DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨璁板綍缂栧彿',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '杞Щ鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规缂栧彿',
- `from_warehouse_id` BIGINT DEFAULT NULL COMMENT '绉诲嚭浠撳簱缂栧彿',
- `from_location_id` BIGINT DEFAULT NULL COMMENT '绉诲嚭搴撳尯缂栧彿',
- `from_area_id` BIGINT DEFAULT NULL COMMENT '绉诲嚭搴撲綅缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杞Щ鍗曡';
-
--- MES 杞Щ鍗曟槑缁�
-CREATE TABLE `mes_wm_transfer_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '杞Щ鍗曡缂栧彿',
- `transfer_id` BIGINT DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡缂栧彿',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '涓婃灦鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规缂栧彿',
- `to_warehouse_id` BIGINT DEFAULT NULL COMMENT '绉诲叆浠撳簱缂栧彿',
- `to_location_id` BIGINT DEFAULT NULL COMMENT '绉诲叆搴撳尯缂栧彿',
- `to_area_id` BIGINT DEFAULT NULL COMMENT '绉诲叆搴撲綅缂栧彿',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 杞Щ鍗曟槑缁�';
-
--- =====================================================
--- 6.79 鐗╂枡閫�鏂欏崟
--- =====================================================
-
--- MES 鐗╂枡閫�鏂欏崟
-CREATE TABLE `mes_wm_item_consume` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `return_date` DATETIME DEFAULT NULL COMMENT '閫�鏂欐棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�鏂欏崟';
-
--- MES 鐗╂枡閫�鏂欏崟琛�
-CREATE TABLE `mes_wm_item_consume_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `consume_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�鏂欏崟琛�';
-
--- MES 鐗╂枡閫�鏂欏崟鏄庣粏
-CREATE TABLE `mes_wm_item_consume_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `consume_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�鏂欏崟鏄庣粏';
-
--- =====================================================
--- 6.80 鐗╂枡閫�搴撳崟
--- =====================================================
-
--- MES 鐗╂枡閫�搴撳崟
-CREATE TABLE `mes_wm_item_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `receipt_date` DATETIME DEFAULT NULL COMMENT '閫�搴撴棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�搴撳崟';
-
--- MES 鐗╂枡閫�搴撳崟琛�
-CREATE TABLE `mes_wm_item_receipt_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '閫�搴撳崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�搴撳崟琛�';
-
--- MES 鐗╂枡閫�搴撳崟鏄庣粏
-CREATE TABLE `mes_wm_item_receipt_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '閫�搴撳崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐗╂枡閫�搴撳崟鏄庣粏';
-
--- =====================================================
--- 6.81 鐢熶骇棰嗘枡鍗�
--- =====================================================
-
--- MES 鐢熶骇棰嗘枡鍗�
-CREATE TABLE `mes_wm_product_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `issue_date` DATETIME DEFAULT NULL COMMENT '棰嗘枡鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇棰嗘枡鍗�';
-
--- MES 鐢熶骇棰嗘枡鍗曡
-CREATE TABLE `mes_wm_product_issue_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `issue_id` BIGINT DEFAULT NULL COMMENT '棰嗘枡鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇棰嗘枡鍗曡';
-
--- MES 鐢熶骇棰嗘枡鍗曟槑缁�
-CREATE TABLE `mes_wm_product_issue_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `issue_id` BIGINT DEFAULT NULL COMMENT '棰嗘枡鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇棰嗘枡鍗曟槑缁�';
-
--- =====================================================
--- 6.82 鐢熶骇鍏ュ簱鍗�
--- =====================================================
-
--- MES 鐢熶骇鍏ュ簱鍗�
-CREATE TABLE `mes_wm_product_produce` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `produce_date` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇鍏ュ簱鍗�';
-
--- MES 鐢熶骇鍏ュ簱鍗曡
-CREATE TABLE `mes_wm_product_produce_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `produce_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇鍏ュ簱鍗曡';
-
--- MES 鐢熶骇鍏ュ簱鍗曟槑缁�
-CREATE TABLE `mes_wm_product_produce_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `produce_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇鍏ュ簱鍗曟槑缁�';
-
--- =====================================================
--- 6.83 鐢熶骇閫�鏂欏崟
--- =====================================================
-
--- MES 鐢熶骇閫�鏂欏崟
-CREATE TABLE `mes_wm_product_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `receipt_date` DATETIME DEFAULT NULL COMMENT '閫�鏂欐棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟';
-
--- MES 鐢熶骇閫�鏂欏崟琛�
-CREATE TABLE `mes_wm_product_receipt_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟琛�';
-
--- MES 鐢熶骇閫�鏂欏崟鏄庣粏
-CREATE TABLE `mes_wm_product_receipt_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟鏄庣粏';
-
--- =====================================================
--- 6.84 閿�鍞嚭搴撳崟
--- =====================================================
-
--- MES 閿�鍞嚭搴撳崟
-CREATE TABLE `mes_wm_product_sales` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛 ID',
- `sales_date` DATETIME DEFAULT NULL COMMENT '鍑哄簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞嚭搴撳崟';
-
--- MES 閿�鍞嚭搴撳崟琛�
-CREATE TABLE `mes_wm_product_sales_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `sales_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞嚭搴撳崟琛�';
-
--- MES 閿�鍞嚭搴撳崟鏄庣粏
-CREATE TABLE `mes_wm_product_sales_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `sales_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞嚭搴撳崟鏄庣粏';
-
--- =====================================================
--- 6.85 閿�鍞��璐у崟
--- =====================================================
-
--- MES 閿�鍞��璐у崟
-CREATE TABLE `mes_wm_return_sales` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `client_id` BIGINT DEFAULT NULL COMMENT '瀹㈡埛 ID',
- `return_date` DATETIME DEFAULT NULL COMMENT '閫�璐ф棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞��璐у崟';
-
--- MES 閿�鍞��璐у崟琛�
-CREATE TABLE `mes_wm_return_sales_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `return_id` BIGINT DEFAULT NULL COMMENT '閫�璐у崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞��璐у崟琛�';
-
--- MES 閿�鍞��璐у崟鏄庣粏
-CREATE TABLE `mes_wm_return_sales_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `return_id` BIGINT DEFAULT NULL COMMENT '閫�璐у崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閿�鍞��璐у崟鏄庣粏';
-
--- =====================================================
--- 6.86 閲囪喘閫�璐у崟
--- =====================================================
-
--- MES 閲囪喘閫�璐у崟
-CREATE TABLE `mes_wm_return_vendor` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `return_date` DATETIME DEFAULT NULL COMMENT '閫�璐ф棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閲囪喘閫�璐у崟';
-
--- MES 閲囪喘閫�璐у崟琛�
-CREATE TABLE `mes_wm_return_vendor_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `return_id` BIGINT DEFAULT NULL COMMENT '閫�璐у崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閲囪喘閫�璐у崟琛�';
-
--- MES 閲囪喘閫�璐у崟鏄庣粏
-CREATE TABLE `mes_wm_return_vendor_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `return_id` BIGINT DEFAULT NULL COMMENT '閫�璐у崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 閲囪喘閫�璐у崟鏄庣粏';
-
--- =====================================================
--- 6.87 鐢熶骇閫�鏂欏崟锛堝彂鏂欙級
--- =====================================================
-
--- MES 鐢熶骇閫�鏂欏崟锛堝彂鏂欙級
-CREATE TABLE `mes_wm_return_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
- `issue_date` DATETIME DEFAULT NULL COMMENT '閫�鏂欐棩鏈�',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟锛堝彂鏂欙級';
-
--- MES 鐢熶骇閫�鏂欏崟琛岋紙鍙戞枡锛�
-CREATE TABLE `mes_wm_return_issue_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `issue_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟琛岋紙鍙戞枡锛�';
-
--- MES 鐢熶骇閫�鏂欏崟鏄庣粏锛堝彂鏂欙級
-CREATE TABLE `mes_wm_return_issue_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `issue_id` BIGINT DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐢熶骇閫�鏂欏崟鏄庣粏锛堝彂鏂欙級';
-
--- =====================================================
--- 6.88 澶栧崗鍙戞枡鍗�
--- =====================================================
-
--- MES 澶栧崗鍙戞枡鍗�
-CREATE TABLE `mes_wm_outsource_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '澶栧崗宸ュ崟 ID',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `issue_date` DATETIME DEFAULT NULL COMMENT '鍙戞枡鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍙戞枡鍗�';
-
--- MES 澶栧崗鍙戞枡鍗曡
-CREATE TABLE `mes_wm_outsource_issue_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `issue_id` BIGINT DEFAULT NULL COMMENT '鍙戞枡鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍙戞枡鍗曡';
-
--- MES 澶栧崗鍙戞枡鍗曟槑缁�
-CREATE TABLE `mes_wm_outsource_issue_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `issue_id` BIGINT DEFAULT NULL COMMENT '鍙戞枡鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍙戞枡鍗曟槑缁�';
-
--- =====================================================
--- 6.89 澶栧崗鍏ュ簱鍗�
--- =====================================================
-
--- MES 澶栧崗鍏ュ簱鍗�
-CREATE TABLE `mes_wm_outsource_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `work_order_id` BIGINT DEFAULT NULL COMMENT '澶栧崗宸ュ崟 ID',
- `vendor_id` BIGINT DEFAULT NULL COMMENT '渚涘簲鍟� ID',
- `receipt_date` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍏ュ簱鍗�';
-
--- MES 澶栧崗鍏ュ簱鍗曡
-CREATE TABLE `mes_wm_outsource_receipt_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍏ュ簱鍗曡';
-
--- MES 澶栧崗鍏ュ簱鍗曟槑缁�
-CREATE TABLE `mes_wm_outsource_receipt_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 澶栧崗鍏ュ簱鍗曟槑缁�';
-
--- =====================================================
--- 6.90 鍏朵粬鍏ュ簱鍗�
--- =====================================================
-
--- MES 鍏朵粬鍏ュ簱鍗�
-CREATE TABLE `mes_wm_misc_receipt` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `receipt_date` DATETIME DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍏ュ簱鍗�';
-
--- MES 鍏朵粬鍏ュ簱鍗曡
-CREATE TABLE `mes_wm_misc_receipt_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍏ュ簱鍗曡';
-
--- MES 鍏朵粬鍏ュ簱鍗曟槑缁�
-CREATE TABLE `mes_wm_misc_receipt_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `receipt_id` BIGINT DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍏ュ簱鍗曟槑缁�';
-
--- =====================================================
--- 6.91 鍏朵粬鍑哄簱鍗�
--- =====================================================
-
--- MES 鍏朵粬鍑哄簱鍗�
-CREATE TABLE `mes_wm_misc_issue` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鍗曞彿',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鍚嶇О',
- `issue_date` DATETIME DEFAULT NULL COMMENT '鍑哄簱鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍑哄簱鍗�';
-
--- MES 鍏朵粬鍑哄簱鍗曡
-CREATE TABLE `mes_wm_misc_issue_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `issue_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍑哄簱鍗曡';
-
--- MES 鍏朵粬鍑哄簱鍗曟槑缁�
-CREATE TABLE `mes_wm_misc_issue_detail` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `line_id` BIGINT DEFAULT NULL COMMENT '琛� ID',
- `issue_id` BIGINT DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '鏁伴噺',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鍏朵粬鍑哄簱鍗曟槑缁�';
-
--- =====================================================
--- 6.92 鐩樼偣璁″垝
--- =====================================================
-
--- MES 鐩樼偣璁″垝
-CREATE TABLE `mes_wm_stock_taking_plan` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鐩樼偣璁″垝缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鐩樼偣璁″垝鍚嶇О',
- `plan_date` DATETIME DEFAULT NULL COMMENT '鐩樼偣鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣璁″垝';
-
--- MES 鐩樼偣璁″垝鍙傛暟
-CREATE TABLE `mes_wm_stock_taking_plan_param` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣璁″垝 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `item_type_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡鍒嗙被 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣璁″垝鍙傛暟';
-
--- =====================================================
--- 6.93 鐩樼偣浠诲姟
--- =====================================================
-
--- MES 鐩樼偣浠诲姟
-CREATE TABLE `mes_wm_stock_taking_task` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `code` VARCHAR(100) DEFAULT NULL COMMENT '鐩樼偣浠诲姟缂栫爜',
- `name` VARCHAR(100) DEFAULT NULL COMMENT '鐩樼偣浠诲姟鍚嶇О',
- `plan_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣璁″垝 ID',
- `task_date` DATETIME DEFAULT NULL COMMENT '鐩樼偣鏃ユ湡',
- `status` INT DEFAULT NULL COMMENT '鐘舵��',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣浠诲姟';
-
--- MES 鐩樼偣浠诲姟琛�
-CREATE TABLE `mes_wm_stock_taking_task_line` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `task_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣浠诲姟 ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '璐﹂潰鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣浠诲姟琛�';
-
--- MES 鐩樼偣浠诲姟缁撴灉
-CREATE TABLE `mes_wm_stock_taking_task_result` (
- `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `task_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣浠诲姟 ID',
- `line_id` BIGINT DEFAULT NULL COMMENT '鐩樼偣浠诲姟琛� ID',
- `material_stock_id` BIGINT DEFAULT NULL COMMENT '搴撳瓨 ID',
- `item_id` BIGINT DEFAULT NULL COMMENT '鐗╂枡 ID',
- `batch_id` BIGINT DEFAULT NULL COMMENT '鎵规 ID',
- `warehouse_id` BIGINT DEFAULT NULL COMMENT '浠撳簱 ID',
- `location_id` BIGINT DEFAULT NULL COMMENT '搴撳尯 ID',
- `area_id` BIGINT DEFAULT NULL COMMENT '搴撲綅 ID',
- `quantity` DECIMAL(24,6) DEFAULT NULL COMMENT '瀹炵洏鏁伴噺',
- `remark` VARCHAR(255) DEFAULT NULL COMMENT '澶囨敞',
- `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='MES 鐩樼偣浠诲姟缁撴灉';
diff --git a/docs/workflow_guide.md b/docs/workflow_guide.md
deleted file mode 100644
index 9c1888a..0000000
--- a/docs/workflow_guide.md
+++ /dev/null
@@ -1,771 +0,0 @@
-# 鑺嬮亾 ruoyi-vue-pro 宸ヤ綔娴佺▼鎿嶄綔鏂囨。
-
-## 涓�銆侀」鐩杩�
-
-### 1.1 椤圭洰绠�浠�
-
-鑺嬮亾 ruoyi-vue-pro 鏄竴濂楀叏閮ㄥ紑婧愮殑浼佷笟绾у揩閫熷紑鍙戝钩鍙帮紝鍩轰簬 Spring Boot 4.0 + Vue 3 鏋勫缓锛屽寘鍚郴缁熺鐞嗐�佸伐浣滄祦銆丆RM銆丒RP銆丮ES銆乄MS銆丮DM 绛夊涓笟鍔℃ā鍧椼��
-
-### 1.2 宸茶В閿佹ā鍧�
-
-| 妯″潡 | 璇存槑 | 琛ㄦ暟閲� |
-|------|------|--------|
-| yudao-module-system | 绯荤粺绠$悊锛堢敤鎴枫�佽鑹层�佽彍鍗曘�佸瓧鍏哥瓑锛� | 32 |
-| yudao-module-infra | 鍩虹璁炬柦锛堜唬鐮佺敓鎴愩�佹枃浠躲�佸畾鏃朵换鍔$瓑锛� | 11 |
-| yudao-module-bpm | 宸ヤ綔娴佸紩鎿� | 8 |
-| yudao-module-crm | 瀹㈡埛鍏崇郴绠$悊 | 19 |
-| yudao-module-mdm | 涓绘暟鎹鐞嗭紙缁熶竴鐗╂枡銆佸垎绫汇�佸崟浣嶇瓑锛� | 6 |
-| yudao-module-erp | 浼佷笟璧勬簮璁″垝 | 33 |
-| yudao-module-mes | 鍒堕�犳墽琛岀郴缁� | 71 |
-| yudao-module-wms | 浠撳簱绠$悊绯荤粺 | 18 |
-
-### 1.3 妯″潡闆嗘垚鏋舵瀯锛堟牳蹇冩敼閫狅級
-
-鏈」鐩凡瀹炵幇 **MDM 涓绘暟鎹鐞�** 妯″潡锛屾墦閫� ERP銆丮ES銆乄MS 涓変釜涓氬姟妯″潡鐨勬暟鎹宀涳細
-
-```
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� MDM 涓绘暟鎹鐞嗘ā鍧� 鈹�
- 鈹� (鐗╂枡銆丼KU銆佸垎绫汇�佸崟浣嶃�佸搧鐗�) 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹�
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹�
- 鈻� 鈻� 鈻�
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� ERP 妯″潡 鈹� 鈹� WMS 妯″潡 鈹� 鈹� MES 妯″潡 鈹�
- 鈹� 浜у搧 = 鎴愬搧 鈹� 鈹� 鍟嗗搧 = 鐗╂枡 鈹� 鈹� 鐗╂枡 = 鍘熸枡 鈹�
- 鈹� itemType=2 鈹� 鈹� itemType=1 鈹� 鈹� itemType=1 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹�
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈻尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� WMS 搴撳瓨绠$悊 API 鈹�
- 鈹� (缁熶竴搴撳瓨鍏ュ簱/鍑哄簱/鏌ヨ) 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**鏁版嵁缁熶竴璇存槑锛�**
-
-| 涓氬姟妯″潡 | 鍘熸暟鎹〃 | 鐜版暟鎹簮 | 鐗╂枡绫诲瀷鏄犲皠 |
-|----------|----------|----------|--------------|
-| ERP | erp_product | MDM Item | itemType=2锛堟垚鍝侊級 |
-| WMS | wms_item + wms_item_sku | MDM Item + SKU | itemType=1锛堢墿鏂欙級 |
-| MES | mes_md_item | MDM Item | itemType=1锛堢墿鏂欙級 |
-
----
-
-## 浜屻�佸紑鍙戠幆澧冮厤缃�
-
-### 2.1 鐜瑕佹眰
-
-- JDK 21+
-- MySQL 8.0+
-- Redis 6.0+
-- Node.js 18+
-- Maven 3.8+
-
-### 2.2 鏁版嵁搴撳垵濮嬪寲
-
-```bash
-# 1. 鍒涘缓鏁版嵁搴�
-CREATE DATABASE `ruoyi-vue-pro` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
-# 2. 鎵ц SQL 鑴氭湰
-mysql -u root -p ruoyi-vue-pro < docs/database_schema.sql
-
-# 3. 瀵煎叆鍒濆鏁版嵁锛堣彍鍗曘�佸瓧鍏哥瓑锛�
-mysql -u root -p ruoyi-vue-pro < sql/ruoyi-vue-pro.sql
-```
-
-### 2.3 鍚庣鍚姩
-
-```bash
-# 1. 杩涘叆椤圭洰鐩綍
-cd ruoyi-vue-pro
-
-# 2. 缂栬瘧椤圭洰
-mvn clean install -DskipTests
-
-# 3. 鍚姩鏈嶅姟
-cd yudao-server
-mvn spring-boot:run -Dspring-boot.run.profiles=local
-```
-
-### 2.4 鍓嶇鍚姩
-
-```bash
-# 1. 杩涘叆鍓嶇鐩綍
-cd yudao-ui-admin
-
-# 2. 瀹夎渚濊禆
-npm install
-
-# 3. 鍚姩寮�鍙戞湇鍔″櫒
-npm run dev
-```
-
----
-
-## 涓夈�佷富鏁版嵁绠$悊妯″潡 (MDM)
-
-### 3.1 MDM 妯″潡姒傝堪
-
-MDM锛圡aster Data Management锛変富鏁版嵁绠$悊妯″潡鏄暣涓郴缁熺殑鏁版嵁鏍稿績锛岃礋璐g粺涓�绠$悊锛�
-
-- **鐗╂枡涓绘暟鎹�** - 浜у搧銆佺墿鏂欍�佸崐鎴愬搧鐨勭粺涓�妗f
-- **鐗╂枡 SKU** - 鐗╂枡鐨勮鏍煎彉浣擄紙灏哄銆侀鑹茬瓑锛�
-- **鐗╂枡鍒嗙被** - 鐗╂枡鐨勫垎绫讳綋绯�
-- **璁¢噺鍗曚綅** - 缁熶竴鐨勮閲忓崟浣嶇鐞�
-- **鍝佺墝绠$悊** - 鍝佺墝妗f绠$悊
-
-### 3.2 鐗╂枡绫诲瀷璇存槑
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� MDM 鐗╂枡绫诲瀷 (itemType) 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 1 - 鐗╂枡/鍘熸枡 鈫� 鐢ㄤ簬 WMS 鍟嗗搧銆丮ES 鐗╂枡 鈹�
-鈹� 2 - 鎴愬搧/浜у搧 鈫� 鐢ㄤ簬 ERP 浜у搧 鈹�
-鈹� 3 - 鍗婃垚鍝� 鈫� 鐢ㄤ簬 MES 鐢熶骇涓棿浠� 鈹�
-鈹� 4 - 杈呮枡 鈫� 鐢ㄤ簬鐢熶骇杈呭姪鏉愭枡 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-### 3.3 鐗╂枡绠$悊娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍒涘缓鐗╂枡 鈹� -> 鈹� 璁剧疆鍒嗙被 鈹� -> 鈹� 閰嶇疆 SKU 鈹� -> 鈹� 鍚敤鐗╂枡 鈹�
-鈹� 鍩烘湰淇℃伅 鈹� 鈹� 鍗曚綅鍝佺墝 鈹� 鈹� 瑙勬牸浠锋牸 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹�
- v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 缂栫爜鐢熸垚 鈹� 鈹� 鍒嗙被鍏宠仈 鈹� 鈹� 澶氳鏍兼敮鎸� 鈹�
-鈹� 鏉$爜绠$悊 鈹� 鈹� 鍗曚綅鎹㈢畻 鈹� 鈹� 浠锋牸浣撶郴 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**鎿嶄綔姝ラ锛�**
-
-1. 杩涘叆銆怣DM銆�->銆愮墿鏂欑鐞嗐��
-2. 鐐瑰嚮銆愭柊澧炪�戯紝濉啓鐗╂枡鍩烘湰淇℃伅
- - 鐗╂枡缂栫爜锛堝敮涓�锛�
- - 鐗╂枡鍚嶇О
- - 鐗╂枡鏉$爜
- - 瑙勬牸鍨嬪彿
-3. 閫夋嫨鐗╂枡鍒嗙被銆佽閲忓崟浣嶃�佸搧鐗�
-4. 璁剧疆鐗╂枡绫诲瀷锛堢墿鏂�/鎴愬搧/鍗婃垚鍝侊級
-5. 閰嶇疆浠锋牸锛堥噰璐环銆侀攢鍞环銆佹垚鏈环锛�
-6. 淇濆瓨鍚庯紝鍙坊鍔� SKU 瑙勬牸
-
-**娑夊強琛細**
-- `mdm_item` - 鐗╂枡涓昏〃
-- `mdm_item_sku` - 鐗╂枡 SKU 琛�
-- `mdm_item_category` - 鐗╂枡鍒嗙被琛�
-- `mdm_unit_measure` - 璁¢噺鍗曚綅琛�
-- `mdm_brand` - 鍝佺墝琛�
-
-### 3.4 SKU 绠$悊璇存槑
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鐗╂枡 (Item) 鈹�
-鈹� id: 1001 code: ITEM001 name: T鎭� 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� SKU 鍒楄〃 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� SKU-001 鈹� SKU-002 鈹� SKU-003 鈹�
-鈹� 绾㈣壊 / L 鈹� 钃濊壊 / M 鈹� 榛戣壊 / XL 鈹�
-鈹� 鏉$爜: 001REDL 鈹� 鏉$爜: 001BLUEM 鈹� 鏉$爜: 001BLACKXL 鈹�
-鈹� 閿�鍞环: 99 鈹� 閿�鍞环: 99 鈹� 閿�鍞环: 109 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**SKU 瀛楁锛�**
-- SKU 缂栫爜銆丼KU 鍚嶇О銆丼KU 鏉$爜
-- 灏哄锛堥暱/瀹�/楂橈級
-- 閲嶉噺锛堟瘺閲�/鍑�閲嶏級
-- 浠锋牸锛堟垚鏈环/閿�鍞环锛�
-
----
-
-## 鍥涖�佸姛鑳芥ā鍧楀伐浣滄祦绋�
-
-### 4.1 绯荤粺绠$悊妯″潡 (System)
-
-#### 4.1.1 鐢ㄦ埛绠$悊娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鏂板鐢ㄦ埛 鈹� -> 鈹� 鍒嗛厤瑙掕壊 鈹� -> 鈹� 鍒嗛厤閮ㄩ棬 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹�
- v
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鍚敤/绂佺敤 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**鎿嶄綔姝ラ锛�**
-
-1. 鐧诲綍绯荤粺绠$悊鍚庡彴
-2. 杩涘叆銆愮郴缁熺鐞嗐��->銆愮敤鎴风鐞嗐��
-3. 鐐瑰嚮銆愭柊澧炪�戞寜閽紝濉啓鐢ㄦ埛鍩烘湰淇℃伅
-4. 閫夋嫨鐢ㄦ埛鎵�灞為儴闂�
-5. 鍒嗛厤鐢ㄦ埛瑙掕壊锛堝彲澶氶�夛級
-6. 璁剧疆鐢ㄦ埛宀椾綅
-7. 鐐瑰嚮銆愮‘瀹氥�戜繚瀛�
-
-**娑夊強琛細**
-- `system_users` - 鐢ㄦ埛琛�
-- `system_user_role` - 鐢ㄦ埛瑙掕壊鍏宠仈琛�
-- `system_user_post` - 鐢ㄦ埛宀椾綅鍏宠仈琛�
-
-#### 4.1.2 瑙掕壊鏉冮檺閰嶇疆娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍒涘缓瑙掕壊 鈹� -> 鈹� 鍒嗛厤鑿滃崟 鈹� -> 鈹� 鍒嗛厤鏁版嵁 鈹�
-鈹� 鈹� 鈹� 鏉冮檺 鈹� 鈹� 鏉冮檺鑼冨洿 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**鎿嶄綔姝ラ锛�**
-
-1. 杩涘叆銆愮郴缁熺鐞嗐��->銆愯鑹茬鐞嗐��
-2. 鐐瑰嚮銆愭柊澧炪�戝垱寤鸿鑹�
-3. 鐐瑰嚮銆愯彍鍗曟潈闄愩�戝垎閰嶈彍鍗曡闂潈闄�
-4. 鐐瑰嚮銆愭暟鎹潈闄愩�戣缃暟鎹寖鍥达紙鍏ㄩ儴銆佹湰閮ㄩ棬銆佷粎鏈汉绛夛級
-5. 淇濆瓨閰嶇疆
-
-**娑夊強琛細**
-- `system_role` - 瑙掕壊琛�
-- `system_role_menu` - 瑙掕壊鑿滃崟鍏宠仈琛�
-
----
-
-### 4.2 宸ヤ綔娴佹ā鍧� (BPM)
-
-#### 4.2.1 娴佺▼璁捐娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍒涘缓娴佺▼ 鈹� -> 鈹� 璁捐琛ㄥ崟 鈹� -> 鈹� 璁捐娴佺▼ 鈹� -> 鈹� 鍙戝竷娴佺▼ 鈹�
-鈹� 鍒嗙被 鈹� 鈹� 鈹� 鈹� 鍥� 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**鎿嶄綔姝ラ锛�**
-
-1. 杩涘叆銆愬伐浣滄祦銆�->銆愭祦绋嬬鐞嗐��->銆愭祦绋嬪垎绫汇��
-2. 鍒涘缓娴佺▼鍒嗙被锛堝锛氬鎵规祦绋嬨�佷笟鍔℃祦绋嬶級
-3. 杩涘叆銆愯〃鍗曠鐞嗐�戯紝鍒涘缓涓氬姟琛ㄥ崟
-4. 杩涘叆銆愭祦绋嬫ā鍨嬨�戯紝鐐瑰嚮銆愭柊澧炴ā鍨嬨��
-5. 閫夋嫨琛ㄥ崟绫诲瀷锛堝姩鎬佽〃鍗�/鑷畾涔夎〃鍗曪級
-6. 浣跨敤娴佺▼璁捐鍣ㄨ璁℃祦绋嬶紙鎷栨嫿鑺傜偣銆侀厤缃鎵逛汉锛�
-7. 鐐瑰嚮銆愬彂甯冦�戝惎鐢ㄦ祦绋�
-
-**娑夊強琛細**
-- `bpm_category` - 娴佺▼鍒嗙被琛�
-- `bpm_form` - 琛ㄥ崟瀹氫箟琛�
-- `bpm_process_definition_info` - 娴佺▼瀹氫箟鎵╁睍琛�
-
-#### 4.2.2 娴佺▼瀹℃壒娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍙戣捣鐢宠 鈹� -> 鈹� 鎻愪氦瀹℃壒 鈹� -> 鈹� 瀹℃壒澶勭悊 鈹� -> 鈹� 娴佺▼褰掓。 鈹�
-鈹� 鈹� 鈹� 鈹� 鈹� (閫氳繃/椹冲洖)鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**瀹℃壒浜烘搷浣滐細**
-
-1. 鐧诲綍绯荤粺锛岃繘鍏ャ�愬緟鍔炰换鍔°��
-2. 鏌ョ湅寰呭姙浜嬮」锛岀偣鍑汇�愬鐞嗐��
-3. 鏌ョ湅鐢宠鍐呭鍜岃〃鍗曟暟鎹�
-4. 閫夋嫨瀹℃壒缁撴灉锛氶�氳繃/椹冲洖/杞姙
-5. 濉啓瀹℃壒鎰忚
-6. 鐐瑰嚮銆愭彁浜ゃ�戝畬鎴愬鎵�
-
-**娑夊強琛細**
-- `bpm_oa_leave` - 璇峰亣鐢宠琛紙绀轰緥涓氬姟琛級
-- `bpm_process_instance_copy` - 娴佺▼鎶勯�佽〃
-
----
-
-### 4.3 瀹㈡埛鍏崇郴绠$悊妯″潡 (CRM)
-
-#### 4.3.1 绾跨储杞鎴锋祦绋�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 褰曞叆绾跨储 鈹� -> 鈹� 璺熻繘绾跨储 鈹� -> 鈹� 杞寲瀹㈡埛 鈹� -> 鈹� 鍒嗛厤璐熻矗浜� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹�
- v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 绾跨储姹� 鈹� 鈹� 璺熻繘璁板綍 鈹�
-鈹� 鍏捣鍥炴敹 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**鎿嶄綔姝ラ锛�**
-
-1. 杩涘叆銆怌RM銆�->銆愮嚎绱㈢鐞嗐��
-2. 鐐瑰嚮銆愭柊澧炪�戝綍鍏ョ嚎绱俊鎭紙濮撳悕銆佽仈绯绘柟寮忋�佹潵婧愮瓑锛�
-3. 鍦ㄧ嚎绱㈣鎯呴〉锛屾坊鍔犮�愯窡杩涜褰曘��
-4. 绾跨储鎴愮啛鍚庯紝鐐瑰嚮銆愯浆鍖栦负瀹㈡埛銆�
-5. 绯荤粺鑷姩鍒涘缓瀹㈡埛妗f锛屽叧鑱斿師绾跨储
-6. 涓哄鎴峰垎閰嶈礋璐d汉
-
-**娑夊強琛細**
-- `crm_clue` - 绾跨储琛�
-- `crm_customer` - 瀹㈡埛琛�
-- `crm_follow_up_record` - 璺熻繘璁板綍琛�
-- `crm_permission` - 鏁版嵁鏉冮檺琛�
-
----
-
-### 4.4 浼佷笟璧勬簮璁″垝妯″潡 (ERP)
-
-#### 4.4.1 浜у搧绠$悊锛圡DM 闆嗘垚锛�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� ERP 浜у搧 = MDM 鐗╂枡 (itemType=2) 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� ErpProductService 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈻� 鈹�
-鈹� MdmItemApi.createItem() 鈹�鈹�鈫� MDM 鍒涘缓鐗╂枡 鈹�
-鈹� MdmItemApi.updateItem() 鈹�鈹�鈫� MDM 鏇存柊鐗╂枡 鈹�
-鈹� MdmItemApi.getItem() 鈹�鈹�鈫� MDM 鏌ヨ鐗╂枡 鈹�
-鈹� MdmItemApi.getItemPage() 鈹�鈹�鈫� MDM 鍒嗛〉鏌ヨ 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**瀛楁鏄犲皠锛�**
-
-| ERP 瀛楁 | MDM 瀛楁 | 璇存槑 |
-|----------|----------|------|
-| id | id | 缁熶竴 ID |
-| name | name | 浜у搧鍚嶇О |
-| barCode | barCode | 浜у搧鏉$爜 |
-| standard | specification | 瑙勬牸鍨嬪彿 |
-| unitId | unitMeasureId | 鍗曚綅缂栧彿 |
-| salePrice | salesPrice | 閿�鍞环鏍� |
-| minPrice | costPrice | 鏈�浣庝环鏍�/鎴愭湰浠� |
-
-#### 4.4.2 閲囪喘涓氬姟娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 閲囪喘鐢宠 鈹� -> 鈹� 閲囪喘璁㈠崟 鈹� -> 鈹� 閲囪喘鍏ュ簱 鈹� -> 鈹� 閲囪喘浠樻 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹� 鈹�
- v v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 闇�姹傞儴闂� 鈹� 鈹� 渚涘簲鍟� 鈹� 鈹� WMS鍏ュ簱 鈹� 鈹� 璐㈠姟 鈹�
-鈹� 鍙戣捣 鈹� 鈹� 纭 鈹� 鈹� API璋冪敤 鈹� 鈹� 缁撶畻 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**閲囪喘鍏ュ簱闆嗘垚锛�**
-
-```
-ERP 閲囪喘鍏ュ簱
- 鈹�
- 鈻�
-ErpStockRecordService.createStockRecord()
- 鈹�
- 鈻�
-WmsInventoryApi.receipt() 鈹�鈹�鈫� WMS 鍏ュ簱鎿嶄綔
- 鈹�
- 鈻�
-WMS 搴撳瓨澧炲姞
-```
-
-**娑夊強琛細**
-- `erp_supplier` - 渚涘簲鍟嗚〃
-- `erp_purchase_order` - 閲囪喘璁㈠崟琛�
-- `erp_purchase_in` - 閲囪喘鍏ュ簱琛�
-- `erp_stock_record` - 搴撳瓨娴佹按琛紙ERP 鏈湴璁板綍锛�
-
-#### 4.4.3 閿�鍞笟鍔℃祦绋�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 閿�鍞姤浠� 鈹� -> 鈹� 閿�鍞鍗� 鈹� -> 鈹� 閿�鍞嚭搴� 鈹� -> 鈹� 閿�鍞敹娆� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹� 鈹�
- v v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 瀹㈡埛璇环 鈹� 鈹� 鍚堝悓绛捐 鈹� 鈹� WMS鍑哄簱 鈹� 鈹� 瀵硅处寮�绁� 鈹�
-鈹� 鈹� 鈹� 鈹� 鈹� API璋冪敤 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**閿�鍞嚭搴撻泦鎴愶細**
-
-```
-ERP 閿�鍞嚭搴�
- 鈹�
- 鈻�
-ErpStockRecordService.createStockRecord()
- 鈹�
- 鈻�
-WmsInventoryApi.shipment() 鈹�鈹�鈫� WMS 鍑哄簱鎿嶄綔
- 鈹�
- 鈻�
-WMS 搴撳瓨鍑忓皯
-```
-
-**娑夊強琛細**
-- `erp_customer` - 瀹㈡埛琛�
-- `erp_sale_order` - 閿�鍞鍗曡〃
-- `erp_sale_out` - 閿�鍞嚭搴撹〃
-- `erp_finance_receipt` - 鏀舵鍗曡〃
-
-#### 4.4.4 搴撳瓨鏌ヨ锛圵MS 闆嗘垚锛�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� ERP 搴撳瓨 = WMS 搴撳瓨 API 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� ErpStockService 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈻� 鈹�
-鈹� MdmItemSkuApi.getItemSkuListByItemId() 鈹�鈹�鈫� 鑾峰彇榛樿 SKU 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈻� 鈹�
-鈹� WmsInventoryApi.getAvailableQuantity() 鈹�鈹�鈫� 鏌ヨ鍙敤搴撳瓨 鈹�
-鈹� WmsInventoryApi.getInventoryList() 鈹�鈹�鈫� 鏌ヨ搴撳瓨鍒楄〃 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
----
-
-### 4.5 鍒堕�犳墽琛岀郴缁熸ā鍧� (MES)
-
-#### 4.5.1 鐗╂枡绠$悊锛圡DM 闆嗘垚锛�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� MES 鐗╂枡 = MDM 鐗╂枡 (itemType=1) 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� MesMdItemService 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈻� 鈹�
-鈹� MdmItemApi.getItem() 鈹�鈹�鈫� MDM 鏌ヨ鐗╂枡 鈹�
-鈹� MdmItemApi.getItemList() 鈹�鈹�鈫� MDM 鏌ヨ鐗╂枡鍒楄〃 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-#### 4.5.2 鐢熶骇鎵ц娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鐢熶骇宸ュ崟 鈹� -> 鈹� 宸ュ崟娲惧伐 鈹� -> 鈹� 鐢熶骇棰嗘枡 鈹� -> 鈹� 鐢熶骇鎶ュ伐 鈹�
-鈹� 涓嬭揪 鈹� 鈹� 鈹� 鈹� 鈹� 鈹� 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹� 鈹�
- v v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 璁″垝鎺掔▼ 鈹� 鈹� 浠诲姟鍒嗛厤 鈹� 鈹� WMS鍑哄簱 鈹� 鈹� 杩涘害鍙嶉 鈹�
-鈹� 鐗╂枡妫�鏌� 鈹� 鈹� 宸ヤ綔绔欐寚娲� 鈹� 鈹� API璋冪敤 鈹� 鈹� 璐ㄩ噺璁板綍 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹�
- v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鐢熶骇鍏ュ簱 鈹�
-鈹� WMS鍏ュ簱 鈹�
-鈹� API璋冪敤 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**娑夊強琛細**
-- `mes_pro_work_order` - 鐢熶骇宸ュ崟琛�
-- `mes_pro_task` - 鐢熶骇浠诲姟琛�
-- `mes_pro_work_record` - 鎶ュ伐璁板綍琛�
-- `mes_wm_item_consume` - 鐗╂枡娑堣�楄〃
-
----
-
-### 4.6 浠撳簱绠$悊绯荤粺妯″潡 (WMS)
-
-#### 4.6.1 鍟嗗搧绠$悊锛圡DM 闆嗘垚锛�
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� WMS 鍟嗗搧 = MDM 鐗╂枡 (itemType=1) 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� WmsItemService 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈻� 鈹�
-鈹� MdmItemApi.createItem() 鈹�鈹�鈫� MDM 鍒涘缓鐗╂枡 鈹�
-鈹� MdmItemApi.updateItem() 鈹�鈹�鈫� MDM 鏇存柊鐗╂枡 鈹�
-鈹� MdmItemApi.getItemPage() 鈹�鈹�鈫� MDM 鍒嗛〉鏌ヨ 鈹�
-鈹� MdmItemApi.getItemList() 鈹�鈹�鈫� MDM 鏌ヨ鍒楄〃 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**瀛楁鏄犲皠锛�**
-
-| WMS 瀛楁 | MDM 瀛楁 | 璇存槑 |
-|----------|----------|------|
-| id | id | 缁熶竴 ID |
-| code | code | 鍟嗗搧缂栫爜 |
-| name | name | 鍟嗗搧鍚嶇О |
-| unit | unitMeasure.name | 鍗曚綅鍚嶇О锛堜粠璁¢噺鍗曚綅鑾峰彇锛� |
-| categoryId | categoryId | 鍒嗙被缂栧彿 |
-| brandId | brandId | 鍝佺墝缂栧彿 |
-
-#### 4.6.2 搴撳瓨绠$悊鏍稿績
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� WMS 搴撳瓨绠$悊 API 鈹�
-鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� WmsInventoryApi 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈹溾攢 receipt() 鍏ュ簱鎿嶄綔 鈹�
-鈹� 鈹� 鈹斺攢 鍙傛暟: bizType, bizId, warehouseId, items[] 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈹溾攢 shipment() 鍑哄簱鎿嶄綔 鈹�
-鈹� 鈹� 鈹斺攢 鍙傛暟: bizType, bizId, warehouseId, items[] 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈹溾攢 reserve() 搴撳瓨棰勭暀锛堥攣搴撳瓨锛� 鈹�
-鈹� 鈹� 鈹斺攢 鍙傛暟: bizType, bizId, warehouseId, items[] 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈹溾攢 releaseReserve() 閲婃斁棰勭暀 鈹�
-鈹� 鈹� 鈹斺攢 鍙傛暟: reserveNo 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈹溾攢 getInventoryList() 鏌ヨ搴撳瓨鍒楄〃 鈹�
-鈹� 鈹� 鈹斺攢 鍙傛暟: skuIds, warehouseIds, onlyPositive 鈹�
-鈹� 鈹� 鈹�
-鈹� 鈹斺攢 getAvailableQuantity() 鏌ヨ鍙敤搴撳瓨 鈹�
-鈹� 鈹斺攢 鍙傛暟: skuId, warehouseId 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-#### 4.6.3 鍏ュ簱涓氬姟娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍏ュ簱棰勭害 鈹� -> 鈹� 鍒拌揣鐧昏 鈹� -> 鈹� 鏀惰揣楠屾敹 鈹� -> 鈹� 涓婃灦浣滀笟 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹� 鈹�
- v v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� ERP閲囪喘鍗� 鈹� 鈹� 閫佽揣鍗曟嵁 鈹� 鈹� 璐ㄩ噺妫�楠� 鈹� 鈹� 搴撲綅鍒嗛厤 鈹�
-鈹� MES鐢熶骇鍏ュ簱 鈹� 鈹� 杞﹁締淇℃伅 鈹� 鈹� 鏁伴噺纭 鈹� 鈹� 鎵规绠$悊 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**API 璋冪敤绀轰緥锛�**
-
-```java
-// ERP/MES 璋冪敤 WMS 鍏ュ簱
-WmsReceiptReqDTO req = new WmsReceiptReqDTO();
-req.setBizType(WmsInventoryBizTypeEnum.PURCHASE_RECEIPT.getType());
-req.setBizId(purchaseInId);
-req.setBizNo(purchaseInNo);
-req.setWarehouseId(warehouseId);
-req.setItems(List.of(
- new WmsReceiptReqDTO.Item(skuId, quantity, price)
-));
-wmsInventoryApi.receipt(req);
-```
-
-#### 4.6.4 鍑哄簱涓氬姟娴佺▼
-
-```
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 鍑哄簱鐢宠 鈹� -> 鈹� 娉㈡鐢熸垚 鈹� -> 鈹� 鎷h揣浣滀笟 鈹� -> 鈹� 鍙戣揣纭 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹� 鈹�
- v v v v
-鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-鈹� 閿�鍞鍗� 鈹� 鈹� 璁㈠崟鍚堝苟 鈹� 鈹� 鎵规鍒嗛厤 鈹� 鈹� 瑁呰溅鍙戣繍 鈹�
-鈹� 鐢熶骇棰嗘枡 鈹� 鈹� 浼樺厛绾ф帓搴� 鈹� 鈹� 搴撲綅鎸囧紩 鈹� 鈹� 鐗╂祦璺熻釜 鈹�
-鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-**API 璋冪敤绀轰緥锛�**
-
-```java
-// ERP/MES 璋冪敤 WMS 鍑哄簱
-WmsShipmentReqDTO req = new WmsShipmentReqDTO();
-req.setBizType(WmsInventoryBizTypeEnum.SALE_SHIPMENT.getType());
-req.setBizId(saleOutId);
-req.setBizNo(saleOutNo);
-req.setWarehouseId(warehouseId);
-req.setItems(List.of(
- new WmsShipmentReqDTO.Item(skuId, quantity)
-));
-wmsInventoryApi.shipment(req);
-```
-
-**娑夊強琛細**
-- `wms_inventory` - 搴撳瓨琛�
-- `wms_inventory_history` - 搴撳瓨娴佹按琛�
-- `wms_inventory_reserve` - 搴撳瓨棰勭暀琛�
-
----
-
-## 浜斻�佺郴缁熼泦鎴愯鏄�
-
-### 5.1 妯″潡闂存暟鎹祦杞�
-
-```
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� MDM 妯″潡 鈹�
- 鈹� (鐗╂枡涓绘暟鎹�) 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹�
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹�
- v v v
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹� 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� ERP 妯″潡 鈹� 鈹� WMS 妯″潡 鈹� 鈹� MES 妯″潡 鈹�
- 鈹� (鎴愬搧) 鈹� 鈹� (鐗╂枡+SKU) 鈹� 鈹� (鐗╂枡) 鈹�
- 鈹� itemType=2 鈹� 鈹� itemType=1 鈹� 鈹� itemType=1 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹� 鈹斺攢鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� 鈹� 鈹�
- 鈹� 鈹� 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹�
- 鈹屸攢鈹�鈹�鈹�鈹�鈹�v鈹�鈹�鈹�鈹�鈹�鈹�鈹�
- 鈹� WMS 搴撳瓨 鈹�
- 鈹� API 鈹�
- 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
-```
-
-### 5.2 API 鎺ュ彛娓呭崟
-
-| API 鎺ュ彛 | 鎻愪緵鏂� | 璋冪敤鏂� | 璇存槑 |
-|----------|--------|--------|------|
-| MdmItemApi | MDM | ERP/WMS/MES | 鐗╂枡涓绘暟鎹� CRUD |
-| MdmItemSkuApi | MDM | ERP/WMS/MES | SKU 绠$悊 |
-| MdmItemCategoryApi | MDM | ERP/WMS/MES | 鐗╂枡鍒嗙被 |
-| MdmUnitMeasureApi | MDM | ERP/WMS/MES | 璁¢噺鍗曚綅 |
-| WmsInventoryApi | WMS | ERP/MES | 搴撳瓨鍏ュ簱/鍑哄簱/鏌ヨ |
-
-### 5.3 涓氬姟鏁版嵁鍏宠仈
-
-| 涓氬姟鍦烘櫙 | 娑夊強妯″潡 | 鏁版嵁娴佸悜 | API 璋冪敤 |
-|----------|----------|----------|----------|
-| ERP 浜у搧绠$悊 | ERP 鈫� MDM | 浜у搧 CRUD | MdmItemApi |
-| WMS 鍟嗗搧绠$悊 | WMS 鈫� MDM | 鍟嗗搧 CRUD | MdmItemApi |
-| MES 鐗╂枡绠$悊 | MES 鈫� MDM | 鐗╂枡鏌ヨ | MdmItemApi |
-| 閲囪喘鍏ュ簱 | ERP 鈫� WMS | 搴撳瓨澧炲姞 | WmsInventoryApi.receipt() |
-| 閿�鍞嚭搴� | ERP 鈫� WMS | 搴撳瓨鍑忓皯 | WmsInventoryApi.shipment() |
-| 鐢熶骇棰嗘枡 | MES 鈫� WMS | 搴撳瓨鍑忓皯 | WmsInventoryApi.shipment() |
-| 鐢熶骇鍏ュ簱 | MES 鈫� WMS | 搴撳瓨澧炲姞 | WmsInventoryApi.receipt() |
-| 搴撳瓨鏌ヨ | ERP/MES 鈫� WMS | 搴撳瓨鏌ヨ | WmsInventoryApi.getAvailableQuantity() |
-
----
-
-## 鍏�佸父瑙侀棶棰樺鐞�
-
-### 6.1 鐢ㄦ埛鏃犳硶鐧诲綍
-
-**鎺掓煡姝ラ锛�**
-
-1. 妫�鏌ョ敤鎴风姸鎬佹槸鍚﹀惎鐢�
-2. 妫�鏌ョ敤鎴疯鑹叉槸鍚﹀垎閰�
-3. 妫�鏌ヨ鑹茶彍鍗曟潈闄�
-4. 妫�鏌ヨ处鎴锋槸鍚﹁閿佸畾锛堝瘑鐮侀敊璇鏁拌繃澶氾級
-5. 鏌ョ湅鐧诲綍鏃ュ織 `system_login_log`
-
-### 6.2 鏁版嵁鏉冮檺闂
-
-**鎺掓煡姝ラ锛�**
-
-1. 妫�鏌ヨ鑹茬殑鏁版嵁鏉冮檺鑼冨洿璁剧疆
-2. CRM 妯″潡妫�鏌� `crm_permission` 琛�
-3. 纭鏁版嵁鏄惁姝g‘鍒嗛厤璐熻矗浜�
-
-### 6.3 娴佺▼瀹℃壒寮傚父
-
-**鎺掓煡姝ラ锛�**
-
-1. 妫�鏌ユ祦绋嬪畾涔夋槸鍚︽纭彂甯�
-2. 纭瀹℃壒浜洪厤缃槸鍚︽纭�
-3. 鏌ョ湅娴佺▼瀹炰緥鐘舵��
-4. 妫�鏌ュ�欓�夌敤鎴�/鐢ㄦ埛缁勯厤缃�
-
-### 6.4 鐗╂枡鏁版嵁涓嶄竴鑷�
-
-**鎺掓煡姝ラ锛�**
-
-1. 纭鐗╂枡鏄惁鍦� MDM 涓纭垱寤�
-2. 妫�鏌ョ墿鏂欑被鍨嬶紙itemType锛夋槸鍚︽纭�
-3. 纭 SKU 鏄惁姝g‘閰嶇疆
-4. 楠岃瘉鍒嗙被銆佸崟浣嶅叧鑱旀槸鍚︽纭�
-
-### 6.5 搴撳瓨鏁版嵁涓嶄竴鑷�
-
-**鎺掓煡姝ラ锛�**
-
-1. 妫�鏌� `wms_inventory_history` 搴撳瓨娴佹按璁板綍
-2. 鏍稿鍑哄叆搴撳崟鎹槸鍚﹀叏閮ㄥ鏍�
-3. 纭 WMS API 璋冪敤鏄惁鎴愬姛
-4. 鎵ц搴撳瓨鐩樼偣鏍℃
-
----
-
-## 涓冦�侀檮褰�
-
-### 7.1 妯″潡璺緞瀵圭収琛�
-
-| 妯″潡 | 鍚庣璺緞 | 鍓嶇璺緞 |
-|------|----------|----------|
-| System | yudao-module-system | views/system |
-| Infra | yudao-module-infra | views/infra |
-| BPM | yudao-module-bpm | views/bpm |
-| CRM | yudao-module-crm | views/crm |
-| MDM | yudao-module-mdm | views/mdm |
-| ERP | yudao-module-erp | views/erp |
-| MES | yudao-module-mes | views/mes |
-| WMS | yudao-module-wms | views/wms |
-
-### 7.2 鎺ュ彛閴存潈璇存槑
-
-鎵�鏈変笟鍔℃帴鍙i渶瑕佹惡甯� Token 璁块棶锛�
-
-```http
-Authorization: Bearer {access_token}
-```
-
-Token 鑾峰彇鏂瑰紡锛氳皟鐢ㄧ櫥褰曟帴鍙� `/system/auth/login`
-
-### 7.3 澶氱鎴疯鏄�
-
-绯荤粺鏀寔澶氱鎴锋ā寮忥紝绉熸埛闅旂閫氳繃 `tenant_id` 瀛楁瀹炵幇锛�
-
-- System 妯″潡澶ч儴鍒嗚〃鍖呭惈 `tenant_id`
-- 涓氬姟妯″潡锛圕RM銆丒RP銆丮ES銆乄MS銆丮DM锛変笉鍚鎴峰瓧娈碉紝闇�鑷瀹炵幇闅旂閫昏緫
-
-### 7.4 鏍稿績鏀归�犳枃浠舵竻鍗�
-
-| 鏂囦欢 | 鏀归�犺鏄� |
-|------|----------|
-| ErpProductServiceImpl | 浜у搧 CRUD 璋冪敤 MdmItemApi |
-| ErpStockServiceImpl | 搴撳瓨鏌ヨ璋冪敤 WmsInventoryApi |
-| ErpStockRecordServiceImpl | 搴撳瓨鍙樻洿璋冪敤 WmsInventoryApi |
-| WmsItemServiceImpl | 鍟嗗搧 CRUD 璋冪敤 MdmItemApi |
-| MdmItemApi | MDM 鐗╂枡 API 鎺ュ彛 |
-| MdmItemSkuApi | MDM SKU API 鎺ュ彛 |
-| WmsInventoryApi | WMS 搴撳瓨 API 鎺ュ彛 |
-
----
-
-**鏂囨。鐗堟湰**: v2.0
-**鏇存柊鏃ユ湡**: 2026-06-29
-**閫傜敤鐗堟湰**: ruoyi-vue-pro 2026.04-SNAPSHOT
-**鏍稿績鏀归��**: MDM 涓绘暟鎹鐞嗘ā鍧楅泦鎴愶紝鎵撻�� ERP/MES/WMS 鏁版嵁瀛ゅ矝
diff --git a/pom.xml b/pom.xml
index f2aa5e1..c8565b3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,19 +17,18 @@
<module>yudao-module-infra</module>
<module>yudao-module-member</module>
<module>yudao-module-bpm</module>
- <module>yudao-module-report</module>
- <module>yudao-module-mp</module>
- <module>yudao-module-pay</module>
- <module>yudao-module-mall</module>
+<!-- <module>yudao-module-report</module>-->
+<!-- <module>yudao-module-mp</module>-->
+<!-- <module>yudao-module-pay</module>-->
+<!-- <module>yudao-module-mall</module>-->
<module>yudao-module-crm</module>
<module>yudao-module-erp</module>
- <module>yudao-module-iot</module>
+<!-- <module>yudao-module-iot</module>-->
<module>yudao-module-mes</module>
<module>yudao-module-wms</module>
- <module>yudao-module-mdm</module>
- <module>yudao-module-mdm-api</module>
-<!-- 璇峰弬鑰� https://doc.iocoder.cn/ai/build/ 鏂囨。锛屽畬鎴� AI 妯″潡鐨勫惎鍔紒锛侊紒 -->
- <module>yudao-module-ai</module>
+ <module>yudao-module-im</module>
+ <!-- 璇峰弬鑰� https://doc.iocoder.cn/ai/build/ 鏂囨。锛屽畬鎴� AI 妯″潡鐨勫惎鍔紒锛侊紒 -->
+<!-- <module>yudao-module-ai</module>-->
</modules>
<name>${project.artifactId}</name>
@@ -37,9 +36,9 @@
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
- <revision>2026.04-SNAPSHOT</revision>
+ <revision>2026.06-jdk25-SNAPSHOT</revision>
<!-- Maven 鐩稿叧 -->
- <java.version>21</java.version>
+ <java.version>25</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
@@ -47,7 +46,7 @@
<flatten-maven-plugin.version>1.7.2</flatten-maven-plugin.version>
<!-- maven-surefire-plugin 鏆傛椂鏃犳硶閫氳繃 bom 鐨勪緷璧栬鍙栵紙鍏煎鑰佺増鏈� IDEA 2024 鍙婁互鍓嶇増鏈級 -->
<lombok.version>1.18.46</lombok.version>
- <spring.boot.version>4.0.6</spring.boot.version>
+ <spring.boot.version>4.1.0</spring.boot.version>
<mapstruct.version>1.6.3</mapstruct.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@@ -94,7 +93,7 @@
</path>
<path>
<!-- 纭繚 Lombok 鐢熸垚鐨� getter/setter 鏂规硶鑳借 MapStruct 姝g‘璇嗗埆锛�
- 閬垮厤鍑虹幇 No property named 鈥渪xx" exists 鐨勭紪璇戦敊璇� -->
+ 閬垮厤鍑虹幇 No property named "xxx" exists 鐨勭紪璇戦敊璇� -->
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
@@ -151,14 +150,6 @@
<!-- 浣跨敤 huawei / aliyun 鐨� Maven 婧愶紝鎻愬崌涓嬭浇閫熷害 -->
<repositories>
- <repository>
- <id>spring-milestones</id>
- <name>Spring Milestones</name>
- <url>https://repo.spring.io/milestone</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
<repository>
<id>huaweicloud</id>
<name>huawei</name>
diff --git a/script/livekit-poc/README.md b/script/livekit-poc/README.md
new file mode 100644
index 0000000..104cdb2
--- /dev/null
+++ b/script/livekit-poc/README.md
@@ -0,0 +1,32 @@
+# LiveKit Server PoC
+
+鏈�灏忓彲鐢ㄧ殑 LiveKit Server 鑷儴缃查獙璇佺幆澧冿紝鐢ㄤ簬闆舵湡 PoC銆�
+
+## 鍚姩
+
+```bash
+cd tools/livekit-poc
+docker compose up -d
+bash verify.sh
+```
+
+## 绔彛
+
+- 7880锛欻TTP / WebSocket 淇′护锛�
+- 7881锛歐ebRTC TCP fallback锛�
+- 7882/UDP锛歐ebRTC 濯掍綋锛�
+- macOS / Windows锛氬綋鍓� `docker-compose.yml` 璧扮鍙f槧灏勬ā寮忥紝webhook URL 鐢� `host.docker.internal:48080` 璁╁鍣ㄨ闂埌瀹夸富鏈� yudao 鍚庣锛�
+- macOS 涓� host network锛坄network_mode: host`锛夐渶瑕� Docker Desktop 4.34+ 骞跺湪 Settings 鈫� Resources 鈫� Network 鍕鹃�夈�孍nable host networking銆嶏紝鑰佺増鏈潤榛樺け璐ワ紙瀹瑰櫒璺戝緱璧锋潵浣嗙鍙e畬鍏ㄤ笉閫氾級锛�
+- Linux锛氬彲浠ユ妸 `docker-compose.yml` 鏀规垚 `network_mode: host` + 鍒� `ports:` 娈碉紝骞舵妸 `livekit.yaml` 鐨� webhook URL 鏀逛负 `http://127.0.0.1:48080/admin-api/im/livekit/webhook`銆�
+
+## 鍑嵁 (浠� PoC锛屽嬁鐢ㄤ簬鐢熶骇)
+
+- `LIVEKIT_KEYS=devkey: secret-poc-key-min-32-chars-required-here`
+- API Key锛歚devkey`
+- API Secret锛歚secret-poc-key-min-32-chars-required-here`
+
+鐢熶骇鐜蹇呴』鏀圭敤寮洪殢鏈� secret锛屽苟閫氳繃 `--config /etc/livekit.yaml` 鍔犺浇銆�
+
+## 娴忚鍣ㄨ仈璋�
+
+`verify.sh` 璺戝畬浼氳緭鍑轰竴涓� `meet.livekit.io` 閾炬帴锛岀敤涓や釜娴忚鍣紙鎴栦袱鍙版満鍣級鎵撳紑鍚屼竴閾炬帴鍗冲彲鐪嬪埌瀵规柟鐢婚潰銆�
diff --git a/script/livekit-poc/docker-compose.yml b/script/livekit-poc/docker-compose.yml
new file mode 100644
index 0000000..893daf2
--- /dev/null
+++ b/script/livekit-poc/docker-compose.yml
@@ -0,0 +1,20 @@
+services:
+ livekit:
+ image: docker.m.daocloud.io/livekit/livekit-server:latest
+ container_name: yudao-livekit-dev
+ restart: unless-stopped
+ # 绔彛鏄犲皠妯″紡
+ # macOS / Windows 蹇呰蛋杩欑鏂瑰紡锛欴ocker Desktop 4.34 浠ヤ笅娌℃湁 host network
+ # Linux 鍙互鏀� network_mode: host 鐪佸幓鏄犲皠锛屽苟鎶� livekit.yaml 鐨� webhook url 鎹㈡垚 127.0.0.1
+ ports:
+ - "7880:7880" # HTTP / WebSocket 淇′护
+ - "7881:7881" # WebRTC TCP fallback
+ - "7882:7882/udp" # WebRTC UDP (dev 妯″紡 UDP mux 鍗曠鍙�)
+ volumes:
+ # 鎸傝浇 config 鏂囦欢锛泈ebhook 閰嶇疆鍦� livekit.yaml 閲�
+ - ./livekit.yaml:/etc/livekit.yaml:ro
+ command:
+ - --config
+ - /etc/livekit.yaml
+ - --bind
+ - 0.0.0.0
diff --git a/script/livekit-poc/livekit.yaml b/script/livekit-poc/livekit.yaml
new file mode 100644
index 0000000..0dd255e
--- /dev/null
+++ b/script/livekit-poc/livekit.yaml
@@ -0,0 +1,30 @@
+# LiveKit Server 鏈湴寮�鍙戦厤缃紙PoC 鐢紝鍕跨敤浜庣敓浜э級
+# 鏇夸唬 docker --dev 妯″紡锛涗负鏀寔 webhook 蹇呴』鐢� config 鏂囦欢鑰岄潪 env
+
+keys:
+ devkey: secret-poc-key-min-32-chars-required-here
+
+# 绔彛
+port: 7880
+rtc:
+ tcp_port: 7881
+ udp_port: 7882
+ use_external_ip: false
+
+# Webhook锛氭垚鍛樼寮� / 鎴块棿缁撴潫绛変簨浠跺洖璋冨埌 yudao 鍚庣鍋氫笟鍔℃�佸厹搴曟竻鐞�
+# host.docker.internal 璁╁鍣ㄨ闂涓绘満 macOS / Windows 涓婄殑 yudao 鍚庣
+# Linux 涓� docker compose 鍙敼 network_mode: host锛岃繖閲屽悓姝ユ敼鎴� 127.0.0.1
+# api_key 鐢ㄤ簬绛惧彂 JWT锛寉udao 鍚庣鐢ㄧ浉鍚� secret 楠岃瘉绛惧悕
+webhook:
+ api_key: devkey
+ urls:
+ - http://host.docker.internal:48080/admin-api/im/livekit/webhook
+
+# 鎴块棿鏃犱汉鏃跺涔呴攢姣侊紱绉掞紱涔嬪墠 PoC 榛樿 300锛岀粰浣庝簺鏂逛究鎺掓煡
+room:
+ empty_timeout: 300
+ departure_timeout: 20
+
+# 寮�鍙戞ā寮忥細鏀惧 secret 闀垮害闄愬埗 + 鍐呯疆 TURN 鏈嶅姟
+development: true
+log_level: info
diff --git a/script/livekit-poc/verify.sh b/script/livekit-poc/verify.sh
new file mode 100644
index 0000000..9cf9a15
--- /dev/null
+++ b/script/livekit-poc/verify.sh
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+# LiveKit Server PoC 楠岃瘉鑴氭湰锛�
+# 鐢ㄦ硶锛� bash verify.sh
+set -e
+
+API_KEY="${LIVEKIT_API_KEY:-devkey}"
+API_SECRET="${LIVEKIT_API_SECRET:-secret-poc-key-min-32-chars-required-here}"
+HOST="${LIVEKIT_HOST:-localhost:7880}"
+ROOM="${LIVEKIT_ROOM:-poc-room}"
+
+ok() { printf "[OK] %s\n" "$1"; }
+fail() { printf "[FAIL] %s\n" "$1"; exit 1; }
+
+echo "==> 1/5 绛夊緟 HTTP 绔偣灏辩华 (http://${HOST}/)"
+for i in $(seq 1 20); do
+ code=$(curl -s -o /dev/null -w "%{http_code}" "http://${HOST}/" || echo "000")
+ [ "$code" = "200" ] && { ok "HTTP 200"; break; }
+ [ $i -eq 20 ] && fail "20 绉掑唴鏈氨缁� (last code=${code})"
+ sleep 1
+done
+
+echo "==> 2/5 绛惧彂绠$悊 + 瀹㈡埛绔潈闄� Token"
+TOKEN=$(API_KEY="$API_KEY" API_SECRET="$API_SECRET" ROOM="$ROOM" python3 - <<'PY'
+import json, time, hmac, hashlib, base64, os
+def b64u(b): return base64.urlsafe_b64encode(b).rstrip(b'=').decode()
+header = b64u(json.dumps({"alg":"HS256","typ":"JWT"}, separators=(',',':')).encode())
+payload = b64u(json.dumps({
+ "iss": os.environ["API_KEY"],
+ "sub": "poc-tester",
+ "name": "PoC Tester",
+ "video": {
+ "roomJoin": True, "room": os.environ["ROOM"],
+ "canPublish": True, "canSubscribe": True, "canPublishData": True,
+ "roomCreate": True, "roomList": True, "roomAdmin": True
+ },
+ "exp": int(time.time()) + 3600,
+ "nbf": int(time.time())
+}, separators=(',',':')).encode())
+sig = b64u(hmac.new(os.environ["API_SECRET"].encode(),
+ f"{header}.{payload}".encode(),
+ hashlib.sha256).digest())
+print(f"{header}.{payload}.{sig}")
+PY
+)
+[ -n "$TOKEN" ] || fail "Token 鐢熸垚澶辫触"
+ok "Token 宸茬敓鎴� (${#TOKEN} chars)"
+
+echo "==> 3/5 鍒涘缓鎴块棿 ${ROOM} (CreateRoom RPC)"
+create_resp=$(curl -s -X POST "http://${HOST}/twirp/livekit.RoomService/CreateRoom" \
+ -H "Authorization: Bearer ${TOKEN}" \
+ -H "Content-Type: application/json" \
+ -d "{\"name\":\"${ROOM}\",\"empty_timeout\":300,\"max_participants\":10}")
+echo " 鍝嶅簲: $create_resp"
+echo "$create_resp" | jq -e '.sid' >/dev/null 2>&1 \
+ && ok "鎴块棿宸插垱寤�" \
+ || fail "CreateRoom 澶辫触"
+
+echo "==> 4/5 鍒楀嚭鎴块棿 (ListRooms RPC)"
+list_resp=$(curl -s -X POST "http://${HOST}/twirp/livekit.RoomService/ListRooms" \
+ -H "Authorization: Bearer ${TOKEN}" \
+ -H "Content-Type: application/json" \
+ -d '{}')
+room_count=$(echo "$list_resp" | jq '.rooms | length' 2>/dev/null || echo "0")
+ok "褰撳墠鎴块棿鏁�: ${room_count}"
+echo "$list_resp" | jq '.'
+
+echo "==> 5/5 鍒犻櫎鎴块棿 (DeleteRoom RPC) 鈥斺�� 娓呯悊"
+del_resp=$(curl -s -X POST "http://${HOST}/twirp/livekit.RoomService/DeleteRoom" \
+ -H "Authorization: Bearer ${TOKEN}" \
+ -H "Content-Type: application/json" \
+ -d "{\"room\":\"${ROOM}\"}")
+ok "鍒犻櫎鍝嶅簲: $del_resp"
+
+# 閲嶆柊绛句竴涓粎 client 鏉冮檺鐨� token锛涚敤浜庢祻瑙堝櫒杩涗細
+CLIENT_TOKEN=$(API_KEY="$API_KEY" API_SECRET="$API_SECRET" ROOM="$ROOM" python3 - <<'PY'
+import json, time, hmac, hashlib, base64, os
+def b64u(b): return base64.urlsafe_b64encode(b).rstrip(b'=').decode()
+header = b64u(json.dumps({"alg":"HS256","typ":"JWT"}, separators=(',',':')).encode())
+payload = b64u(json.dumps({
+ "iss": os.environ["API_KEY"],
+ "sub": "browser-tester",
+ "name": "Browser",
+ "video": {
+ "roomJoin": True, "room": os.environ["ROOM"],
+ "canPublish": True, "canSubscribe": True, "canPublishData": True
+ },
+ "exp": int(time.time()) + 7200
+}, separators=(',',':')).encode())
+sig = b64u(hmac.new(os.environ["API_SECRET"].encode(),
+ f"{header}.{payload}".encode(),
+ hashlib.sha256).digest())
+print(f"{header}.{payload}.{sig}")
+PY
+)
+
+echo ""
+echo "============================================================"
+echo " LiveKit Server 楠岃瘉閫氳繃"
+echo "============================================================"
+echo " 娴忚鍣ㄦ祴璇� (寮�涓や釜绐楀彛鑳戒簰閫�)锛�"
+echo " https://meet.livekit.io/?liveKitUrl=ws%3A%2F%2F${HOST}&token=${CLIENT_TOKEN}"
+echo ""
+echo " 鍋滄鏈嶅姟锛�"
+echo " docker compose -f tools/livekit-poc/docker-compose.yml down"
+echo "============================================================"
diff --git a/sql/dm/ruoyi-vue-pro-dm8.sql b/sql/dm/ruoyi-vue-pro-dm8.sql
index 3cc9a9a..fb67458 100644
--- a/sql/dm/ruoyi-vue-pro-dm8.sql
+++ b/sql/dm/ruoyi-vue-pro-dm8.sql
@@ -14,27 +14,27 @@
-- ----------------------------
CREATE TABLE infra_api_access_log (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- trace_id varchar(64) DEFAULT '' NULL,
+ trace_id varchar(64 char) DEFAULT '' NULL,
user_id bigint DEFAULT 0 NOT NULL,
user_type smallint DEFAULT 0 NOT NULL,
- application_name varchar(50) NOT NULL,
- request_method varchar(16) DEFAULT '' NULL,
- request_url varchar(255) DEFAULT '' NULL,
+ application_name varchar(50 char) NOT NULL,
+ request_method varchar(16 char) DEFAULT '' NULL,
+ request_url varchar(255 char) DEFAULT '' NULL,
request_params text NULL,
response_body text NULL,
- user_ip varchar(50) NOT NULL,
- user_agent varchar(512) NOT NULL,
- operate_module varchar(50) DEFAULT NULL NULL,
- operate_name varchar(50) DEFAULT NULL NULL,
+ user_ip varchar(50 char) NOT NULL,
+ user_agent varchar(512 char) NOT NULL,
+ operate_module varchar(50 char) DEFAULT NULL NULL,
+ operate_name varchar(50 char) DEFAULT NULL NULL,
operate_type smallint DEFAULT 0 NULL,
begin_time datetime NOT NULL,
end_time datetime NOT NULL,
duration int NOT NULL,
result_code int DEFAULT 0 NOT NULL,
- result_msg varchar(512) DEFAULT '' NULL,
- creator varchar(64) DEFAULT '' NULL,
+ result_msg varchar(512 char) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -74,30 +74,30 @@
-- ----------------------------
CREATE TABLE infra_api_error_log (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- trace_id varchar(64) NOT NULL,
+ trace_id varchar(64 char) NOT NULL,
user_id bigint DEFAULT 0 NOT NULL,
user_type smallint DEFAULT 0 NOT NULL,
- application_name varchar(50) NOT NULL,
- request_method varchar(16) NOT NULL,
- request_url varchar(255) NOT NULL,
- request_params varchar(8000) NOT NULL,
- user_ip varchar(50) NOT NULL,
- user_agent varchar(512) NOT NULL,
+ application_name varchar(50 char) NOT NULL,
+ request_method varchar(16 char) NOT NULL,
+ request_url varchar(255 char) NOT NULL,
+ request_params varchar(8000 char) NOT NULL,
+ user_ip varchar(50 char) NOT NULL,
+ user_agent varchar(512 char) NOT NULL,
exception_time datetime NOT NULL,
- exception_name varchar(128) DEFAULT '' NULL,
+ exception_name varchar(128 char) DEFAULT '' NULL,
exception_message text NOT NULL,
exception_root_cause_message text NOT NULL,
exception_stack_trace text NOT NULL,
- exception_class_name varchar(512) NOT NULL,
- exception_file_name varchar(512) NOT NULL,
- exception_method_name varchar(512) NOT NULL,
+ exception_class_name varchar(512 char) NOT NULL,
+ exception_file_name varchar(512 char) NOT NULL,
+ exception_method_name varchar(512 char) NOT NULL,
exception_line_number int NOT NULL,
process_status smallint NOT NULL,
process_time datetime DEFAULT NULL NULL,
process_user_id int DEFAULT 0 NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -141,25 +141,25 @@
CREATE TABLE infra_codegen_column (
id bigint NOT NULL PRIMARY KEY IDENTITY,
table_id bigint NOT NULL,
- column_name varchar(200) NOT NULL,
- data_type varchar(100) NOT NULL,
- column_comment varchar(500) NOT NULL,
+ column_name varchar(200 char) NOT NULL,
+ data_type varchar(100 char) NOT NULL,
+ column_comment varchar(500 char) NOT NULL,
nullable bit NOT NULL,
primary_key bit NOT NULL,
ordinal_position int NOT NULL,
- java_type varchar(32) NOT NULL,
- java_field varchar(64) NOT NULL,
- dict_type varchar(200) DEFAULT '' NULL,
- example varchar(64) DEFAULT NULL NULL,
+ java_type varchar(32 char) NOT NULL,
+ java_field varchar(64 char) NOT NULL,
+ dict_type varchar(200 char) DEFAULT '' NULL,
+ example varchar(64 char) DEFAULT NULL NULL,
create_operation bit NOT NULL,
update_operation bit NOT NULL,
list_operation bit NOT NULL,
- list_operation_condition varchar(32) DEFAULT '=' NOT NULL,
+ list_operation_condition varchar(32 char) DEFAULT '=' NOT NULL,
list_operation_result bit NOT NULL,
- html_type varchar(32) NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ html_type varchar(32 char) NOT NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -198,14 +198,14 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
data_source_config_id bigint NOT NULL,
scene smallint DEFAULT 1 NOT NULL,
- table_name varchar(200) DEFAULT '' NULL,
- table_comment varchar(500) DEFAULT '' NULL,
- remark varchar(500) DEFAULT NULL NULL,
- module_name varchar(30) NOT NULL,
- business_name varchar(30) NOT NULL,
- class_name varchar(100) DEFAULT '' NULL,
- class_comment varchar(50) NOT NULL,
- author varchar(50) NOT NULL,
+ table_name varchar(200 char) DEFAULT '' NULL,
+ table_comment varchar(500 char) DEFAULT '' NULL,
+ remark varchar(500 char) DEFAULT NULL NULL,
+ module_name varchar(30 char) NOT NULL,
+ business_name varchar(30 char) NOT NULL,
+ class_name varchar(100 char) DEFAULT '' NULL,
+ class_comment varchar(50 char) NOT NULL,
+ author varchar(50 char) NOT NULL,
template_type smallint DEFAULT 1 NOT NULL,
front_type smallint NOT NULL,
parent_menu_id bigint DEFAULT NULL NULL,
@@ -214,9 +214,9 @@
sub_join_many bit DEFAULT NULL NULL,
tree_parent_column_id bigint DEFAULT NULL NULL,
tree_name_column_id bigint DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -252,16 +252,16 @@
-- ----------------------------
CREATE TABLE infra_config (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- category varchar(50) NOT NULL,
+ category varchar(50 char) NOT NULL,
type smallint NOT NULL,
- name varchar(100) DEFAULT '' NULL,
- config_key varchar(100) DEFAULT '' NULL,
- value varchar(500) DEFAULT '' NULL,
+ name varchar(100 char) DEFAULT '' NULL,
+ config_key varchar(100 char) DEFAULT '' NULL,
+ value varchar(500 char) DEFAULT '' NULL,
visible bit NOT NULL,
- remark varchar(500) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ remark varchar(500 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -304,13 +304,13 @@
-- ----------------------------
CREATE TABLE infra_data_source_config (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(100) DEFAULT '' NULL,
- url varchar(1024) NOT NULL,
- username varchar(255) NOT NULL,
- password varchar(255) DEFAULT '' NULL,
- creator varchar(64) DEFAULT '' NULL,
+ name varchar(100 char) DEFAULT '' NULL,
+ url varchar(1024 char) NOT NULL,
+ username varchar(255 char) NOT NULL,
+ password varchar(255 char) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -333,14 +333,14 @@
CREATE TABLE infra_file (
id bigint NOT NULL PRIMARY KEY IDENTITY,
config_id bigint DEFAULT NULL NULL,
- name varchar(256) DEFAULT NULL NULL,
- path varchar(512) NOT NULL,
- url varchar(1024) NOT NULL,
- type varchar(128) DEFAULT NULL NULL,
+ name varchar(256 char) DEFAULT NULL NULL,
+ path varchar(512 char) NOT NULL,
+ url varchar(1024 char) NOT NULL,
+ type varchar(128 char) DEFAULT NULL NULL,
size int NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -364,14 +364,14 @@
-- ----------------------------
CREATE TABLE infra_file_config (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(63) NOT NULL,
+ name varchar(63 char) NOT NULL,
storage smallint NOT NULL,
- remark varchar(255) DEFAULT NULL NULL,
+ remark varchar(255 char) DEFAULT NULL NULL,
master bit NOT NULL,
- config varchar(4096) NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ config varchar(4096 char) NOT NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -415,11 +415,11 @@
CREATE TABLE infra_file_content (
id bigint NOT NULL PRIMARY KEY IDENTITY,
config_id bigint NOT NULL,
- path varchar(512) NOT NULL,
+ path varchar(512 char) NOT NULL,
content blob NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -442,17 +442,17 @@
-- ----------------------------
CREATE TABLE infra_job (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(32) NOT NULL,
+ name varchar(32 char) NOT NULL,
status smallint NOT NULL,
- handler_name varchar(64) NOT NULL,
- handler_param varchar(255) DEFAULT NULL NULL,
- cron_expression varchar(32) NOT NULL,
+ handler_name varchar(64 char) NOT NULL,
+ handler_param varchar(255 char) DEFAULT NULL NULL,
+ cron_expression varchar(32 char) NOT NULL,
retry_count int DEFAULT 0 NOT NULL,
retry_interval int DEFAULT 0 NOT NULL,
monitor_timeout int DEFAULT 0 NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -506,17 +506,17 @@
CREATE TABLE infra_job_log (
id bigint NOT NULL PRIMARY KEY IDENTITY,
job_id bigint NOT NULL,
- handler_name varchar(64) NOT NULL,
- handler_param varchar(255) DEFAULT NULL NULL,
+ handler_name varchar(64 char) NOT NULL,
+ handler_param varchar(255 char) DEFAULT NULL NULL,
execute_index smallint DEFAULT 1 NOT NULL,
begin_time datetime NOT NULL,
end_time datetime DEFAULT NULL NULL,
duration int DEFAULT NULL NULL,
status smallint NOT NULL,
- result varchar(4000) DEFAULT '' NULL,
- creator varchar(64) DEFAULT '' NULL,
+ result varchar(4000 char) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -546,16 +546,16 @@
-- ----------------------------
CREATE TABLE system_dept (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(30) DEFAULT '' NULL,
+ name varchar(30 char) DEFAULT '' NULL,
parent_id bigint DEFAULT 0 NOT NULL,
sort int DEFAULT 0 NOT NULL,
leader_user_id bigint DEFAULT NULL NULL,
- phone varchar(11) DEFAULT NULL NULL,
- email varchar(50) DEFAULT NULL NULL,
+ phone varchar(11 char) DEFAULT NULL NULL,
+ email varchar(50 char) DEFAULT NULL NULL,
status smallint NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -608,16 +608,16 @@
CREATE TABLE system_dict_data (
id bigint NOT NULL PRIMARY KEY IDENTITY,
sort int DEFAULT 0 NOT NULL,
- label varchar(100) DEFAULT '' NULL,
- value varchar(100) DEFAULT '' NULL,
- dict_type varchar(100) DEFAULT '' NULL,
+ label varchar(100 char) DEFAULT '' NULL,
+ value varchar(100 char) DEFAULT '' NULL,
+ dict_type varchar(100 char) DEFAULT '' NULL,
status smallint DEFAULT 0 NOT NULL,
- color_type varchar(100) DEFAULT '' NULL,
- css_class varchar(100) DEFAULT '' NULL,
- remark varchar(500) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ color_type varchar(100 char) DEFAULT '' NULL,
+ css_class varchar(100 char) DEFAULT '' NULL,
+ remark varchar(500 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -1270,6 +1270,8 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '鏀粯瀹濆皬绋嬪簭', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3036, 60, 'Admin Uniapp 绉诲姩绔�', '60', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-12-16 19:25:51', '1', '2025-12-17 09:46:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3037, 42, 'Vben5.0 Antdv Next Schema 妯$増', '42', 'infra_codegen_front_type', 0, '', '', '', '1', NOW(), '1', NOW(), '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3038, 43, 'Vben5.0 Antdv Next 鏍囧噯妯$増', '43', 'infra_codegen_front_type', 0, '', '', '', '1', NOW(), '1', NOW(), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3040, 1, 'UDP', 'udp', 'iot_protocol_type', 0, '', '', 'UDP 鍗忚', '1', '2026-02-04 00:32:47', '1', '2026-02-04 00:32:47', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3041, 2, 'WebSocket', 'websocket', 'iot_protocol_type', 0, '', '', 'WebSocket 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3042, 3, 'HTTP', 'http', 'iot_protocol_type', 0, '', '', 'HTTP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
@@ -1552,9 +1554,9 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3443, 1, '鑽夌', '0', 'mes_wm_product_produce_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3444, 2, '宸插畬鎴�', '4', 'mes_wm_product_produce_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3445, 3, '宸插彇娑�', '5', 'mes_wm_product_produce_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '猫聧鈥懊�', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '氓路虏氓庐艗忙藛聬', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '氓路虏氓聫鈥撁β端�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '鑽夌', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '宸插畬鎴�', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '宸插彇娑�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
COMMIT;
SET IDENTITY_INSERT system_dict_data OFF;
-- @formatter:on
@@ -1564,13 +1566,13 @@
-- ----------------------------
CREATE TABLE system_dict_type (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(100) DEFAULT '' NULL,
- type varchar(100) DEFAULT '' NULL,
+ name varchar(100 char) DEFAULT '' NULL,
+ type varchar(100 char) DEFAULT '' NULL,
status smallint DEFAULT 0 NOT NULL,
- remark varchar(500) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ remark varchar(500 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
deleted_time datetime DEFAULT NULL NULL
@@ -1790,16 +1792,16 @@
CREATE TABLE system_login_log (
id bigint NOT NULL PRIMARY KEY IDENTITY,
log_type bigint NOT NULL,
- trace_id varchar(64) DEFAULT '' NULL,
+ trace_id varchar(64 char) DEFAULT '' NULL,
user_id bigint DEFAULT 0 NOT NULL,
user_type smallint DEFAULT 0 NOT NULL,
- username varchar(50) DEFAULT '' NULL,
+ username varchar(50 char) DEFAULT '' NULL,
result smallint NOT NULL,
- user_ip varchar(50) NOT NULL,
- user_agent varchar(512) NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ user_ip varchar(50 char) NOT NULL,
+ user_agent varchar(512 char) NOT NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -1830,16 +1832,16 @@
-- ----------------------------
CREATE TABLE system_mail_account (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- mail varchar(255) NOT NULL,
- username varchar(255) NOT NULL,
- password varchar(255) NOT NULL,
- host varchar(255) NOT NULL,
+ mail varchar(255 char) NOT NULL,
+ username varchar(255 char) NOT NULL,
+ password varchar(255 char) NOT NULL,
+ host varchar(255 char) NOT NULL,
port int NOT NULL,
ssl_enable bit DEFAULT '0' NOT NULL,
starttls_enable bit DEFAULT '0' NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -1879,24 +1881,24 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
user_id bigint DEFAULT NULL NULL,
user_type smallint DEFAULT NULL NULL,
- to_mails varchar(1024) NOT NULL,
- cc_mails varchar(1024) DEFAULT NULL NULL,
- bcc_mails varchar(1024) DEFAULT NULL NULL,
+ to_mails varchar(1024 char) NOT NULL,
+ cc_mails varchar(1024 char) DEFAULT NULL NULL,
+ bcc_mails varchar(1024 char) DEFAULT NULL NULL,
account_id bigint NOT NULL,
- from_mail varchar(255) NOT NULL,
+ from_mail varchar(255 char) NOT NULL,
template_id bigint NOT NULL,
- template_code varchar(63) NOT NULL,
- template_nickname varchar(255) DEFAULT NULL NULL,
- template_title varchar(255) NOT NULL,
+ template_code varchar(63 char) NOT NULL,
+ template_nickname varchar(255 char) DEFAULT NULL NULL,
+ template_title varchar(255 char) NOT NULL,
template_content text NOT NULL,
- template_params varchar(255) NOT NULL,
+ template_params varchar(255 char) NOT NULL,
send_status smallint DEFAULT 0 NOT NULL,
send_time datetime DEFAULT NULL NULL,
- send_message_id varchar(255) DEFAULT NULL NULL,
- send_exception varchar(4096) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ send_message_id varchar(255 char) DEFAULT NULL NULL,
+ send_exception varchar(4096 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -1931,18 +1933,18 @@
-- ----------------------------
CREATE TABLE system_mail_template (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(63) NOT NULL,
- code varchar(63) NOT NULL,
+ name varchar(63 char) NOT NULL,
+ code varchar(63 char) NOT NULL,
account_id bigint NOT NULL,
- nickname varchar(255) DEFAULT NULL NULL,
- title varchar(255) NOT NULL,
- content varchar(10240) NOT NULL,
- params varchar(255) NOT NULL,
+ nickname varchar(255 char) DEFAULT NULL NULL,
+ title varchar(255 char) NOT NULL,
+ content varchar(10240 char) NOT NULL,
+ params varchar(255 char) NOT NULL,
status smallint NOT NULL,
- remark varchar(255) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ remark varchar(255 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -1981,22 +1983,22 @@
-- ----------------------------
CREATE TABLE system_menu (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(50) NOT NULL,
- permission varchar(100) DEFAULT '' NULL,
+ name varchar(50 char) NOT NULL,
+ permission varchar(100 char) DEFAULT '' NULL,
type smallint NOT NULL,
sort int DEFAULT 0 NOT NULL,
parent_id bigint DEFAULT 0 NOT NULL,
- path varchar(200) DEFAULT '' NULL,
- icon varchar(100) DEFAULT '#' NULL,
- component varchar(255) DEFAULT NULL NULL,
- component_name varchar(255) DEFAULT NULL NULL,
+ path varchar(200 char) DEFAULT '' NULL,
+ icon varchar(100 char) DEFAULT '#' NULL,
+ component varchar(255 char) DEFAULT NULL NULL,
+ component_name varchar(255 char) DEFAULT NULL NULL,
status smallint DEFAULT 0 NOT NULL,
visible bit DEFAULT '1' NOT NULL,
keep_alive bit DEFAULT '1' NOT NULL,
always_show bit DEFAULT '1' NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -3357,13 +3359,13 @@
-- ----------------------------
CREATE TABLE system_notice (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- title varchar(50) NOT NULL,
+ title varchar(50 char) NOT NULL,
content text NOT NULL,
type smallint NOT NULL,
status smallint DEFAULT 0 NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3402,16 +3404,16 @@
user_id bigint NOT NULL,
user_type smallint NOT NULL,
template_id bigint NOT NULL,
- template_code varchar(64) NOT NULL,
- template_nickname varchar(63) NOT NULL,
- template_content varchar(1024) NOT NULL,
+ template_code varchar(64 char) NOT NULL,
+ template_nickname varchar(63 char) NOT NULL,
+ template_content varchar(1024 char) NOT NULL,
template_type int NOT NULL,
- template_params varchar(255) NOT NULL,
+ template_params varchar(255 char) NOT NULL,
read_status bit NOT NULL,
read_time datetime DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3461,17 +3463,17 @@
-- ----------------------------
CREATE TABLE system_notify_template (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(63) NOT NULL,
- code varchar(64) NOT NULL,
- nickname varchar(255) NOT NULL,
- content varchar(1024) NOT NULL,
+ name varchar(63 char) NOT NULL,
+ code varchar(64 char) NOT NULL,
+ nickname varchar(255 char) NOT NULL,
+ content varchar(1024 char) NOT NULL,
type smallint NOT NULL,
- params varchar(255) DEFAULT NULL NULL,
+ params varchar(255 char) DEFAULT NULL NULL,
status smallint NOT NULL,
- remark varchar(255) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ remark varchar(255 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -3499,15 +3501,15 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
user_id bigint NOT NULL,
user_type smallint NOT NULL,
- user_info varchar(512) NOT NULL,
- access_token varchar(255) NOT NULL,
- refresh_token varchar(32) NOT NULL,
- client_id varchar(255) NOT NULL,
- scopes varchar(255) DEFAULT NULL NULL,
+ user_info varchar(512 char) NOT NULL,
+ access_token varchar(255 char) NOT NULL,
+ refresh_token varchar(32 char) NOT NULL,
+ client_id varchar(255 char) NOT NULL,
+ scopes varchar(255 char) DEFAULT NULL NULL,
expires_time datetime NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3540,13 +3542,13 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
user_id bigint NOT NULL,
user_type smallint NOT NULL,
- client_id varchar(255) NOT NULL,
- scope varchar(255) DEFAULT '' NULL,
+ client_id varchar(255 char) NOT NULL,
+ scope varchar(255 char) DEFAULT '' NULL,
approved bit DEFAULT '0' NOT NULL,
expires_time datetime NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3574,24 +3576,24 @@
-- ----------------------------
CREATE TABLE system_oauth2_client (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- client_id varchar(255) NOT NULL,
- secret varchar(255) NOT NULL,
- name varchar(255) NOT NULL,
- logo varchar(255) NOT NULL,
- description varchar(255) DEFAULT NULL NULL,
+ client_id varchar(255 char) NOT NULL,
+ secret varchar(255 char) NOT NULL,
+ name varchar(255 char) NOT NULL,
+ logo varchar(255 char) NOT NULL,
+ description varchar(255 char) DEFAULT NULL NULL,
status smallint NOT NULL,
access_token_validity_seconds int NOT NULL,
refresh_token_validity_seconds int NOT NULL,
- redirect_uris varchar(255) NOT NULL,
- authorized_grant_types varchar(255) NOT NULL,
- scopes varchar(255) DEFAULT NULL NULL,
- auto_approve_scopes varchar(255) DEFAULT NULL NULL,
- authorities varchar(255) DEFAULT NULL NULL,
- resource_ids varchar(255) DEFAULT NULL NULL,
- additional_information varchar(4096) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ redirect_uris varchar(255 char) NOT NULL,
+ authorized_grant_types varchar(255 char) NOT NULL,
+ scopes varchar(255 char) DEFAULT NULL NULL,
+ auto_approve_scopes varchar(255 char) DEFAULT NULL NULL,
+ authorities varchar(255 char) DEFAULT NULL NULL,
+ resource_ids varchar(255 char) DEFAULT NULL NULL,
+ additional_information varchar(4096 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -3641,15 +3643,15 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
user_id bigint NOT NULL,
user_type smallint NOT NULL,
- code varchar(32) NOT NULL,
- client_id varchar(255) NOT NULL,
- scopes varchar(255) DEFAULT '' NULL,
+ code varchar(32 char) NOT NULL,
+ client_id varchar(255 char) NOT NULL,
+ scopes varchar(255 char) DEFAULT '' NULL,
expires_time datetime NOT NULL,
- redirect_uri varchar(255) DEFAULT NULL NULL,
- state varchar(255) DEFAULT '' NULL,
- creator varchar(64) DEFAULT '' NULL,
+ redirect_uri varchar(255 char) DEFAULT NULL NULL,
+ state varchar(255 char) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3680,14 +3682,14 @@
CREATE TABLE system_oauth2_refresh_token (
id bigint NOT NULL PRIMARY KEY IDENTITY,
user_id bigint NOT NULL,
- refresh_token varchar(32) NOT NULL,
+ refresh_token varchar(32 char) NOT NULL,
user_type smallint NOT NULL,
- client_id varchar(255) NOT NULL,
- scopes varchar(255) DEFAULT NULL NULL,
+ client_id varchar(255 char) NOT NULL,
+ scopes varchar(255 char) DEFAULT NULL NULL,
expires_time datetime NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3715,22 +3717,22 @@
-- ----------------------------
CREATE TABLE system_operate_log (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- trace_id varchar(64) DEFAULT '' NULL,
+ trace_id varchar(64 char) DEFAULT '' NULL,
user_id bigint NOT NULL,
user_type smallint DEFAULT 0 NOT NULL,
- type varchar(50) NOT NULL,
- sub_type varchar(50) NOT NULL,
+ type varchar(50 char) NOT NULL,
+ sub_type varchar(50 char) NOT NULL,
biz_id bigint NOT NULL,
- action varchar(2000) DEFAULT '' NULL,
+ action varchar(2000 char) DEFAULT '' NULL,
success bit DEFAULT '1' NOT NULL,
- extra varchar(2000) DEFAULT '' NULL,
- request_method varchar(16) DEFAULT '' NULL,
- request_url varchar(255) DEFAULT '' NULL,
- user_ip varchar(50) DEFAULT NULL NULL,
- user_agent varchar(512) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ extra varchar(2000 char) DEFAULT '' NULL,
+ request_method varchar(16 char) DEFAULT '' NULL,
+ request_url varchar(255 char) DEFAULT '' NULL,
+ user_ip varchar(50 char) DEFAULT NULL NULL,
+ user_agent varchar(512 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3766,14 +3768,14 @@
-- ----------------------------
CREATE TABLE system_post (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- code varchar(64) NOT NULL,
- name varchar(50) NOT NULL,
+ code varchar(64 char) NOT NULL,
+ name varchar(50 char) NOT NULL,
sort int NOT NULL,
status smallint NOT NULL,
- remark varchar(500) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ remark varchar(500 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3811,17 +3813,17 @@
-- ----------------------------
CREATE TABLE system_role (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(30) NOT NULL,
- code varchar(100) NOT NULL,
+ name varchar(30 char) NOT NULL,
+ code varchar(100 char) NOT NULL,
sort int NOT NULL,
data_scope smallint DEFAULT 1 NOT NULL,
- data_scope_dept_ids varchar(500) DEFAULT '' NULL,
+ data_scope_dept_ids varchar(500 char) DEFAULT '' NULL,
status smallint NOT NULL,
type smallint NOT NULL,
- remark varchar(500) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ remark varchar(500 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -3866,9 +3868,9 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
role_id bigint NOT NULL,
menu_id bigint NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -4787,16 +4789,16 @@
-- ----------------------------
CREATE TABLE system_sms_channel (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- signature varchar(12) NOT NULL,
- code varchar(63) NOT NULL,
+ signature varchar(12 char) NOT NULL,
+ code varchar(63 char) NOT NULL,
status smallint NOT NULL,
- remark varchar(255) DEFAULT NULL NULL,
- api_key varchar(128) NOT NULL,
- api_secret varchar(128) DEFAULT NULL NULL,
- callback_url varchar(255) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ remark varchar(255 char) DEFAULT NULL NULL,
+ api_key varchar(128 char) NOT NULL,
+ api_secret varchar(128 char) DEFAULT NULL NULL,
+ callback_url varchar(255 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -4833,17 +4835,17 @@
-- ----------------------------
CREATE TABLE system_sms_code (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- mobile varchar(11) NOT NULL,
- code varchar(6) NOT NULL,
- create_ip varchar(15) NOT NULL,
+ mobile varchar(11 char) NOT NULL,
+ code varchar(6 char) NOT NULL,
+ create_ip varchar(15 char) NOT NULL,
scene smallint NOT NULL,
today_index smallint NOT NULL,
used smallint NOT NULL,
used_time datetime DEFAULT NULL NULL,
- used_ip varchar(255) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ used_ip varchar(255 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -4874,29 +4876,29 @@
CREATE TABLE system_sms_log (
id bigint NOT NULL PRIMARY KEY IDENTITY,
channel_id bigint NOT NULL,
- channel_code varchar(63) NOT NULL,
+ channel_code varchar(63 char) NOT NULL,
template_id bigint NOT NULL,
- template_code varchar(63) NOT NULL,
+ template_code varchar(63 char) NOT NULL,
template_type smallint NOT NULL,
- template_content varchar(255) NOT NULL,
- template_params varchar(255) NOT NULL,
- api_template_id varchar(63) NOT NULL,
- mobile varchar(11) NOT NULL,
+ template_content varchar(255 char) NOT NULL,
+ template_params varchar(255 char) NOT NULL,
+ api_template_id varchar(63 char) NOT NULL,
+ mobile varchar(11 char) NOT NULL,
user_id bigint DEFAULT NULL NULL,
user_type smallint DEFAULT NULL NULL,
send_status smallint DEFAULT 0 NOT NULL,
send_time datetime DEFAULT NULL NULL,
- api_send_code varchar(63) DEFAULT NULL NULL,
- api_send_msg varchar(255) DEFAULT NULL NULL,
- api_request_id varchar(255) DEFAULT NULL NULL,
- api_serial_no varchar(255) DEFAULT NULL NULL,
+ api_send_code varchar(63 char) DEFAULT NULL NULL,
+ api_send_msg varchar(255 char) DEFAULT NULL NULL,
+ api_request_id varchar(255 char) DEFAULT NULL NULL,
+ api_serial_no varchar(255 char) DEFAULT NULL NULL,
receive_status smallint DEFAULT 0 NOT NULL,
receive_time datetime DEFAULT NULL NULL,
- api_receive_code varchar(63) DEFAULT NULL NULL,
- api_receive_msg varchar(255) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ api_receive_code varchar(63 char) DEFAULT NULL NULL,
+ api_receive_msg varchar(255 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -4937,17 +4939,17 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
type smallint NOT NULL,
status smallint NOT NULL,
- code varchar(63) NOT NULL,
- name varchar(63) NOT NULL,
- content varchar(255) NOT NULL,
- params varchar(255) NOT NULL,
- remark varchar(255) DEFAULT NULL NULL,
- api_template_id varchar(63) NOT NULL,
+ code varchar(63 char) NOT NULL,
+ name varchar(63 char) NOT NULL,
+ content varchar(255 char) NOT NULL,
+ params varchar(255 char) NOT NULL,
+ remark varchar(255 char) DEFAULT NULL NULL,
+ api_template_id varchar(63 char) NOT NULL,
channel_id bigint NOT NULL,
- channel_code varchar(63) NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ channel_code varchar(63 char) NOT NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -4999,17 +5001,17 @@
-- ----------------------------
CREATE TABLE system_social_client (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(255) NOT NULL,
+ name varchar(255 char) NOT NULL,
social_type smallint NOT NULL,
user_type smallint NOT NULL,
- client_id varchar(255) NOT NULL,
- client_secret varchar(255) NOT NULL,
- agent_id varchar(255) DEFAULT NULL NULL,
- public_key varchar(2048) DEFAULT NULL NULL,
+ client_id varchar(255 char) NOT NULL,
+ client_secret varchar(255 char) NOT NULL,
+ agent_id varchar(255 char) DEFAULT NULL NULL,
+ public_key varchar(2048 char) DEFAULT NULL NULL,
status smallint NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5055,17 +5057,17 @@
CREATE TABLE system_social_user (
id bigint NOT NULL PRIMARY KEY IDENTITY,
type smallint NOT NULL,
- openid varchar(32) NOT NULL,
- token varchar(256) DEFAULT NULL NULL,
- raw_token_info varchar(1024) NOT NULL,
- nickname varchar(32) NOT NULL,
- avatar varchar(255) DEFAULT NULL NULL,
- raw_user_info varchar(1024) NOT NULL,
- code varchar(256) NOT NULL,
- state varchar(256) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ openid varchar(32 char) NOT NULL,
+ token varchar(256 char) DEFAULT NULL NULL,
+ raw_token_info varchar(1024 char) NOT NULL,
+ nickname varchar(32 char) NOT NULL,
+ avatar varchar(255 char) DEFAULT NULL NULL,
+ raw_user_info varchar(1024 char) NOT NULL,
+ code varchar(256 char) NOT NULL,
+ state varchar(256 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5101,9 +5103,9 @@
user_type smallint NOT NULL,
social_type smallint NOT NULL,
social_user_id bigint NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5129,18 +5131,18 @@
-- ----------------------------
CREATE TABLE system_tenant (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(30) NOT NULL,
+ name varchar(30 char) NOT NULL,
contact_user_id bigint DEFAULT NULL NULL,
- contact_name varchar(30) NOT NULL,
- contact_mobile varchar(500) DEFAULT NULL NULL,
+ contact_name varchar(30 char) NOT NULL,
+ contact_mobile varchar(500 char) DEFAULT NULL NULL,
status smallint DEFAULT 0 NOT NULL,
- websites varchar(1024) DEFAULT '' NULL,
+ websites varchar(1024 char) DEFAULT '' NULL,
package_id bigint NOT NULL,
expire_time datetime NOT NULL,
account_count int NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -5179,13 +5181,13 @@
-- ----------------------------
CREATE TABLE system_tenant_package (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(30) NOT NULL,
+ name varchar(30 char) NOT NULL,
status smallint DEFAULT 0 NOT NULL,
- remark varchar(256) DEFAULT '' NULL,
- menu_ids varchar(4096) NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ remark varchar(256 char) DEFAULT '' NULL,
+ menu_ids varchar(4096 char) NOT NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL
);
@@ -5219,9 +5221,9 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
user_id bigint DEFAULT 0 NOT NULL,
post_id bigint DEFAULT 0 NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5265,9 +5267,9 @@
id bigint NOT NULL PRIMARY KEY IDENTITY,
user_id bigint NOT NULL,
role_id bigint NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NULL,
deleted bit DEFAULT '0' NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5321,22 +5323,22 @@
-- ----------------------------
CREATE TABLE system_users (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- username varchar(30) NOT NULL,
- password varchar(100) DEFAULT '' NULL,
- nickname varchar(30) NOT NULL,
- remark varchar(500) DEFAULT NULL NULL,
+ username varchar(30 char) NOT NULL,
+ password varchar(100 char) DEFAULT '' NULL,
+ nickname varchar(30 char) NOT NULL,
+ remark varchar(500 char) DEFAULT NULL NULL,
dept_id bigint DEFAULT NULL NULL,
- post_ids varchar(255) DEFAULT NULL NULL,
- email varchar(50) DEFAULT '' NULL,
- mobile varchar(11) DEFAULT '' NULL,
+ post_ids varchar(255 char) DEFAULT NULL NULL,
+ email varchar(50 char) DEFAULT '' NULL,
+ mobile varchar(11 char) DEFAULT '' NULL,
sex smallint DEFAULT 0 NULL,
- avatar varchar(512) DEFAULT '' NULL,
+ avatar varchar(512 char) DEFAULT '' NULL,
status smallint DEFAULT 0 NOT NULL,
- login_ip varchar(50) DEFAULT '' NULL,
+ login_ip varchar(50 char) DEFAULT '' NULL,
login_date datetime DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5403,14 +5405,14 @@
-- ----------------------------
CREATE TABLE yudao_demo01_contact (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(100) DEFAULT '' NULL,
+ name varchar(100 char) DEFAULT '' NULL,
sex smallint NOT NULL,
birthday datetime NOT NULL,
- description varchar(255) NOT NULL,
- avatar varchar(512) DEFAULT NULL NULL,
- creator varchar(64) DEFAULT '' NULL,
+ description varchar(255 char) NOT NULL,
+ avatar varchar(512 char) DEFAULT NULL NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5445,11 +5447,11 @@
-- ----------------------------
CREATE TABLE yudao_demo02_category (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(100) DEFAULT '' NULL,
+ name varchar(100 char) DEFAULT '' NULL,
parent_id bigint NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5488,11 +5490,11 @@
CREATE TABLE yudao_demo03_course (
id bigint NOT NULL PRIMARY KEY IDENTITY,
student_id bigint NOT NULL,
- name varchar(100) DEFAULT '' NULL,
+ name varchar(100 char) DEFAULT '' NULL,
score smallint NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5542,11 +5544,11 @@
CREATE TABLE yudao_demo03_grade (
id bigint NOT NULL PRIMARY KEY IDENTITY,
student_id bigint NOT NULL,
- name varchar(100) DEFAULT '' NULL,
- teacher varchar(255) NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ name varchar(100 char) DEFAULT '' NULL,
+ teacher varchar(255 char) NOT NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5581,13 +5583,13 @@
-- ----------------------------
CREATE TABLE yudao_demo03_student (
id bigint NOT NULL PRIMARY KEY IDENTITY,
- name varchar(100) DEFAULT '' NULL,
+ name varchar(100 char) DEFAULT '' NULL,
sex smallint NOT NULL,
birthday datetime NOT NULL,
- description varchar(255) NOT NULL,
- creator varchar(64) DEFAULT '' NULL,
+ description varchar(255 char) NOT NULL,
+ creator varchar(64 char) DEFAULT '' NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
- updater varchar(64) DEFAULT '' NULL,
+ updater varchar(64 char) DEFAULT '' NULL,
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
deleted bit DEFAULT '0' NOT NULL,
tenant_id bigint DEFAULT 0 NOT NULL
@@ -5617,4 +5619,3 @@
COMMIT;
SET IDENTITY_INSERT yudao_demo03_student OFF;
-- @formatter:on
-
diff --git a/sql/highgo/quartz.sql b/sql/highgo/quartz.sql
new file mode 100644
index 0000000..46bb938
--- /dev/null
+++ b/sql/highgo/quartz.sql
@@ -0,0 +1,208 @@
+-- https://github.com/quartz-scheduler/quartz/blob/main/quartz/src/main/resources/org/quartz/impl/jdbcjobstore/tables_postgres.sql
+-- Thanks to Patrick Lightbody for submitting this...
+--
+-- In your Quartz properties file, you'll need to set
+-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
+
+DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
+DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
+DROP TABLE IF EXISTS QRTZ_LOCKS;
+DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
+DROP TABLE IF EXISTS QRTZ_CALENDARS;
+
+CREATE TABLE QRTZ_JOB_DETAILS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ JOB_NAME VARCHAR(200) NOT NULL,
+ JOB_GROUP VARCHAR(200) NOT NULL,
+ DESCRIPTION VARCHAR(250) NULL,
+ JOB_CLASS_NAME VARCHAR(250) NOT NULL,
+ IS_DURABLE BOOL NOT NULL,
+ IS_NONCONCURRENT BOOL NOT NULL,
+ IS_UPDATE_DATA BOOL NOT NULL,
+ REQUESTS_RECOVERY BOOL NOT NULL,
+ JOB_DATA BYTEA NULL,
+ PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
+);
+
+CREATE TABLE QRTZ_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ JOB_NAME VARCHAR(200) NOT NULL,
+ JOB_GROUP VARCHAR(200) NOT NULL,
+ DESCRIPTION VARCHAR(250) NULL,
+ NEXT_FIRE_TIME BIGINT NULL,
+ PREV_FIRE_TIME BIGINT NULL,
+ PRIORITY INTEGER NULL,
+ TRIGGER_STATE VARCHAR(16) NOT NULL,
+ TRIGGER_TYPE VARCHAR(8) NOT NULL,
+ START_TIME BIGINT NOT NULL,
+ END_TIME BIGINT NULL,
+ CALENDAR_NAME VARCHAR(200) NULL,
+ MISFIRE_INSTR SMALLINT NULL,
+ JOB_DATA BYTEA NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
+ REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)
+);
+
+CREATE TABLE QRTZ_SIMPLE_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ REPEAT_COUNT BIGINT NOT NULL,
+ REPEAT_INTERVAL BIGINT NOT NULL,
+ TIMES_TRIGGERED BIGINT NOT NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_CRON_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ CRON_EXPRESSION VARCHAR(120) NOT NULL,
+ TIME_ZONE_ID VARCHAR(80),
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_SIMPROP_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ STR_PROP_1 VARCHAR(512) NULL,
+ STR_PROP_2 VARCHAR(512) NULL,
+ STR_PROP_3 VARCHAR(512) NULL,
+ INT_PROP_1 INT NULL,
+ INT_PROP_2 INT NULL,
+ LONG_PROP_1 BIGINT NULL,
+ LONG_PROP_2 BIGINT NULL,
+ DEC_PROP_1 NUMERIC(13, 4) NULL,
+ DEC_PROP_2 NUMERIC(13, 4) NULL,
+ BOOL_PROP_1 BOOL NULL,
+ BOOL_PROP_2 BOOL NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_BLOB_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ BLOB_DATA BYTEA NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
+ FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_CALENDARS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ CALENDAR_NAME VARCHAR(200) NOT NULL,
+ CALENDAR BYTEA NOT NULL,
+ PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)
+);
+
+
+CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)
+);
+
+CREATE TABLE QRTZ_FIRED_TRIGGERS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ ENTRY_ID VARCHAR(95) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ INSTANCE_NAME VARCHAR(200) NOT NULL,
+ FIRED_TIME BIGINT NOT NULL,
+ SCHED_TIME BIGINT NOT NULL,
+ PRIORITY INTEGER NOT NULL,
+ STATE VARCHAR(16) NOT NULL,
+ JOB_NAME VARCHAR(200) NULL,
+ JOB_GROUP VARCHAR(200) NULL,
+ IS_NONCONCURRENT BOOL NULL,
+ REQUESTS_RECOVERY BOOL NULL,
+ PRIMARY KEY (SCHED_NAME, ENTRY_ID)
+);
+
+CREATE TABLE QRTZ_SCHEDULER_STATE
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ INSTANCE_NAME VARCHAR(200) NOT NULL,
+ LAST_CHECKIN_TIME BIGINT NOT NULL,
+ CHECKIN_INTERVAL BIGINT NOT NULL,
+ PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)
+);
+
+CREATE TABLE QRTZ_LOCKS
+(
+ SCHED_NAME VARCHAR(120) NOT NULL,
+ LOCK_NAME VARCHAR(40) NOT NULL,
+ PRIMARY KEY (SCHED_NAME, LOCK_NAME)
+);
+
+CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY
+ ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
+CREATE INDEX IDX_QRTZ_J_GRP
+ ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
+
+CREATE INDEX IDX_QRTZ_T_J
+ ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
+CREATE INDEX IDX_QRTZ_T_JG
+ ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
+CREATE INDEX IDX_QRTZ_T_C
+ ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
+CREATE INDEX IDX_QRTZ_T_G
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
+CREATE INDEX IDX_QRTZ_T_STATE
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
+CREATE INDEX IDX_QRTZ_T_N_STATE
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
+CREATE INDEX IDX_QRTZ_T_N_G_STATE
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
+CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME
+ ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
+CREATE INDEX IDX_QRTZ_T_NFT_ST
+ ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
+CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE
+ ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
+CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE
+ ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
+CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP
+ ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);
+
+CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
+CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
+CREATE INDEX IDX_QRTZ_FT_J_G
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
+CREATE INDEX IDX_QRTZ_FT_JG
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
+CREATE INDEX IDX_QRTZ_FT_T_G
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
+CREATE INDEX IDX_QRTZ_FT_TG
+ ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
+
+
+COMMIT;
\ No newline at end of file
diff --git a/sql/highgo/ruoyi-vue-pro.sql b/sql/highgo/ruoyi-vue-pro.sql
new file mode 100644
index 0000000..6384bc2
--- /dev/null
+++ b/sql/highgo/ruoyi-vue-pro.sql
@@ -0,0 +1,6198 @@
+/*
+ Yudao Database Transfer Tool
+
+ Source Server Type : MySQL
+
+ Target Server Type : HighGo
+
+ Date: 2026-06-13 20:18:03
+*/
+
+
+-- ----------------------------
+-- Table structure for dual
+-- ----------------------------
+DROP TABLE IF EXISTS dual;
+CREATE TABLE dual
+(
+ id int2
+);
+
+COMMENT ON TABLE dual IS '鏁版嵁搴撹繛鎺ョ殑琛�';
+
+-- ----------------------------
+-- Records of dual
+-- ----------------------------
+-- @formatter:off
+INSERT INTO dual VALUES (1);
+-- @formatter:on
+
+-- ----------------------------
+-- Table structure for infra_api_access_log
+-- ----------------------------
+DROP TABLE IF EXISTS infra_api_access_log;
+CREATE TABLE infra_api_access_log (
+ id int8 NOT NULL,
+ trace_id varchar(64) NOT NULL DEFAULT '',
+ user_id int8 NOT NULL DEFAULT 0,
+ user_type int2 NOT NULL DEFAULT 0,
+ application_name varchar(50) NOT NULL,
+ request_method varchar(16) NOT NULL DEFAULT '',
+ request_url varchar(255) NOT NULL DEFAULT '',
+ request_params text NULL,
+ response_body text NULL,
+ user_ip varchar(50) NOT NULL,
+ user_agent varchar(512) NOT NULL,
+ operate_module varchar(50) NULL DEFAULT NULL,
+ operate_name varchar(50) NULL DEFAULT NULL,
+ operate_type int2 NULL DEFAULT 0,
+ begin_time timestamp NOT NULL,
+ end_time timestamp NOT NULL,
+ duration int4 NOT NULL,
+ result_code int4 NOT NULL DEFAULT 0,
+ result_msg varchar(512) NULL DEFAULT '',
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_api_access_log ADD CONSTRAINT pk_infra_api_access_log PRIMARY KEY (id);
+
+CREATE INDEX idx_infra_api_access_log_01 ON infra_api_access_log (create_time);
+
+COMMENT ON COLUMN infra_api_access_log.id IS '鏃ュ織涓婚敭';
+COMMENT ON COLUMN infra_api_access_log.trace_id IS '閾捐矾杩借釜缂栧彿';
+COMMENT ON COLUMN infra_api_access_log.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN infra_api_access_log.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN infra_api_access_log.application_name IS '搴旂敤鍚�';
+COMMENT ON COLUMN infra_api_access_log.request_method IS '璇锋眰鏂规硶鍚�';
+COMMENT ON COLUMN infra_api_access_log.request_url IS '璇锋眰鍦板潃';
+COMMENT ON COLUMN infra_api_access_log.request_params IS '璇锋眰鍙傛暟';
+COMMENT ON COLUMN infra_api_access_log.response_body IS '鍝嶅簲缁撴灉';
+COMMENT ON COLUMN infra_api_access_log.user_ip IS '鐢ㄦ埛 IP';
+COMMENT ON COLUMN infra_api_access_log.user_agent IS '娴忚鍣� UA';
+COMMENT ON COLUMN infra_api_access_log.operate_module IS '鎿嶄綔妯″潡';
+COMMENT ON COLUMN infra_api_access_log.operate_name IS '鎿嶄綔鍚�';
+COMMENT ON COLUMN infra_api_access_log.operate_type IS '鎿嶄綔鍒嗙被';
+COMMENT ON COLUMN infra_api_access_log.begin_time IS '寮�濮嬭姹傛椂闂�';
+COMMENT ON COLUMN infra_api_access_log.end_time IS '缁撴潫璇锋眰鏃堕棿';
+COMMENT ON COLUMN infra_api_access_log.duration IS '鎵ц鏃堕暱';
+COMMENT ON COLUMN infra_api_access_log.result_code IS '缁撴灉鐮�';
+COMMENT ON COLUMN infra_api_access_log.result_msg IS '缁撴灉鎻愮ず';
+COMMENT ON COLUMN infra_api_access_log.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_api_access_log.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_api_access_log.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_api_access_log.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_api_access_log.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN infra_api_access_log.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE infra_api_access_log IS 'API 璁块棶鏃ュ織琛�';
+
+DROP SEQUENCE IF EXISTS infra_api_access_log_seq;
+CREATE SEQUENCE infra_api_access_log_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for infra_api_error_log
+-- ----------------------------
+DROP TABLE IF EXISTS infra_api_error_log;
+CREATE TABLE infra_api_error_log (
+ id int8 NOT NULL,
+ trace_id varchar(64) NOT NULL,
+ user_id int8 NOT NULL DEFAULT 0,
+ user_type int2 NOT NULL DEFAULT 0,
+ application_name varchar(50) NOT NULL,
+ request_method varchar(16) NOT NULL,
+ request_url varchar(255) NOT NULL,
+ request_params varchar(8000) NOT NULL,
+ user_ip varchar(50) NOT NULL,
+ user_agent varchar(512) NOT NULL,
+ exception_time timestamp NOT NULL,
+ exception_name varchar(128) NOT NULL DEFAULT '',
+ exception_message text NOT NULL,
+ exception_root_cause_message text NOT NULL,
+ exception_stack_trace text NOT NULL,
+ exception_class_name varchar(512) NOT NULL,
+ exception_file_name varchar(512) NOT NULL,
+ exception_method_name varchar(512) NOT NULL,
+ exception_line_number int4 NOT NULL,
+ process_status int2 NOT NULL,
+ process_time timestamp NULL DEFAULT NULL,
+ process_user_id int4 NULL DEFAULT 0,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_api_error_log ADD CONSTRAINT pk_infra_api_error_log PRIMARY KEY (id);
+
+CREATE INDEX idx_infra_api_error_log_01 ON infra_api_error_log (create_time);
+
+COMMENT ON COLUMN infra_api_error_log.id IS '缂栧彿';
+COMMENT ON COLUMN infra_api_error_log.trace_id IS '閾捐矾杩借釜缂栧彿';
+COMMENT ON COLUMN infra_api_error_log.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN infra_api_error_log.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN infra_api_error_log.application_name IS '搴旂敤鍚�';
+COMMENT ON COLUMN infra_api_error_log.request_method IS '璇锋眰鏂规硶鍚�';
+COMMENT ON COLUMN infra_api_error_log.request_url IS '璇锋眰鍦板潃';
+COMMENT ON COLUMN infra_api_error_log.request_params IS '璇锋眰鍙傛暟';
+COMMENT ON COLUMN infra_api_error_log.user_ip IS '鐢ㄦ埛 IP';
+COMMENT ON COLUMN infra_api_error_log.user_agent IS '娴忚鍣� UA';
+COMMENT ON COLUMN infra_api_error_log.exception_time IS '寮傚父鍙戠敓鏃堕棿';
+COMMENT ON COLUMN infra_api_error_log.exception_name IS '寮傚父鍚�';
+COMMENT ON COLUMN infra_api_error_log.exception_message IS '寮傚父瀵艰嚧鐨勬秷鎭�';
+COMMENT ON COLUMN infra_api_error_log.exception_root_cause_message IS '寮傚父瀵艰嚧鐨勬牴娑堟伅';
+COMMENT ON COLUMN infra_api_error_log.exception_stack_trace IS '寮傚父鐨勬爤杞ㄨ抗';
+COMMENT ON COLUMN infra_api_error_log.exception_class_name IS '寮傚父鍙戠敓鐨勭被鍏ㄥ悕';
+COMMENT ON COLUMN infra_api_error_log.exception_file_name IS '寮傚父鍙戠敓鐨勭被鏂囦欢';
+COMMENT ON COLUMN infra_api_error_log.exception_method_name IS '寮傚父鍙戠敓鐨勬柟娉曞悕';
+COMMENT ON COLUMN infra_api_error_log.exception_line_number IS '寮傚父鍙戠敓鐨勬柟娉曟墍鍦ㄨ';
+COMMENT ON COLUMN infra_api_error_log.process_status IS '澶勭悊鐘舵��';
+COMMENT ON COLUMN infra_api_error_log.process_time IS '澶勭悊鏃堕棿';
+COMMENT ON COLUMN infra_api_error_log.process_user_id IS '澶勭悊鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN infra_api_error_log.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_api_error_log.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_api_error_log.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_api_error_log.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_api_error_log.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN infra_api_error_log.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE infra_api_error_log IS '绯荤粺寮傚父鏃ュ織';
+
+DROP SEQUENCE IF EXISTS infra_api_error_log_seq;
+CREATE SEQUENCE infra_api_error_log_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for infra_codegen_column
+-- ----------------------------
+DROP TABLE IF EXISTS infra_codegen_column;
+CREATE TABLE infra_codegen_column (
+ id int8 NOT NULL,
+ table_id int8 NOT NULL,
+ column_name varchar(200) NOT NULL,
+ data_type varchar(100) NOT NULL,
+ column_comment varchar(500) NOT NULL,
+ nullable bool NOT NULL,
+ primary_key bool NOT NULL,
+ ordinal_position int4 NOT NULL,
+ java_type varchar(32) NOT NULL,
+ java_field varchar(64) NOT NULL,
+ dict_type varchar(200) NULL DEFAULT '',
+ example varchar(64) NULL DEFAULT NULL,
+ create_operation bool NOT NULL,
+ update_operation bool NOT NULL,
+ list_operation bool NOT NULL,
+ list_operation_condition varchar(32) NOT NULL DEFAULT '=',
+ list_operation_result bool NOT NULL,
+ html_type varchar(32) NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_codegen_column ADD CONSTRAINT pk_infra_codegen_column PRIMARY KEY (id);
+
+CREATE INDEX idx_infra_codegen_column_01 ON infra_codegen_column (table_id);
+
+COMMENT ON COLUMN infra_codegen_column.id IS '缂栧彿';
+COMMENT ON COLUMN infra_codegen_column.table_id IS '琛ㄧ紪鍙�';
+COMMENT ON COLUMN infra_codegen_column.column_name IS '瀛楁鍚�';
+COMMENT ON COLUMN infra_codegen_column.data_type IS '瀛楁绫诲瀷';
+COMMENT ON COLUMN infra_codegen_column.column_comment IS '瀛楁鎻忚堪';
+COMMENT ON COLUMN infra_codegen_column.nullable IS '鏄惁鍏佽涓虹┖';
+COMMENT ON COLUMN infra_codegen_column.primary_key IS '鏄惁涓婚敭';
+COMMENT ON COLUMN infra_codegen_column.ordinal_position IS '鎺掑簭';
+COMMENT ON COLUMN infra_codegen_column.java_type IS 'Java 灞炴�х被鍨�';
+COMMENT ON COLUMN infra_codegen_column.java_field IS 'Java 灞炴�у悕';
+COMMENT ON COLUMN infra_codegen_column.dict_type IS '瀛楀吀绫诲瀷';
+COMMENT ON COLUMN infra_codegen_column.example IS '鏁版嵁绀轰緥';
+COMMENT ON COLUMN infra_codegen_column.create_operation IS '鏄惁涓� Create 鍒涘缓鎿嶄綔鐨勫瓧娈�';
+COMMENT ON COLUMN infra_codegen_column.update_operation IS '鏄惁涓� Update 鏇存柊鎿嶄綔鐨勫瓧娈�';
+COMMENT ON COLUMN infra_codegen_column.list_operation IS '鏄惁涓� List 鏌ヨ鎿嶄綔鐨勫瓧娈�';
+COMMENT ON COLUMN infra_codegen_column.list_operation_condition IS 'List 鏌ヨ鎿嶄綔鐨勬潯浠剁被鍨�';
+COMMENT ON COLUMN infra_codegen_column.list_operation_result IS '鏄惁涓� List 鏌ヨ鎿嶄綔鐨勮繑鍥炲瓧娈�';
+COMMENT ON COLUMN infra_codegen_column.html_type IS '鏄剧ず绫诲瀷';
+COMMENT ON COLUMN infra_codegen_column.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_codegen_column.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_codegen_column.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_codegen_column.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_codegen_column.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_codegen_column IS '浠g爜鐢熸垚琛ㄥ瓧娈靛畾涔�';
+
+DROP SEQUENCE IF EXISTS infra_codegen_column_seq;
+CREATE SEQUENCE infra_codegen_column_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for infra_codegen_table
+-- ----------------------------
+DROP TABLE IF EXISTS infra_codegen_table;
+CREATE TABLE infra_codegen_table (
+ id int8 NOT NULL,
+ data_source_config_id int8 NOT NULL,
+ scene int2 NOT NULL DEFAULT 1,
+ table_name varchar(200) NOT NULL DEFAULT '',
+ table_comment varchar(500) NOT NULL DEFAULT '',
+ remark varchar(500) NULL DEFAULT NULL,
+ module_name varchar(30) NOT NULL,
+ business_name varchar(30) NOT NULL,
+ class_name varchar(100) NOT NULL DEFAULT '',
+ class_comment varchar(50) NOT NULL,
+ author varchar(50) NOT NULL,
+ template_type int2 NOT NULL DEFAULT 1,
+ front_type int2 NOT NULL,
+ parent_menu_id int8 NULL DEFAULT NULL,
+ master_table_id int8 NULL DEFAULT NULL,
+ sub_join_column_id int8 NULL DEFAULT NULL,
+ sub_join_many bool NULL DEFAULT NULL,
+ tree_parent_column_id int8 NULL DEFAULT NULL,
+ tree_name_column_id int8 NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_codegen_table ADD CONSTRAINT pk_infra_codegen_table PRIMARY KEY (id);
+
+COMMENT ON COLUMN infra_codegen_table.id IS '缂栧彿';
+COMMENT ON COLUMN infra_codegen_table.data_source_config_id IS '鏁版嵁婧愰厤缃殑缂栧彿';
+COMMENT ON COLUMN infra_codegen_table.scene IS '鐢熸垚鍦烘櫙';
+COMMENT ON COLUMN infra_codegen_table.table_name IS '琛ㄥ悕绉�';
+COMMENT ON COLUMN infra_codegen_table.table_comment IS '琛ㄦ弿杩�';
+COMMENT ON COLUMN infra_codegen_table.remark IS '澶囨敞';
+COMMENT ON COLUMN infra_codegen_table.module_name IS '妯″潡鍚�';
+COMMENT ON COLUMN infra_codegen_table.business_name IS '涓氬姟鍚�';
+COMMENT ON COLUMN infra_codegen_table.class_name IS '绫诲悕绉�';
+COMMENT ON COLUMN infra_codegen_table.class_comment IS '绫绘弿杩�';
+COMMENT ON COLUMN infra_codegen_table.author IS '浣滆��';
+COMMENT ON COLUMN infra_codegen_table.template_type IS '妯℃澘绫诲瀷';
+COMMENT ON COLUMN infra_codegen_table.front_type IS '鍓嶇绫诲瀷';
+COMMENT ON COLUMN infra_codegen_table.parent_menu_id IS '鐖惰彍鍗曠紪鍙�';
+COMMENT ON COLUMN infra_codegen_table.master_table_id IS '涓昏〃鐨勭紪鍙�';
+COMMENT ON COLUMN infra_codegen_table.sub_join_column_id IS '瀛愯〃鍏宠仈涓昏〃鐨勫瓧娈电紪鍙�';
+COMMENT ON COLUMN infra_codegen_table.sub_join_many IS '涓昏〃涓庡瓙琛ㄦ槸鍚︿竴瀵瑰';
+COMMENT ON COLUMN infra_codegen_table.tree_parent_column_id IS '鏍戣〃鐨勭埗瀛楁缂栧彿';
+COMMENT ON COLUMN infra_codegen_table.tree_name_column_id IS '鏍戣〃鐨勫悕瀛楀瓧娈电紪鍙�';
+COMMENT ON COLUMN infra_codegen_table.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_codegen_table.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_codegen_table.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_codegen_table.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_codegen_table.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_codegen_table IS '浠g爜鐢熸垚琛ㄥ畾涔�';
+
+DROP SEQUENCE IF EXISTS infra_codegen_table_seq;
+CREATE SEQUENCE infra_codegen_table_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for infra_config
+-- ----------------------------
+DROP TABLE IF EXISTS infra_config;
+CREATE TABLE infra_config (
+ id int8 NOT NULL,
+ category varchar(50) NOT NULL,
+ type int2 NOT NULL,
+ name varchar(100) NOT NULL DEFAULT '',
+ config_key varchar(100) NOT NULL DEFAULT '',
+ value varchar(500) NOT NULL DEFAULT '',
+ visible bool NOT NULL,
+ remark varchar(500) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_config ADD CONSTRAINT pk_infra_config PRIMARY KEY (id);
+
+CREATE INDEX idx_infra_config_01 ON infra_config (config_key);
+
+COMMENT ON COLUMN infra_config.id IS '鍙傛暟涓婚敭';
+COMMENT ON COLUMN infra_config.category IS '鍙傛暟鍒嗙粍';
+COMMENT ON COLUMN infra_config.type IS '鍙傛暟绫诲瀷';
+COMMENT ON COLUMN infra_config.name IS '鍙傛暟鍚嶇О';
+COMMENT ON COLUMN infra_config.config_key IS '鍙傛暟閿悕';
+COMMENT ON COLUMN infra_config.value IS '鍙傛暟閿��';
+COMMENT ON COLUMN infra_config.visible IS '鏄惁鍙';
+COMMENT ON COLUMN infra_config.remark IS '澶囨敞';
+COMMENT ON COLUMN infra_config.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_config.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_config.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_config.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_config.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_config IS '鍙傛暟閰嶇疆琛�';
+
+-- ----------------------------
+-- Records of infra_config
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 'biz', 1, '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜', 'system.user.init-password', '123456', '0', '鍒濆鍖栧瘑鐮� 123456', 'admin', '2021-01-05 17:03:48', '1', '2024-07-20 17:22:47', '0');
+INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (7, 'url', 2, 'MySQL 鐩戞帶鐨勫湴鍧�', 'url.druid', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:33:38', '0');
+INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 'url', 2, 'SkyWalking 鐩戞帶鐨勫湴鍧�', 'url.skywalking', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:57:03', '0');
+INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 'url', 2, 'Spring Boot Admin 鐩戞帶鐨勫湴鍧�', 'url.spring-boot-admin', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:52:07', '0');
+INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (10, 'url', 2, 'Swagger 鎺ュ彛鏂囨。鐨勫湴鍧�', 'url.swagger', '', '1', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:59:00', '0');
+INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 'test2', 2, 'test3', 'test4', 'test5', '1', 'test6', '1', '2023-12-03 09:55:16', '1', '2025-04-06 21:00:09', '0');
+INSERT INTO infra_config (id, category, type, name, config_key, value, visible, remark, creator, create_time, updater, update_time, deleted) VALUES (13, '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜', 2, '鐢ㄦ埛绠$悊-娉ㄥ唽寮�鍏�', 'system.user.register-enabled', 'true', '0', '', '1', '2025-04-26 17:23:41', '1', '2025-04-26 17:23:41', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS infra_config_seq;
+CREATE SEQUENCE infra_config_seq
+ START 14;
+
+-- ----------------------------
+-- Table structure for infra_data_source_config
+-- ----------------------------
+DROP TABLE IF EXISTS infra_data_source_config;
+CREATE TABLE infra_data_source_config (
+ id int8 NOT NULL,
+ name varchar(100) NOT NULL DEFAULT '',
+ url varchar(1024) NOT NULL,
+ username varchar(255) NOT NULL,
+ password varchar(255) NOT NULL DEFAULT '',
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_data_source_config ADD CONSTRAINT pk_infra_data_source_config PRIMARY KEY (id);
+
+COMMENT ON COLUMN infra_data_source_config.id IS '涓婚敭缂栧彿';
+COMMENT ON COLUMN infra_data_source_config.name IS '鍙傛暟鍚嶇О';
+COMMENT ON COLUMN infra_data_source_config.url IS '鏁版嵁婧愯繛鎺�';
+COMMENT ON COLUMN infra_data_source_config.username IS '鐢ㄦ埛鍚�';
+COMMENT ON COLUMN infra_data_source_config.password IS '瀵嗙爜';
+COMMENT ON COLUMN infra_data_source_config.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_data_source_config.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_data_source_config.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_data_source_config.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_data_source_config.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_data_source_config IS '鏁版嵁婧愰厤缃〃';
+
+DROP SEQUENCE IF EXISTS infra_data_source_config_seq;
+CREATE SEQUENCE infra_data_source_config_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for infra_file
+-- ----------------------------
+DROP TABLE IF EXISTS infra_file;
+CREATE TABLE infra_file (
+ id int8 NOT NULL,
+ config_id int8 NULL DEFAULT NULL,
+ name varchar(256) NULL DEFAULT NULL,
+ path varchar(512) NOT NULL,
+ url varchar(1024) NOT NULL,
+ type varchar(128) NULL DEFAULT NULL,
+ size int4 NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_file ADD CONSTRAINT pk_infra_file PRIMARY KEY (id);
+
+COMMENT ON COLUMN infra_file.id IS '鏂囦欢缂栧彿';
+COMMENT ON COLUMN infra_file.config_id IS '閰嶇疆缂栧彿';
+COMMENT ON COLUMN infra_file.name IS '鏂囦欢鍚�';
+COMMENT ON COLUMN infra_file.path IS '鏂囦欢璺緞';
+COMMENT ON COLUMN infra_file.url IS '鏂囦欢 URL';
+COMMENT ON COLUMN infra_file.type IS '鏂囦欢绫诲瀷';
+COMMENT ON COLUMN infra_file.size IS '鏂囦欢澶у皬';
+COMMENT ON COLUMN infra_file.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_file.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_file.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_file.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_file.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_file IS '鏂囦欢琛�';
+
+DROP SEQUENCE IF EXISTS infra_file_seq;
+CREATE SEQUENCE infra_file_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for infra_file_config
+-- ----------------------------
+DROP TABLE IF EXISTS infra_file_config;
+CREATE TABLE infra_file_config (
+ id int8 NOT NULL,
+ name varchar(63) NOT NULL,
+ storage int2 NOT NULL,
+ remark varchar(255) NULL DEFAULT NULL,
+ master bool NOT NULL,
+ config varchar(4096) NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_file_config ADD CONSTRAINT pk_infra_file_config PRIMARY KEY (id);
+
+COMMENT ON COLUMN infra_file_config.id IS '缂栧彿';
+COMMENT ON COLUMN infra_file_config.name IS '閰嶇疆鍚�';
+COMMENT ON COLUMN infra_file_config.storage IS '瀛樺偍鍣�';
+COMMENT ON COLUMN infra_file_config.remark IS '澶囨敞';
+COMMENT ON COLUMN infra_file_config.master IS '鏄惁涓轰富閰嶇疆';
+COMMENT ON COLUMN infra_file_config.config IS '瀛樺偍閰嶇疆';
+COMMENT ON COLUMN infra_file_config.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_file_config.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_file_config.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_file_config.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_file_config.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_file_config IS '鏂囦欢閰嶇疆琛�';
+
+-- ----------------------------
+-- Records of infra_file_config
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (4, '鏁版嵁搴擄紙绀轰緥锛�', 1, '鎴戞槸鏁版嵁搴�', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (22, '涓冪墰瀛樺偍鍣紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鑷繁鐨勫瘑閽ワ紒锛侊紒', '1', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-01-13 22:11:12', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (24, '鑵捐浜戝瓨鍌紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鐨勫瘑閽ワ紒锛侊紒', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"https://cos.ap-shanghai.myqcloud.com","domain":"http://tengxun-oss.iocoder.cn","bucket":"aoteman-1255880240","accessKey":"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt","accessSecret":"X","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 16:03:22', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (25, '闃块噷浜戝瓨鍌紙绀轰緥锛�', 20, '', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"oss-cn-beijing.aliyuncs.com","domain":"http://ali-oss.iocoder.cn","bucket":"yunai-aoteman","accessKey":"LTAI5tEQLgnDyjh3WpNcdMKA","accessSecret":"X","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 16:47:08', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (26, '鐏北浜戝瓨鍌紙绀轰緥锛�', 20, '', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"tos-s3-cn-beijing.volces.com","domain":null,"bucket":"yunai","accessKey":"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE","accessSecret":"X==","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 16:56:42', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (27, '鍗庝负浜戝瓨鍌紙绀轰緥锛�', 20, '', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"obs.cn-east-3.myhuaweicloud.com","domain":"","bucket":"yudao","accessKey":"PVDONDEIOTW88LF8DC4U","accessSecret":"X","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 17:18:41', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (28, 'MinIO 瀛樺偍锛堢ず渚嬶級', 20, '', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"http://127.0.0.1:9000","domain":"http://127.0.0.1:9000/yudao","bucket":"yudao","accessKey":"admin","accessSecret":"password","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 17:43:10', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (29, '鏈湴瀛樺偍锛堢ず渚嬶級', 10, 'mac/linux 浣跨敤 /锛寃indows 浣跨敤 \', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig","basePath":"/Users/yunai/tmp/file","domain":"http://127.0.0.1:48080"}', '1', '2025-05-02 11:25:45', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (30, 'SFTP 瀛樺偍锛堢ず渚嬶級', 12, '', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig","basePath":"/upload","domain":"http://127.0.0.1:48080","host":"127.0.0.1","port":2222,"username":"foo","password":"pass"}', '1', '2025-05-02 16:34:10', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (34, '涓冪墰浜戝瓨鍌ㄣ�愮鏈夈�戯紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鑷繁鐨勫瘑閽ワ紒锛侊紒', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://t151glocd.hn-bkt.clouddn.com","bucket":"ruoyi-vue-pro-private","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY","enablePathStyleAccess":false,"enablePublicAccess":false}', '1', '2025-08-17 21:22:00', '1', '2026-05-17 14:05:15', '0');
+INSERT INTO infra_file_config (id, name, storage, remark, master, config, creator, create_time, updater, update_time, deleted) VALUES (35, '1', 20, '1', '0', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"http://www.baidu.com","domain":"http://www.xxx.com","bucket":"1","accessKey":"2","accessSecret":"3","enablePathStyleAccess":false,"enablePublicAccess":false,"region":"1"}', '1', '2025-10-02 14:32:12', '1', '2026-05-17 14:05:15', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS infra_file_config_seq;
+CREATE SEQUENCE infra_file_config_seq
+ START 36;
+
+-- ----------------------------
+-- Table structure for infra_file_content
+-- ----------------------------
+DROP TABLE IF EXISTS infra_file_content;
+CREATE TABLE infra_file_content (
+ id int8 NOT NULL,
+ config_id int8 NOT NULL,
+ path varchar(512) NOT NULL,
+ content bytea NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_file_content ADD CONSTRAINT pk_infra_file_content PRIMARY KEY (id);
+
+CREATE INDEX idx_infra_file_content_01 ON infra_file_content (config_id, path);
+
+COMMENT ON COLUMN infra_file_content.id IS '缂栧彿';
+COMMENT ON COLUMN infra_file_content.config_id IS '閰嶇疆缂栧彿';
+COMMENT ON COLUMN infra_file_content.path IS '鏂囦欢璺緞';
+COMMENT ON COLUMN infra_file_content.content IS '鏂囦欢鍐呭';
+COMMENT ON COLUMN infra_file_content.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_file_content.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_file_content.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_file_content.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_file_content.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_file_content IS '鏂囦欢琛�';
+
+DROP SEQUENCE IF EXISTS infra_file_content_seq;
+CREATE SEQUENCE infra_file_content_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for infra_job
+-- ----------------------------
+DROP TABLE IF EXISTS infra_job;
+CREATE TABLE infra_job (
+ id int8 NOT NULL,
+ name varchar(32) NOT NULL,
+ status int2 NOT NULL,
+ handler_name varchar(64) NOT NULL,
+ handler_param varchar(255) NULL DEFAULT NULL,
+ cron_expression varchar(32) NOT NULL,
+ retry_count int4 NOT NULL DEFAULT 0,
+ retry_interval int4 NOT NULL DEFAULT 0,
+ monitor_timeout int4 NOT NULL DEFAULT 0,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_job ADD CONSTRAINT pk_infra_job PRIMARY KEY (id);
+
+COMMENT ON COLUMN infra_job.id IS '浠诲姟缂栧彿';
+COMMENT ON COLUMN infra_job.name IS '浠诲姟鍚嶇О';
+COMMENT ON COLUMN infra_job.status IS '浠诲姟鐘舵��';
+COMMENT ON COLUMN infra_job.handler_name IS '澶勭悊鍣ㄧ殑鍚嶅瓧';
+COMMENT ON COLUMN infra_job.handler_param IS '澶勭悊鍣ㄧ殑鍙傛暟';
+COMMENT ON COLUMN infra_job.cron_expression IS 'CRON 琛ㄨ揪寮�';
+COMMENT ON COLUMN infra_job.retry_count IS '閲嶈瘯娆℃暟';
+COMMENT ON COLUMN infra_job.retry_interval IS '閲嶈瘯闂撮殧';
+COMMENT ON COLUMN infra_job.monitor_timeout IS '鐩戞帶瓒呮椂鏃堕棿';
+COMMENT ON COLUMN infra_job.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_job.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_job.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_job.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_job.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_job IS '瀹氭椂浠诲姟琛�';
+
+-- ----------------------------
+-- Records of infra_job
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (5, '鏀粯閫氱煡 Job', 2, 'payNotifyJob', NULL, '* * * * * ?', 0, 0, 0, '1', '2021-10-27 08:34:42', '1', '2024-09-12 13:32:48', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (17, '鏀粯璁㈠崟鍚屾 Job', 2, 'payOrderSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (18, '鏀粯璁㈠崟杩囨湡 Job', 2, 'payOrderExpireJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (19, '閫�娆捐鍗曠殑鍚屾 Job', 2, 'payRefundSyncJob', NULL, '0 0/1 * * * ?', 0, 0, 0, '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (21, 'Mall 浜ゆ槗璁㈠崟鐨勮嚜鍔ㄨ繃鏈� Job', 2, 'tradeOrderAutoCancelJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-25 23:43:26', '1', '2025-10-02 11:08:34', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (22, 'Mall 浜ゆ槗璁㈠崟鐨勮嚜鍔ㄦ敹璐� Job', 2, 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 19:23:53', '1', '2025-10-02 11:08:36', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (23, 'Mall 浜ゆ槗璁㈠崟鐨勮嚜鍔ㄨ瘎璁� Job', 2, 'tradeOrderAutoCommentJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-26 23:38:29', '1', '2025-10-02 11:08:38', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (24, 'Mall 浣i噾瑙e喕 Job', 2, 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', 3, 0, 0, '1', '2023-09-28 22:01:46', '1', '2025-10-02 11:08:04', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (25, '璁块棶鏃ュ織娓呯悊 Job', 2, 'accessLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (26, '閿欒鏃ュ織娓呯悊 Job', 2, 'errorLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (27, '浠诲姟鏃ュ織娓呯悊 Job', 2, 'jobLogCleanJob', '', '0 0 0 * * ?', 3, 0, 0, '1', '2023-10-03 11:01:33', '1', '2024-09-12 13:40:34', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (33, 'demoJob', 2, 'demoJob', '', '0 * * * * ?', 1, 1, 0, '1', '2024-10-27 19:38:46', '1', '2025-05-10 18:13:54', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (35, '杞处璁㈠崟鐨勫悓姝� Job', 2, 'payTransferSyncJob', '', '0 * * * * ?', 0, 0, 0, '1', '2025-05-10 17:35:54', '1', '2025-05-10 18:13:52', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (36, 'IoT 璁惧绂荤嚎妫�鏌� Job', 2, 'iotDeviceOfflineCheckJob', '', '0 * * * * ?', 0, 0, 0, '1', '2025-07-03 23:48:44', '"1"', '2025-07-03 23:48:47', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (37, 'IoT OTA 鍗囩骇鎺ㄩ�� Job', 2, 'iotOtaUpgradeJob', '', '0 * * * * ?', 0, 0, 0, '1', '2025-07-03 23:49:07', '"1"', '2025-07-03 23:49:13', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (38, 'Mall 鎷煎洟杩囨湡 Job', 2, 'combinationRecordExpireJob', '', '0 * * * * ?', 0, 0, 0, '1', '2025-10-02 11:07:11', '1', '2025-10-02 11:07:14', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (39, 'Mall 浼樻儬鍒歌繃鏈� Job', 2, 'couponExpireJob', '', '0 * * * * ?', 0, 0, 0, '1', '2025-10-02 11:07:34', '1', '2025-10-02 11:07:37', '0');
+INSERT INTO infra_job (id, name, status, handler_name, handler_param, cron_expression, retry_count, retry_interval, monitor_timeout, creator, create_time, updater, update_time, deleted) VALUES (40, 'Mall 鍟嗗搧缁熻 Job', 2, 'productStatisticsJob', '', '0 0 0 * * ?', 0, 0, 0, '1', '2025-11-22 18:51:25', '1', '2025-11-22 18:56:21', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS infra_job_seq;
+CREATE SEQUENCE infra_job_seq
+ START 41;
+
+-- ----------------------------
+-- Table structure for infra_job_log
+-- ----------------------------
+DROP TABLE IF EXISTS infra_job_log;
+CREATE TABLE infra_job_log (
+ id int8 NOT NULL,
+ job_id int8 NOT NULL,
+ handler_name varchar(64) NOT NULL,
+ handler_param varchar(255) NULL DEFAULT NULL,
+ execute_index int2 NOT NULL DEFAULT 1,
+ begin_time timestamp NOT NULL,
+ end_time timestamp NULL DEFAULT NULL,
+ duration int4 NULL DEFAULT NULL,
+ status int2 NOT NULL,
+ result varchar(4000) NULL DEFAULT '',
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE infra_job_log ADD CONSTRAINT pk_infra_job_log PRIMARY KEY (id);
+
+CREATE INDEX idx_infra_job_log_01 ON infra_job_log (job_id);
+CREATE INDEX idx_infra_job_log_02 ON infra_job_log (create_time);
+
+COMMENT ON COLUMN infra_job_log.id IS '鏃ュ織缂栧彿';
+COMMENT ON COLUMN infra_job_log.job_id IS '浠诲姟缂栧彿';
+COMMENT ON COLUMN infra_job_log.handler_name IS '澶勭悊鍣ㄧ殑鍚嶅瓧';
+COMMENT ON COLUMN infra_job_log.handler_param IS '澶勭悊鍣ㄧ殑鍙傛暟';
+COMMENT ON COLUMN infra_job_log.execute_index IS '绗嚑娆℃墽琛�';
+COMMENT ON COLUMN infra_job_log.begin_time IS '寮�濮嬫墽琛屾椂闂�';
+COMMENT ON COLUMN infra_job_log.end_time IS '缁撴潫鎵ц鏃堕棿';
+COMMENT ON COLUMN infra_job_log.duration IS '鎵ц鏃堕暱';
+COMMENT ON COLUMN infra_job_log.status IS '浠诲姟鐘舵��';
+COMMENT ON COLUMN infra_job_log.result IS '缁撴灉鏁版嵁';
+COMMENT ON COLUMN infra_job_log.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN infra_job_log.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN infra_job_log.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN infra_job_log.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN infra_job_log.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE infra_job_log IS '瀹氭椂浠诲姟鏃ュ織琛�';
+
+DROP SEQUENCE IF EXISTS infra_job_log_seq;
+CREATE SEQUENCE infra_job_log_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_dept
+-- ----------------------------
+DROP TABLE IF EXISTS system_dept;
+CREATE TABLE system_dept (
+ id int8 NOT NULL,
+ name varchar(30) NOT NULL DEFAULT '',
+ parent_id int8 NOT NULL DEFAULT 0,
+ sort int4 NOT NULL DEFAULT 0,
+ leader_user_id int8 NULL DEFAULT NULL,
+ phone varchar(11) NULL DEFAULT NULL,
+ email varchar(50) NULL DEFAULT NULL,
+ status int2 NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_dept ADD CONSTRAINT pk_system_dept PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_dept.id IS '閮ㄩ棬id';
+COMMENT ON COLUMN system_dept.name IS '閮ㄩ棬鍚嶇О';
+COMMENT ON COLUMN system_dept.parent_id IS '鐖堕儴闂╥d';
+COMMENT ON COLUMN system_dept.sort IS '鏄剧ず椤哄簭';
+COMMENT ON COLUMN system_dept.leader_user_id IS '璐熻矗浜�';
+COMMENT ON COLUMN system_dept.phone IS '鑱旂郴鐢佃瘽';
+COMMENT ON COLUMN system_dept.email IS '閭';
+COMMENT ON COLUMN system_dept.status IS '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+COMMENT ON COLUMN system_dept.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_dept.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_dept.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_dept.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_dept.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_dept.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_dept IS '閮ㄩ棬琛�';
+
+-- ----------------------------
+-- Records of system_dept
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, '鑺嬮亾婧愮爜', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2026-01-04 18:01:12', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (101, '娣卞湷鎬诲叕鍙�', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2025-03-29 15:49:55', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (102, '闀挎矙鍒嗗叕鍙�', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, '鐮斿彂閮ㄩ棬', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2026-01-04 18:01:24', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, '甯傚満閮ㄩ棬', 101, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:38', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (105, '娴嬭瘯閮ㄩ棬', 101, 3, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:15', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (106, '璐㈠姟閮ㄩ棬', 101, 4, 103, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-15 21:32:22', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, '杩愮淮閮ㄩ棬', 101, 5, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-12-02 09:28:22', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, '甯傚満閮ㄩ棬', 102, 1, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-02-16 08:35:45', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '璐㈠姟閮ㄩ棬', 102, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:29', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, '鏂伴儴闂�', 0, 1, NULL, NULL, NULL, 0, '110', '2022-02-23 20:46:30', '110', '2022-02-23 20:46:30', '0', 121);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '椤剁骇閮ㄩ棬', 0, 1, NULL, NULL, NULL, 0, '113', '2022-03-07 21:44:50', '113', '2022-03-07 21:44:50', '0', 122);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, '浜у搧閮ㄩ棬', 101, 100, 1, NULL, NULL, 1, '1', '2023-12-02 09:45:13', '1', '2023-12-02 09:45:31', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, '鏀寔閮ㄩ棬', 102, 3, 104, NULL, NULL, 1, '1', '2023-12-02 09:47:38', '1', '2025-03-29 15:00:56', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (116, '鏌愪釜瀛愰儴闂�', 0, 1, NULL, NULL, NULL, 0, '1', '2025-12-08 14:51:12', '1', '2025-12-08 14:51:12', '0', 1);
+INSERT INTO system_dept (id, name, parent_id, sort, leader_user_id, phone, email, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, '鏌愪釜瀛愰儴闂� 2', 0, 2, NULL, NULL, NULL, 0, '1', '2025-12-08 14:51:25', '1', '2025-12-08 14:51:25', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_dept_seq;
+CREATE SEQUENCE system_dept_seq
+ START 118;
+
+-- ----------------------------
+-- Table structure for system_dict_data
+-- ----------------------------
+DROP TABLE IF EXISTS system_dict_data;
+CREATE TABLE system_dict_data (
+ id int8 NOT NULL,
+ sort int4 NOT NULL DEFAULT 0,
+ label varchar(100) NOT NULL DEFAULT '',
+ value varchar(100) NOT NULL DEFAULT '',
+ dict_type varchar(100) NOT NULL DEFAULT '',
+ status int2 NOT NULL DEFAULT 0,
+ color_type varchar(100) NULL DEFAULT '',
+ css_class varchar(100) NULL DEFAULT '',
+ remark varchar(500) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_dict_data ADD CONSTRAINT pk_system_dict_data PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_dict_data.id IS '瀛楀吀缂栫爜';
+COMMENT ON COLUMN system_dict_data.sort IS '瀛楀吀鎺掑簭';
+COMMENT ON COLUMN system_dict_data.label IS '瀛楀吀鏍囩';
+COMMENT ON COLUMN system_dict_data.value IS '瀛楀吀閿��';
+COMMENT ON COLUMN system_dict_data.dict_type IS '瀛楀吀绫诲瀷';
+COMMENT ON COLUMN system_dict_data.status IS '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+COMMENT ON COLUMN system_dict_data.color_type IS '棰滆壊绫诲瀷';
+COMMENT ON COLUMN system_dict_data.css_class IS 'css 鏍峰紡';
+COMMENT ON COLUMN system_dict_data.remark IS '澶囨敞';
+COMMENT ON COLUMN system_dict_data.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_dict_data.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_dict_data.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_dict_data.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_dict_data.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_dict_data IS '瀛楀吀鏁版嵁琛�';
+
+-- ----------------------------
+-- Records of system_dict_data
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1, 1, '鐢�', '1', 'system_user_sex', 0, 'primary', 'A', '鎬у埆鐢�', 'admin', '2021-01-05 17:03:48', '1', '2025-12-10 13:19:26', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2, 2, '濂�', '2', 'system_user_sex', 0, 'success', '', '鎬у埆濂�', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 23:30:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (8, 1, '姝e父', '1', 'infra_job_status', 0, 'success', '', '姝e父鐘舵��', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (9, 2, '鏆傚仠', '2', 'infra_job_status', 0, 'danger', '', '鍋滅敤鐘舵��', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (12, 1, '绯荤粺鍐呯疆', '1', 'infra_config_type', 0, 'danger', '', '鍙傛暟绫诲瀷 - 绯荤粺鍐呯疆', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (13, 2, '鑷畾涔�', '2', 'infra_config_type', 0, 'primary', '', '鍙傛暟绫诲瀷 - 鑷畾涔�', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (14, 1, '閫氱煡', '1', 'system_notice_type', 0, 'success', '', '閫氱煡', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:05:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (15, 2, '鍏憡', '2', 'system_notice_type', 0, 'info', '', '鍏憡', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:06:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (16, 0, '鍏跺畠', '0', 'infra_operate_type', 0, 'default', '', '鍏跺畠鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (17, 1, '鏌ヨ', '1', 'infra_operate_type', 0, 'info', '', '鏌ヨ鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (18, 2, '鏂板', '2', 'infra_operate_type', 0, 'primary', '', '鏂板鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:21', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (19, 3, '淇敼', '3', 'infra_operate_type', 0, 'warning', '', '淇敼鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (20, 4, '鍒犻櫎', '4', 'infra_operate_type', 0, 'danger', '', '鍒犻櫎鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (22, 5, '瀵煎嚭', '5', 'infra_operate_type', 0, 'default', '', '瀵煎嚭鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (23, 6, '瀵煎叆', '6', 'infra_operate_type', 0, 'default', '', '瀵煎叆鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (27, 1, '寮�鍚�', '0', 'common_status', 0, 'primary', '', '寮�鍚姸鎬�', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (28, 2, '鍏抽棴', '1', 'common_status', 0, 'info', '', '鍏抽棴鐘舵��', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:44', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (29, 1, '鐩綍', '1', 'system_menu_type', 0, '', '', '鐩綍', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (30, 2, '鑿滃崟', '2', 'system_menu_type', 0, '', '', '鑿滃崟', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (31, 3, '鎸夐挳', '3', 'system_menu_type', 0, '', '', '鎸夐挳', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (32, 1, '鍐呯疆', '1', 'system_role_type', 0, 'danger', '', '鍐呯疆瑙掕壊', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (33, 2, '鑷畾涔�', '2', 'system_role_type', 0, 'primary', '', '鑷畾涔夎鑹�', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (34, 1, '鍏ㄩ儴鏁版嵁鏉冮檺', '1', 'system_data_scope', 0, '', '', '鍏ㄩ儴鏁版嵁鏉冮檺', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (35, 2, '鎸囧畾閮ㄩ棬鏁版嵁鏉冮檺', '2', 'system_data_scope', 0, '', '', '鎸囧畾閮ㄩ棬鏁版嵁鏉冮檺', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (36, 3, '鏈儴闂ㄦ暟鎹潈闄�', '3', 'system_data_scope', 0, '', '', '鏈儴闂ㄦ暟鎹潈闄�', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (37, 4, '鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺', '4', 'system_data_scope', 0, '', '', '鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:21', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (38, 5, '浠呮湰浜烘暟鎹潈闄�', '5', 'system_data_scope', 0, '', '', '浠呮湰浜烘暟鎹潈闄�', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (39, 0, '鎴愬姛', '0', 'system_login_result', 0, 'success', '', '鐧婚檰缁撴灉 - 鎴愬姛', '', '2021-01-18 06:17:36', '1', '2022-02-16 13:23:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (40, 10, '璐﹀彿鎴栧瘑鐮佷笉姝g‘', '10', 'system_login_result', 0, 'primary', '', '鐧婚檰缁撴灉 - 璐﹀彿鎴栧瘑鐮佷笉姝g‘', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (41, 20, '鐢ㄦ埛琚鐢�', '20', 'system_login_result', 0, 'warning', '', '鐧婚檰缁撴灉 - 鐢ㄦ埛琚鐢�', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:23:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (42, 30, '楠岃瘉鐮佷笉瀛樺湪', '30', 'system_login_result', 0, 'info', '', '鐧婚檰缁撴灉 - 楠岃瘉鐮佷笉瀛樺湪', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (43, 31, '楠岃瘉鐮佷笉姝g‘', '31', 'system_login_result', 0, 'info', '', '鐧婚檰缁撴灉 - 楠岃瘉鐮佷笉姝g‘', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:11', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (44, 100, '鏈煡寮傚父', '100', 'system_login_result', 0, 'danger', '', '鐧婚檰缁撴灉 - 鏈煡寮傚父', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (45, 1, '鏄�', 'true', 'infra_boolean_string', 0, 'danger', '', 'Boolean 鏄惁绫诲瀷 - 鏄�', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:01:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (46, 1, '鍚�', 'false', 'infra_boolean_string', 0, 'info', '', 'Boolean 鏄惁绫诲瀷 - 鍚�', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:09:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (50, 1, '鍗曡〃锛堝鍒犳敼鏌ワ級', '1', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:09:06', '', '2022-03-10 16:33:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (51, 2, '鏍戣〃锛堝鍒犳敼鏌ワ級', '2', 'infra_codegen_template_type', 0, '', '', NULL, '', '2021-02-05 07:14:46', '', '2022-03-10 16:33:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (53, 0, '鍒濆鍖栦腑', '0', 'infra_job_status', 0, 'primary', '', NULL, '', '2021-02-07 07:46:49', '1', '2022-02-16 19:33:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (57, 0, '杩愯涓�', '0', 'infra_job_log_status', 0, 'primary', '', 'RUNNING', '', '2021-02-08 10:04:24', '1', '2022-02-16 19:07:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (58, 1, '鎴愬姛', '1', 'infra_job_log_status', 0, 'success', '', NULL, '', '2021-02-08 10:06:57', '1', '2022-02-16 19:07:52', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (59, 2, '澶辫触', '2', 'infra_job_log_status', 0, 'warning', '', '澶辫触', '', '2021-02-08 10:07:38', '1', '2022-02-16 19:07:56', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (60, 1, '浼氬憳', '1', 'user_type', 0, 'primary', '', NULL, '', '2021-02-26 00:16:27', '1', '2022-02-16 10:22:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (61, 2, '绠$悊鍛�', '2', 'user_type', 0, 'success', '', NULL, '', '2021-02-26 00:16:34', '1', '2025-04-06 18:37:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (62, 0, '鏈鐞�', '0', 'infra_api_error_log_process_status', 0, 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (63, 1, '宸插鐞�', '1', 'infra_api_error_log_process_status', 0, 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (64, 2, '宸插拷鐣�', '2', 'infra_api_error_log_process_status', 0, 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (66, 1, '闃块噷浜�', 'ALIYUN', 'system_sms_channel_code', 0, 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2024-07-22 22:23:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (67, 1, '楠岃瘉鐮�', '1', 'system_sms_template_type', 0, 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (68, 2, '閫氱煡', '2', 'system_sms_template_type', 0, 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (69, 0, '钀ラ攢', '3', 'system_sms_template_type', 0, 'danger', '', NULL, '1', '2021-04-05 21:51:15', '1', '2022-02-16 12:48:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (70, 0, '鍒濆鍖�', '0', 'system_sms_send_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:18:33', '1', '2022-02-16 10:26:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (71, 1, '鍙戦�佹垚鍔�', '10', 'system_sms_send_status', 0, 'success', '', NULL, '1', '2021-04-11 20:18:43', '1', '2022-02-16 10:25:56', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (72, 2, '鍙戦�佸け璐�', '20', 'system_sms_send_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:18:49', '1', '2022-02-16 10:26:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (73, 3, '涓嶅彂閫�', '30', 'system_sms_send_status', 0, 'info', '', NULL, '1', '2021-04-11 20:19:44', '1', '2022-02-16 10:26:10', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (74, 0, '绛夊緟缁撴灉', '0', 'system_sms_receive_status', 0, 'primary', '', NULL, '1', '2021-04-11 20:27:43', '1', '2022-02-16 10:28:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (75, 1, '鎺ユ敹鎴愬姛', '10', 'system_sms_receive_status', 0, 'success', '', NULL, '1', '2021-04-11 20:29:25', '1', '2022-02-16 10:28:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (76, 2, '鎺ユ敹澶辫触', '20', 'system_sms_receive_status', 0, 'danger', '', NULL, '1', '2021-04-11 20:29:31', '1', '2022-02-16 10:28:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (77, 0, '璋冭瘯(閽夐拤)', 'DEBUG_DING_TALK', 'system_sms_channel_code', 0, 'info', '', NULL, '1', '2021-04-13 00:20:37', '1', '2022-02-16 10:10:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (80, 100, '璐﹀彿鐧诲綍', '100', 'system_login_type', 0, 'primary', '', '璐﹀彿鐧诲綍', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (81, 101, '绀句氦鐧诲綍', '101', 'system_login_type', 0, 'info', '', '绀句氦鐧诲綍', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (83, 200, '涓诲姩鐧诲嚭', '200', 'system_login_type', 0, 'primary', '', '涓诲姩鐧诲嚭', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (85, 202, '寮哄埗鐧诲嚭', '202', 'system_login_type', 0, 'danger', '', '寮哄埗閫�鍑�', '1', '2021-10-06 00:53:41', '1', '2022-02-16 13:11:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (86, 0, '鐥呭亣', '1', 'bpm_oa_leave_type', 0, 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (87, 1, '浜嬪亣', '2', 'bpm_oa_leave_type', 0, 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (88, 2, '濠氬亣', '3', 'bpm_oa_leave_type', 0, 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (112, 0, '寰俊 Wap 缃戠珯鏀粯', 'wx_wap', 'pay_channel_code', 0, 'success', '', '寰俊 Wap 缃戠珯鏀粯', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (113, 1, '寰俊鍏紬鍙锋敮浠�', 'wx_pub', 'pay_channel_code', 0, 'success', '', '寰俊鍏紬鍙锋敮浠�', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (114, 2, '寰俊灏忕▼搴忔敮浠�', 'wx_lite', 'pay_channel_code', 0, 'success', '', '寰俊灏忕▼搴忔敮浠�', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (115, 3, '寰俊 App 鏀粯', 'wx_app', 'pay_channel_code', 0, 'success', '', '寰俊 App 鏀粯', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (116, 10, '鏀粯瀹� PC 缃戠珯鏀粯', 'alipay_pc', 'pay_channel_code', 0, 'primary', '', '鏀粯瀹� PC 缃戠珯鏀粯', '1', '2021-12-03 10:42:09', '1', '2023-07-19 20:09:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (117, 11, '鏀粯瀹� Wap 缃戠珯鏀粯', 'alipay_wap', 'pay_channel_code', 0, 'primary', '', '鏀粯瀹� Wap 缃戠珯鏀粯', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (118, 12, '鏀粯瀹� App 鏀粯', 'alipay_app', 'pay_channel_code', 0, 'primary', '', '鏀粯瀹� App 鏀粯', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (119, 14, '鏀粯瀹濇壂鐮佹敮浠�', 'alipay_qr', 'pay_channel_code', 0, 'primary', '', '鏀粯瀹濇壂鐮佹敮浠�', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (120, 10, '閫氱煡鎴愬姛', '10', 'pay_notify_status', 0, 'success', '', '閫氱煡鎴愬姛', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (121, 20, '閫氱煡澶辫触', '20', 'pay_notify_status', 0, 'danger', '', '閫氱煡澶辫触', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (122, 0, '绛夊緟閫氱煡', '0', 'pay_notify_status', 0, 'info', '', '鏈�氱煡', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (123, 10, '鏀粯鎴愬姛', '10', 'pay_order_status', 0, 'success', '', '鏀粯鎴愬姛', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (124, 30, '鏀粯鍏抽棴', '30', 'pay_order_status', 0, 'info', '', '鏀粯鍏抽棴', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (125, 0, '绛夊緟鏀粯', '0', 'pay_order_status', 0, 'info', '', '鏈敮浠�', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (600, 5, '棣栭〉', '1', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (601, 4, '绉掓潃娲诲姩椤�', '2', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (602, 3, '鐮嶄环娲诲姩椤�', '3', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (603, 2, '闄愭椂鎶樻墸椤�', '4', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (604, 1, '婊″噺閫侀〉', '5', 'promotion_banner_position', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1118, 0, '绛夊緟閫�娆�', '0', 'pay_refund_status', 0, 'info', '', '绛夊緟閫�娆�', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1119, 20, '閫�娆惧け璐�', '20', 'pay_refund_status', 0, 'danger', '', '閫�娆惧け璐�', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1124, 10, '閫�娆炬垚鍔�', '10', 'pay_refund_status', 0, 'success', '', '閫�娆炬垚鍔�', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1127, 1, '瀹℃壒涓�', '1', 'bpm_process_instance_status', 0, 'default', '', '娴佺▼瀹炰緥鐨勭姸鎬� - 杩涜涓�', '1', '2022-01-07 23:47:22', '1', '2024-03-16 16:11:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1128, 2, '瀹℃壒閫氳繃', '2', 'bpm_process_instance_status', 0, 'success', '', '娴佺▼瀹炰緥鐨勭姸鎬� - 宸插畬鎴�', '1', '2022-01-07 23:47:49', '1', '2024-03-16 16:11:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1129, 1, '瀹℃壒涓�', '1', 'bpm_task_status', 0, 'primary', '', '娴佺▼瀹炰緥鐨勭粨鏋� - 澶勭悊涓�', '1', '2022-01-07 23:48:32', '1', '2024-03-08 22:41:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1130, 2, '瀹℃壒閫氳繃', '2', 'bpm_task_status', 0, 'success', '', '娴佺▼瀹炰緥鐨勭粨鏋� - 閫氳繃', '1', '2022-01-07 23:48:45', '1', '2024-03-08 22:41:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1131, 3, '瀹℃壒涓嶉�氳繃', '3', 'bpm_task_status', 0, 'danger', '', '娴佺▼瀹炰緥鐨勭粨鏋� - 涓嶉�氳繃', '1', '2022-01-07 23:48:55', '1', '2024-03-08 22:41:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1132, 4, '宸插彇娑�', '4', 'bpm_task_status', 0, 'info', '', '娴佺▼瀹炰緥鐨勭粨鏋� - 鎾ら攢', '1', '2022-01-07 23:49:06', '1', '2024-03-08 22:41:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1133, 10, '娴佺▼琛ㄥ崟', '10', 'bpm_model_form_type', 0, '', '', '娴佺▼鐨勮〃鍗曠被鍨� - 娴佺▼琛ㄥ崟', '103', '2022-01-11 23:51:30', '103', '2022-01-11 23:51:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1134, 20, '涓氬姟琛ㄥ崟', '20', 'bpm_model_form_type', 0, '', '', '娴佺▼鐨勮〃鍗曠被鍨� - 涓氬姟琛ㄥ崟', '103', '2022-01-11 23:51:47', '103', '2022-01-11 23:51:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1135, 10, '瑙掕壊', '10', 'bpm_task_candidate_strategy', 0, 'info', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 瑙掕壊', '103', '2022-01-12 23:21:22', '1', '2024-03-06 02:53:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1136, 20, '閮ㄩ棬鐨勬垚鍛�', '20', 'bpm_task_candidate_strategy', 0, 'primary', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 閮ㄩ棬鐨勬垚鍛�', '103', '2022-01-12 23:21:47', '1', '2024-03-06 02:53:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1137, 21, '閮ㄩ棬鐨勮礋璐d汉', '21', 'bpm_task_candidate_strategy', 0, 'primary', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 閮ㄩ棬鐨勮礋璐d汉', '103', '2022-01-12 23:33:36', '1', '2024-03-06 02:53:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1138, 30, '鐢ㄦ埛', '30', 'bpm_task_candidate_strategy', 0, 'info', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 鐢ㄦ埛', '103', '2022-01-12 23:34:02', '1', '2024-03-06 02:53:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1139, 40, '鐢ㄦ埛缁�', '40', 'bpm_task_candidate_strategy', 0, 'warning', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 鐢ㄦ埛缁�', '103', '2022-01-12 23:34:21', '1', '2024-03-06 02:53:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1140, 60, '娴佺▼琛ㄨ揪寮�', '60', 'bpm_task_candidate_strategy', 0, 'danger', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 娴佺▼琛ㄨ揪寮�', '103', '2022-01-12 23:34:43', '1', '2024-03-06 02:53:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1141, 22, '宀椾綅', '22', 'bpm_task_candidate_strategy', 0, 'success', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 宀椾綅', '103', '2022-01-14 18:41:55', '1', '2024-03-06 02:53:21', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1145, 1, '绠$悊鍚庡彴', '1', 'infra_codegen_scene', 0, '', '', '浠g爜鐢熸垚鐨勫満鏅灇涓� - 绠$悊鍚庡彴', '1', '2022-02-02 13:15:06', '1', '2022-03-10 16:32:59', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1146, 2, '鐢ㄦ埛 APP', '2', 'infra_codegen_scene', 0, '', '', '浠g爜鐢熸垚鐨勫満鏅灇涓� - 鐢ㄦ埛 APP', '1', '2022-02-02 13:15:19', '1', '2022-03-10 16:33:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1150, 1, '鏁版嵁搴�', '1', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:28', '1', '2022-03-15 00:25:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1151, 10, '鏈湴纾佺洏', '10', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:25:41', '1', '2022-03-15 00:25:56', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1152, 11, 'FTP 鏈嶅姟鍣�', '11', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:06', '1', '2022-03-15 00:26:10', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1153, 12, 'SFTP 鏈嶅姟鍣�', '12', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:22', '1', '2022-03-15 00:26:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1154, 20, 'S3 瀵硅薄瀛樺偍', '20', 'infra_file_storage', 0, 'default', '', NULL, '1', '2022-03-15 00:26:31', '1', '2022-03-15 00:26:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1155, 103, '鐭俊鐧诲綍', '103', 'system_login_type', 0, 'default', '', NULL, '1', '2022-05-09 23:57:58', '1', '2022-05-09 23:58:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1156, 1, 'password', 'password', 'system_oauth2_grant_type', 0, 'default', '', '瀵嗙爜妯″紡', '1', '2022-05-12 00:22:05', '1', '2022-05-11 16:26:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1157, 2, 'authorization_code', 'authorization_code', 'system_oauth2_grant_type', 0, 'primary', '', '鎺堟潈鐮佹ā寮�', '1', '2022-05-12 00:22:59', '1', '2022-05-11 16:26:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1158, 3, 'implicit', 'implicit', 'system_oauth2_grant_type', 0, 'success', '', '绠�鍖栨ā寮�', '1', '2022-05-12 00:23:40', '1', '2022-05-11 16:26:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1159, 4, 'client_credentials', 'client_credentials', 'system_oauth2_grant_type', 0, 'default', '', '瀹㈡埛绔ā寮�', '1', '2022-05-12 00:23:51', '1', '2022-05-11 16:26:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1160, 5, 'refresh_token', 'refresh_token', 'system_oauth2_grant_type', 0, 'info', '', '鍒锋柊妯″紡', '1', '2022-05-12 00:24:02', '1', '2022-05-11 16:26:11', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1162, 1, '閿�鍞腑', '1', 'product_spu_status', 0, 'success', '', '鍟嗗搧 SPU 鐘舵�� - 閿�鍞腑', '1', '2022-10-24 21:19:47', '1', '2022-10-24 21:20:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1163, 0, '浠撳簱涓�', '0', 'product_spu_status', 0, 'info', '', '鍟嗗搧 SPU 鐘舵�� - 浠撳簱涓�', '1', '2022-10-24 21:20:54', '1', '2022-10-24 21:21:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1164, 0, '鍥炴敹绔�', '-1', 'product_spu_status', 0, 'default', '', '鍟嗗搧 SPU 鐘舵�� - 鍥炴敹绔�', '1', '2022-10-24 21:21:11', '1', '2022-10-24 21:21:11', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1165, 1, '婊″噺', '1', 'promotion_discount_type', 0, 'success', '', '浼樻儬绫诲瀷 - 婊″噺', '1', '2022-11-01 12:46:41', '1', '2022-11-01 12:50:11', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1166, 2, '鎶樻墸', '2', 'promotion_discount_type', 0, 'primary', '', '浼樻儬绫诲瀷 - 鎶樻墸', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1167, 1, '鍥哄畾鏃ユ湡', '1', 'promotion_coupon_template_validity_type', 0, 'default', '', '浼樻儬鍔垫ā鏉跨殑鏈夐檺鏈熺被鍨� - 鍥哄畾鏃ユ湡', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1168, 2, '棰嗗彇涔嬪悗', '2', 'promotion_coupon_template_validity_type', 0, 'default', '', '浼樻儬鍔垫ā鏉跨殑鏈夐檺鏈熺被鍨� - 棰嗗彇涔嬪悗', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1169, 1, '閫氱敤鍔�', '1', 'promotion_product_scope', 0, 'default', '', '钀ラ攢鐨勫晢鍝佽寖鍥� - 鍏ㄩ儴鍟嗗搧鍙備笌', '1', '2022-11-02 00:28:22', '1', '2023-09-28 00:27:42', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1170, 2, '鍟嗗搧鍔�', '2', 'promotion_product_scope', 0, 'default', '', '钀ラ攢鐨勫晢鍝佽寖鍥� - 鎸囧畾鍟嗗搧鍙備笌', '1', '2022-11-02 00:28:34', '1', '2023-09-28 00:27:44', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1171, 1, '鏈娇鐢�', '1', 'promotion_coupon_status', 0, 'primary', '', '浼樻儬鍔电殑鐘舵�� - 宸查鍙�', '1', '2022-11-04 00:15:08', '1', '2023-10-03 12:54:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1172, 2, '宸蹭娇鐢�', '2', 'promotion_coupon_status', 0, 'success', '', '浼樻儬鍔电殑鐘舵�� - 宸蹭娇鐢�', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1173, 3, '宸茶繃鏈�', '3', 'promotion_coupon_status', 0, 'info', '', '浼樻儬鍔电殑鐘舵�� - 宸茶繃鏈�', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1174, 1, '鐩存帴棰嗗彇', '1', 'promotion_coupon_take_type', 0, 'primary', '', '浼樻儬鍔电殑棰嗗彇鏂瑰紡 - 鐩存帴棰嗗彇', '1', '2022-11-04 19:13:00', '1', '2022-11-04 19:13:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1175, 2, '鎸囧畾鍙戞斁', '2', 'promotion_coupon_take_type', 0, 'success', '', '浼樻儬鍔电殑棰嗗彇鏂瑰紡 - 鎸囧畾鍙戞斁', '1', '2022-11-04 19:13:13', '1', '2022-11-04 19:14:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1176, 10, '鏈紑濮�', '10', 'promotion_activity_status', 0, 'primary', '', '淇冮攢娲诲姩鐨勭姸鎬佹灇涓� - 鏈紑濮�', '1', '2022-11-04 22:54:49', '1', '2022-11-04 22:55:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1177, 20, '杩涜涓�', '20', 'promotion_activity_status', 0, 'success', '', '淇冮攢娲诲姩鐨勭姸鎬佹灇涓� - 杩涜涓�', '1', '2022-11-04 22:55:06', '1', '2022-11-04 22:55:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1178, 30, '宸茬粨鏉�', '30', 'promotion_activity_status', 0, 'info', '', '淇冮攢娲诲姩鐨勭姸鎬佹灇涓� - 宸茬粨鏉�', '1', '2022-11-04 22:55:41', '1', '2022-11-04 22:55:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1179, 40, '宸插叧闂�', '40', 'promotion_activity_status', 0, 'warning', '', '淇冮攢娲诲姩鐨勭姸鎬佹灇涓� - 宸插叧闂�', '1', '2022-11-04 22:56:10', '1', '2022-11-04 22:56:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1180, 10, '婊� N 鍏�', '10', 'promotion_condition_type', 0, 'primary', '', '钀ラ攢鐨勬潯浠剁被鍨� - 婊� N 鍏�', '1', '2022-11-04 22:59:45', '1', '2022-11-04 22:59:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1181, 20, '婊� N 浠�', '20', 'promotion_condition_type', 0, 'success', '', '钀ラ攢鐨勬潯浠剁被鍨� - 婊� N 浠�', '1', '2022-11-04 23:00:02', '1', '2022-11-04 23:00:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1182, 10, '鐢宠鍞悗', '10', 'trade_after_sale_status', 0, 'primary', '', '浜ゆ槗鍞悗鐘舵�� - 鐢宠鍞悗', '1', '2022-11-19 20:53:33', '1', '2022-11-19 20:54:42', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1183, 20, '鍟嗗搧寰呴��璐�', '20', 'trade_after_sale_status', 0, 'primary', '', '浜ゆ槗鍞悗鐘舵�� - 鍟嗗搧寰呴��璐�', '1', '2022-11-19 20:54:36', '1', '2022-11-19 20:58:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1184, 30, '鍟嗗寰呮敹璐�', '30', 'trade_after_sale_status', 0, 'primary', '', '浜ゆ槗鍞悗鐘舵�� - 鍟嗗寰呮敹璐�', '1', '2022-11-19 20:56:56', '1', '2022-11-19 20:59:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1185, 40, '绛夊緟閫�娆�', '40', 'trade_after_sale_status', 0, 'primary', '', '浜ゆ槗鍞悗鐘舵�� - 绛夊緟閫�娆�', '1', '2022-11-19 20:59:54', '1', '2022-11-19 21:00:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1186, 50, '閫�娆炬垚鍔�', '50', 'trade_after_sale_status', 0, 'default', '', '浜ゆ槗鍞悗鐘舵�� - 閫�娆炬垚鍔�', '1', '2022-11-19 21:00:33', '1', '2022-11-19 21:00:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1187, 61, '涔板鍙栨秷', '61', 'trade_after_sale_status', 0, 'info', '', '浜ゆ槗鍞悗鐘舵�� - 涔板鍙栨秷', '1', '2022-11-19 21:01:29', '1', '2022-11-19 21:01:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1188, 62, '鍟嗗鎷掔粷', '62', 'trade_after_sale_status', 0, 'info', '', '浜ゆ槗鍞悗鐘舵�� - 鍟嗗鎷掔粷', '1', '2022-11-19 21:02:17', '1', '2022-11-19 21:02:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1189, 63, '鍟嗗鎷掓敹璐�', '63', 'trade_after_sale_status', 0, 'info', '', '浜ゆ槗鍞悗鐘舵�� - 鍟嗗鎷掓敹璐�', '1', '2022-11-19 21:02:37', '1', '2022-11-19 21:03:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1190, 10, '鍞腑閫�娆�', '10', 'trade_after_sale_type', 0, 'success', '', '浜ゆ槗鍞悗鐨勭被鍨� - 鍞腑閫�娆�', '1', '2022-11-19 21:05:05', '1', '2022-11-19 21:38:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1191, 20, '鍞悗閫�娆�', '20', 'trade_after_sale_type', 0, 'primary', '', '浜ゆ槗鍞悗鐨勭被鍨� - 鍞悗閫�娆�', '1', '2022-11-19 21:05:32', '1', '2022-11-19 21:38:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1192, 10, '浠呴��娆�', '10', 'trade_after_sale_way', 0, 'primary', '', '浜ゆ槗鍞悗鐨勬柟寮� - 浠呴��娆�', '1', '2022-11-19 21:39:19', '1', '2022-11-19 21:39:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1193, 20, '閫�璐ч��娆�', '20', 'trade_after_sale_way', 0, 'success', '', '浜ゆ槗鍞悗鐨勬柟寮� - 閫�璐ч��娆�', '1', '2022-11-19 21:39:38', '1', '2022-11-19 21:39:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1194, 10, '寰俊灏忕▼搴�', '10', 'terminal', 0, 'default', '', '缁堢 - 寰俊灏忕▼搴�', '1', '2022-12-10 10:51:11', '1', '2022-12-10 10:51:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1195, 20, 'H5 缃戦〉', '20', 'terminal', 0, 'default', '', '缁堢 - H5 缃戦〉', '1', '2022-12-10 10:51:30', '1', '2022-12-10 10:51:59', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1196, 11, '寰俊鍏紬鍙�', '11', 'terminal', 0, 'default', '', '缁堢 - 寰俊鍏紬鍙�', '1', '2022-12-10 10:54:16', '1', '2022-12-10 10:52:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1197, 31, '鑻规灉 App', '31', 'terminal', 0, 'default', '', '缁堢 - 鑻规灉 App', '1', '2022-12-10 10:54:42', '1', '2022-12-10 10:52:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1198, 32, '瀹夊崜 App', '32', 'terminal', 0, 'default', '', '缁堢 - 瀹夊崜 App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1199, 0, '鏅�氳鍗�', '0', 'trade_order_type', 0, 'default', '', '浜ゆ槗璁㈠崟鐨勭被鍨� - 鏅�氳鍗�', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1200, 1, '绉掓潃璁㈠崟', '1', 'trade_order_type', 0, 'default', '', '浜ゆ槗璁㈠崟鐨勭被鍨� - 绉掓潃璁㈠崟', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1201, 2, '鐮嶄环璁㈠崟', '2', 'trade_order_type', 0, 'default', '', '浜ゆ槗璁㈠崟鐨勭被鍨� - 鎷煎洟璁㈠崟', '1', '2022-12-10 16:34:36', '1', '2024-09-07 14:18:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1202, 3, '鎷煎洟璁㈠崟', '3', 'trade_order_type', 0, 'default', '', '浜ゆ槗璁㈠崟鐨勭被鍨� - 鐮嶄环璁㈠崟', '1', '2022-12-10 16:34:48', '1', '2024-09-07 14:18:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1203, 0, '寰呮敮浠�', '0', 'trade_order_status', 0, 'default', '', '浜ゆ槗璁㈠崟鐘舵�� - 寰呮敮浠�', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1204, 10, '寰呭彂璐�', '10', 'trade_order_status', 0, 'primary', '', '浜ゆ槗璁㈠崟鐘舵�� - 寰呭彂璐�', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1205, 20, '宸插彂璐�', '20', 'trade_order_status', 0, 'primary', '', '浜ゆ槗璁㈠崟鐘舵�� - 宸插彂璐�', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1206, 30, '宸插畬鎴�', '30', 'trade_order_status', 0, 'success', '', '浜ゆ槗璁㈠崟鐘舵�� - 宸插畬鎴�', '1', '2022-12-10 16:50:30', '1', '2022-12-10 16:51:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1207, 40, '宸插彇娑�', '40', 'trade_order_status', 0, 'danger', '', '浜ゆ槗璁㈠崟鐘舵�� - 宸插彇娑�', '1', '2022-12-10 16:50:50', '1', '2022-12-10 16:51:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1208, 0, '鏈敭鍚�', '0', 'trade_order_item_after_sale_status', 0, 'info', '', '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵�� - 鏈敭鍚�', '1', '2022-12-10 20:58:42', '1', '2022-12-10 20:59:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1209, 10, '鍞悗涓�', '10', 'trade_order_item_after_sale_status', 0, 'primary', '', '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵�� - 鍞悗涓�', '1', '2022-12-10 20:59:21', '1', '2024-07-21 17:01:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1210, 20, '宸查��娆�', '20', 'trade_order_item_after_sale_status', 0, 'success', '', '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵�� - 宸查��娆�', '1', '2022-12-10 20:59:46', '1', '2024-07-21 17:01:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1211, 1, '瀹屽叏鍖归厤', '1', 'mp_auto_reply_request_match', 0, 'primary', '', '鍏紬鍙疯嚜鍔ㄥ洖澶嶇殑璇锋眰鍏抽敭瀛楀尮閰嶆ā寮� - 瀹屽叏鍖归厤', '1', '2023-01-16 23:30:39', '1', '2023-01-16 23:31:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1212, 2, '鍗婂尮閰�', '2', 'mp_auto_reply_request_match', 0, 'success', '', '鍏紬鍙疯嚜鍔ㄥ洖澶嶇殑璇锋眰鍏抽敭瀛楀尮閰嶆ā寮� - 鍗婂尮閰�', '1', '2023-01-16 23:30:55', '1', '2023-01-16 23:31:10', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1213, 1, '鏂囨湰', 'text', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 鏂囨湰', '1', '2023-01-17 22:17:32', '1', '2023-01-17 22:17:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1214, 2, '鍥剧墖', 'image', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 鍥剧墖', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1215, 3, '璇煶', 'voice', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 璇煶', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:20:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1216, 4, '瑙嗛', 'video', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 瑙嗛', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:21:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1217, 5, '灏忚棰�', 'shortvideo', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 灏忚棰�', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:59', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1218, 6, '鍥炬枃', 'news', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 鍥炬枃', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1219, 7, '闊充箰', 'music', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 闊充箰', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1220, 8, '鍦扮悊浣嶇疆', 'location', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 鍦扮悊浣嶇疆', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:23:51', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1221, 9, '閾炬帴', 'link', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 閾炬帴', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1222, 10, '浜嬩欢', 'event', 'mp_message_type', 0, 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 浜嬩欢', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1223, 0, '鍒濆鍖�', '0', 'system_mail_send_status', 0, 'primary', '', '閭欢鍙戦�佺姸鎬� - 鍒濆鍖朶n', '1', '2023-01-26 09:53:49', '1', '2023-01-26 16:36:14', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1224, 10, '鍙戦�佹垚鍔�', '10', 'system_mail_send_status', 0, 'success', '', '閭欢鍙戦�佺姸鎬� - 鍙戦�佹垚鍔�', '1', '2023-01-26 09:54:28', '1', '2023-01-26 16:36:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1225, 20, '鍙戦�佸け璐�', '20', 'system_mail_send_status', 0, 'danger', '', '閭欢鍙戦�佺姸鎬� - 鍙戦�佸け璐�', '1', '2023-01-26 09:54:50', '1', '2023-01-26 16:36:26', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1226, 30, '涓嶅彂閫�', '30', 'system_mail_send_status', 0, 'info', '', '閭欢鍙戦�佺姸鎬� - 涓嶅彂閫�', '1', '2023-01-26 09:55:06', '1', '2023-01-26 16:36:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1227, 1, '閫氱煡鍏憡', '1', 'system_notify_template_type', 0, 'primary', '', '绔欏唴淇℃ā鐗堢殑绫诲瀷 - 閫氱煡鍏憡', '1', '2023-01-28 10:35:59', '1', '2023-01-28 10:35:59', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1228, 2, '绯荤粺娑堟伅', '2', 'system_notify_template_type', 0, 'success', '', '绔欏唴淇℃ā鐗堢殑绫诲瀷 - 绯荤粺娑堟伅', '1', '2023-01-28 10:36:20', '1', '2023-01-28 10:36:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1230, 13, '鏀粯瀹濇潯鐮佹敮浠�', 'alipay_bar', 'pay_channel_code', 0, 'primary', '', '鏀粯瀹濇潯鐮佹敮浠�', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1231, 10, 'Vue2 Element UI 鏍囧噯妯$増', '10', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1232, 20, 'Vue3 Element Plus 鏍囧噯妯$増', '20', 'infra_codegen_front_type', 0, '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1234, 30, 'Vben2.0 Ant Design Schema 妯$増', '30', 'infra_codegen_front_type', 1, '', '', '', '1', '2023-04-13 00:04:26', '1', '2025-07-27 10:55:14', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1244, 0, '鎸変欢', '1', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1245, 1, '鎸夐噸閲�', '2', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1246, 2, '鎸変綋绉�', '3', 'trade_delivery_express_charge_mode', 0, '', '', '', '1', '2023-05-21 22:47:18', '1', '2023-05-21 22:47:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1335, 11, '璁㈠崟绉垎鎶垫墸', '11', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:27', '1', '2023-10-11 07:41:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1336, 1, '绛惧埌', '1', 'member_point_biz_type', 0, '', '', '', '1', '2023-06-10 12:15:48', '1', '2023-08-20 11:59:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1341, 20, '宸查��娆�', '20', 'pay_order_status', 0, 'danger', '', '宸查��娆�', '1', '2023-07-19 18:05:37', '1', '2023-07-19 18:05:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1342, 21, '璇锋眰鎴愬姛锛屼絾鏄粨鏋滃け璐�', '21', 'pay_notify_status', 0, 'warning', '', '璇锋眰鎴愬姛锛屼絾鏄粨鏋滃け璐�', '1', '2023-07-19 18:10:47', '1', '2023-07-19 18:11:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1343, 22, '璇锋眰澶辫触', '22', 'pay_notify_status', 0, 'warning', '', NULL, '1', '2023-07-19 18:11:05', '1', '2023-07-19 18:11:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1344, 4, '寰俊鎵爜鏀粯', 'wx_native', 'pay_channel_code', 0, 'success', '', '寰俊鎵爜鏀粯', '1', '2023-07-19 20:07:47', '1', '2023-07-19 20:09:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1345, 5, '寰俊鏉$爜鏀粯', 'wx_bar', 'pay_channel_code', 0, 'success', '', '寰俊鏉$爜鏀粯\n', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1346, 1, '鏀粯鍗�', '1', 'pay_notify_type', 0, 'primary', '', '鏀粯鍗�', '1', '2023-07-20 12:23:17', '1', '2023-07-20 12:23:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1347, 2, '閫�娆惧崟', '2', 'pay_notify_type', 0, 'danger', '', NULL, '1', '2023-07-20 12:23:26', '1', '2023-07-20 12:23:26', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1348, 20, '妯℃嫙鏀粯', 'mock', 'pay_channel_code', 0, 'default', '', '妯℃嫙鏀粯', '1', '2023-07-29 11:10:51', '1', '2023-07-29 03:14:10', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1349, 12, '璁㈠崟绉垎鎶垫墸锛堟暣鍗曞彇娑堬級', '12', 'member_point_biz_type', 0, '', '', '', '1', '2023-08-20 12:00:03', '1', '2023-10-11 07:42:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1350, 0, '绠$悊鍛樿皟鏁�', '0', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1351, 1, '閭�鏂板鍔�', '1', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1352, 11, '涓嬪崟濂栧姳', '11', 'member_experience_biz_type', 0, 'success', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1353, 12, '涓嬪崟濂栧姳锛堟暣鍗曞彇娑堬級', '12', 'member_experience_biz_type', 0, 'warning', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1354, 4, '绛惧埌濂栧姳', '4', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1355, 5, '鎶藉濂栧姳', '5', 'member_experience_biz_type', 0, '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1356, 1, '蹇�掑彂璐�', '1', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1357, 2, '鐢ㄦ埛鑷彁', '2', 'trade_delivery_type', 0, '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1358, 3, '鍝佺被鍔�', '3', 'promotion_product_scope', 0, 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-28 00:27:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1359, 1, '浜轰汉鍒嗛攢', '1', 'brokerage_enabled_condition', 0, '', '', '鎵�鏈夌敤鎴烽兘鍙互鍒嗛攢', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1360, 2, '鎸囧畾鍒嗛攢', '2', 'brokerage_enabled_condition', 0, '', '', '浠呭彲鍚庡彴鎵嬪姩璁剧疆鎺ㄥ箍鍛�', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1361, 1, '棣栨缁戝畾', '1', 'brokerage_bind_mode', 0, '', '', '鍙鐢ㄦ埛娌℃湁鎺ㄥ箍浜猴紝闅忔椂閮藉彲浠ョ粦瀹氭帹骞垮叧绯�', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1362, 2, '娉ㄥ唽缁戝畾', '2', 'brokerage_bind_mode', 0, '', '', '浠呮柊鐢ㄦ埛娉ㄥ唽鏃舵墠鑳界粦瀹氭帹骞垮叧绯�', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1363, 3, '瑕嗙洊缁戝畾', '3', 'brokerage_bind_mode', 0, '', '', '濡傛灉鐢ㄦ埛宸茬粡鏈夋帹骞夸汉锛屾帹骞夸汉浼氳鍙樻洿', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1364, 1, '閽卞寘', '1', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1365, 2, '閾惰鍗�', '2', 'brokerage_withdraw_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1366, 3, '寰俊鏀舵鐮�', '3', 'brokerage_withdraw_type', 0, '', '', '鎵嬪姩鎵撴', '', '2023-09-28 02:46:05', '1', '2025-05-10 08:24:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1367, 4, '鏀粯瀹濇敹娆剧爜', '4', 'brokerage_withdraw_type', 0, '', '', '鎵嬪姩鎵撴', '', '2023-09-28 02:46:05', '1', '2025-05-10 08:24:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1368, 1, '璁㈠崟杩斾剑', '1', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1369, 2, '鐢宠鎻愮幇', '2', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1370, 3, '鐢宠鎻愮幇椹冲洖', '3', 'brokerage_record_biz_type', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1371, 0, '寰呯粨绠�', '0', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1372, 1, '宸茬粨绠�', '1', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1373, 2, '宸插彇娑�', '2', 'brokerage_record_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1374, 0, '瀹℃牳涓�', '0', 'brokerage_withdraw_status', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1375, 10, '瀹℃牳閫氳繃', '10', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1376, 11, '鎻愮幇鎴愬姛', '11', 'brokerage_withdraw_status', 0, 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1377, 20, '瀹℃牳涓嶉�氳繃', '20', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1378, 21, '鎻愮幇澶辫触', '21', 'brokerage_withdraw_status', 0, 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1379, 0, '宸ュ晢閾惰', '0', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1380, 1, '寤鸿閾惰', '1', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1381, 2, '鍐滀笟閾惰', '2', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1382, 3, '涓浗閾惰', '3', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1383, 4, '浜ら�氶摱琛�', '4', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1384, 5, '鎷涘晢閾惰', '5', 'brokerage_bank_name', 0, '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1385, 21, '閽卞寘', 'wallet', 'pay_channel_code', 0, 'primary', '', '', '1', '2023-10-01 21:46:19', '1', '2023-10-01 21:48:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1386, 1, '鐮嶄环涓�', '1', 'promotion_bargain_record_status', 0, 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1387, 2, '鐮嶄环鎴愬姛', '2', 'promotion_bargain_record_status', 0, 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1388, 3, '鐮嶄环澶辫触', '3', 'promotion_bargain_record_status', 0, 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1389, 0, '鎷煎洟涓�', '0', 'promotion_combination_record_status', 0, '', '', '', '1', '2023-10-08 07:24:44', '1', '2024-10-13 10:08:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1390, 1, '鎷煎洟鎴愬姛', '1', 'promotion_combination_record_status', 0, 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2024-10-13 10:08:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1391, 2, '鎷煎洟澶辫触', '2', 'promotion_combination_record_status', 0, 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2024-10-13 10:08:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1392, 2, '绠$悊鍛樹慨鏀�', '2', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1393, 13, '璁㈠崟绉垎鎶垫墸锛堝崟涓��娆撅級', '13', 'member_point_biz_type', 0, '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1394, 21, '璁㈠崟绉垎濂栧姳', '21', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1395, 22, '璁㈠崟绉垎濂栧姳锛堟暣鍗曞彇娑堬級', '22', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1396, 23, '璁㈠崟绉垎濂栧姳锛堝崟涓��娆撅級', '23', 'member_point_biz_type', 0, 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1397, 13, '涓嬪崟濂栧姳锛堝崟涓��娆撅級', '13', 'member_experience_biz_type', 0, 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1398, 5, '缃戜笂杞处', '5', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1399, 6, '鏀粯瀹�', '6', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:38', '1', '2023-10-18 21:55:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1400, 7, '寰俊鏀粯', '7', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:53', '1', '2023-10-18 21:55:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1401, 8, '鍏朵粬', '8', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:56:06', '1', '2023-10-18 21:56:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1402, 1, 'IT', '1', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:15', '1', '2024-02-18 23:30:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1403, 2, '閲戣瀺涓�', '2', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:29', '1', '2024-02-18 23:30:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1404, 3, '鎴垮湴浜�', '3', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:41', '1', '2024-02-18 23:30:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1405, 4, '鍟嗕笟鏈嶅姟', '4', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:02:54', '1', '2024-02-18 23:30:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1406, 5, '杩愯緭/鐗╂祦', '5', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:03', '1', '2024-02-18 23:31:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1407, 6, '鐢熶骇', '6', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:13', '1', '2024-02-18 23:31:08', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1408, 7, '鏀垮簻', '7', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:27', '1', '2024-02-18 23:31:13', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1409, 8, '鏂囧寲浼犲獟', '8', 'crm_customer_industry', 0, 'default', '', '', '1', '2023-10-28 23:03:37', '1', '2024-02-18 23:31:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1422, 1, 'A 锛堥噸鐐瑰鎴凤級', '1', 'crm_customer_level', 0, 'primary', '', '', '1', '2023-10-28 23:07:13', '1', '2023-10-28 23:07:13', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1423, 2, 'B 锛堟櫘閫氬鎴凤級', '2', 'crm_customer_level', 0, 'info', '', '', '1', '2023-10-28 23:07:35', '1', '2023-10-28 23:07:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1424, 3, 'C 锛堥潪浼樺厛瀹㈡埛锛�', '3', 'crm_customer_level', 0, 'default', '', '', '1', '2023-10-28 23:07:53', '1', '2023-10-28 23:07:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1425, 1, '淇冮攢', '1', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:29', '1', '2023-10-28 23:08:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1426, 2, '鎼滅储寮曟搸', '2', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:39', '1', '2023-10-28 23:08:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1427, 3, '骞垮憡', '3', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:47', '1', '2023-10-28 23:08:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1428, 4, '杞粙缁�', '4', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:08:58', '1', '2023-10-28 23:08:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1429, 5, '绾夸笂娉ㄥ唽', '5', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:12', '1', '2023-10-28 23:09:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1430, 6, '绾夸笂鍜ㄨ', '6', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:22', '1', '2023-10-28 23:09:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1431, 7, '棰勭害涓婇棬', '7', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:09:39', '1', '2023-10-28 23:09:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1432, 8, '闄屾嫓', '8', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:04', '1', '2023-10-28 23:10:04', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1433, 9, '鐢佃瘽鍜ㄨ', '9', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:18', '1', '2023-10-28 23:10:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1434, 10, '閭欢鍜ㄨ', '10', 'crm_customer_source', 0, 'default', '', '', '1', '2023-10-28 23:10:33', '1', '2023-10-28 23:10:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1435, 10, 'Gitee', '10', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:42', '1', '2023-11-04 13:04:42', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1436, 20, '閽夐拤', '20', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:04:54', '1', '2023-11-04 13:04:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1437, 30, '浼佷笟寰俊', '30', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:09', '1', '2023-11-04 13:05:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1438, 31, '寰俊鍏紬骞冲彴', '31', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1439, 32, '寰俊寮�鏀惧钩鍙�', '32', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1440, 34, '寰俊灏忕▼搴�', '34', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1441, 1, '涓婃灦', '1', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:34', '1', '2023-10-30 21:49:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1442, 0, '涓嬫灦', '0', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:13', '1', '2023-10-30 21:49:13', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1443, 15, '瀛愯〃', '15', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-13 23:06:16', '1', '2023-11-13 23:06:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1444, 10, '涓昏〃锛堟爣鍑嗘ā寮忥級', '10', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:32:49', '1', '2023-11-14 12:32:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1445, 11, '涓昏〃锛圗RP 妯″紡锛�', '11', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:33:05', '1', '2023-11-14 12:33:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1446, 12, '涓昏〃锛堝唴宓屾ā寮忥級', '12', 'infra_codegen_template_type', 0, '', '', '', '1', '2023-11-14 12:33:31', '1', '2023-11-14 12:33:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1447, 1, '璐熻矗浜�', '1', 'crm_permission_level', 0, 'default', '', '', '1', '2023-11-30 09:53:12', '1', '2023-11-30 09:53:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1448, 2, '鍙', '2', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:29', '1', '2023-11-30 09:53:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1449, 3, '璇诲啓', '3', 'crm_permission_level', 0, '', '', '', '1', '2023-11-30 09:53:36', '1', '2023-11-30 09:53:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1450, 0, '鏈彁浜�', '0', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:56:59', '1', '2023-11-30 18:56:59', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1451, 10, '瀹℃壒涓�', '10', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:10', '1', '2023-11-30 18:57:10', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1452, 20, '瀹℃牳閫氳繃', '20', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:24', '1', '2023-11-30 18:57:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1453, 30, '瀹℃牳涓嶉�氳繃', '30', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:32', '1', '2023-11-30 18:57:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1454, 40, '宸插彇娑�', '40', 'crm_audit_status', 0, '', '', '', '1', '2023-11-30 18:57:42', '1', '2023-11-30 18:57:42', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1456, 1, '鏀エ', '1', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:29', '1', '2023-10-18 21:54:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1457, 2, '鐜伴噾', '2', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:41', '1', '2023-10-18 21:54:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1458, 3, '閭斂姹囨', '3', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:54:53', '1', '2023-10-18 21:54:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1459, 4, '鐢垫眹', '4', 'crm_receivable_return_type', 0, 'default', '', '', '1', '2023-10-18 21:55:07', '1', '2023-10-18 21:55:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1461, 1, '涓�', '1', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:26', '1', '2023-12-05 23:02:26', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1462, 2, '鍧�', '2', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:34', '1', '2023-12-05 23:02:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1463, 3, '鍙�', '3', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:02:57', '1', '2023-12-05 23:02:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1464, 4, '鎶�', '4', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:05', '1', '2023-12-05 23:03:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1465, 5, '鏋�', '5', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:14', '1', '2023-12-05 23:03:14', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1466, 6, '鐡�', '6', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:20', '1', '2023-12-05 23:03:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1467, 7, '鐩�', '7', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:30', '1', '2023-12-05 23:03:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1468, 8, '鍙�', '8', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:41', '1', '2023-12-05 23:03:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1469, 9, '鍚�', '9', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:03:48', '1', '2023-12-05 23:03:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1470, 10, '鍗冨厠', '10', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:03', '1', '2023-12-05 23:04:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1471, 11, '绫�', '11', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:12', '1', '2023-12-05 23:04:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1472, 12, '绠�', '12', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:25', '1', '2023-12-05 23:04:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1473, 13, '濂�', '13', 'crm_product_unit', 0, '', '', '', '1', '2023-12-05 23:04:34', '1', '2023-12-05 23:04:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1474, 1, '鎵撶數璇�', '1', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:20', '1', '2024-01-15 20:48:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1475, 2, '鍙戠煭淇�', '2', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:48:31', '1', '2024-01-15 20:48:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1476, 3, '涓婇棬鎷滆', '3', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:07', '1', '2024-01-15 20:49:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1477, 4, '寰俊娌熼��', '4', 'crm_follow_up_type', 0, '', '', '', '1', '2024-01-15 20:49:15', '1', '2024-01-15 20:49:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1482, 4, '杞处澶辫触', '20', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2025-05-08 12:59:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1483, 3, '杞处鎴愬姛', '10', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2025-05-08 12:58:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1484, 2, '杞处杩涜涓�', '5', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2025-05-08 12:58:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1485, 1, '绛夊緟杞处', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1486, 10, '鍏跺畠鍏ュ簱', '10', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:07:25', '1', '2024-02-05 18:07:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1487, 11, '鍏跺畠鍏ュ簱锛堜綔搴燂級', '11', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:08:07', '1', '2024-02-05 19:20:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1488, 20, '鍏跺畠鍑哄簱', '20', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-05 18:08:51', '1', '2024-02-05 18:08:51', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1489, 21, '鍏跺畠鍑哄簱锛堜綔搴燂級', '21', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-05 18:09:00', '1', '2024-02-05 19:20:10', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1490, 10, '鏈鏍�', '10', 'erp_audit_status', 0, 'default', '', '', '1', '2024-02-06 00:00:21', '1', '2024-02-06 00:00:21', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1491, 20, '宸插鏍�', '20', 'erp_audit_status', 0, 'success', '', '', '1', '2024-02-06 00:00:35', '1', '2024-02-06 00:00:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1492, 30, '璋冩嫧鍏ュ簱', '30', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:19', '1', '2024-02-07 12:36:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1493, 31, '璋冩嫧鍏ュ簱锛堜綔搴燂級', '31', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:29', '1', '2024-02-07 20:37:11', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1494, 32, '璋冩嫧鍑哄簱', '32', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-07 20:34:38', '1', '2024-02-07 12:36:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1495, 33, '璋冩嫧鍑哄簱锛堜綔搴燂級', '33', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-07 20:34:49', '1', '2024-02-07 20:37:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1496, 40, '鐩樼泩鍏ュ簱', '40', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:53:00', '1', '2024-02-08 08:53:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1497, 41, '鐩樼泩鍏ュ簱锛堜綔搴燂級', '41', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:53:39', '1', '2024-02-16 19:40:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1498, 42, '鐩樹簭鍑哄簱', '42', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-08 08:54:16', '1', '2024-02-08 08:54:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1499, 43, '鐩樹簭鍑哄簱锛堜綔搴燂級', '43', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-08 08:54:31', '1', '2024-02-16 19:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1500, 50, '閿�鍞嚭搴�', '50', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-11 21:47:25', '1', '2024-02-11 21:50:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1501, 51, '閿�鍞嚭搴擄紙浣滃簾锛�', '51', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-11 21:47:37', '1', '2024-02-11 21:51:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1502, 60, '閿�鍞��璐у叆搴�', '60', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-12 06:51:05', '1', '2024-02-12 06:51:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1503, 61, '閿�鍞��璐у叆搴擄紙浣滃簾锛�', '61', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-12 06:51:18', '1', '2024-02-12 06:51:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1504, 70, '閲囪喘鍏ュ簱', '70', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:02', '1', '2024-02-16 13:10:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1505, 71, '閲囪喘鍏ュ簱锛堜綔搴燂級', '71', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:10', '1', '2024-02-16 19:40:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1506, 80, '閲囪喘閫�璐у嚭搴�', '80', 'erp_stock_record_biz_type', 0, '', '', '', '1', '2024-02-16 13:10:17', '1', '2024-02-16 13:10:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1507, 81, '閲囪喘閫�璐у嚭搴擄紙浣滃簾锛�', '81', 'erp_stock_record_biz_type', 0, 'danger', '', '', '1', '2024-02-16 13:10:26', '1', '2024-02-16 19:40:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1509, 3, '瀹℃壒涓嶉�氳繃', '3', 'bpm_process_instance_status', 0, 'danger', '', '', '1', '2024-03-16 16:12:06', '1', '2024-03-16 16:12:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1510, 4, '宸插彇娑�', '4', 'bpm_process_instance_status', 0, 'warning', '', '', '1', '2024-03-16 16:12:22', '1', '2024-03-16 16:12:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1511, 5, '宸查��鍥�', '5', 'bpm_task_status', 0, 'warning', '', '', '1', '2024-03-16 19:10:46', '1', '2024-03-08 22:41:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1512, 6, '濮旀淳涓�', '6', 'bpm_task_status', 0, 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1513, 7, '瀹℃壒閫氳繃涓�', '7', 'bpm_task_status', 0, 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1514, 0, '寰呭鎵�', '0', 'bpm_task_status', 0, 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1515, 35, '鍙戣捣浜鸿嚜閫�', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1516, 1, '鎵ц鐩戝惉鍣�', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1517, 1, '浠诲姟鐩戝惉鍣�', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1526, 1, 'Java 绫�', 'class', 'bpm_process_listener_value_type', 0, 'primary', '', '', '1', '2024-03-23 15:08:45', '1', '2024-03-23 19:14:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1527, 2, '琛ㄨ揪寮�', 'expression', 'bpm_process_listener_value_type', 0, 'success', '', '', '1', '2024-03-23 15:09:06', '1', '2024-03-23 19:14:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1528, 3, '浠g悊琛ㄨ揪寮�', 'delegateExpression', 'bpm_process_listener_value_type', 0, 'info', '', '', '1', '2024-03-23 15:11:23', '1', '2024-03-23 19:14:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1529, 1, '澶�', '1', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:26', '1', '2024-03-29 22:50:26', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1530, 2, '鍛�', '2', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:36', '1', '2024-03-29 22:50:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1531, 3, '鏈�', '3', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:50:46', '1', '2024-03-29 22:50:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1532, 4, '瀛e害', '4', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:01', '1', '2024-03-29 22:51:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1533, 5, '骞�', '5', 'date_interval', 0, '', '', '', '1', '2024-03-29 22:51:07', '1', '2024-03-29 22:51:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1534, 1, '璧㈠崟', '1', 'crm_business_end_status_type', 0, 'success', '', '', '1', '2024-04-13 23:26:57', '1', '2024-04-13 23:26:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1535, 2, '杈撳崟', '2', 'crm_business_end_status_type', 0, 'primary', '', '', '1', '2024-04-13 23:27:31', '1', '2024-04-13 23:27:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1536, 3, '鏃犳晥', '3', 'crm_business_end_status_type', 0, 'info', '', '', '1', '2024-04-13 23:27:59', '1', '2024-04-13 23:27:59', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1537, 1, 'OpenAI', 'OpenAI', 'ai_platform', 0, '', '', '', '1', '2024-05-09 22:33:47', '1', '2024-05-09 22:58:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1538, 2, 'Ollama', 'Ollama', 'ai_platform', 0, '', '', '', '1', '2024-05-17 23:02:55', '1', '2024-05-17 23:02:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1539, 3, '鏂囧績涓�瑷�', 'YiYan', 'ai_platform', 0, '', '', '', '1', '2024-05-18 09:24:20', '1', '2024-05-18 09:29:01', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1540, 4, '璁鏄熺伀', 'XingHuo', 'ai_platform', 0, '', '', '', '1', '2024-05-18 10:08:56', '1', '2024-05-18 10:08:56', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1541, 5, '閫氫箟鍗冮棶', 'TongYi', 'ai_platform', 0, '', '', '', '1', '2024-05-18 10:32:29', '1', '2024-07-06 15:42:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1542, 6, 'StableDiffusion', 'StableDiffusion', 'ai_platform', 0, '', '', '', '1', '2024-06-01 15:09:31', '1', '2024-06-01 15:10:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1543, 10, '杩涜涓�', '10', 'ai_image_status', 0, 'primary', '', '', '1', '2024-06-26 20:51:41', '1', '2024-06-26 20:52:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1544, 20, '宸插畬鎴�', '20', 'ai_image_status', 0, 'success', '', '', '1', '2024-06-26 20:52:07', '1', '2024-06-26 20:52:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1545, 30, '宸插け璐�', '30', 'ai_image_status', 0, 'warning', '', '', '1', '2024-06-26 20:52:25', '1', '2024-06-26 20:52:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1546, 7, 'Midjourney', 'Midjourney', 'ai_platform', 0, '', '', '', '1', '2024-06-26 22:14:46', '1', '2024-06-26 22:14:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1547, 10, '杩涜涓�', '10', 'ai_music_status', 0, 'primary', '', '', '1', '2024-06-27 22:45:22', '1', '2024-06-28 00:56:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1548, 20, '宸插畬鎴�', '20', 'ai_music_status', 0, 'success', '', '', '1', '2024-06-27 22:45:33', '1', '2024-06-28 00:56:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1549, 30, '宸插け璐�', '30', 'ai_music_status', 0, 'danger', '', '', '1', '2024-06-27 22:45:44', '1', '2024-06-28 00:56:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1550, 1, '姝岃瘝妯″紡', '1', 'ai_generate_mode', 0, '', '', '', '1', '2024-06-27 22:46:31', '1', '2024-06-28 01:22:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1551, 2, '鎻忚堪妯″紡', '2', 'ai_generate_mode', 0, '', '', '', '1', '2024-06-27 22:46:37', '1', '2024-06-28 01:22:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1552, 8, 'Suno', 'Suno', 'ai_platform', 0, '', '', '', '1', '2024-06-29 09:13:36', '1', '2024-06-29 09:13:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1553, 9, 'DeepSeek', 'DeepSeek', 'ai_platform', 0, '', '', '', '1', '2024-07-06 12:04:30', '1', '2024-07-06 12:05:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1554, 13, '鏅鸿氨', 'ZhiPu', 'ai_platform', 0, '', '', '', '1', '2024-07-06 18:00:35', '1', '2025-02-24 20:18:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1555, 4, '闀�', '4', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:49:03', '1', '2024-07-07 15:49:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1556, 5, '娈佃惤', '5', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:49:54', '1', '2024-07-07 15:49:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1557, 6, '鏂囩珷', '6', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:05', '1', '2024-07-07 15:50:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1558, 7, '鍗氬鏂囩珷', '7', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:23', '1', '2024-07-07 15:50:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1559, 8, '鎯虫硶', '8', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:31', '1', '2024-07-07 15:50:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1560, 9, '澶х翰', '9', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:50:37', '1', '2024-07-07 15:50:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1561, 1, '鑷姩', '1', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:06', '1', '2024-07-07 15:51:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1562, 2, '鍙嬪杽', '2', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:19', '1', '2024-07-07 15:51:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1563, 3, '闅忔剰', '3', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:27', '1', '2024-07-07 15:51:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1564, 4, '鍙嬪ソ', '4', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:37', '1', '2024-07-07 15:51:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1565, 5, '涓撲笟', '5', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:51:49', '1', '2024-07-07 15:52:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1566, 6, '璇欒皭', '6', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:52:15', '1', '2024-07-07 15:52:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1567, 7, '鏈夎叮', '7', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:52:24', '1', '2024-07-07 15:52:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1568, 8, '姝e紡', '8', 'ai_write_tone', 0, '', '', '', '1', '2024-07-07 15:54:33', '1', '2024-07-07 15:54:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1570, 1, '鑷姩', '1', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:19:34', '1', '2024-07-07 15:19:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1571, 2, '鐢靛瓙閭欢', '2', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:19:50', '1', '2024-07-07 15:49:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1572, 3, '娑堟伅', '3', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:20:01', '1', '2024-07-07 15:49:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1573, 4, '璇勮', '4', 'ai_write_format', 0, '', '', '', '1', '2024-07-07 15:20:13', '1', '2024-07-07 15:49:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1574, 1, '鑷姩', '1', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:18', '1', '2024-07-07 15:44:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1575, 2, '涓枃', '2', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:28', '1', '2024-07-07 15:44:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1576, 3, '鑻辨枃', '3', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:44:37', '1', '2024-07-07 15:44:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1577, 4, '闊╄', '4', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:46:28', '1', '2024-07-07 15:46:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1578, 5, '鏃ヨ', '5', 'ai_write_language', 0, '', '', '', '1', '2024-07-07 15:46:44', '1', '2024-07-07 15:46:44', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1579, 1, '鑷姩', '1', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:34', '1', '2024-07-07 15:48:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1580, 2, '鐭�', '2', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:44', '1', '2024-07-07 15:48:44', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1581, 3, '涓瓑', '3', 'ai_write_length', 0, '', '', '', '1', '2024-07-07 15:48:52', '1', '2024-07-07 15:48:52', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1584, 1, '鎾板啓', '1', 'ai_write_type', 0, '', '', '', '1', '2024-07-10 21:26:00', '1', '2024-07-10 21:26:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1585, 2, '鍥炲', '2', 'ai_write_type', 0, '', '', '', '1', '2024-07-10 21:26:06', '1', '2024-07-10 21:26:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1586, 2, '鑵捐浜�', 'TENCENT', 'system_sms_channel_code', 0, '', '', '', '1', '2024-07-22 22:23:16', '1', '2024-07-22 22:23:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1587, 3, '鍗庝负浜�', 'HUAWEI', 'system_sms_channel_code', 0, '', '', '', '1', '2024-07-22 22:23:46', '1', '2024-07-22 22:23:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1588, 1, 'OpenAI 寰蒋', 'AzureOpenAI', 'ai_platform', 0, '', '', '', '1', '2024-08-10 14:07:41', '1', '2024-08-10 14:07:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1589, 10, 'BPMN 璁捐鍣�', '10', 'bpm_model_type', 0, 'primary', '', '', '1', '2024-08-26 15:22:17', '1', '2024-08-26 16:46:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1590, 20, 'SIMPLE 璁捐鍣�', '20', 'bpm_model_type', 0, 'success', '', '', '1', '2024-08-26 15:22:27', '1', '2024-08-26 16:45:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1591, 4, '涓冪墰浜�', 'QINIU', 'system_sms_channel_code', 0, '', '', '', '1', '2024-08-31 08:45:03', '1', '2024-08-31 08:45:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1592, 3, '鏂颁汉鍒�', '3', 'promotion_coupon_take_type', 0, 'info', '', '鏂颁汉娉ㄥ唽鍚庯紝鑷姩鍙戞斁', '1', '2024-09-03 11:57:16', '1', '2024-09-03 11:57:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1593, 5, '寰俊闆堕挶', '5', 'brokerage_withdraw_type', 0, '', '', 'API 鎵撴', '1', '2024-10-13 11:06:48', '1', '2025-05-10 08:24:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1683, 10, '瀛楄妭璞嗗寘', 'DouBao', 'ai_platform', 0, '', '', '', '1', '2025-02-23 19:51:40', '1', '2025-02-23 19:52:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1684, 11, '鑵捐娣峰厓', 'HunYuan', 'ai_platform', 0, '', '', '', '1', '2025-02-23 20:58:04', '1', '2025-02-23 20:58:04', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1685, 12, '纭呭熀娴佸姩', 'SiliconFlow', 'ai_platform', 0, '', '', '', '1', '2025-02-24 20:19:09', '1', '2025-02-24 20:19:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1686, 1, '鑱婂ぉ', '1', 'ai_model_type', 0, '', '', '', '1', '2025-03-03 12:26:34', '1', '2025-03-03 12:26:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1687, 2, '鍥惧儚', '2', 'ai_model_type', 0, '', '', '', '1', '2025-03-03 12:27:23', '1', '2025-03-03 12:27:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1688, 3, '闊抽', '3', 'ai_model_type', 0, '', '', '', '1', '2025-03-03 12:27:51', '1', '2025-03-03 12:27:51', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1689, 4, '瑙嗛', '4', 'ai_model_type', 0, '', '', '', '1', '2025-03-03 12:28:03', '1', '2025-03-03 12:28:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1690, 5, '鍚戦噺', '5', 'ai_model_type', 0, '', '', '', '1', '2025-03-03 12:28:15', '1', '2025-03-03 12:28:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1691, 6, '閲嶆帓', '6', 'ai_model_type', 0, '', '', '', '1', '2025-03-03 12:28:26', '1', '2025-03-03 12:28:26', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1692, 14, 'MiniMax', 'MiniMax', 'ai_platform', 0, '', '', '', '1', '2025-03-11 20:04:51', '1', '2025-03-11 20:04:51', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1693, 15, '鏈堜箣鏆楅潰', 'Moonshot', 'ai_platform', 0, '', '', '', '1', '2025-03-11 20:05:08', '1', '2025-11-24 07:17:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2002, 0, '鐩磋繛璁惧', '0', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:54:58', '1', '2025-03-17 09:28:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2003, 2, '缃戝叧璁惧', '2', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:55:08', '1', '2025-03-17 09:28:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2004, 1, '缃戝叧瀛愯澶�', '1', 'iot_product_device_type', 0, 'default', '', '', '1', '2024-08-10 11:55:20', '1', '2025-03-17 09:28:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2005, 1, '宸插彂甯�', '1', 'iot_product_status', 0, 'success', '', '', '1', '2024-08-10 12:10:33', '1', '2025-03-17 09:28:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2006, 0, '寮�鍙戜腑', '0', 'iot_product_status', 0, 'default', '', '', '1', '2024-08-10 14:19:18', '1', '2025-03-17 09:28:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2009, 0, 'Wi-Fi', '0', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:04:47', '1', '2025-03-17 09:28:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2010, 1, '绉诲姩缃戠粶', '1', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:14', '1', '2025-06-12 23:27:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2011, 2, '浠ュお缃�', '2', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:35', '1', '2025-03-17 09:28:51', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2012, 3, '鍏朵粬', '3', 'iot_net_type', 0, '', '', '', '1', '2024-09-06 22:05:52', '1', '2025-03-17 09:28:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2018, 0, '鏈縺娲�', '0', 'iot_device_state', 0, '', '', '', '1', '2024-09-21 08:13:34', '1', '2025-03-17 09:29:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2019, 1, '鍦ㄧ嚎', '1', 'iot_device_state', 0, '', '', '', '1', '2024-09-21 08:13:48', '1', '2025-03-17 09:29:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2020, 2, '绂荤嚎', '2', 'iot_device_state', 0, '', '', '', '1', '2024-09-21 08:13:59', '1', '2025-03-17 09:29:14', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2021, 1, '灞炴��', '1', 'iot_thing_model_type', 0, '', '', '', '1', '2024-09-29 20:03:01', '1', '2025-03-17 09:29:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2022, 2, '鏈嶅姟', '2', 'iot_thing_model_type', 0, '', '', '', '1', '2024-09-29 20:03:11', '1', '2025-03-17 09:29:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2023, 3, '浜嬩欢', '3', 'iot_thing_model_type', 0, '', '', '', '1', '2024-09-29 20:03:20', '1', '2025-03-17 09:29:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2030, 1, '鍗囨瘡鍒嗛挓', 'L/min', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2031, 2, '姣厠姣忓崈鍏�', 'mg/kg', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2032, 3, '娴婂害', 'NTU', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2033, 4, 'PH鍊�', 'pH', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2034, 5, '鍦熷¥EC鍊�', 'dS/m', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2035, 6, '澶槼鎬昏緪灏�', 'W/銕�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:36:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2036, 7, '闄嶉洦閲�', 'mm/hour', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:36:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2037, 8, '涔�', 'var', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:36:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2038, 9, '鍘樻硦', 'cP', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:36:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2039, 10, '楗卞拰搴�', 'aw', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:11', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2040, 11, '涓�', 'pcs', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2041, 12, '鍘樻柉', 'cst', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2042, 13, '宸�', 'bar', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2043, 14, '绾冲厠姣忓崌', 'ppt', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2044, 15, '鍗佷嚎鍒嗕箣涓�', 'ppb', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2045, 16, '寰タ姣忓帢绫�', 'uS/cm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2046, 17, '鐗涢】姣忓簱浠�', 'N/C', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2047, 18, '浼忕壒姣忕背', 'V/m', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2048, 19, '婊撮��', 'ml/min', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2049, 20, '姣背姹炴煴', 'mmHg', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2050, 21, '琛�绯�', 'mmol/L', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2051, 22, '姣背姣忕', 'mm/s', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2052, 23, '杞瘡绫�', 'turn/m', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2053, 24, '娆�', 'count', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2054, 25, '妗�', 'gear', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:11', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2055, 26, '姝�', 'stepCount', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:13', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2056, 27, '鏍囧噯绔嬫柟绫虫瘡灏忔椂', 'Nm3/h', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2057, 28, '鍗冧紡', 'kV', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2058, 29, '鍗冧紡瀹�', 'kVA', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2060, 30, '鍗冧箯', 'kVar', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2061, 31, '寰摝姣忓钩鏂瑰帢绫�', 'uw/cm2', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2062, 32, '鍙�', '鍙�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2063, 33, '鐩稿婀垮害', '%RH', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2064, 34, '绔嬫柟绫虫瘡绉�', 'm鲁/s', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2065, 35, '鍏枻姣忕', 'kg/s', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2066, 36, '杞瘡鍒嗛挓', 'r/min', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2067, 37, '鍚ㄦ瘡灏忔椂', 't/h', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2068, 38, '鍗冨崱姣忓皬鏃�', 'KCL/h', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2069, 39, '鍗囨瘡绉�', 'L/s', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2070, 40, '鍏嗗笗', 'MPa', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2071, 41, '绔嬫柟绫虫瘡灏忔椂', 'm鲁/h', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2072, 42, '鍗冧箯鏃�', 'kvarh', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2073, 43, '寰厠姣忓崌', '渭g/L', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2074, 44, '鍗冨崱璺噷', 'kcal', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2075, 45, '鍚夊瓧鑺�', 'GB', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2076, 46, '鍏嗗瓧鑺�', 'MB', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2077, 47, '鍗冨瓧鑺�', 'KB', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2078, 48, '瀛楄妭', 'B', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2079, 49, '寰厠姣忓钩鏂瑰垎绫虫瘡澶�', '渭g/(d銕÷穌)', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2080, 50, '鏃�', '', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2081, 51, '鐧句竾鍒嗙巼', 'ppm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2082, 52, '鍍忕礌', 'pixel', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2083, 53, '鐓у害', 'Lux', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2084, 54, '閲嶅姏鍔犻�熷害', 'grav', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2085, 55, '鍒嗚礉', 'dB', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2086, 56, '鐧惧垎姣�', '%', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2087, 57, '娴佹槑', 'lm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2088, 58, '姣旂壒', 'bit', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2089, 59, '鍏嬫瘡姣崌', 'g/mL', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2090, 60, '鍏嬫瘡鍗�', 'g/L', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2091, 61, '姣厠姣忓崌', 'mg/L', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2092, 62, '寰厠姣忕珛鏂圭背', '渭g/m鲁', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2093, 63, '姣厠姣忕珛鏂圭背', 'mg/m鲁', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2094, 64, '鍏嬫瘡绔嬫柟绫�', 'g/m鲁', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2095, 65, '鍗冨厠姣忕珛鏂圭背', 'kg/m鲁', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2096, 66, '绾虫硶', 'nF', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2097, 67, '鐨硶', 'pF', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2098, 68, '寰硶', '渭F', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2099, 69, '娉曟媺', 'F', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2100, 70, '娆у', '惟', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2101, 71, '寰畨', '渭A', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2102, 72, '姣畨', 'mA', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2103, 73, '鍗冨畨', 'kA', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2104, 74, '瀹夊煿', 'A', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2105, 75, '姣紡', 'mV', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2106, 76, '浼忕壒', 'V', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2107, 77, '姣', 'ms', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2108, 78, '绉�', 's', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2109, 79, '鍒嗛挓', 'min', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2110, 80, '灏忔椂', 'h', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2111, 81, '鏃�', 'day', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2112, 82, '鍛�', 'week', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2113, 83, '鏈�', 'month', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2114, 84, '骞�', 'year', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2115, 85, '鑺�', 'kn', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2116, 86, '鍗冪背姣忓皬鏃�', 'km/h', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2117, 87, '绫虫瘡绉�', 'm/s', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2118, 88, '瑙掔', '鈥�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2119, 89, '鍒�', '鈥�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2120, 90, '搴�', '掳', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2121, 91, '寮у害', 'rad', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2122, 92, '璧吂', 'Hz', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2123, 93, '寰摝', '渭W', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2124, 94, '姣摝', 'mW', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2125, 95, '鍗冪摝鐗�', 'kW', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2126, 96, '鐡︾壒', 'W', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2127, 97, '鍗¤矾閲�', 'cal', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2128, 98, '鍗冪摝鏃�', 'kW路h', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2129, 99, '鐡︽椂', 'Wh', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2130, 100, '鐢靛瓙浼�', 'eV', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2131, 101, '鍗冪劍', 'kJ', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2132, 102, '鐒﹁��', 'J', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2133, 103, '鍗庢皬搴�', '鈩�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2134, 104, '寮�灏旀枃', 'K', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2135, 105, '鍚�', 't', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2136, 106, '鎽勬皬搴�', '掳C', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2137, 107, '姣笗', '1e-3Pa', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2138, 108, '鐧惧笗', 'hPa', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2139, 109, '鍗冨笗', 'kPa', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2140, 110, '甯曟柉鍗�', 'Pa', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2141, 111, '姣厠', 'mg', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2142, 112, '鍏�', 'g', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2143, 113, '鍗冨厠', 'kg', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2144, 114, '鐗�', 'N', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2145, 115, '姣崌', 'mL', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2146, 116, '鍗�', 'L', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2147, 117, '绔嬫柟姣背', 'mm鲁', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2148, 118, '绔嬫柟鍘樼背', 'cm鲁', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2149, 119, '绔嬫柟鍗冪背', 'km鲁', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2150, 120, '绔嬫柟绫�', 'm鲁', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2151, 121, '鍏》', 'h銕�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2152, 122, '骞虫柟鍘樼背', 'c銕�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2153, 123, '骞虫柟姣背', 'm銕�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2154, 124, '骞虫柟鍗冪背', 'k銕�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2155, 125, '骞虫柟绫�', '銕�', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2156, 126, '绾崇背', 'nm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2157, 127, '寰背', '渭m', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2158, 128, '姣背', 'mm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2159, 129, '鍘樼背', 'cm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2160, 130, '鍒嗙背', 'dm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2161, 131, '鍗冪背', 'km', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2162, 132, '绫�', 'm', 'iot_thing_model_unit', 0, '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2165, 1, 'HTTP', '1', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:39:54', '1', '2025-06-24 12:44:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2166, 2, 'TCP', '2', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:40:06', '1', '2025-06-24 12:44:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2167, 3, 'WebSocket', '3', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:40:24', '1', '2025-06-24 12:44:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2168, 10, 'MQTT', '10', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:40:37', '1', '2025-06-24 12:44:44', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2169, 20, 'Database', '20', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:05', '1', '2025-06-24 12:44:44', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2170, 21, 'Redis Stream', '21', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:18', '1', '2025-06-24 12:44:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2171, 30, 'RocketMQ', '30', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:30', '1', '2025-06-24 12:44:42', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2172, 31, 'RabbitMQ', '31', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:47', '1', '2025-06-24 12:44:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2173, 32, 'Kafka', '32', 'iot_data_sink_type_enum', 0, 'default', '', '', '1', '2025-03-09 12:41:59', '1', '2025-06-24 12:44:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2174, 1, '璁惧涓婁笅绾垮彉鏇�', '1', 'iot_rule_scene_trigger_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:00:01', '"1"', '2025-07-06 10:28:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2175, 2, '鐗╂ā鍨嬪睘鎬т笂鎶�', '2', 'iot_rule_scene_trigger_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:00:09', '"1"', '2025-07-06 10:28:22', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2176, 1, '璁惧鐘舵��', 'state', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:24:58', '1', '2025-03-20 15:24:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2177, 2, '璁惧灞炴��', 'property', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:25:09', '1', '2025-03-20 15:25:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2178, 3, '璁惧浜嬩欢', 'event', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:25:23', '1', '2025-03-20 15:25:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2179, 4, '璁惧鏈嶅姟', 'service', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:25:39', '1', '2025-03-20 15:25:39', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2180, 5, '璁惧閰嶇疆', 'config', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:25:51', '1', '2025-03-20 15:25:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2181, 6, '璁惧 OTA', 'ota', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:26:17', '1', '2025-03-20 15:26:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2182, 7, '璁惧娉ㄥ唽', 'register', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:26:35', '1', '2025-03-20 15:26:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2183, 8, '璁惧鎷撴墤', 'topology', 'iot_device_message_type_enum', 0, 'primary', '', '', '1', '2025-03-20 15:26:46', '1', '2025-03-20 15:26:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2184, 1, '璁惧灞炴�ц缃�', '1', 'iot_rule_scene_action_type_enum', 0, 'primary', '', '', '1', '2025-03-28 15:27:12', '"1"', '2025-07-06 10:37:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2185, 2, '璁惧鏈嶅姟璋冪敤', '2', 'iot_rule_scene_action_type_enum', 0, 'primary', '', '', '1', '2025-03-28 15:27:25', '"1"', '2025-07-06 10:37:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (2186, 100, '鍛婅瑙﹀彂', '100', 'iot_rule_scene_action_type_enum', 0, 'primary', '', '', '1', '2025-03-28 15:27:35', '"1"', '2025-07-06 10:37:50', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3000, 16, '鐧惧窛鏅鸿兘', 'BaiChuan', 'ai_platform', 0, '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3001, 40, 'Vben5.0 Ant Design Schema 妯$増', '40', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-09-04 23:25:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3002, 6, '鏀粯瀹濅綑棰�', '6', 'brokerage_withdraw_type', 0, '', '', 'API 鎵撴', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3004, 3, 'WARN', '3', 'iot_alert_level', 0, 'warning', '', '', '1', '2025-06-27 20:32:22', '1', '2025-06-27 20:34:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3005, 1, 'INFO', '1', 'iot_alert_level', 0, 'primary', '', '', '1', '2025-06-27 20:33:28', '1', '2025-06-27 20:34:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3006, 5, 'ERROR', '5', 'iot_alert_level', 0, 'danger', '', '', '1', '2025-06-27 20:33:50', '1', '2025-06-27 20:33:50', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3007, 1, '鐭俊', '1', 'iot_alert_receive_type', 0, '', '', '', '1', '2025-06-27 22:49:30', '1', '2025-06-27 22:49:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3008, 2, '閭', '2', 'iot_alert_receive_type', 0, '', '', '', '1', '2025-06-27 22:49:39', '1', '2025-06-27 22:50:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3009, 3, '绔欏唴淇�', '3', 'iot_alert_receive_type', 0, '', '', '', '1', '2025-06-27 22:50:20', '1', '2025-06-27 22:50:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3010, 1, '鍏ㄩ儴璁惧', '1', 'iot_ota_task_device_scope', 0, '', '', '', '1', '2025-07-02 09:43:09', '1', '2025-07-02 09:43:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3011, 2, '鎸囧畾璁惧', '2', 'iot_ota_task_device_scope', 0, '', '', '', '1', '2025-07-02 09:43:15', '1', '2025-07-02 09:43:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3012, 10, '杩涜涓�', '10', 'iot_ota_task_status', 0, 'primary', '', '', '1', '2025-07-02 09:44:01', '"1"', '2025-07-02 09:44:21', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3013, 20, '宸茬粨鏉�', '20', 'iot_ota_task_status', 0, 'success', '', '', '1', '2025-07-02 09:44:14', '"1"', '2025-07-02 23:56:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3014, 30, '宸插彇娑�', '30', 'iot_ota_task_status', 0, 'danger', '', '', '1', '2025-07-02 09:44:36', '1', '2025-07-02 09:44:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3015, 0, '寰呮帹閫�', '0', 'iot_ota_task_record_status', 0, '', '', '', '1', '2025-07-02 09:45:16', '1', '2025-07-02 09:45:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3016, 10, '宸叉帹閫�', '10', 'iot_ota_task_record_status', 0, '', '', '', '1', '2025-07-02 09:45:25', '1', '2025-07-02 09:45:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3017, 20, '鍗囩骇涓�', '20', 'iot_ota_task_record_status', 0, 'primary', '', '', '1', '2025-07-02 09:45:37', '1', '2025-07-02 09:45:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3018, 30, '鍗囩骇鎴愬姛', '30', 'iot_ota_task_record_status', 0, 'success', '', '', '1', '2025-07-02 09:45:47', '1', '2025-07-02 09:45:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3019, 40, '鍗囩骇澶辫触', '40', 'iot_ota_task_record_status', 0, 'danger', '', '', '1', '2025-07-02 09:46:02', '1', '2025-07-02 09:46:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3020, 50, '鍗囩骇鍙栨秷', '50', 'iot_ota_task_record_status', 0, 'warning', '', '', '1', '2025-07-02 09:46:09', '"1"', '2025-07-02 09:46:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3024, 3, '璁惧浜嬩欢涓婃姤', '3', 'iot_rule_scene_trigger_type_enum', 0, '', '', '', '1', '2025-07-06 10:28:29', '1', '2025-07-06 10:28:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3025, 4, '璁惧鏈嶅姟璋冪敤', '4', 'iot_rule_scene_trigger_type_enum', 0, '', '', '', '1', '2025-07-06 10:28:35', '1', '2025-07-06 10:28:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3026, 100, '瀹氭椂瑙﹀彂', '100', 'iot_rule_scene_trigger_type_enum', 0, '', '', '', '1', '2025-07-06 10:28:48', '1', '2025-07-06 10:28:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3027, 101, '鍛婅鎭㈠', '101', 'iot_rule_scene_action_type_enum', 0, '', '', '', '1', '2025-07-06 10:37:57', '1', '2025-07-06 10:37:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3028, 2, 'Anthropic', 'Anthropic', 'ai_platform', 0, '', '', '', '1', '2025-08-21 22:54:24', '1', '2025-08-21 22:57:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3029, 2, '璋锋瓕 Gemini', 'Gemini', 'ai_platform', 0, '', '', '', '1', '2025-08-22 22:39:35', '1', '2025-08-22 22:44:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3030, 1, '鏂囦欢绯荤粺', 'filesystem', 'ai_mcp_client_name', 0, '', '', '', '1', '2025-08-28 13:58:43', '1', '2025-08-28 21:19:42', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3031, 41, 'Vben5.0 Ant Design 鏍囧噯妯$増', '41', 'infra_codegen_front_type', 0, '', '', '', '1', '2025-09-04 23:26:07', '1', '2025-09-04 23:26:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3032, 50, 'Vben5.0 Element Plus Schema 妯$増', '50', 'infra_codegen_front_type', 0, '', '', '', '1', '2025-09-04 23:26:38', '1', '2025-09-04 23:26:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3033, 51, 'Vben5.0 Element Plus 鏍囧噯妯$増', '51', 'infra_codegen_front_type', 0, '', '', '', '1', '2025-09-04 23:26:49', '1', '2025-09-04 23:26:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '鏀粯瀹濆皬绋嬪簭', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3036, 60, 'Admin Uniapp 绉诲姩绔�', '60', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-12-16 19:25:51', '1', '2025-12-17 09:46:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3037, 42, 'Vben5.0 Antdv Next Schema 妯$増', '42', 'infra_codegen_front_type', 0, '', '', '', '1', '2026-05-23 13:52:25', '1', '2026-05-23 13:52:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3038, 43, 'Vben5.0 Antdv Next 鏍囧噯妯$増', '43', 'infra_codegen_front_type', 0, '', '', '', '1', '2026-05-23 13:52:25', '1', '2026-05-23 13:52:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3040, 1, 'UDP', 'udp', 'iot_protocol_type', 0, '', '', 'UDP 鍗忚', '1', '2026-02-04 00:32:47', '1', '2026-02-04 00:32:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3041, 2, 'WebSocket', 'websocket', 'iot_protocol_type', 0, '', '', 'WebSocket 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3042, 3, 'HTTP', 'http', 'iot_protocol_type', 0, '', '', 'HTTP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3043, 4, 'MQTT', 'mqtt', 'iot_protocol_type', 0, 'success', '', 'MQTT 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3044, 5, 'EMQX', 'emqx', 'iot_protocol_type', 0, 'success', '', 'EMQX 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3045, 6, 'CoAP', 'coap', 'iot_protocol_type', 0, '', '', 'CoAP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3046, 7, 'Modbus TCP Server', 'modbus_tcp_server', 'iot_protocol_type', 0, '', '', 'Modbus TCP Server 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-12 15:16:45', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3047, 0, 'JSON', 'json', 'iot_serialize_type', 0, 'success', '', 'JSON 鏍煎紡', '1', '2026-02-04 00:33:19', '1', '2026-02-04 00:33:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3048, 1, '浜岃繘鍒�', 'binary', 'iot_serialize_type', 0, 'warning', '', '浜岃繘鍒舵牸寮�', '1', '2026-02-04 00:33:19', '1', '2026-02-04 00:33:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3049, 8, 'Modbus TCP Client', 'modbus_tcp_client', 'iot_protocol_type', 0, '', '', 'Modbus TCP Client 鍗忚', '1', '2026-02-08 18:29:46', '1', '2026-02-12 15:16:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3050, 2, '杈圭紭閲囬泦', '2', 'iot_modbus_mode', 0, 'success', '', '璁惧涓诲姩涓婃姤鏁版嵁锛屾棤闇�杞', '1', '2025-06-12 22:56:06', '1', '2026-02-09 13:03:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3051, 1, 'Modbus TCP', '1', 'iot_modbus_frame_format', 0, 'default', '', 'MBAP 澶撮儴鏍煎紡', '1', '2025-06-12 22:56:06', '1', '2025-06-12 22:56:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3052, 2, 'Modbus RTU', '2', 'iot_modbus_frame_format', 0, 'warning', '', 'CRC16 鏍¢獙鏍煎紡', '1', '2025-06-12 22:56:06', '1', '2025-06-12 22:56:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3053, 1, '浜戠杞', '1', 'iot_modbus_mode', 0, 'primary', '', '缃戝叧涓诲姩杞璇诲彇璁惧瀵勫瓨鍣�', '1', '2025-06-12 22:56:06', '1', '2025-06-12 22:56:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3054, 1, '浼佷笟瀹㈡埛', '1', 'mes_client_type', 0, 'primary', '', '', '1', '2026-02-15 14:38:25', '1', '2026-02-15 14:38:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3055, 2, '涓汉', '2', 'mes_client_type', 0, 'success', '', '', '1', '2026-02-15 14:38:25', '1', '2026-02-15 14:38:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3056, 1, '浼樿川渚涘簲鍟�', 'A', 'mes_vendor_level', 0, 'success', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3057, 2, '姝e父', 'B', 'mes_vendor_level', 0, 'primary', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3058, 3, '閲嶇偣鍏虫敞', 'C', 'mes_vendor_level', 0, 'warning', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3059, 4, '鍔h川渚涘簲鍟�', 'D', 'mes_vendor_level', 0, 'danger', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3060, 5, '榛戝悕鍗�', 'E', 'mes_vendor_level', 0, 'info', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3061, 1, '鍋囨湡', '2', 'mes_cal_holiday_type', 0, 'success', '', '', '1', '2026-02-16 07:35:58', '1', '2026-02-16 11:20:42', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3062, 2, '宸ヤ綔鏃�', '1', 'mes_cal_holiday_type', 0, 'primary', '', '', '1', '2026-02-16 07:35:58', '1', '2026-02-16 11:20:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3063, 1, '鍦ㄥ簱', '1', 'mes_tm_tool_status', 0, 'success', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3064, 2, '棰嗙敤涓�', '2', 'mes_tm_tool_status', 0, 'primary', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3065, 3, '缁翠慨涓�', '3', 'mes_tm_tool_status', 0, 'warning', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3066, 4, '鎶ュ簾', '4', 'mes_tm_tool_status', 0, 'danger', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3067, 1, '瀹氭湡缁存姢', '1', 'mes_tm_mainten_type', 0, 'primary', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3068, 2, '鎸変娇鐢ㄦ鏁扮淮鎶�', '2', 'mes_tm_mainten_type', 0, 'success', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3069, 1, '鍋滄満', '1', 'mes_dv_machinery_status', 0, 'success', '', '', '1', '2026-02-17 01:00:06', '1', '2026-02-17 03:28:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3070, 2, '鐢熶骇涓�', '2', 'mes_dv_machinery_status', 0, 'info', '', '', '1', '2026-02-17 01:00:06', '1', '2026-02-17 03:28:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3071, 3, '缁存姢涓�', '3', 'mes_dv_machinery_status', 0, 'danger', '', '', '1', '2026-02-17 01:00:06', '1', '2026-02-17 03:28:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3072, 1, '灏哄', '1', 'mes_indicator_type', 0, '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3073, 2, '澶栬', '2', 'mes_indicator_type', 0, '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3074, 3, '閲嶉噺', '3', 'mes_indicator_type', 0, '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3075, 4, '鎬ц兘', '4', 'mes_indicator_type', 0, '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3076, 5, '鎴愬垎', '5', 'mes_indicator_type', 0, '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3077, 1, '鑷村懡缂洪櫡', '1', 'mes_defect_level', 0, 'danger', '', '', '1', '2026-02-17 02:18:18', '1', '2026-02-21 12:21:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3078, 2, '涓ラ噸缂洪櫡', '2', 'mes_defect_level', 0, 'warning', '', '', '1', '2026-02-17 02:18:18', '1', '2026-02-21 12:21:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3079, 3, '杞诲井缂洪櫡', '3', 'mes_defect_level', 0, 'info', '', '', '1', '2026-02-17 02:18:18', '1', '2026-02-21 12:21:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3080, 1, '鍗曠櫧鐝�', '1', 'mes_cal_shift_type', 0, 'primary', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3081, 2, '涓ょ彮鍊�', '2', 'mes_cal_shift_type', 0, 'success', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3082, 3, '涓夌彮鍊�', '3', 'mes_cal_shift_type', 0, 'warning', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3083, 1, '鎸夊搴�', '1', 'mes_cal_shift_method', 0, '', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3084, 2, '鎸夋湀', '2', 'mes_cal_shift_method', 0, '', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3085, 3, '鎸夊懆', '3', 'mes_cal_shift_method', 0, '', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3086, 4, '鎸夊ぉ', '4', 'mes_cal_shift_method', 0, '', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3089, 0, '鑽夌', '0', 'mes_cal_plan_status', 0, 'info', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3090, 1, '宸茬‘璁�', '1', 'mes_cal_plan_status', 0, 'success', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3100, 0, '鑽夌', '0', 'mes_pro_work_order_status', 0, 'info', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3101, 1, '宸茬‘璁�', '1', 'mes_pro_work_order_status', 0, 'primary', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3102, 2, '宸插畬鎴�', '2', 'mes_pro_work_order_status', 0, 'success', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3103, 3, '宸插彇娑�', '3', 'mes_pro_work_order_status', 0, 'warning', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3104, 1, '瀹㈡埛璁㈠崟', '1', 'mes_pro_work_order_source_type', 0, 'primary', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3105, 2, '搴撳瓨澶囪揣', '2', 'mes_pro_work_order_source_type', 0, 'success', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3106, 1, '鑷鐢熶骇', '1', 'mes_pro_work_order_type', 0, 'primary', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3107, 2, '浠e伐', '2', 'mes_pro_work_order_type', 0, 'warning', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3108, 3, '閲囪喘', '3', 'mes_pro_work_order_type', 0, 'info', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3121, 1, 'IQC锛堟潵鏂欐楠岋級', '1', 'mes_qc_type', 0, 'primary', '', '鏉ユ枡璐ㄩ噺妫�楠�', '1', '2026-02-18 14:12:05', '1', '2026-02-18 14:12:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3122, 2, 'IPQC锛堣繃绋嬫楠岋級', '2', 'mes_qc_type', 0, 'warning', '', '鐢熶骇鍒剁▼璐ㄩ噺妫�楠�', '1', '2026-02-18 14:12:05', '1', '2026-03-24 15:21:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3123, 3, 'OQC锛堝嚭璐ф楠岋級', '3', 'mes_qc_type', 0, 'success', '', '鍑鸿揣璐ㄩ噺妫�楠�', '1', '2026-02-18 14:12:05', '1', '2026-02-18 14:12:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3124, 4, 'RQC锛堥��鏂欐楠岋級', '4', 'mes_qc_type', 0, 'danger', '', '閫�璐ц川閲忔楠�', '1', '2026-02-18 14:12:05', '1', '2026-03-24 15:22:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3125, 0, '寮�濮�-寮�濮�(SS)', '0', 'mes_pro_link_type', 0, 'default', '', '鍓嶅簭寮�濮嬪悗锛屽悗搴忓彲浠ュ紑濮�', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3126, 1, '缁撴潫-缁撴潫(FF)', '1', 'mes_pro_link_type', 0, 'default', '', '鍓嶅簭缁撴潫鍚庯紝鍚庡簭鎵嶈兘缁撴潫', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3127, 2, '寮�濮�-缁撴潫(SF)', '2', 'mes_pro_link_type', 0, 'default', '', '鍓嶅簭寮�濮嬪悗锛屽悗搴忔墠鑳界粨鏉�', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3128, 3, '缁撴潫-寮�濮�(FS)', '3', 'mes_pro_link_type', 0, 'default', '', '鍓嶅簭缁撴潫鍚庯紝鍚庡簭鎵嶈兘寮�濮�', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3129, 1, '鍒嗛挓', 'MINUTE', 'mes_time_unit_type', 0, 'default', '', '', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3130, 2, '灏忔椂', 'HOUR', 'mes_time_unit_type', 0, 'default', '', '', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3131, 3, '澶�', 'DAY', 'mes_time_unit_type', 0, 'default', '', '', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3137, 1, '璁惧鐐规', '1', 'mes_dv_subject_type', 0, 'info', '', '', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3138, 2, '璁惧淇濆吇', '2', 'mes_dv_subject_type', 0, 'success', '', '', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3139, 1, '寰呬繚鍏�', '0', 'mes_mainten_record_status', 0, 'info', '', NULL, 'admin', '2026-02-20 02:59:55', '1', '2026-04-16 05:32:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3140, 2, '宸插畬鎴�', '4', 'mes_mainten_record_status', 0, 'success', '', NULL, 'admin', '2026-02-20 02:59:55', '1', '2026-04-16 05:32:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3141, 1, '姝e父', '1', 'mes_mainten_status', 0, 'success', '', NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3142, 2, '寮傚父', '0', 'mes_mainten_status', 0, 'danger', '', NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3143, 1, '澶�', '1', 'mes_dv_cycle_type', 0, 'default', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3144, 2, '鍛�', '2', 'mes_dv_cycle_type', 0, 'default', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3145, 3, '鏈�', '3', 'mes_dv_cycle_type', 0, 'default', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3146, 4, '骞�', '4', 'mes_dv_cycle_type', 0, 'default', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3147, 0, '鑽夌', '0', 'mes_dv_check_plan_status', 0, 'info', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3148, 1, '宸插惎鐢�', '1', 'mes_dv_check_plan_status', 0, 'success', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3149, 1, '寰呯偣妫�', '10', 'mes_dv_check_record_status', 0, 'info', '', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3150, 2, '宸插畬鎴�', '20', 'mes_dv_check_record_status', 0, 'success', '', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3151, 1, '姝e父', '1', 'mes_dv_check_result', 0, 'success', '', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3152, 2, '寮傚父', '2', 'mes_dv_check_result', 0, 'danger', '', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3157, 1, '淇鎴愬姛', '1', 'mes_dv_repair_result', 0, 'success', '', '', '1', '2026-02-20 10:56:24', '1', '2026-02-20 10:56:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3158, 2, '鎶ュ簾', '2', 'mes_dv_repair_result', 0, 'danger', '', '', '1', '2026-02-20 10:56:24', '1', '2026-02-20 10:56:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3161, 1, '鏍¢獙閫氳繃', '1', 'mes_qc_check_result', 0, 'success', '', '', '1', '2026-02-20 11:23:35', '1', '2026-02-20 16:15:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3162, 2, '鏍¢獙涓嶉�氳繃', '2', 'mes_qc_check_result', 0, 'danger', '', '', '1', '2026-02-20 11:23:35', '1', '2026-02-20 16:15:52', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3166, 0, '鏈缃�', '0', 'mes_pro_andon_status', 0, 'danger', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3167, 1, '宸插缃�', '1', 'mes_pro_andon_status', 0, 'success', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3168, 1, '涓�绾�', '1', 'mes_pro_andon_level', 0, 'danger', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3169, 2, '浜岀骇', '2', 'mes_pro_andon_level', 0, 'warning', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3170, 3, '涓夌骇', '3', 'mes_pro_andon_level', 0, 'info', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3171, 0, '鑽夌', '0', 'mes_pro_feedback_status', 0, 'info', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3172, 2, '瀹℃壒涓�', '2', 'mes_pro_feedback_status', 0, 'primary', '', '', '1', '2026-02-21 00:50:32', '1', '2026-03-19 00:51:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3173, 3, '寰呮楠�', '3', 'mes_pro_feedback_status', 0, 'warning', '', '', '1', '2026-02-21 00:50:32', '1', '2026-03-19 00:51:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3174, 4, '宸插畬鎴�', '4', 'mes_pro_feedback_status', 0, 'success', '', '', '1', '2026-02-21 00:50:32', '1', '2026-03-19 00:51:54', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3176, 1, '鑷鎶ュ伐', '1', 'mes_pro_feedback_type', 0, 'primary', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3177, 2, '缁熶竴鎶ュ伐', '2', 'mes_pro_feedback_type', 0, 'success', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3178, 1, 'PC', 'PC', 'mes_pro_feedback_channel', 0, 'primary', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3179, 2, 'APP', 'APP', 'mes_pro_feedback_channel', 0, 'success', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3180, 3, 'PDA', 'PDA', 'mes_pro_feedback_channel', 0, 'info', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3181, 1, '娴偣', '1', 'mes_qc_result_type', 0, 'primary', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3182, 2, '鏁存暟', '2', 'mes_qc_result_type', 0, 'success', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3183, 3, '鏂囨湰', '3', 'mes_qc_result_type', 0, 'info', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3184, 4, '瀛楀吀', '4', 'mes_qc_result_type', 0, 'warning', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3185, 5, '鏂囦欢', '5', 'mes_qc_result_type', 0, 'danger', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3186, 1, '鐢熶骇閫�鏂�', '1', 'mes_rqc_type', 0, 'default', '', '鐢熶骇閫�鏂欐楠�', '1', '2026-02-22 06:44:09', '1', '2026-02-22 06:44:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3187, 2, '閿�鍞��璐�', '2', 'mes_rqc_type', 0, 'default', '', '閿�鍞��璐ф楠�', '1', '2026-02-22 06:44:09', '1', '2026-02-22 06:44:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3188, 1, '鑷埗宸ュ簭妫�楠�', '1', 'mes_ipqc_type', 0, 'primary', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3189, 2, '棣栨', '2', 'mes_ipqc_type', 0, 'success', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3190, 3, '宸℃', '3', 'mes_ipqc_type', 0, 'warning', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3191, 4, '鑷', '4', 'mes_ipqc_type', 0, 'info', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3192, 5, '鎴愬搧妫�楠�', '5', 'mes_ipqc_type', 0, 'danger', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3205, 0, '鑽夌', '0', 'mes_wm_arrival_notice_status', 0, 'info', '', '', '1', '2026-02-22 14:53:18', '1', '2026-02-22 14:53:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3206, 2, '寰呰川妫�', '2', 'mes_wm_arrival_notice_status', 0, 'warning', '', '', '1', '2026-02-22 14:53:18', '1', '2026-02-26 05:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3207, 3, '寰呭叆搴�', '3', 'mes_wm_arrival_notice_status', 0, 'success', '', '', '1', '2026-02-22 14:53:18', '1', '2026-02-26 05:24:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3208, 4, '宸插畬鎴�', '4', 'mes_wm_arrival_notice_status', 0, 'primary', '', '', '1', '2026-02-22 14:53:18', '1', '2026-02-26 05:24:52', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3209, 0, '鑽夌', '0', 'mes_wm_item_receipt_status', 0, 'info', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-22 14:54:05', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3210, 1, '寰呬笂鏋�', '2', 'mes_wm_item_receipt_status', 0, 'warning', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-26 08:03:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3211, 2, '寰呮墽琛屽叆搴�', '3', 'mes_wm_item_receipt_status', 0, 'success', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-26 08:03:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3212, 3, '宸插畬鎴�', '4', 'mes_wm_item_receipt_status', 0, 'primary', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-26 08:03:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3213, 4, '宸插彇娑�', '5', 'mes_wm_item_receipt_status', 0, 'danger', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-26 08:03:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3214, 1, '鑽夌', '0', 'mes_order_status', 0, 'info', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3215, 2, '宸茬‘璁�', '1', 'mes_order_status', 0, 'primary', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3216, 3, '瀹℃壒涓�', '2', 'mes_order_status', 0, 'warning', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3217, 4, '宸插鎵�', '3', 'mes_order_status', 0, 'success', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3218, 5, '宸插畬鎴�', '4', 'mes_order_status', 0, 'success', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3219, 6, '宸插彇娑�', '5', 'mes_order_status', 0, 'danger', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3220, 1, '鑽夌', '0', 'mes_wm_issue_status', 0, 'info', '', '鑽夌鐘舵�侊紝鏈畬鎴�', '1', '2026-02-26 15:54:25', '1', '2026-02-26 15:54:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3221, 2, '宸插畬鎴�', '4', 'mes_wm_issue_status', 0, 'success', '', '宸插畬鎴愬嚭搴�', '1', '2026-02-26 15:54:25', '1', '2026-02-26 15:54:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3222, 1, '鑽夌', '0', 'mes_wm_product_issue_status', 0, 'info', '', '鑽夌鐘舵�侊紝鍙紪杈�', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3223, 2, '寰呮嫞璐�', '2', 'mes_wm_product_issue_status', 0, 'warning', '', '瀹℃壒涓紝鍙墽琛屾嫞璐�', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3224, 3, '寰呮墽琛岄鍑�', '3', 'mes_wm_product_issue_status', 0, 'primary', '', '宸插鎵癸紝鎷h揣瀹屾垚', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3225, 4, '宸插畬鎴�', '4', 'mes_wm_product_issue_status', 0, 'success', '', '宸插畬鎴愬嚭搴�', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3226, 5, '宸插彇娑�', '5', 'mes_wm_product_issue_status', 0, 'success', '', '宸插畬鎴愬嚭搴�', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3232, 1, '鑽夌', '0', 'mes_wm_return_issue_status', 0, 'info', '', '鑽夌鐘舵�侊紝鍙紪杈�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:24', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3233, 2, '寰呮楠�', '1', 'mes_wm_return_issue_status', 0, 'default', '', '宸茬‘璁わ紝绛夊緟璐ㄦ', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3234, 3, '寰呬笂鏋�', '2', 'mes_wm_return_issue_status', 0, 'warning', '', '妫�楠屽畬鎴愶紝绛夊緟浠撳簱涓婃灦', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3235, 4, '寰呮墽琛岄��鏂�', '3', 'mes_wm_return_issue_status', 0, 'primary', '', '涓婃灦瀹屾垚锛岀瓑寰呮墽琛岄��鏂欐搷浣�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3236, 5, '宸插畬鎴�', '4', 'mes_wm_return_issue_status', 0, 'success', '', '閫�鏂欐墽琛屽畬鎴愶紝搴撳瓨宸叉洿鏂�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:37', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3237, 6, '宸插彇娑�', '5', 'mes_wm_return_issue_status', 0, 'danger', '', '宸插彇娑�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3238, 1, '浣欐枡閫�鏂�', '1', 'mes_wm_return_issue_type', 0, 'success', '', '浣欐枡閫�鍥烇紝鐩存帴鍚堟牸', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:27:47', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3239, 2, '涓嶈壇閫�鏂�', '2', 'mes_wm_return_issue_type', 0, 'danger', '', '涓嶈壇鍝侀��鍥�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:27:49', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3240, 3, '鍏朵粬閫�鏂�', '3', 'mes_wm_return_issue_type', 0, 'info', '', '鍏朵粬鍘熷洜閫�鏂�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:27:55', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3241, 1, '寰呮', '0', 'mes_wm_quality_status', 0, 'warning', '', '寰呮鐘舵��', '1', '2026-02-28 15:00:53', '1', '2026-02-28 15:00:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3242, 2, '鍚堟牸', '1', 'mes_wm_quality_status', 0, 'success', '', '鍚堟牸鐘舵��', '1', '2026-02-28 15:00:53', '1', '2026-02-28 15:00:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3243, 3, '涓嶅悎鏍�', '2', 'mes_wm_quality_status', 0, 'danger', '', '涓嶅悎鏍肩姸鎬�', '1', '2026-02-28 15:00:53', '1', '2026-02-28 15:00:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3244, 1, '鑽夌', '0', 'mes_wm_product_receipt_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3245, 2, '寰呬笂鏋�', '2', 'mes_wm_product_receipt_status', 0, 'primary', '', '寰呬笂鏋�', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3246, 3, '寰呮墽琛屽叆搴�', '3', 'mes_wm_product_receipt_status', 0, 'warning', '', '寰呮墽琛屽叆搴�', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3247, 4, '宸插畬鎴�', '4', 'mes_wm_product_receipt_status', 0, 'success', '', '宸插畬鎴�', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3248, 5, '宸插彇娑�', '5', 'mes_wm_product_receipt_status', 0, 'danger', '', '宸插彇娑�', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3252, 1, '鑽夌', '0', 'mes_wm_product_sales_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-03-02 08:55:11', '1', '2026-03-02 08:55:11', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3253, 3, '寰呮嫞璐�', '2', 'mes_wm_product_sales_status', 0, 'warning', '', '寰呮嫞璐х姸鎬�', '1', '2026-03-02 08:55:11', '1', '2026-03-27 11:44:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3254, 4, '寰呭嚭搴�', '3', 'mes_wm_product_sales_status', 0, 'primary', '', '寰呭嚭搴撶姸鎬�', '1', '2026-03-02 08:55:11', '1', '2026-03-27 11:44:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3255, 5, '宸插畬鎴�', '4', 'mes_wm_product_sales_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-03-02 08:55:11', '1', '2026-03-27 11:44:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3256, 6, '宸插彇娑�', '5', 'mes_wm_product_sales_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-03-02 08:55:11', '1', '2026-03-27 11:44:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3272, 1, '鑽夌', '0', 'mes_wm_misc_receipt_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-03-03 07:33:41', '1', '2026-03-03 07:33:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3273, 2, '寰呮墽琛屽叆搴�', '3', 'mes_wm_misc_receipt_status', 0, 'primary', '', '寰呮墽琛屽叆搴撶姸鎬�', '1', '2026-03-03 07:33:41', '1', '2026-03-03 07:37:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3274, 3, '宸插畬鎴�', '4', 'mes_wm_misc_receipt_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-03-03 07:33:41', '1', '2026-03-03 07:33:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3275, 4, '宸插彇娑�', '5', 'mes_wm_misc_receipt_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-03-03 07:33:41', '1', '2026-03-03 07:33:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3277, 1, '搴撳瓨璋冩暣', '1', 'mes_wm_misc_receipt_type', 0, 'primary', '', '搴撳瓨璋冩暣鍏ュ簱', '1', '2026-03-03 07:34:33', '1', '2026-03-03 07:34:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3278, 1, '搴撳瓨璋冩暣', '1', 'mes_wm_misc_issue_type', 0, 'primary', '', '搴撳瓨璋冩暣鍑哄簱', '1', '2026-03-03 07:34:33', '1', '2026-03-03 07:34:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3279, 2, '鎶ュ簾鍑哄簱', '2', 'mes_wm_misc_issue_type', 0, 'danger', '', '鎶ュ簾鍑哄簱', '1', '2026-03-03 07:36:13', '1', '2026-03-03 07:36:13', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3280, 1, '鑽夌', '0', 'mes_wm_outsource_receipt_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3281, 2, '寰呮楠�', '1', 'mes_wm_outsource_receipt_status', 0, 'warning', '', '宸茬‘璁わ紝绛夊緟璐ㄦ', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3282, 3, '寰呬笂鏋�', '2', 'mes_wm_outsource_receipt_status', 0, 'primary', '', '妫�楠屽畬鎴愶紝绛夊緟浠撳簱涓婃灦', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3283, 4, '寰呮墽琛屽叆搴�', '3', 'mes_wm_outsource_receipt_status', 0, 'warning', '', '涓婃灦瀹屾垚锛岀瓑寰呮墽琛屽叆搴撴搷浣�', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3284, 5, '宸插畬鎴�', '4', 'mes_wm_outsource_receipt_status', 0, 'success', '', '鍏ュ簱鎵ц瀹屾垚锛屽簱瀛樺凡鏇存柊', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3285, 6, '宸插彇娑�', '5', 'mes_wm_outsource_receipt_status', 0, 'danger', '', '宸插彇娑�', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3286, 1, '鑽夌', '0', 'mes_wm_outsource_issue_status', 0, 'info', '', '鑽夌鐘舵�侊紝鍙紪杈戙�佸垹闄ゃ�佹墽琛屽嚭搴�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3287, 2, '寰呮嫞璐�', '2', 'mes_wm_outsource_issue_status', 0, 'warning', '', '寰呮嫞璐х姸鎬�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3288, 3, '寰呮墽琛屽嚭搴�', '3', 'mes_wm_outsource_issue_status', 0, 'primary', '', '寰呮墽琛屽嚭搴撶姸鎬�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3289, 4, '宸插畬鎴�', '4', 'mes_wm_outsource_issue_status', 0, 'success', '', '宸插畬鎴愶紝搴撳瓨宸叉墸鍑�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3290, 5, '宸插彇娑�', '5', 'mes_wm_outsource_issue_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3301, 1, '杈撳叆瀛楃', '1', 'mes_md_auto_code_part_type', 0, 'default', '', '杈撳叆瀛楃', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3302, 2, '褰撳墠鏃ユ湡', '2', 'mes_md_auto_code_part_type', 0, 'primary', '', '褰撳墠鏃ユ湡鏃堕棿', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3303, 3, '鍥哄畾瀛楃', '3', 'mes_md_auto_code_part_type', 0, 'success', '', '鍥哄畾瀛楃', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3304, 4, '娴佹按鍙�', '4', 'mes_md_auto_code_part_type', 0, 'warning', '', '娴佹按鍙�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3305, 1, '宸﹁ˉ榻�', '1', 'mes_md_auto_code_padded_method', 0, 'primary', '', '宸﹁ˉ榻�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3306, 2, '鍙宠ˉ榻�', '2', 'mes_md_auto_code_padded_method', 0, 'success', '', '鍙宠ˉ榻�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3307, 1, '鎸夊勾', '1', 'mes_md_auto_code_cycle_method', 0, 'default', '', '鎸夊勾寰幆', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3308, 2, '鎸夋湀', '2', 'mes_md_auto_code_cycle_method', 0, 'primary', '', '鎸夋湀寰幆', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3309, 3, '鎸夊ぉ', '3', 'mes_md_auto_code_cycle_method', 0, 'success', '', '鎸夊ぉ寰幆', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3310, 4, '鎸夊皬鏃�', '4', 'mes_md_auto_code_cycle_method', 0, 'warning', '', '鎸夊皬鏃跺惊鐜�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3311, 5, '鎸夊垎閽�', '5', 'mes_md_auto_code_cycle_method', 0, 'danger', '', '鎸夊垎閽熷惊鐜�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3312, 10, '鎸変紶鍏ュ瓧绗�', '10', 'mes_md_auto_code_cycle_method', 0, 'info', '', '鎸変紶鍏ュ瓧绗﹀惊鐜�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3313, 1, '浜岀淮鐮�', '1', 'mes_wm_barcode_format', 0, 'primary', '', 'QR_CODE', '1', '2026-03-05 14:37:20', '1', '2026-03-06 13:18:21', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3314, 2, 'EAN13 鍟嗗搧鏉$爜', '2', 'mes_wm_barcode_format', 0, 'success', '', 'EAN13', '1', '2026-03-05 14:37:20', '1', '2026-03-06 13:18:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3315, 3, 'CODE39 宸ヤ笟鏉$爜', '3', 'mes_wm_barcode_format', 0, 'info', '', 'CODE39', '1', '2026-03-05 14:37:20', '1', '2026-03-06 13:18:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3316, 4, 'UPC-A 缇庡浗鍟嗗搧鐮�', '4', 'mes_wm_barcode_format', 0, 'warning', '', 'UPC_A', '1', '2026-03-05 14:37:20', '1', '2026-03-06 13:18:28', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3318, 3, '搴撲綅', '104', 'mes_wm_barcode_biz_type', 0, 'default', '', 'AREA', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3319, 4, '瑁呯鍗�', '105', 'mes_wm_barcode_biz_type', 0, 'default', '', 'PACKAGE', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3320, 5, '搴撳瓨', '106', 'mes_wm_barcode_biz_type', 0, 'default', '', 'STOCK', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3321, 6, '鎵规', '107', 'mes_wm_barcode_biz_type', 0, 'default', '', 'BATCH', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3322, 7, '娴佽浆鍗�', '300', 'mes_wm_barcode_biz_type', 0, 'primary', '', 'PROCARD', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3323, 8, '宸ュ崟', '301', 'mes_wm_barcode_biz_type', 0, 'primary', '', 'WORKORDER', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3324, 9, '娴佽浆鍗�', '302', 'mes_wm_barcode_biz_type', 0, 'primary', '', 'TRANSORDER', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3325, 10, '璁惧', '400', 'mes_wm_barcode_biz_type', 0, 'success', '', 'MACHINERY', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3327, 12, '浜у搧鐗╂枡', '600', 'mes_wm_barcode_biz_type', 0, 'info', '', 'ITEM', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3328, 13, '渚涘簲鍟�', '601', 'mes_wm_barcode_biz_type', 0, 'info', '', 'VENDOR', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3329, 14, '宸ヤ綔绔�', '602', 'mes_wm_barcode_biz_type', 0, 'info', '', 'WORKSTATION', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3330, 15, '杞﹂棿', '603', 'mes_wm_barcode_biz_type', 0, 'info', '', 'WORKSHOP', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3331, 16, '浜哄憳', '604', 'mes_wm_barcode_biz_type', 0, 'info', '', 'USER', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3351, 1, '浠撳簱', '102', 'mes_wm_barcode_biz_type', 0, '', '', NULL, '', '2026-03-07 06:22:27', '', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3352, 2, '搴撳尯', '103', 'mes_wm_barcode_biz_type', 0, '', '', NULL, '', '2026-03-07 06:22:27', '', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3353, 11, '宸ュ叿', '500', 'mes_wm_barcode_biz_type', 0, '', '', NULL, '', '2026-03-07 06:22:27', '', '2026-03-07 06:22:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3354, 17, '瀹㈡埛', '605', 'mes_wm_barcode_biz_type', 0, '', '', NULL, '', '2026-03-07 06:22:27', '', '2026-03-07 06:25:19', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3355, 1, '鑽夌', '0', 'mes_wm_package_status', 0, 'info', '', '鑽夌鐘舵�侊紝鍙紪杈�', '1', '2026-03-08 02:05:46', '1', '2026-03-08 02:05:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3356, 2, '宸插畬鎴�', '4', 'mes_wm_package_status', 0, 'success', '', '瑁呯宸插畬鎴�', '1', '2026-03-08 02:05:46', '1', '2026-03-08 02:05:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3357, 1, '鑽夌', '0', 'mes_wm_transfer_status', 0, 'info', '', '鑽夌鐘舵�侊紝鍙紪杈�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3358, 2, '寰呯‘璁�', '1', 'mes_wm_transfer_status', 0, 'warning', '', '澶栭儴璋冩嫧寰呯‘璁ゅ埌璐�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3359, 3, '寰呬笂鏋�', '2', 'mes_wm_transfer_status', 0, 'primary', '', '寰呯淮鎶ょ洰鏍囧簱浣嶆槑缁�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3360, 4, '寰呮墽琛�', '3', 'mes_wm_transfer_status', 0, 'success', '', '鐩爣搴撲綅宸插垎閰嶏紝寰呮墽琛岃皟鎷�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3361, 5, '宸插畬鎴�', '4', 'mes_wm_transfer_status', 0, 'success', '', '璋冩嫧宸插畬鎴�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3362, 6, '宸插彇娑�', '5', 'mes_wm_transfer_status', 0, 'danger', '', '璋冩嫧宸插彇娑�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3363, 1, '鍐呴儴璋冩嫧', '1', 'mes_wm_transfer_type', 0, 'success', '', '鍐呴儴浠撳偍璋冩嫧', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3364, 2, '澶栭儴璋冩嫧', '2', 'mes_wm_transfer_type', 0, 'warning', '', '澶栭儴閰嶉��/澶栭儴鏀惰揣璋冩嫧', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3365, 1, '闈欐�佺洏鐐�', '1', 'mes_wm_stock_taking_type', 0, 'primary', '', '闈欐�佺洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3366, 2, '鍔ㄦ�佺洏鐐�', '2', 'mes_wm_stock_taking_type', 0, 'success', '', '鍔ㄦ�佺洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3367, 1, '浠撳簱', '102', 'mes_wm_stock_taking_plan_param_type', 0, 'primary', '', '鎸変粨搴撶洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3368, 2, '搴撳尯', '103', 'mes_wm_stock_taking_plan_param_type', 0, 'success', '', '鎸夊簱鍖虹洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3369, 3, '搴撲綅', '104', 'mes_wm_stock_taking_plan_param_type', 0, 'info', '', '鎸夊簱浣嶇洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3370, 4, '鐗╂枡', '600', 'mes_wm_stock_taking_plan_param_type', 0, 'warning', '', '鎸夌墿鏂欑洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3371, 5, '鎵规', '107', 'mes_wm_stock_taking_plan_param_type', 0, 'danger', '', '鎸夋壒娆$洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3372, 1, '鑽夌', '0', 'mes_wm_stock_taking_task_status', 0, 'info', '', '鑽夌', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3373, 2, '瀹℃壒涓�', '2', 'mes_wm_stock_taking_task_status', 0, 'primary', '', '鐩樼偣浠诲姟瀹℃壒涓�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3374, 3, '宸插畬鎴�', '4', 'mes_wm_stock_taking_task_status', 0, 'success', '', '宸插畬鎴�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3375, 4, '宸插彇娑�', '5', 'mes_wm_stock_taking_task_status', 0, 'danger', '', '宸插彇娑�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3377, 1, '姝e父', '1', 'mes_wm_stock_taking_task_line_status', 0, 'success', '', '姝e父', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3378, 2, '鐩樼泩', '2', 'mes_wm_stock_taking_task_line_status', 0, 'primary', '', '鐩樼泩', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3379, 3, '鐩樹簭', '3', 'mes_wm_stock_taking_task_line_status', 0, 'danger', '', '鐩樹簭', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3380, 6, '璐ㄩ噺鐘舵��', '900', 'mes_wm_stock_taking_plan_param_type', 0, 'default', '', '鎸夎川閲忕姸鎬佺洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3381, 1, '鐗╂枡', 'ITEM', 'mes_md_item_or_product', 0, 'info', '', '', '1', '2026-03-15 01:55:06', '1', '2026-03-15 01:55:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3382, 2, '浜у搧', 'PRODUCT', 'mes_md_item_or_product', 0, 'success', '', '', '1', '2026-03-15 01:55:06', '1', '2026-03-15 01:55:06', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3383, 1, '鑽夌', '0', 'mes_wm_item_consume_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-03-19 15:06:23', '1', '2026-03-19 15:06:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3384, 2, '宸插畬鎴�', '4', 'mes_wm_item_consume_status', 0, 'success', '', '宸插畬鎴�', '1', '2026-03-19 15:06:23', '1', '2026-03-19 15:06:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3385, 1, '鍒拌揣閫氱煡鍗�', '100', 'mes_qc_source_doc_type', 0, 'primary', '', 'IQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3386, 2, '澶栧崗鍏ュ簱鍗�', '121', 'mes_qc_source_doc_type', 0, 'warning', '', 'IQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3387, 3, '鐢熶骇鎶ュ伐', '304', 'mes_qc_source_doc_type', 0, 'success', '', 'IPQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3388, 4, '閿�鍞嚭搴撳崟', '118', 'mes_qc_source_doc_type', 0, 'info', '', 'OQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3389, 5, '鐢熶骇閫�鏂欏崟', '116', 'mes_qc_source_doc_type', 0, 'danger', '', 'RQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3390, 6, '閿�鍞��璐у崟', '119', 'mes_qc_source_doc_type', 0, 'default', '', 'RQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3397, 2, '寰呮娴�', '1', 'mes_wm_product_sales_status', 0, 'warning', '', 'OQC 妫�楠屼腑', '1', '2026-03-27 11:44:48', '1', '2026-03-27 11:44:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3398, 0, '鑽夌', '0', 'mes_wm_return_vendor_status', 0, 'info', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3399, 1, '寰呮嫞璐�', '2', 'mes_wm_return_vendor_status', 0, 'primary', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3400, 2, '寰呮墽琛岄��璐�', '3', 'mes_wm_return_vendor_status', 0, 'warning', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3401, 3, '宸插畬鎴�', '4', 'mes_wm_return_vendor_status', 0, 'success', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3402, 4, '宸插彇娑�', '5', 'mes_wm_return_vendor_status', 0, 'danger', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3403, 1, '鑽夌', '0', 'mes_wm_sales_notice_status', 0, 'info', '', '鑽夌鐘舵�侊紝鍙互淇敼鍜屽垹闄�', '1', '2026-03-30 08:54:30', '1', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3404, 2, '寰呭嚭搴�', '3', 'mes_wm_sales_notice_status', 0, 'success', '', '宸叉彁浜ょ姸鎬侊紝涓嶅彲淇敼鍜屽垹闄�', '1', '2026-03-30 08:54:30', '1', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3405, 3, '宸插畬鎴�', '4', 'mes_wm_sales_notice_status', 0, '', '', NULL, '1', '2026-03-30 10:02:10', '1', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3406, 1, '鑽夌', '0', 'mes_wm_misc_issue_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-03-30 15:00:18', '1', '2026-03-30 15:00:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3407, 2, '寰呭嚭搴�', '3', 'mes_wm_misc_issue_status', 0, 'warning', '', '寰呭嚭搴撶姸鎬�', '1', '2026-03-30 15:00:18', '1', '2026-03-30 15:00:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3408, 3, '宸插畬鎴�', '4', 'mes_wm_misc_issue_status', 0, 'success', '', '鎵ц鍑哄簱鍚庣殑鐘舵��', '1', '2026-03-30 15:00:18', '1', '2026-03-30 15:00:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3409, 4, '宸插彇娑�', '5', 'mes_wm_misc_issue_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-03-30 15:00:18', '1', '2026-03-30 15:00:18', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3415, 1, '娉ㄥ', '1', 'mes_cal_calendar_type', 0, 'primary', '', '', '1', '2026-04-01 15:23:14', '1', '2026-04-01 16:08:31', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3416, 2, '鏈哄姞宸�', '2', 'mes_cal_calendar_type', 0, 'success', '', '', '1', '2026-04-01 15:23:14', '1', '2026-04-01 16:08:32', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3417, 3, '缁勮', '3', 'mes_cal_calendar_type', 0, 'warning', '', '', '1', '2026-04-01 15:23:14', '1', '2026-04-01 16:08:33', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3418, 4, '浠撳簱', '4', 'mes_cal_calendar_type', 0, 'danger', '', '', '1', '2026-04-01 15:23:14', '1', '2026-04-01 16:08:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3419, 0, '鑽夌', '0', 'mes_dv_repair_status', 0, 'info', '', '', '1', '2026-04-03 17:20:23', '1', '2026-04-03 17:20:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3420, 1, '缁翠慨涓�', '1', 'mes_dv_repair_status', 0, 'primary', '', '', '1', '2026-04-03 17:20:23', '1', '2026-04-03 17:20:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3421, 2, '寰呴獙鏀�', '2', 'mes_dv_repair_status', 0, 'warning', '', '', '1', '2026-04-03 17:20:23', '1', '2026-04-03 17:20:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3422, 3, '宸茬‘璁�', '4', 'mes_dv_repair_status', 0, 'success', '', '', '1', '2026-04-03 17:20:23', '1', '2026-04-03 17:20:23', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3423, 0, '鑽夌', '0', 'mes_wm_return_sales_status', 0, 'info', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3424, 1, '寰呮楠�', '1', 'mes_wm_return_sales_status', 0, 'warning', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3425, 2, '寰呮墽琛�', '2', 'mes_wm_return_sales_status', 0, 'warning', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3426, 3, '寰呬笂鏋�', '3', 'mes_wm_return_sales_status', 0, 'primary', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3427, 4, '宸插畬鎴�', '4', 'mes_wm_return_sales_status', 0, 'success', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3428, 5, '宸插彇娑�', '5', 'mes_wm_return_sales_status', 0, 'danger', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3436, 1, '涓婂伐', '1', 'mes_pro_work_record_type', 0, 'success', '', '', '1', '2026-04-05 14:07:27', '1', '2026-04-05 14:07:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3437, 2, '涓嬪伐', '2', 'mes_pro_work_record_type', 0, 'danger', '', '', '1', '2026-04-05 14:07:27', '1', '2026-04-05 14:07:27', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3443, 1, '鑽夌', '0', 'mes_wm_product_produce_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3444, 2, '宸插畬鎴�', '4', 'mes_wm_product_produce_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3445, 3, '宸插彇娑�', '5', 'mes_wm_product_produce_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '猫聧鈥懊�', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '氓路虏氓庐艗忙藛聬', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '氓路虏氓聫鈥撁β端�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3520, 1, '鏈', '0', 'im_private_message_status', 0, 'warning', '', '绉佽亰=鏈锛岀兢鑱�=姝e父', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 15:14:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3521, 2, '宸叉挙鍥�', '2', 'im_private_message_status', 0, 'danger', '', 'RECALL', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 15:14:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3522, 3, '宸茶', '3', 'im_private_message_status', 0, 'success', '', 'READ锛堜粎绉佽亰锛�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 15:14:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3525, 1, '姝e父', '0', 'im_group_message_status', 0, 'success', '', '缇よ亰姝e父锛堝垵濮嬬姸鎬侊級', 'admin', '2026-04-30 15:14:36', 'admin', '2026-04-30 15:14:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3526, 2, '宸叉挙鍥�', '2', 'im_group_message_status', 0, 'danger', '', '缇よ亰宸叉挙鍥�', 'admin', '2026-04-30 15:14:36', 'admin', '2026-04-30 15:14:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3530, 1, '涓嶉渶瑕佸洖鎵�', '0', 'im_group_message_receipt_status', 0, 'info', '', 'NO_RECEIPT', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3531, 2, '寰呭畬鎴�', '1', 'im_group_message_receipt_status', 0, 'warning', '', 'PENDING', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3532, 3, '宸插畬鎴�', '2', 'im_group_message_receipt_status', 0, 'success', '', 'DONE', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3540, 1, '姝e父', '0', 'im_friend_status', 0, 'success', '', '姝e父濂藉弸鍏崇郴', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3541, 2, '宸插垹闄�', '1', 'im_friend_status', 0, 'danger', '', '宸插垹闄ゅソ鍙嬪叧绯�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3550, 1, '姝e父', '0', 'im_group_status', 0, 'success', '', '缇ゆ甯�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3551, 2, '宸茶В鏁�', '1', 'im_group_status', 0, 'info', '', '缇ゅ凡瑙f暎', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3552, 1, '缇や富', '1', 'im_group_member_role', 0, 'primary', '', NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3553, 2, '绠$悊鍛�', '2', 'im_group_member_role', 0, 'warning', '', NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3554, 3, '鏅�氭垚鍛�', '3', 'im_group_member_role', 0, 'info', '', NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3555, 1, '鎼滅储', '1', 'im_friend_add_source', 0, 'default', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-05 11:46:57', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3556, 2, '缇よ亰', '2', 'im_friend_add_source', 0, 'default', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-05 11:46:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3557, 3, '鎵爜', '3', 'im_friend_add_source', 0, 'default', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-05 11:46:50', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3558, 4, '鍚嶇墖', '4', 'im_friend_add_source', 0, 'default', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-05 11:46:48', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3559, 1, '绛夊緟楠岃瘉', '0', 'im_friend_request_handle_result', 0, 'warning', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3560, 2, '宸叉坊鍔�', '1', 'im_friend_request_handle_result', 0, 'success', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3561, 3, '宸叉嫆缁�', '2', 'im_friend_request_handle_result', 0, 'info', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3562, 101, '鏂囨湰', '101', 'im_message_type', 0, '', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3563, 102, '鍥剧墖', '102', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3564, 103, '璇煶', '103', 'im_message_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3565, 104, '瑙嗛', '104', 'im_message_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3566, 105, '鏂囦欢', '105', 'im_message_type', 0, 'info', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3568, 2101, '鎾ゅ洖', '2101', 'im_message_type', 0, 'danger', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3569, 2200, '鍥炴墽', '2200', 'im_message_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3570, 2201, '宸茶', '2201', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3571, 1501, '缇ゅ垱寤�', '1501', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3572, 1502, '缇や俊鎭彉鏇�', '1502', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3573, 1503, '鍏ョ兢鐢宠', '1503', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3574, 1504, '鎴愬憳閫�缇�', '1504', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3575, 1505, '鍏ョ兢鐢宠閫氳繃', '1505', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3576, 1506, '鍏ョ兢鐢宠鎷掔粷', '1506', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3577, 1507, '缇や富杞', '1507', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3578, 1508, '鎴愬憳琚Щ鍑�', '1508', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3579, 1509, '鎴愬憳鍔犲叆', '1509', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3580, 1510, '鑷敱杩涚兢', '1510', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3581, 1511, '缇よВ鏁�', '1511', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3582, 1512, '鎴愬憳绂佽█', '1512', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3583, 1513, '鎴愬憳鍙栨秷绂佽█', '1513', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3584, 1514, '鍏ㄧ兢绂佽█', '1514', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3585, 1515, '鍏ㄧ兢鍙栨秷绂佽█', '1515', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3586, 1516, '鎴愬憳鏄电О鍙樻洿', '1516', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3587, 1517, '娣诲姞绠$悊鍛�', '1517', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3588, 1518, '鎾ら攢绠$悊鍛�', '1518', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3589, 1519, '缇ゅ叕鍛婂彉鏇�', '1519', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3590, 1520, '缇ゅ悕鍙樻洿', '1520', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3591, 1531, '缇ゆ秷鎭疆椤�', '1531', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3592, 1532, '缇ゆ秷鎭彇娑堢疆椤�', '1532', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3593, 1533, '缇ゅ皝绂佸彉鏇�', '1533', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3594, 1204, '鏂板濂藉弸', '1204', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 13:26:53', 'admin', '2026-05-05 13:26:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3595, 1205, '濂藉弸琚垹闄�', '1205', 'im_message_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 13:26:53', 'admin', '2026-05-05 13:26:53', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3596, 1, '鎼滅储', '1', 'im_group_add_source', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3597, 2, '閭�璇�', '2', 'im_group_add_source', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3598, 3, '鎵爜', '3', 'im_group_add_source', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3599, 4, '鍒嗕韩閾炬帴', '4', 'im_group_add_source', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3600, 1, '鏈鐞�', '0', 'im_group_request_handle_result', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3601, 2, '鍚屾剰', '1', 'im_group_request_handle_result', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3602, 3, '鎷掔粷', '2', 'im_group_request_handle_result', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061051, 1, '瀹㈡埛', '1', 'merchant_type', 0, 'primary', '', '瀹㈡埛', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061052, 2, '渚涘簲鍟�', '2', 'merchant_type', 0, 'success', '', '渚涘簲鍟�', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061053, 3, '瀹㈡埛/渚涘簲鍟�', '3', 'merchant_type', 0, 'warning', '', '瀹㈡埛/渚涘簲鍟�', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061061, 1, '鍏ュ簱鍗�', '1', 'wms_order_type', 0, 'success', '', '', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061062, 2, '鍑哄簱鍗�', '2', 'wms_order_type', 0, 'danger', '', '', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061063, 3, '绉诲簱鍗�', '3', 'wms_order_type', 0, 'primary', '', '', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061064, 4, '鐩樺簱鍗�', '4', 'wms_order_type', 0, 'warning', '', '', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061071, 1, '鑽夌', '0', 'wms_order_status', 0, 'info', '', '鑽夌', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061072, 2, '宸插畬鎴�', '4', 'wms_order_status', 0, 'success', '', '宸插畬鎴�', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061073, 3, '宸蹭綔搴�', '5', 'wms_order_status', 0, 'danger', '', '宸蹭綔搴�', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061081, 1, '鐢熶骇鍏ュ簱', '100', 'wms_receipt_order_type', 0, 'success', '', '', '1', '2026-05-11 11:21:49', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061082, 2, '閲囪喘鍏ュ簱', '101', 'wms_receipt_order_type', 0, 'primary', '', '', '1', '2026-05-11 11:21:49', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061083, 3, '閫�璐у叆搴�', '102', 'wms_receipt_order_type', 0, 'warning', '', '', '1', '2026-05-11 11:21:49', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061084, 4, '褰掕繕鍏ュ簱', '103', 'wms_receipt_order_type', 0, 'info', '', '', '1', '2026-05-13 16:02:33', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061091, 1, '閫�璐у嚭搴�', '200', 'wms_shipment_order_type', 0, 'warning', '', '閫�璐у嚭搴�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061092, 2, '閿�鍞嚭搴�', '201', 'wms_shipment_order_type', 0, 'primary', '', '閿�鍞嚭搴�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061093, 3, '鐢熶骇鍑哄簱', '202', 'wms_shipment_order_type', 0, 'success', '', '鐢熶骇鍑哄簱', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061096, 1, '璇煶', '1', 'im_rtc_call_media_type', 0, '', '', '璇煶閫氳瘽', 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061097, 2, '瑙嗛', '2', 'im_rtc_call_media_type', 0, '', '', '瑙嗛閫氳瘽', 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061098, 1, '绉佽亰', '1', 'im_rtc_call_conversation_type', 0, 'primary', '', '涓�瀵逛竴绉佽亰閫氳瘽', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061099, 2, '缇よ亰', '2', 'im_rtc_call_conversation_type', 0, 'success', '', '缇ゅ唴澶氫汉閫氳瘽', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061100, 1, '鍒涘缓', '10', 'im_rtc_call_status', 0, 'info', '', '閫氳瘽宸插垱寤猴紝绛夊緟鎺ラ��', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061101, 2, '杩涜涓�', '20', 'im_rtc_call_status', 0, 'primary', '', '宸叉湁浜烘帴閫氾紝閫氳瘽涓�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061102, 3, '宸茬粨鏉�', '30', 'im_rtc_call_status', 0, 'success', '', '閫氳瘽缁撴潫', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061103, 1, '閫氳瘽缁撴潫', '1', 'im_rtc_call_end_reason', 0, 'success', '', '鎺ラ�氬悗浠讳竴鏂逛富鍔ㄦ寕鏂�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061104, 2, '宸叉嫆缁�', '2', 'im_rtc_call_end_reason', 0, 'warning', '', '琚彨鎺ラ�氬墠鐐规嫆鎺�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061105, 3, '宸插彇娑�', '3', 'im_rtc_call_end_reason', 0, 'info', '', '涓诲彨鎺ラ�氬墠涓诲姩鍙栨秷', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061106, 4, '鏃犱汉鎺ュ惉', '4', 'im_rtc_call_end_reason', 0, 'info', '', '鎸搩瓒呮椂鏈帴閫�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061107, 5, '瀵规柟姝e繖', '5', 'im_rtc_call_end_reason', 0, 'warning', '', '瀵规柟鍦ㄥ彟涓�閫氳瘽涓�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061108, 6, '閫氳瘽寮傚父', '9', 'im_rtc_call_end_reason', 0, 'danger', '', '缃戠粶涓柇銆佽澶囧け璐ョ瓑', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061109, 1, '鍙戣捣浜�', '1', 'im_rtc_participant_role', 0, 'primary', '', '閫氳瘽鍙戣捣鑰�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061110, 2, '琚個璇疯��', '2', 'im_rtc_participant_role', 0, 'info', '', '琚個璇峰姞鍏�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061111, 3, '涓诲姩鍔犲叆鑰�', '3', 'im_rtc_participant_role', 0, 'success', '', '缇ら�氳瘽鍦烘櫙锛屾梺瑙傝�呬富鍔ㄥ姞鍏�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061112, 1, '閭�璇蜂腑', '10', 'im_rtc_participant_status', 0, 'info', '', '宸插彂鍑� invite锛岀瓑寰呭搷搴�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061113, 2, '宸插姞鍏�', '20', 'im_rtc_participant_status', 0, 'primary', '', '宸叉帴閫氬苟杩涘叆鎴块棿', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061114, 3, '宸叉嫆缁�', '30', 'im_rtc_participant_status', 0, 'warning', '', '鎺ラ�氬墠鐐规嫆鎺�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061115, 4, '鏈簲绛�', '40', 'im_rtc_participant_status', 0, 'info', '', '閫氳瘽宸茬粨鏉熶粛鏈簲绛�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061116, 5, '宸茬寮�', '50', 'im_rtc_participant_status', 0, 'success', '', '鎺ラ�氬悗鎸傛柇 / 绂诲紑', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061117, 1610, '閫氳瘽寮�濮�', '1610', 'im_message_type', 0, 'info', '', '鍏ユ秷鎭祦锛涚鑱婂畾鍚戦�氱煡锛岀兢鑱婂叏鍛樺箍鎾�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061118, 1611, '閫氳瘽缁撴潫', '1611', 'im_message_type', 0, 'info', '', '鍏ユ秷鎭祦锛涚鑱婂噯姘旀场锛岀兢鑱婄郴缁� tip', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061119, 125, '绱犳潗', '125', 'im_message_type', 0, 'success', '', '棰戦亾杩愯惀鎺ㄩ�佺殑鍥炬枃鍗$墖娑堟伅', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061120, 1, '瀵屾枃鏈�', '1', 'im_channel_material_type', 0, 'primary', '', '', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (1061121, 2, '澶栭摼', '2', 'im_channel_material_type', 0, 'info', '', '', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_dict_data_seq;
+CREATE SEQUENCE system_dict_data_seq
+ START 1061122;
+
+-- ----------------------------
+-- Table structure for system_dict_type
+-- ----------------------------
+DROP TABLE IF EXISTS system_dict_type;
+CREATE TABLE system_dict_type (
+ id int8 NOT NULL,
+ name varchar(100) NOT NULL DEFAULT '',
+ type varchar(100) NOT NULL DEFAULT '',
+ status int2 NOT NULL DEFAULT 0,
+ remark varchar(500) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ deleted_time timestamp NULL DEFAULT NULL
+);
+
+ALTER TABLE system_dict_type ADD CONSTRAINT pk_system_dict_type PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_dict_type.id IS '瀛楀吀涓婚敭';
+COMMENT ON COLUMN system_dict_type.name IS '瀛楀吀鍚嶇О';
+COMMENT ON COLUMN system_dict_type.type IS '瀛楀吀绫诲瀷';
+COMMENT ON COLUMN system_dict_type.status IS '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+COMMENT ON COLUMN system_dict_type.remark IS '澶囨敞';
+COMMENT ON COLUMN system_dict_type.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_dict_type.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_dict_type.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_dict_type.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_dict_type.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_dict_type.deleted_time IS '鍒犻櫎鏃堕棿';
+COMMENT ON TABLE system_dict_type IS '瀛楀吀绫诲瀷琛�';
+
+-- ----------------------------
+-- Records of system_dict_type
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1, '鐢ㄦ埛鎬у埆', 'system_user_sex', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-05-16 20:29:32', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (6, '鍙傛暟绫诲瀷', 'infra_config_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (7, '閫氱煡绫诲瀷', 'system_notice_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (9, '鎿嶄綔绫诲瀷', 'infra_operate_type', 0, NULL, 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:01', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (10, '绯荤粺鐘舵��', 'common_status', 0, NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (11, 'Boolean 鏄惁绫诲瀷', 'infra_boolean_string', 0, 'boolean 杞槸鍚�', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (104, '鐧婚檰缁撴灉', 'system_login_result', 0, '鐧婚檰缁撴灉', '', '2021-01-18 06:17:11', '', '2022-02-01 16:36:00', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (106, '浠g爜鐢熸垚妯℃澘绫诲瀷', 'infra_codegen_template_type', 0, NULL, '', '2021-02-05 07:08:06', '1', '2022-05-16 20:26:50', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (107, '瀹氭椂浠诲姟鐘舵��', 'infra_job_status', 0, NULL, '', '2021-02-07 07:44:16', '', '2022-02-01 16:51:11', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (108, '瀹氭椂浠诲姟鏃ュ織鐘舵��', 'infra_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2022-02-01 16:50:43', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (109, '鐢ㄦ埛绫诲瀷', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (110, 'API 寮傚父鏁版嵁鐨勫鐞嗙姸鎬�', 'infra_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2022-02-01 16:50:53', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (111, '鐭俊娓犻亾缂栫爜', 'system_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2022-02-16 02:09:08', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (112, '鐭俊妯℃澘鐨勭被鍨�', 'system_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2022-02-01 16:35:06', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (113, '鐭俊鍙戦�佺姸鎬�', 'system_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2022-02-01 16:35:09', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (114, '鐭俊鎺ユ敹鐘舵��', 'system_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2022-02-01 16:35:14', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (116, '鐧婚檰鏃ュ織鐨勭被鍨�', 'system_login_type', 0, '鐧婚檰鏃ュ織鐨勭被鍨�', '1', '2021-10-06 00:50:46', '1', '2022-02-01 16:35:56', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (117, 'OA 璇峰亣绫诲瀷', 'bpm_oa_leave_type', 0, NULL, '1', '2021-09-21 22:34:33', '1', '2022-01-22 10:41:37', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (130, '鏀粯娓犻亾缂栫爜绫诲瀷', 'pay_channel_code', 0, '鏀粯娓犻亾鐨勭紪鐮�', '1', '2021-12-03 10:35:08', '1', '2023-07-10 10:11:39', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (131, '鏀粯鍥炶皟鐘舵��', 'pay_notify_status', 0, '鏀粯鍥炶皟鐘舵�侊紙鍖呮嫭閫�娆惧洖璋冿級', '1', '2021-12-03 10:53:29', '1', '2023-07-19 18:09:43', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (132, '鏀粯璁㈠崟鐘舵��', 'pay_order_status', 0, '鏀粯璁㈠崟鐘舵��', '1', '2021-12-03 11:17:50', '1', '2021-12-03 11:17:50', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (134, '閫�娆捐鍗曠姸鎬�', 'pay_refund_status', 0, '閫�娆捐鍗曠姸鎬�', '1', '2021-12-10 16:42:50', '1', '2023-07-19 10:13:17', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (139, '娴佺▼瀹炰緥鐨勭姸鎬�', 'bpm_process_instance_status', 0, '娴佺▼瀹炰緥鐨勭姸鎬�', '1', '2022-01-07 23:46:42', '1', '2022-01-07 23:46:42', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (140, '娴佺▼瀹炰緥鐨勭粨鏋�', 'bpm_task_status', 0, '娴佺▼瀹炰緥鐨勭粨鏋�', '1', '2022-01-07 23:48:10', '1', '2024-03-08 22:42:03', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (141, '娴佺▼鐨勮〃鍗曠被鍨�', 'bpm_model_form_type', 0, '娴佺▼鐨勮〃鍗曠被鍨�', '103', '2022-01-11 23:50:45', '103', '2022-01-11 23:50:45', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (142, '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨�', 'bpm_task_candidate_strategy', 0, 'BPM 浠诲姟鐨勫�欓�変汉鐨勭瓥鐣�', '103', '2022-01-12 23:21:04', '103', '2024-03-06 02:53:59', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (144, '浠g爜鐢熸垚鐨勫満鏅灇涓�', 'infra_codegen_scene', 0, '浠g爜鐢熸垚鐨勫満鏅灇涓�', '1', '2022-02-02 13:14:45', '1', '2022-03-10 16:33:46', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (145, '瑙掕壊绫诲瀷', 'system_role_type', 0, '瑙掕壊绫诲瀷', '1', '2022-02-16 13:01:46', '1', '2022-02-16 13:01:46', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (146, '鏂囦欢瀛樺偍鍣�', 'infra_file_storage', 0, '鏂囦欢瀛樺偍鍣�', '1', '2022-03-15 00:24:38', '1', '2022-03-15 00:24:38', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (147, 'OAuth 2.0 鎺堟潈绫诲瀷', 'system_oauth2_grant_type', 0, 'OAuth 2.0 鎺堟潈绫诲瀷锛堟ā寮忥級', '1', '2022-05-12 00:20:52', '1', '2022-05-11 16:25:49', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (149, '鍟嗗搧 SPU 鐘舵��', 'product_spu_status', 0, '鍟嗗搧 SPU 鐘舵��', '1', '2022-10-24 21:19:04', '1', '2022-10-24 21:19:08', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (150, '浼樻儬绫诲瀷', 'promotion_discount_type', 0, '浼樻儬绫诲瀷', '1', '2022-11-01 12:46:06', '1', '2022-11-01 12:46:06', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (151, '浼樻儬鍔垫ā鏉跨殑鏈夐檺鏈熺被鍨�', 'promotion_coupon_template_validity_type', 0, '浼樻儬鍔垫ā鏉跨殑鏈夐檺鏈熺被鍨�', '1', '2022-11-02 00:06:20', '1', '2022-11-04 00:08:26', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (152, '钀ラ攢鐨勫晢鍝佽寖鍥�', 'promotion_product_scope', 0, '钀ラ攢鐨勫晢鍝佽寖鍥�', '1', '2022-11-02 00:28:01', '1', '2022-11-02 00:28:01', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (153, '浼樻儬鍔电殑鐘舵��', 'promotion_coupon_status', 0, '浼樻儬鍔电殑鐘舵��', '1', '2022-11-04 00:14:49', '1', '2022-11-04 00:14:49', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (154, '浼樻儬鍔电殑棰嗗彇鏂瑰紡', 'promotion_coupon_take_type', 0, '浼樻儬鍔电殑棰嗗彇鏂瑰紡', '1', '2022-11-04 19:12:27', '1', '2022-11-04 19:12:27', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (155, '淇冮攢娲诲姩鐨勭姸鎬�', 'promotion_activity_status', 0, '淇冮攢娲诲姩鐨勭姸鎬�', '1', '2022-11-04 22:54:23', '1', '2022-11-04 22:54:23', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (156, '钀ラ攢鐨勬潯浠剁被鍨�', 'promotion_condition_type', 0, '钀ラ攢鐨勬潯浠剁被鍨�', '1', '2022-11-04 22:59:23', '1', '2022-11-04 22:59:23', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (157, '浜ゆ槗鍞悗鐘舵��', 'trade_after_sale_status', 0, '浜ゆ槗鍞悗鐘舵��', '1', '2022-11-19 20:52:56', '1', '2022-11-19 20:52:56', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (158, '浜ゆ槗鍞悗鐨勭被鍨�', 'trade_after_sale_type', 0, '浜ゆ槗鍞悗鐨勭被鍨�', '1', '2022-11-19 21:04:09', '1', '2022-11-19 21:04:09', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (159, '浜ゆ槗鍞悗鐨勬柟寮�', 'trade_after_sale_way', 0, '浜ゆ槗鍞悗鐨勬柟寮�', '1', '2022-11-19 21:39:04', '1', '2022-11-19 21:39:04', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (160, '缁堢', 'terminal', 0, '缁堢', '1', '2022-12-10 10:50:50', '1', '2022-12-10 10:53:11', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (161, '浜ゆ槗璁㈠崟鐨勭被鍨�', 'trade_order_type', 0, '浜ゆ槗璁㈠崟鐨勭被鍨�', '1', '2022-12-10 16:33:54', '1', '2022-12-10 16:33:54', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (162, '浜ゆ槗璁㈠崟鐨勭姸鎬�', 'trade_order_status', 0, '浜ゆ槗璁㈠崟鐨勭姸鎬�', '1', '2022-12-10 16:48:44', '1', '2022-12-10 16:48:44', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (163, '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵��', 'trade_order_item_after_sale_status', 0, '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵��', '1', '2022-12-10 20:58:08', '1', '2022-12-10 20:58:08', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (164, '鍏紬鍙疯嚜鍔ㄥ洖澶嶇殑璇锋眰鍏抽敭瀛楀尮閰嶆ā寮�', 'mp_auto_reply_request_match', 0, '鍏紬鍙疯嚜鍔ㄥ洖澶嶇殑璇锋眰鍏抽敭瀛楀尮閰嶆ā寮�', '1', '2023-01-16 23:29:56', '1', '2023-01-16 23:29:56', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (165, '鍏紬鍙风殑娑堟伅绫诲瀷', 'mp_message_type', 0, '鍏紬鍙风殑娑堟伅绫诲瀷', '1', '2023-01-17 22:17:09', '1', '2023-01-17 22:17:09', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (166, '閭欢鍙戦�佺姸鎬�', 'system_mail_send_status', 0, '閭欢鍙戦�佺姸鎬�', '1', '2023-01-26 09:53:13', '1', '2023-01-26 09:53:13', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (167, '绔欏唴淇℃ā鐗堢殑绫诲瀷', 'system_notify_template_type', 0, '绔欏唴淇℃ā鐗堢殑绫诲瀷', '1', '2023-01-28 10:35:10', '1', '2023-01-28 10:35:10', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (168, '浠g爜鐢熸垚鐨勫墠绔被鍨�', 'infra_codegen_front_type', 0, '', '1', '2023-04-12 23:57:52', '1', '2023-04-12 23:57:52', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (170, '蹇�掕璐规柟寮�', 'trade_delivery_express_charge_mode', 0, '鐢ㄤ簬鍟嗗煄浜ゆ槗妯″潡閰嶉�佺鐞�', '1', '2023-05-21 22:45:03', '1', '2023-05-21 22:45:03', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (171, '绉垎涓氬姟绫诲瀷', 'member_point_biz_type', 0, '', '1', '2023-06-10 12:15:00', '1', '2023-06-28 13:48:20', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (173, '鏀粯閫氱煡绫诲瀷', 'pay_notify_type', 0, NULL, '1', '2023-07-20 12:23:03', '1', '2023-07-20 12:23:03', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (174, '浼氬憳缁忛獙涓氬姟绫诲瀷', 'member_experience_biz_type', 0, NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (175, '浜ゆ槗閰嶉�佺被鍨�', 'trade_delivery_type', 0, '', '1', '2023-08-23 00:03:14', '1', '2023-08-23 00:03:14', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (176, '鍒嗕剑妯″紡', 'brokerage_enabled_condition', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (177, '鍒嗛攢鍏崇郴缁戝畾妯″紡', 'brokerage_bind_mode', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (178, '浣i噾鎻愮幇绫诲瀷', 'brokerage_withdraw_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (179, '浣i噾璁板綍涓氬姟绫诲瀷', 'brokerage_record_biz_type', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (180, '浣i噾璁板綍鐘舵��', 'brokerage_record_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (181, '浣i噾鎻愮幇鐘舵��', 'brokerage_withdraw_status', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (182, '浣i噾鎻愮幇閾惰', 'brokerage_bank_name', 0, NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (183, '鐮嶄环璁板綍鐨勭姸鎬�', 'promotion_bargain_record_status', 0, '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (184, '鎷煎洟璁板綍鐨勭姸鎬�', 'promotion_combination_record_status', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (185, '鍥炴-鍥炴鏂瑰紡', 'crm_receivable_return_type', 0, '鍥炴-鍥炴鏂瑰紡', '1', '2023-10-18 21:54:10', '1', '2023-10-18 21:54:10', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (186, 'CRM 瀹㈡埛琛屼笟', 'crm_customer_industry', 0, 'CRM 瀹㈡埛鎵�灞炶涓�', '1', '2023-10-28 22:57:07', '1', '2024-02-18 23:30:22', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (187, '瀹㈡埛绛夌骇', 'crm_customer_level', 0, 'CRM 瀹㈡埛绛夌骇', '1', '2023-10-28 22:59:12', '1', '2023-10-28 15:11:16', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (188, '瀹㈡埛鏉ユ簮', 'crm_customer_source', 0, 'CRM 瀹㈡埛鏉ユ簮', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (600, 'Banner 浣嶇疆', 'promotion_banner_position', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (601, '绀句氦绫诲瀷', 'system_social_type', 0, '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (604, '浜у搧鐘舵��', 'crm_product_status', 0, '', '1', '2023-10-30 21:47:59', '1', '2023-10-30 21:48:45', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (605, 'CRM 鏁版嵁鏉冮檺鐨勭骇鍒�', 'crm_permission_level', 0, '', '1', '2023-11-30 09:51:59', '1', '2023-11-30 09:51:59', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (606, 'CRM 瀹℃壒鐘舵��', 'crm_audit_status', 0, '', '1', '2023-11-30 18:56:23', '1', '2023-11-30 18:56:23', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (607, 'CRM 浜у搧鍗曚綅', 'crm_product_unit', 0, '', '1', '2023-12-05 23:01:51', '1', '2023-12-05 23:01:51', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (608, 'CRM 璺熻繘鏂瑰紡', 'crm_follow_up_type', 0, '', '1', '2024-01-15 20:48:05', '1', '2024-01-15 20:48:05', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (610, '杞处璁㈠崟鐘舵��', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (611, 'ERP 搴撳瓨鏄庣粏鐨勪笟鍔$被鍨�', 'erp_stock_record_biz_type', 0, 'ERP 搴撳瓨鏄庣粏鐨勪笟鍔$被鍨�', '1', '2024-02-05 18:07:02', '1', '2024-02-05 18:07:02', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (612, 'ERP 瀹℃壒鐘舵��', 'erp_audit_status', 0, '', '1', '2024-02-06 00:00:07', '1', '2024-02-06 00:00:07', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (613, 'BPM 鐩戝惉鍣ㄧ被鍨�', 'bpm_process_listener_type', 0, '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (615, 'BPM 鐩戝惉鍣ㄥ�肩被鍨�', 'bpm_process_listener_value_type', 0, '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (616, '鏃堕棿闂撮殧', 'date_interval', 0, '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (619, 'CRM 鍟嗘満缁撴潫鐘舵�佺被鍨�', 'crm_business_end_status_type', 0, '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (620, 'AI 妯″瀷骞冲彴', 'ai_platform', 0, '', '1', '2024-05-09 22:27:38', '1', '2024-05-09 22:27:38', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (621, 'AI 缁樼敾鐘舵��', 'ai_image_status', 0, '', '1', '2024-06-26 20:51:23', '1', '2024-06-26 20:51:23', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (622, 'AI 闊充箰鐘舵��', 'ai_music_status', 0, '', '1', '2024-06-27 22:45:07', '1', '2024-06-28 00:56:27', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (623, 'AI 闊充箰鐢熸垚妯″紡', 'ai_generate_mode', 0, '', '1', '2024-06-27 22:46:21', '1', '2024-06-28 01:22:29', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (624, '鍐欎綔璇皵', 'ai_write_tone', 0, '', '1', '2024-07-07 15:19:02', '1', '2024-07-07 15:19:02', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (625, '鍐欎綔璇█', 'ai_write_language', 0, '', '1', '2024-07-07 15:18:52', '1', '2024-07-07 15:18:52', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (626, '鍐欎綔闀垮害', 'ai_write_length', 0, '', '1', '2024-07-07 15:18:41', '1', '2024-07-07 15:18:41', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (627, '鍐欎綔鏍煎紡', 'ai_write_format', 0, '', '1', '2024-07-07 15:14:34', '1', '2024-07-07 15:14:34', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (628, 'AI 鍐欎綔绫诲瀷', 'ai_write_type', 0, '', '1', '2024-07-10 21:25:29', '1', '2024-07-10 21:25:29', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (629, 'BPM 娴佺▼妯″瀷绫诲瀷', 'bpm_model_type', 0, '', '1', '2024-08-26 15:21:43', '1', '2024-08-26 15:21:43', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (640, 'AI 妯″瀷绫诲瀷', 'ai_model_type', 0, '', '1', '2025-03-03 12:24:07', '1', '2025-03-03 12:24:07', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1001, 'IoT 浜у搧璁惧绫诲瀷', 'iot_product_device_type', 0, '', '1', '2024-08-10 11:54:30', '1', '2025-03-17 09:25:08', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1002, 'IoT 浜у搧鐘舵��', 'iot_product_status', 0, '', '1', '2024-08-10 12:06:09', '1', '2025-03-17 09:25:10', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1004, 'IoT 鑱旂綉鏂瑰紡', 'iot_net_type', 0, '', '1', '2024-09-06 22:04:13', '1', '2025-03-17 09:25:14', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1006, 'IoT 璁惧鐘舵��', 'iot_device_state', 0, '', '1', '2024-09-21 08:12:55', '1', '2025-03-17 09:25:19', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1007, 'IoT 鐗╂ā鍨嬪姛鑳界被鍨�', 'iot_thing_model_type', 0, '', '1', '2024-09-29 20:02:36', '1', '2025-03-17 09:25:24', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1011, 'IoT 鐗╂ā鍨嬪崟浣�', 'iot_thing_model_unit', 0, '', '1', '2024-12-25 17:36:46', '1', '2025-03-17 09:25:35', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1013, 'IoT 鏁版嵁娴佽浆鐩殑鐨勭被鍨嬫灇涓�', 'iot_data_sink_type_enum', 0, '', '1', '2025-03-09 12:39:36', '1', '2025-06-24 12:45:24', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1014, 'IoT 鍦烘櫙娴佽浆鐨勮Е鍙戠被鍨嬫灇涓�', 'iot_rule_scene_trigger_type_enum', 0, '', '1', '2025-03-20 14:59:44', '1', '2025-03-20 14:59:44', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1015, 'IoT 璁惧娑堟伅绫诲瀷鏋氫妇', 'iot_device_message_type_enum', 0, '', '1', '2025-03-20 15:01:15', '1', '2025-03-20 15:01:15', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1016, 'IoT 瑙勫垯鍦烘櫙鐨勮Е鍙戠被鍨嬫灇涓�', 'iot_rule_scene_action_type_enum', 0, '', '1', '2025-03-28 15:26:54', '1', '2025-03-28 15:29:13', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1017, 'MES 鐗╂枡娑堣�楄褰曠姸鎬�', 'mes_wm_item_consume_status', 0, 'MES 鐗╂枡娑堣�楄褰曠姸鎬�', '1', '2026-03-19 15:06:23', '1', '2026-03-19 15:06:23', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2001, 'IoT 鍛婅绾у埆', 'iot_alert_level', 0, '', '1', '2025-06-27 20:30:57', '1', '2025-06-27 20:30:57', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2002, 'IoT 鍛婅', 'iot_alert_receive_type', 0, '', '1', '2025-06-27 22:49:19', '1', '2025-06-27 22:49:19', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2003, 'IoT 鍥轰欢璁惧鑼冨洿', 'iot_ota_task_device_scope', 0, '', '1', '2025-07-02 09:42:49', '1', '2025-07-02 09:42:49', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2004, 'IoT 鍥轰欢鍗囩骇浠诲姟鐘舵��', 'iot_ota_task_status', 0, '', '1', '2025-07-02 09:43:43', '1', '2025-07-02 09:43:43', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2005, 'IoT 鍥轰欢鍗囩骇璁板綍鐘舵��', 'iot_ota_task_record_status', 0, '', '1', '2025-07-02 09:45:02', '1', '2025-07-02 09:45:02', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2007, 'AI MCP 瀹㈡埛绔悕瀛�', 'ai_mcp_client_name', 0, '', '1', '2025-08-28 13:57:40', '1', '2025-08-28 13:57:40', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2008, 'IoT 鍗忚绫诲瀷', 'iot_protocol_type', 0, 'IoT 璁惧鎺ュ叆鍗忚绫诲瀷', '1', '2026-02-04 00:31:33', '1', '2026-02-04 00:31:33', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2009, 'IoT 搴忓垪鍖栫被鍨�', 'iot_serialize_type', 0, 'IoT 璁惧娑堟伅搴忓垪鍖栫被鍨�', '1', '2026-02-04 00:33:16', '1', '2026-02-04 00:33:16', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2010, 'IoT Modbus 宸ヤ綔妯″紡', 'iot_modbus_mode', 0, 'Modbus 璁惧鏁版嵁閲囬泦妯″紡', '1', '2025-06-12 22:55:46', '1', '2025-06-12 22:55:46', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2011, 'IoT Modbus 甯ф牸寮�', 'iot_modbus_frame_format', 0, 'Modbus 鏁版嵁甯у崗璁牸寮�', '1', '2025-06-12 22:55:46', '1', '2025-06-12 22:55:46', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2012, 'MES 瀹㈡埛绫诲瀷', 'mes_client_type', 0, '', '1', '2026-02-15 14:38:25', '1', '2026-02-15 14:38:25', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2013, 'MES 渚涘簲鍟嗙骇鍒�', 'mes_vendor_level', 0, '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2014, 'MES 鍋囨湡绫诲瀷', 'mes_cal_holiday_type', 0, 'MES 鏃ュ巻鎺掔彮 - 鍋囨湡绫诲瀷锛圚OLIDAY=鍋囨湡锛學ORKDAY=宸ヤ綔鏃ワ級', '1', '2026-02-16 07:35:58', '1', '2026-02-16 07:35:58', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2015, 'MES 宸ュ叿鐘舵��', 'mes_tm_tool_status', 0, 'MES 宸ュ叿绠$悊 - 宸ュ叿鐘舵�侊紙1=鍦ㄥ簱锛�2=棰嗙敤涓紝3=缁翠慨涓紝4=鎶ュ簾锛�', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2016, 'MES 淇濆吇缁存姢绫诲瀷', 'mes_tm_mainten_type', 0, 'MES 宸ュ叿绠$悊 - 淇濆吇缁存姢绫诲瀷锛�1=瀹氭湡缁存姢锛�2=鎸変娇鐢ㄦ鏁扮淮鎶わ級', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2017, 'MES 璁惧鐘舵��', 'mes_dv_machinery_status', 0, 'MES 璁惧绠$悊 - 璁惧鐘舵�侊紙1=杩愯涓紝2=鍋滄満锛�3=鏁呴殰锛�', '1', '2026-02-17 01:00:06', '1', '2026-02-17 01:00:06', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2018, 'MES 妫�娴嬮」绫诲瀷', 'mes_indicator_type', 0, '', '1', '2026-02-17 02:16:22', '1', '2026-02-21 15:25:04', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2019, 'MES 缂洪櫡绛夌骇', 'mes_defect_level', 0, '', '1', '2026-02-17 02:16:22', '1', '2026-02-17 02:16:22', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2020, 'MES 杞彮鏂瑰紡', 'mes_cal_shift_type', 0, 'MES 鏃ュ巻鎺掔彮 - 杞彮鏂瑰紡', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2021, 'MES 鍊掔彮鏂瑰紡', 'mes_cal_shift_method', 0, 'MES 鏃ュ巻鎺掔彮 - 鍊掔彮鏂瑰紡', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2022, 'MES 鐝粍绫诲瀷', 'mes_cal_calendar_type', 0, 'MES 鏃ュ巻鎺掔彮 - 鐝粍绫诲瀷', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2023, 'MES 鎺掔彮璁″垝鐘舵��', 'mes_cal_plan_status', 0, 'MES 鏃ュ巻鎺掔彮 - 鎺掔彮璁″垝鐘舵��', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2026, 'MES 妫�娴嬬绫�', 'mes_qc_type', 0, 'IQC/IPQC/OQC/RQC', '1', '2026-02-17 08:34:40', '1', '2026-02-17 08:34:40', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2027, 'MES 鐢熶骇宸ュ崟鐘舵��', 'mes_pro_work_order_status', 0, 'MES 鐢熶骇绠$悊 - 宸ュ崟鐘舵�侊紙0=鑽夌锛�1=宸茬‘璁わ紝2=宸插畬鎴愶紝3=宸插彇娑堬級', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2028, 'MES 宸ュ崟鏉ユ簮绫诲瀷', 'mes_pro_work_order_source_type', 0, 'MES 鐢熶骇绠$悊 - 宸ュ崟鏉ユ簮绫诲瀷锛�1=瀹㈡埛璁㈠崟锛�2=搴撳瓨澶囪揣锛�', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2029, 'MES 宸ュ崟绫诲瀷', 'mes_pro_work_order_type', 0, 'MES 鐢熶骇绠$悊 - 宸ュ崟绫诲瀷锛�1=鑷鐢熶骇锛�2=浠e伐锛�3=閲囪喘锛�', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2036, 'MES 宸ュ簭鍏崇郴绫诲瀷', 'mes_pro_link_type', 0, '宸ヨ壓璺嚎涓伐搴忎箣闂寸殑鍏崇郴绫诲瀷', '1', '2026-02-19 04:24:53', '1', '2026-04-05 15:05:07', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2037, 'MES 鏃堕棿鍗曚綅', 'mes_time_unit_type', 0, '鐢熶骇鏃堕棿鐨勮閲忓崟浣�', '1', '2026-02-19 04:24:53', '1', '2026-04-05 15:04:57', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2038, 'MES 鐢熶骇浠诲姟鐘舵��', 'mes_pro_task_status', 0, 'MES 鐢熶骇绠$悊 - 浠诲姟鐘舵�侊紙0=鑽夌锛�1=杩涜涓紝2=鏆傚仠锛�3=宸插畬鎴愶紝4=宸插彇娑堬級', '1', '2026-02-19 15:25:27', '1', '2026-02-19 15:25:27', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2039, 'MES 鐐规淇濆吇椤圭洰绫诲瀷', 'mes_dv_subject_type', 0, 'MES 璁惧绠$悊 - 鐐规淇濆吇椤圭洰绫诲瀷锛�1=璁惧鐐规锛�2=璁惧淇濆吇锛�', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2040, 'MES 淇濆吇璁板綍鐘舵��', 'mes_mainten_record_status', 0, NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2041, 'MES 淇濆吇缁撴灉', 'mes_mainten_status', 0, NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2042, 'MES 鐐规淇濆吇鍛ㄦ湡绫诲瀷', 'mes_dv_cycle_type', 0, 'MES 璁惧绠$悊 - 鐐规淇濆吇鍛ㄦ湡绫诲瀷锛�1=澶╋紝2=鍛紝3=鏈堬紝4=骞达級', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2043, 'MES 鐐规淇濆吇鏂规鐘舵��', 'mes_dv_check_plan_status', 0, 'MES 璁惧绠$悊 - 鐐规淇濆吇鏂规鐘舵�侊紙0=鑽夌锛�1=宸插惎鐢級', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2044, 'MES 鐐规璁板綍鐘舵��', 'mes_dv_check_record_status', 0, NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2045, 'MES 鐐规缁撴灉', 'mes_dv_check_result', 0, NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2046, 'MES 缁翠慨宸ュ崟鐘舵��', 'mes_dv_repair_status', 0, 'MES 璁惧绠$悊 - 缁翠慨宸ュ崟鐘舵�侊紙10=寰呯淮淇紝20=缁翠慨涓紝30=宸插畬鎴愶紝40=宸查獙鏀讹級', '1', '2026-02-20 10:56:24', '1', '2026-02-20 10:56:24', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2047, 'MES 缁翠慨缁撴灉', 'mes_dv_repair_result', 0, 'MES 璁惧绠$悊 - 缁翠慨缁撴灉锛�1=淇鎴愬姛锛�2=鎶ュ簾锛�', '1', '2026-02-20 10:56:24', '1', '2026-02-20 10:56:24', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2049, 'MES 妫�娴嬬粨鏋�', 'mes_qc_check_result', 0, '鏉ユ枡妫�楠岀殑鏈�缁堢粨鏋滃垽瀹�', '1', '2026-02-20 11:23:35', '1', '2026-02-20 11:23:35', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2050, 'MES 鏉ユ簮鍗曟嵁绫诲瀷', 'mes_qc_source_doc_type', 0, 'IQC 鏉ユ枡妫�楠岀殑鏉ユ簮鍗曟嵁绫诲瀷', '1', '2026-02-20 11:23:35', '1', '2026-02-20 11:23:35', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2051, 'MES 瀹夌伅澶勭疆鐘舵��', 'mes_pro_andon_status', 0, 'MES 鐢熶骇绠$悊 - 瀹夌伅澶勭疆鐘舵�侊紙0=鏈缃紝1=宸插缃級', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2052, 'MES 瀹夌伅绾у埆', 'mes_pro_andon_level', 0, 'MES 鐢熶骇绠$悊 - 瀹夌伅绾у埆锛�1=涓�绾э紝2=浜岀骇锛�3=涓夌骇锛�', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2053, 'MES 鐢熶骇鎶ュ伐鐘舵��', 'mes_pro_feedback_status', 0, 'MES 鐢熶骇绠$悊 - 鎶ュ伐鐘舵�侊紙0=鑽夌锛�1=瀹℃壒涓紝2=寰呮楠岋紝3=宸插畬鎴愶紝4=宸插彇娑堬級', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2054, 'MES 鐢熶骇鎶ュ伐绫诲瀷', 'mes_pro_feedback_type', 0, 'MES 鐢熶骇绠$悊 - 鎶ュ伐绫诲瀷锛�1=鑷鎶ュ伐锛�2=缁熶竴鎶ュ伐锛�', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2055, 'MES 鐢熶骇鎶ュ伐閫斿緞', 'mes_pro_feedback_channel', 0, 'MES 鐢熶骇绠$悊 - 鎶ュ伐閫斿緞锛圥C/APP/PDA锛�', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2056, 'MES 璐ㄦ鍊肩被鍨�', 'mes_qc_result_type', 0, '妫�楠岀粨鏋滄槑缁嗙殑鍊肩被鍨嬶細娴偣/鏁存暟/鏂囨湰/瀛楀吀/鏂囦欢', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2057, 'MES 閫�璐ф楠岀被鍨�', 'mes_rqc_type', 0, 'MES 閫�璐ф楠岀被鍨�', '1', '2026-02-22 06:43:18', '1', '2026-02-22 06:43:18', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2062, 'MES IPQC 妫�楠岀被鍨�', 'mes_ipqc_type', 0, 'IPQC 杩囩▼妫�楠岀殑妫�楠岀被鍨�', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2066, 'MES 鍒拌揣閫氱煡鍗曠姸鎬�', 'mes_wm_arrival_notice_status', 0, 'MES 鍒拌揣閫氱煡鍗曠姸鎬�', '1', '2026-02-22 14:53:18', '1', '2026-02-22 14:53:18', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2067, 'MES 閲囪喘鍏ュ簱鍗曠姸鎬�', 'mes_wm_item_receipt_status', 0, 'MES 閲囪喘鍏ュ簱鍗曠姸鎬�', '1', '2026-02-22 14:54:05', '1', '2026-02-22 14:54:05', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2068, 'MES 鍗曟嵁鐘舵��', 'mes_order_status', 0, '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:17:37', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2069, 'MES 棰嗘枡鍑哄簱鍗曠姸鎬�', 'mes_wm_product_issue_status', 0, 'MES 棰嗘枡鍑哄簱鍗曠姸鎬�', '1', '2026-02-26 16:39:44', '1', '2026-04-05 15:05:11', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2073, 'MES 鐢熶骇閫�鏂欏崟鐘舵��', 'mes_wm_return_issue_status', 0, 'MES 鐢熶骇閫�鏂欏崟鐘舵��', '1', '2026-02-28 14:11:09', '1', '2026-04-05 15:05:14', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2074, 'MES 鐢熶骇閫�鏂欑被鍨�', 'mes_wm_return_issue_type', 0, 'MES 鐢熶骇閫�鏂欑被鍨�', '1', '2026-02-28 14:11:09', '1', '2026-04-05 15:05:16', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2075, 'MES 璐ㄩ噺鐘舵��', 'mes_wm_quality_status', 0, 'MES 璐ㄩ噺鐘舵�侊紙寰呮/鍚堟牸/涓嶅悎鏍硷級', '1', '2026-02-28 15:00:53', '1', '2026-02-28 15:00:53', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2100, 'MES 浜у搧鍏ュ簱鍗曠姸鎬�', 'mes_wm_product_receipt_status', 0, 'MES 浜у搧鍏ュ簱鍗曠姸鎬�', '1', '2026-03-01 06:03:04', '1', '2026-04-05 15:05:49', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2102, 'MES 閿�鍞嚭搴撳崟鐘舵��', 'mes_wm_product_sales_status', 0, 'MES 閿�鍞嚭搴撳崟鐘舵��', '1', '2026-03-02 08:55:11', '1', '2026-04-05 15:05:18', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2105, 'MES 鏉傞」鍏ュ簱绫诲瀷', 'mes_wm_misc_receipt_type', 0, '鏉傞」鍏ュ簱绫诲瀷', '1', '2026-03-03 07:18:12', '1', '2026-04-05 15:05:23', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2106, 'MES 鏉傞」鍏ュ簱鐘舵��', 'mes_wm_misc_receipt_status', 0, '鏉傞」鍏ュ簱鐘舵��', '1', '2026-03-03 07:18:12', '1', '2026-04-05 15:05:25', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2109, 'MES 鏉傞」鍑哄簱绫诲瀷', 'mes_wm_misc_issue_type', 0, 'MES 鏉傞」鍑哄簱绫诲瀷', '1', '2026-03-03 07:34:33', '1', '2026-03-03 07:34:33', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2110, 'MES 澶栧崗鍏ュ簱鍗曠姸鎬�', 'mes_wm_outsource_receipt_status', 0, 'MES 澶栧崗鍏ュ簱鍗曠姸鎬�', '1', '2026-03-03 14:03:20', '1', '2026-03-03 14:03:20', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2112, 'MES 澶栧崗鍙戞枡鍗曠姸鎬�', 'mes_wm_outsource_issue_status', 0, 'MES 澶栧崗鍙戞枡鍗曠姸鎬�', '1', '2026-03-03 16:30:56', '1', '2026-04-05 15:05:47', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2113, 'MES 缂栫爜瑙勫垯鍒嗘绫诲瀷', 'mes_md_auto_code_part_type', 0, 'MES 缂栫爜瑙勫垯鍒嗘绫诲瀷', '1', '2026-03-04 14:45:46', '1', '2026-03-04 15:24:40', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2115, 'MES 缂栫爜瑙勫垯琛ラ綈鏂瑰紡', 'mes_md_auto_code_padded_method', 0, 'MES 缂栫爜瑙勫垯琛ラ綈鏂瑰紡', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2116, 'MES 缂栫爜瑙勫垯寰幆鏂瑰紡', 'mes_md_auto_code_cycle_method', 0, 'MES 缂栫爜瑙勫垯寰幆鏂瑰紡', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2117, 'MES 鏉$爜鏍煎紡', 'mes_wm_barcode_format', 0, 'MES 鏉$爜鏍煎紡', '1', '2026-03-05 14:37:20', '1', '2026-04-05 15:05:27', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2118, 'MES 鏉$爜涓氬姟绫诲瀷', 'mes_wm_barcode_biz_type', 0, 'MES 鏉$爜涓氬姟绫诲瀷', '1', '2026-03-05 14:37:20', '1', '2026-04-05 15:05:29', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2121, 'MES 瑁呯鍗曠姸鎬�', 'mes_wm_package_status', 0, 'MES 瑁呯鍗曠姸鎬�', '1', '2026-03-08 02:05:46', '1', '2026-04-05 15:05:35', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2122, 'MES 璋冩嫧鍗曠姸鎬�', 'mes_wm_transfer_status', 0, 'MES 璋冩嫧鍗曠姸鎬�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2123, 'MES 璋冩嫧绫诲瀷', 'mes_wm_transfer_type', 0, 'MES 璋冩嫧绫诲瀷', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2124, 'MES 鐩樼偣绫诲瀷', 'mes_wm_stock_taking_type', 0, 'MES 鐩樼偣绫诲瀷', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2125, 'MES 鐩樼偣鏂规鍙傛暟绫诲瀷', 'mes_wm_stock_taking_plan_param_type', 0, 'MES 鐩樼偣鏂规鍙傛暟绫诲瀷', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2126, 'MES 鐩樼偣浠诲姟鐘舵��', 'mes_wm_stock_taking_task_status', 0, 'MES 鐩樼偣浠诲姟鐘舵��', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2127, 'MES 鐩樼偣浠诲姟琛岀姸鎬�', 'mes_wm_stock_taking_task_line_status', 0, 'MES 鐩樼偣浠诲姟琛岀姸鎬�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2129, 'MES 鐗╂枡浜у搧鏍囪瘑', 'mes_md_item_or_product', 0, '鐗╂枡鍒嗙被锛氱墿鏂�(ITEM) / 浜у搧(PRODUCT)', '1', '2026-03-15 01:55:06', '1', '2026-03-15 01:55:06', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2130, 'MES 渚涘簲鍟嗛��璐у崟鐘舵��', 'mes_wm_return_vendor_status', 0, '閲囪喘閫�璐у崟鐘舵��', '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2131, 'MES 鍙戣揣閫氱煡鍗曠姸鎬�', 'mes_wm_sales_notice_status', 0, 'MES 鍙戣揣閫氱煡鍗曠姸鎬�', '1', '2026-03-30 08:54:30', '1', '2026-04-05 15:53:46', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2132, 'MES 鏉傞」鍑哄簱鍗曠姸鎬�', 'mes_wm_misc_issue_status', 0, '鏉傞」鍑哄簱鍗曠姸鎬�', '1', '2026-03-30 15:00:18', '1', '2026-04-05 15:05:41', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2133, 'MES 閿�鍞��璐у崟鐘舵��', 'mes_wm_return_sales_status', 0, 'MES 閿�鍞��璐у崟鐘舵�佹灇涓�', '1', '2026-04-03 17:20:25', '1', '2026-04-05 15:05:39', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2135, 'MES 涓婁笅宸ョ姸鎬佺被鍨�', 'mes_pro_work_record_type', 0, 'MES 涓婁笅宸ョ姸鎬佺被鍨�', '1', '2026-04-05 14:07:27', '1', '2026-04-05 14:07:27', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2138, 'MES 鐢熶骇鍏ュ簱鍗曠姸鎬�', 'mes_wm_product_produce_status', 0, 'MES 鐢熶骇鍏ュ簱鍗曠姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0', '1970-01-01 00:00:00');
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2200, 'IM 娑堟伅绫诲瀷', 'im_message_type', 0, '瀵瑰簲 ImMessageTypeEnum', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2201, 'IM 绉佽亰娑堟伅鐘舵��', 'im_private_message_status', 0, '瀵瑰簲 ImMessageStatusEnum锛涚鑱� 0=鏈 / 2=宸叉挙鍥� / 3=宸茶', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 15:14:36', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2202, 'IM 缇ゆ秷鎭洖鎵х姸鎬�', 'im_group_message_receipt_status', 0, '瀵瑰簲 ImGroupMessageReceiptStatusEnum', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2203, 'IM 濂藉弸鐘舵��', 'im_friend_status', 0, '0=姝e父 / 1=宸插垹闄�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2204, 'IM 缇ょ姸鎬�', 'im_group_status', 0, '0=姝e父 / 1=宸茶В鏁�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2205, 'IM 缇よ亰娑堟伅鐘舵��', 'im_group_message_status', 0, '瀵瑰簲 ImMessageStatusEnum锛涚兢鑱� 0=姝e父 / 2=宸叉挙鍥烇紙鏃犳湭璇绘蹇碉級', 'admin', '2026-04-30 15:14:36', 'admin', '2026-04-30 15:14:36', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2206, 'IM 缇ゆ垚鍛樿鑹�', 'im_group_member_role', 0, NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2207, 'IM 濂藉弸娣诲姞鏉ユ簮', 'im_friend_add_source', 0, NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2208, 'IM 濂藉弸鐢宠澶勭悊缁撴灉', 'im_friend_request_handle_result', 0, NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2209, 'IM 鍔犵兢鏉ユ簮', 'im_group_add_source', 0, NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (2210, 'IM 鍔犵兢鐢宠澶勭悊缁撴灉', 'im_group_request_handle_result', 0, NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061050, '寰�鏉ヤ紒涓氱被鍨�', 'merchant_type', 0, 'WMS 寰�鏉ヤ紒涓氱被鍨�', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061060, 'WMS 鍗曟嵁绫诲瀷', 'wms_order_type', 0, 'WMS 鍗曟嵁绫诲瀷', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061070, 'WMS 鍗曟嵁鐘舵��', 'wms_order_status', 0, 'WMS 鍗曟嵁鐘舵��', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061080, '鍏ュ簱鍗曠被鍨�', 'wms_receipt_order_type', 0, 'WMS 鍏ュ簱鍗曠被鍨�', '1', '2026-05-11 11:21:49', '1', '2026-05-12 13:40:29', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061090, '鍑哄簱鍗曠被鍨�', 'wms_shipment_order_type', 0, 'WMS 鍑哄簱鍗曠被鍨�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061092, 'IM 閫氳瘽濯掍綋绫诲瀷', 'im_rtc_call_media_type', 0, NULL, 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061093, 'IM 閫氳瘽浼氳瘽绫诲瀷', 'im_rtc_call_conversation_type', 0, '1=绉佽亰锛�2=缇よ亰', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061094, 'IM 閫氳瘽鐘舵��', 'im_rtc_call_status', 0, '10=鍒涘缓锛�20=杩涜涓紱30=宸茬粨鏉�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061095, 'IM 閫氳瘽缁撴潫鍘熷洜', 'im_rtc_call_end_reason', 0, '1=閫氳瘽缁撴潫锛�2=宸叉嫆缁濓紱3=宸插彇娑堬紱4=鏃犱汉鎺ュ惉锛�5=瀵规柟姝e繖锛�9=閫氳瘽寮傚父', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061096, 'IM 閫氳瘽鍙備笌瑙掕壊', 'im_rtc_participant_role', 0, '1=鍙戣捣浜猴紱2=琚個璇疯�咃紱3=涓诲姩鍔犲叆鑰�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061097, 'IM 閫氳瘽鍙備笌鐘舵��', 'im_rtc_participant_status', 0, '10=閭�璇蜂腑锛�20=宸插姞鍏ワ紱30=宸叉嫆缁濓紱40=鏈簲绛旓紱50=宸茬寮�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0', NULL);
+INSERT INTO system_dict_type (id, name, type, status, remark, creator, create_time, updater, update_time, deleted, deleted_time) VALUES (1061098, 'IM 棰戦亾绱犳潗鍐呭绫诲瀷', 'im_channel_material_type', 0, '1=绔欏唴瀵屾枃鏈� / 2=澶栭摼', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', '0', NULL);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_dict_type_seq;
+CREATE SEQUENCE system_dict_type_seq
+ START 1061099;
+
+-- ----------------------------
+-- Table structure for system_login_log
+-- ----------------------------
+DROP TABLE IF EXISTS system_login_log;
+CREATE TABLE system_login_log (
+ id int8 NOT NULL,
+ log_type int8 NOT NULL,
+ trace_id varchar(64) NOT NULL DEFAULT '',
+ user_id int8 NOT NULL DEFAULT 0,
+ user_type int2 NOT NULL DEFAULT 0,
+ username varchar(50) NOT NULL DEFAULT '',
+ result int2 NOT NULL,
+ user_ip varchar(50) NOT NULL,
+ user_agent varchar(512) NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_login_log ADD CONSTRAINT pk_system_login_log PRIMARY KEY (id);
+
+CREATE INDEX idx_system_login_log_01 ON system_login_log (username);
+CREATE INDEX idx_system_login_log_02 ON system_login_log (create_time);
+
+COMMENT ON COLUMN system_login_log.id IS '璁块棶ID';
+COMMENT ON COLUMN system_login_log.log_type IS '鏃ュ織绫诲瀷';
+COMMENT ON COLUMN system_login_log.trace_id IS '閾捐矾杩借釜缂栧彿';
+COMMENT ON COLUMN system_login_log.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_login_log.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_login_log.username IS '鐢ㄦ埛璐﹀彿';
+COMMENT ON COLUMN system_login_log.result IS '鐧婚檰缁撴灉';
+COMMENT ON COLUMN system_login_log.user_ip IS '鐢ㄦ埛 IP';
+COMMENT ON COLUMN system_login_log.user_agent IS '娴忚鍣� UA';
+COMMENT ON COLUMN system_login_log.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_login_log.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_login_log.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_login_log.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_login_log.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_login_log.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_login_log IS '绯荤粺璁块棶璁板綍';
+
+DROP SEQUENCE IF EXISTS system_login_log_seq;
+CREATE SEQUENCE system_login_log_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_mail_account
+-- ----------------------------
+DROP TABLE IF EXISTS system_mail_account;
+CREATE TABLE system_mail_account (
+ id int8 NOT NULL,
+ mail varchar(255) NOT NULL,
+ username varchar(255) NOT NULL,
+ password varchar(255) NOT NULL,
+ host varchar(255) NOT NULL,
+ port int4 NOT NULL,
+ ssl_enable bool NOT NULL DEFAULT '0',
+ starttls_enable bool NOT NULL DEFAULT '0',
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_mail_account ADD CONSTRAINT pk_system_mail_account PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_mail_account.id IS '涓婚敭';
+COMMENT ON COLUMN system_mail_account.mail IS '閭';
+COMMENT ON COLUMN system_mail_account.username IS '鐢ㄦ埛鍚�';
+COMMENT ON COLUMN system_mail_account.password IS '瀵嗙爜';
+COMMENT ON COLUMN system_mail_account.host IS 'SMTP 鏈嶅姟鍣ㄥ煙鍚�';
+COMMENT ON COLUMN system_mail_account.port IS 'SMTP 鏈嶅姟鍣ㄧ鍙�';
+COMMENT ON COLUMN system_mail_account.ssl_enable IS '鏄惁寮�鍚� SSL';
+COMMENT ON COLUMN system_mail_account.starttls_enable IS '鏄惁寮�鍚� STARTTLS';
+COMMENT ON COLUMN system_mail_account.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_mail_account.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_mail_account.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_mail_account.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_mail_account.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_mail_account IS '閭璐﹀彿琛�';
+
+-- ----------------------------
+-- Records of system_mail_account
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (1, '7684413@qq.com', '7684413@qq.com', '1234576', '127.0.0.1', 8080, '0', '0', '1', '2023-01-25 17:39:52', '1', '2025-04-04 16:34:40', '0');
+INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (2, 'ydym_test@163.com', 'ydym_test@163.com', 'WBZTEINMIFVRYSOE', 'smtp.163.com', 465, '1', '0', '1', '2023-01-26 01:26:03', '1', '2025-12-20 18:09:32', '0');
+INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (3, '76854114@qq.com', '3335', '11234', 'yunai1.cn', 466, '0', '0', '1', '2023-01-27 15:06:38', '1', '2023-01-27 07:08:36', '1');
+INSERT INTO system_mail_account (id, mail, username, password, host, port, ssl_enable, starttls_enable, creator, create_time, updater, update_time, deleted) VALUES (4, '7685413x@qq.com', '2', '3', '4', 5, '1', '0', '1', '2023-04-12 23:05:06', '1', '2023-04-12 15:05:11', '1');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_mail_account_seq;
+CREATE SEQUENCE system_mail_account_seq
+ START 5;
+
+-- ----------------------------
+-- Table structure for system_mail_log
+-- ----------------------------
+DROP TABLE IF EXISTS system_mail_log;
+CREATE TABLE system_mail_log (
+ id int8 NOT NULL,
+ user_id int8 NULL DEFAULT NULL,
+ user_type int2 NULL DEFAULT NULL,
+ to_mails varchar(1024) NOT NULL,
+ cc_mails varchar(1024) NULL DEFAULT NULL,
+ bcc_mails varchar(1024) NULL DEFAULT NULL,
+ account_id int8 NOT NULL,
+ from_mail varchar(255) NOT NULL,
+ template_id int8 NOT NULL,
+ template_code varchar(63) NOT NULL,
+ template_nickname varchar(255) NULL DEFAULT NULL,
+ template_title varchar(255) NOT NULL,
+ template_content text NOT NULL,
+ template_params varchar(255) NOT NULL,
+ send_status int2 NOT NULL DEFAULT 0,
+ send_time timestamp NULL DEFAULT NULL,
+ send_message_id varchar(255) NULL DEFAULT NULL,
+ send_exception varchar(4096) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_mail_log ADD CONSTRAINT pk_system_mail_log PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_mail_log.id IS '缂栧彿';
+COMMENT ON COLUMN system_mail_log.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_mail_log.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_mail_log.to_mails IS '鎺ユ敹閭鍦板潃';
+COMMENT ON COLUMN system_mail_log.cc_mails IS '鎶勯�侀偖绠卞湴鍧�';
+COMMENT ON COLUMN system_mail_log.bcc_mails IS '瀵嗛�侀偖绠卞湴鍧�';
+COMMENT ON COLUMN system_mail_log.account_id IS '閭璐﹀彿缂栧彿';
+COMMENT ON COLUMN system_mail_log.from_mail IS '鍙戦�侀偖绠卞湴鍧�';
+COMMENT ON COLUMN system_mail_log.template_id IS '妯℃澘缂栧彿';
+COMMENT ON COLUMN system_mail_log.template_code IS '妯℃澘缂栫爜';
+COMMENT ON COLUMN system_mail_log.template_nickname IS '妯$増鍙戦�佷汉鍚嶇О';
+COMMENT ON COLUMN system_mail_log.template_title IS '閭欢鏍囬';
+COMMENT ON COLUMN system_mail_log.template_content IS '閭欢鍐呭';
+COMMENT ON COLUMN system_mail_log.template_params IS '閭欢鍙傛暟';
+COMMENT ON COLUMN system_mail_log.send_status IS '鍙戦�佺姸鎬�';
+COMMENT ON COLUMN system_mail_log.send_time IS '鍙戦�佹椂闂�';
+COMMENT ON COLUMN system_mail_log.send_message_id IS '鍙戦�佽繑鍥炵殑娑堟伅 ID';
+COMMENT ON COLUMN system_mail_log.send_exception IS '鍙戦�佸紓甯�';
+COMMENT ON COLUMN system_mail_log.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_mail_log.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_mail_log.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_mail_log.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_mail_log.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_mail_log IS '閭欢鏃ュ織琛�';
+
+DROP SEQUENCE IF EXISTS system_mail_log_seq;
+CREATE SEQUENCE system_mail_log_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_mail_template
+-- ----------------------------
+DROP TABLE IF EXISTS system_mail_template;
+CREATE TABLE system_mail_template (
+ id int8 NOT NULL,
+ name varchar(63) NOT NULL,
+ code varchar(63) NOT NULL,
+ account_id int8 NOT NULL,
+ nickname varchar(255) NULL DEFAULT NULL,
+ title varchar(255) NOT NULL,
+ content varchar(10240) NOT NULL,
+ params varchar(255) NOT NULL,
+ status int2 NOT NULL,
+ remark varchar(255) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_mail_template ADD CONSTRAINT pk_system_mail_template PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_mail_template.id IS '缂栧彿';
+COMMENT ON COLUMN system_mail_template.name IS '妯℃澘鍚嶇О';
+COMMENT ON COLUMN system_mail_template.code IS '妯℃澘缂栫爜';
+COMMENT ON COLUMN system_mail_template.account_id IS '鍙戦�佺殑閭璐﹀彿缂栧彿';
+COMMENT ON COLUMN system_mail_template.nickname IS '鍙戦�佷汉鍚嶇О';
+COMMENT ON COLUMN system_mail_template.title IS '妯℃澘鏍囬';
+COMMENT ON COLUMN system_mail_template.content IS '妯℃澘鍐呭';
+COMMENT ON COLUMN system_mail_template.params IS '鍙傛暟鏁扮粍';
+COMMENT ON COLUMN system_mail_template.status IS '寮�鍚姸鎬�';
+COMMENT ON COLUMN system_mail_template.remark IS '澶囨敞';
+COMMENT ON COLUMN system_mail_template.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_mail_template.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_mail_template.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_mail_template.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_mail_template.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_mail_template IS '閭欢妯$増琛�';
+
+-- ----------------------------
+-- Records of system_mail_template
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (13, '鍚庡彴鐢ㄦ埛鐭俊鐧诲綍', 'admin-sms-login', 1, '濂ョ壒鏇�', '浣犵寽鎴戠寽', '<p>鎮ㄧ殑楠岃瘉鐮佹槸{code}锛屽悕瀛楁槸{name}</p>', '["code","name"]', 0, '3', '1', '2021-10-11 08:10:00', '1', '2023-12-02 19:51:14', '0');
+INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (14, '娴嬭瘯妯$増', 'test_01', 2, '鑺嬭壙', '涓�涓爣棰�', '<p>浣犳槸 {key01} 鍚楋紵</p><p><br></p><p>鏄殑璇濓紝璧剁揣 {key02} 涓�涓嬶紒</p>', '["key01","key02"]', 0, NULL, '1', '2023-01-26 01:27:40', '1', '2025-07-26 21:48:45', '0');
+INSERT INTO system_mail_template (id, name, code, account_id, nickname, title, content, params, status, remark, creator, create_time, updater, update_time, deleted) VALUES (15, '3', '2', 2, '7', '4', '<p>45</p>', '[]', 1, '80', '1', '2023-01-27 15:50:35', '1', '2025-07-26 21:47:49', '1');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_mail_template_seq;
+CREATE SEQUENCE system_mail_template_seq
+ START 16;
+
+-- ----------------------------
+-- Table structure for system_menu
+-- ----------------------------
+DROP TABLE IF EXISTS system_menu;
+CREATE TABLE system_menu (
+ id int8 NOT NULL,
+ name varchar(50) NOT NULL,
+ permission varchar(100) NOT NULL DEFAULT '',
+ type int2 NOT NULL,
+ sort int4 NOT NULL DEFAULT 0,
+ parent_id int8 NOT NULL DEFAULT 0,
+ path varchar(200) NULL DEFAULT '',
+ icon varchar(100) NULL DEFAULT '#',
+ component varchar(255) NULL DEFAULT NULL,
+ component_name varchar(255) NULL DEFAULT NULL,
+ status int2 NOT NULL DEFAULT 0,
+ visible bool NOT NULL DEFAULT '1',
+ keep_alive bool NOT NULL DEFAULT '1',
+ always_show bool NOT NULL DEFAULT '1',
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_menu ADD CONSTRAINT pk_system_menu PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_menu.id IS '鑿滃崟ID';
+COMMENT ON COLUMN system_menu.name IS '鑿滃崟鍚嶇О';
+COMMENT ON COLUMN system_menu.permission IS '鏉冮檺鏍囪瘑';
+COMMENT ON COLUMN system_menu.type IS '鑿滃崟绫诲瀷';
+COMMENT ON COLUMN system_menu.sort IS '鏄剧ず椤哄簭';
+COMMENT ON COLUMN system_menu.parent_id IS '鐖惰彍鍗旾D';
+COMMENT ON COLUMN system_menu.path IS '璺敱鍦板潃';
+COMMENT ON COLUMN system_menu.icon IS '鑿滃崟鍥炬爣';
+COMMENT ON COLUMN system_menu.component IS '缁勪欢璺緞';
+COMMENT ON COLUMN system_menu.component_name IS '缁勪欢鍚�';
+COMMENT ON COLUMN system_menu.status IS '鑿滃崟鐘舵��';
+COMMENT ON COLUMN system_menu.visible IS '鏄惁鍙';
+COMMENT ON COLUMN system_menu.keep_alive IS '鏄惁缂撳瓨';
+COMMENT ON COLUMN system_menu.always_show IS '鏄惁鎬绘槸鏄剧ず';
+COMMENT ON COLUMN system_menu.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_menu.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_menu.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_menu.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_menu.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_menu IS '鑿滃崟鏉冮檺琛�';
+
+-- ----------------------------
+-- Records of system_menu
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1, '绯荤粺绠$悊', '', 1, 10, 0, '/system', 'ep:tools', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2025-03-15 21:30:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2, '鍩虹璁炬柦', '', 1, 20, 0, '/infra', 'ep:monitor', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-03-01 08:28:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5, 'OA 绀轰緥', '', 1, 40, 1185, 'oa', 'fa:road', NULL, NULL, 0, '1', '1', '1', 'admin', '2021-09-20 16:26:19', '1', '2024-02-29 12:38:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (100, '鐢ㄦ埛绠$悊', 'system:user:list', 2, 1, 1, 'user', 'ep:avatar', 'system/user/index', 'SystemUser', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2026-01-01 18:43:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (101, '瑙掕壊绠$悊', '', 2, 2, 1, 'role', 'ep:user', 'system/role/index', 'SystemRole', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2026-01-05 19:30:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (102, '鑿滃崟绠$悊', '', 2, 3, 1, 'menu', 'ep:menu', 'system/menu/index', 'SystemMenu', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:03:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (103, '閮ㄩ棬绠$悊', '', 2, 4, 1, 'dept', 'fa:address-card', 'system/dept/index', 'SystemDept', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (104, '宀椾綅绠$悊', '', 2, 5, 1, 'post', 'fa:address-book-o', 'system/post/index', 'SystemPost', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:06:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (105, '瀛楀吀绠$悊', '', 2, 6, 1, 'dict', 'ep:collection', 'system/dict/index', 'SystemDictType', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:07:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (106, '閰嶇疆绠$悊', '', 2, 8, 2, 'config', 'fa:connectdevelop', 'infra/config/index', 'InfraConfig', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:02:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (107, '閫氱煡鍏憡', '', 2, 4, 2739, 'notice', 'ep:takeaway-box', 'system/notice/index', 'SystemNotice', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-22 23:56:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (108, '瀹¤鏃ュ織', '', 1, 9, 1, 'log', 'ep:document-copy', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:08:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (109, '浠ょ墝绠$悊', '', 2, 2, 1261, 'token', 'fa:key', 'system/oauth2/token/index', 'SystemTokenClient', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:13:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (110, '瀹氭椂浠诲姟', '', 2, 7, 2, 'job', 'fa-solid:tasks', 'infra/job/index', 'InfraJob', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:57:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (111, 'MySQL 鐩戞帶', '', 2, 1, 2740, 'druid', 'fa-solid:box', 'infra/druid/index', 'InfraDruid', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:05:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (112, 'Java 鐩戞帶', '', 2, 3, 2740, 'admin-server', 'ep:coffee-cup', 'infra/server/index', 'InfraAdminServer', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (113, 'Redis 鐩戞帶', '', 2, 2, 2740, 'redis', 'fa:reddit-square', 'infra/redis/index', 'InfraRedis', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:06:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (114, '琛ㄥ崟鏋勫缓', 'infra:build:list', 2, 2, 2, 'build', 'fa:wpforms', 'infra/build/index', 'InfraBuild', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (115, '浠g爜鐢熸垚', 'infra:codegen:query', 2, 1, 2, 'codegen', 'ep:document-copy', 'infra/codegen/index', 'InfraCodegen', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 08:51:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (116, 'API 鎺ュ彛', 'infra:swagger:list', 2, 3, 2, 'swagger', 'fa:fighter-jet', 'infra/swagger/index', 'InfraSwagger', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-04-23 00:01:24', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (500, '鎿嶄綔鏃ュ織', '', 2, 1, 108, 'operate-log', 'ep:position', 'system/operatelog/index', 'SystemOperateLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:09:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (501, '鐧诲綍鏃ュ織', '', 2, 2, 108, 'login-log', 'ep:promotion', 'system/loginlog/index', 'SystemLoginLog', 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2024-02-29 01:10:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1001, '鐢ㄦ埛鏌ヨ', 'system:user:query', 3, 1, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1002, '鐢ㄦ埛鏂板', 'system:user:create', 3, 2, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1003, '鐢ㄦ埛淇敼', 'system:user:update', 3, 3, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1004, '鐢ㄦ埛鍒犻櫎', 'system:user:delete', 3, 4, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1005, '鐢ㄦ埛瀵煎嚭', 'system:user:export', 3, 5, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1006, '鐢ㄦ埛瀵煎叆', 'system:user:import', 3, 6, 100, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1007, '閲嶇疆瀵嗙爜', 'system:user:update-password', 3, 7, 100, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1008, '瑙掕壊鏌ヨ', 'system:role:query', 3, 1, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1009, '瑙掕壊鏂板', 'system:role:create', 3, 2, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1010, '瑙掕壊淇敼', 'system:role:update', 3, 3, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1011, '瑙掕壊鍒犻櫎', 'system:role:delete', 3, 4, 101, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1012, '瑙掕壊瀵煎嚭', 'system:role:export', 3, 5, 101, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1013, '鑿滃崟鏌ヨ', 'system:menu:query', 3, 1, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1014, '鑿滃崟鏂板', 'system:menu:create', 3, 2, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1015, '鑿滃崟淇敼', 'system:menu:update', 3, 3, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1016, '鑿滃崟鍒犻櫎', 'system:menu:delete', 3, 4, 102, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1017, '閮ㄩ棬鏌ヨ', 'system:dept:query', 3, 1, 103, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1018, '閮ㄩ棬鏂板', 'system:dept:create', 3, 2, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1019, '閮ㄩ棬淇敼', 'system:dept:update', 3, 3, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1020, '閮ㄩ棬鍒犻櫎', 'system:dept:delete', 3, 4, 103, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1021, '宀椾綅鏌ヨ', 'system:post:query', 3, 1, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1022, '宀椾綅鏂板', 'system:post:create', 3, 2, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1023, '宀椾綅淇敼', 'system:post:update', 3, 3, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1024, '宀椾綅鍒犻櫎', 'system:post:delete', 3, 4, 104, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1025, '宀椾綅瀵煎嚭', 'system:post:export', 3, 5, 104, '', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1026, '瀛楀吀鏌ヨ', 'system:dict:query', 3, 1, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1027, '瀛楀吀鏂板', 'system:dict:create', 3, 2, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1028, '瀛楀吀淇敼', 'system:dict:update', 3, 3, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1029, '瀛楀吀鍒犻櫎', 'system:dict:delete', 3, 4, 105, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1030, '瀛楀吀瀵煎嚭', 'system:dict:export', 3, 5, 105, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1031, '閰嶇疆鏌ヨ', 'infra:config:query', 3, 1, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1032, '閰嶇疆鏂板', 'infra:config:create', 3, 2, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1033, '閰嶇疆淇敼', 'infra:config:update', 3, 3, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1034, '閰嶇疆鍒犻櫎', 'infra:config:delete', 3, 4, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1035, '閰嶇疆瀵煎嚭', 'infra:config:export', 3, 5, 106, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1036, '鍏憡鏌ヨ', 'system:notice:query', 3, 1, 107, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1037, '鍏憡鏂板', 'system:notice:create', 3, 2, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1038, '鍏憡淇敼', 'system:notice:update', 3, 3, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1039, '鍏憡鍒犻櫎', 'system:notice:delete', 3, 4, 107, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1040, '鎿嶄綔鏌ヨ', 'system:operate-log:query', 3, 1, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1042, '鏃ュ織瀵煎嚭', 'system:operate-log:export', 3, 2, 500, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1043, '鐧诲綍鏌ヨ', 'system:login-log:query', 3, 1, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1045, '鏃ュ織瀵煎嚭', 'system:login-log:export', 3, 3, 501, '#', '#', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1046, '浠ょ墝鍒楄〃', 'system:oauth2-token:page', 3, 1, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1048, '浠ょ墝鍒犻櫎', 'system:oauth2-token:delete', 3, 2, 109, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-05-09 23:54:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1050, '浠诲姟鏂板', 'infra:job:create', 3, 2, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1051, '浠诲姟淇敼', 'infra:job:update', 3, 3, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1052, '浠诲姟鍒犻櫎', 'infra:job:delete', 3, 4, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1053, '鐘舵�佷慨鏀�', 'infra:job:update', 3, 5, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1054, '浠诲姟瀵煎嚭', 'infra:job:export', 3, 7, 110, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1056, '鐢熸垚淇敼', 'infra:codegen:update', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1057, '鐢熸垚鍒犻櫎', 'infra:codegen:delete', 3, 3, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1058, '瀵煎叆浠g爜', 'infra:codegen:create', 3, 2, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1059, '棰勮浠g爜', 'infra:codegen:preview', 3, 4, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1060, '鐢熸垚浠g爜', 'infra:codegen:download', 3, 5, 115, '', '', '', NULL, 0, '1', '1', '1', 'admin', '2021-01-05 17:03:48', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1063, '璁剧疆瑙掕壊鑿滃崟鏉冮檺', 'system:permission:assign-role-menu', 3, 6, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:53:44', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1064, '璁剧疆瑙掕壊鏁版嵁鏉冮檺', 'system:permission:assign-role-data-scope', 3, 7, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-06 17:56:31', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1065, '璁剧疆鐢ㄦ埛瑙掕壊', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-07 10:23:28', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1066, '鑾峰緱 Redis 鐩戞帶淇℃伅', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:31', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1067, '鑾峰緱 Redis Key 鍒楄〃', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, '1', '1', '1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1070, '浠g爜鐢熸垚妗堜緥', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, '1', '1', '1', '', '2021-02-06 12:42:49', '1', '2023-11-15 23:45:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1075, '浠诲姟瑙﹀彂', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1077, '閾捐矾杩借釜', '', 2, 4, 2740, 'skywalking', 'fa:eye', 'infra/skywalking/index', 'InfraSkyWalking', 0, '1', '1', '1', '', '2021-02-08 20:41:31', '1', '2024-04-23 00:07:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1078, '璁块棶鏃ュ織', '', 2, 1, 1083, 'api-access-log', 'ep:place', 'infra/apiAccessLog/index', 'InfraApiAccessLog', 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2024-02-29 08:54:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1082, '鏃ュ織瀵煎嚭', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 01:32:59', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1083, 'API 鏃ュ織', '', 2, 4, 2, 'log', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '', '2021-02-26 02:18:24', '1', '2024-04-22 23:58:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1084, '閿欒鏃ュ織', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'ep:warning-filled', 'infra/apiErrorLog/index', 'InfraApiErrorLog', 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2024-02-29 08:55:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1085, '鏃ュ織澶勭悊', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1086, '鏃ュ織瀵煎嚭', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', NULL, 0, '1', '1', '1', '', '2021-02-26 07:53:20', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1087, '浠诲姟鏌ヨ', 'infra:job:query', 3, 1, 110, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:26:19', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1088, '鏃ュ織鏌ヨ', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:28:04', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1089, '鏃ュ織鏌ヨ', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-03-10 01:29:09', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1090, '鏂囦欢鍒楄〃', '', 2, 5, 1243, 'file', 'ep:upload-filled', 'infra/file/index', 'InfraFile', 0, '1', '1', '1', '', '2021-03-12 20:16:20', '1', '2024-02-29 08:53:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1091, '鏂囦欢鏌ヨ', 'infra:file:query', 3, 1, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1092, '鏂囦欢鍒犻櫎', 'infra:file:delete', 3, 4, 1090, '', '', '', NULL, 0, '1', '1', '1', '', '2021-03-12 20:16:20', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1093, '鐭俊绠$悊', '', 1, 1, 2739, 'sms', 'ep:message', NULL, NULL, 0, '1', '1', '1', '1', '2021-04-05 01:10:16', '1', '2024-04-22 23:56:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1094, '鐭俊娓犻亾', '', 2, 0, 1093, 'sms-channel', 'fa:stack-exchange', 'system/sms/channel/index', 'SystemSmsChannel', 0, '1', '1', '1', '', '2021-04-01 11:07:15', '1', '2024-02-29 01:15:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1095, '鐭俊娓犻亾鏌ヨ', 'system:sms-channel:query', 3, 1, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1096, '鐭俊娓犻亾鍒涘缓', 'system:sms-channel:create', 3, 2, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1097, '鐭俊娓犻亾鏇存柊', 'system:sms-channel:update', 3, 3, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1098, '鐭俊娓犻亾鍒犻櫎', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 11:07:15', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1100, '鐭俊妯℃澘', '', 2, 1, 1093, 'sms-template', 'ep:connection', 'system/sms/template/index', 'SystemSmsTemplate', 0, '1', '1', '1', '', '2021-04-01 17:35:17', '1', '2024-02-29 01:16:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1101, '鐭俊妯℃澘鏌ヨ', 'system:sms-template:query', 3, 1, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1102, '鐭俊妯℃澘鍒涘缓', 'system:sms-template:create', 3, 2, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1103, '鐭俊妯℃澘鏇存柊', 'system:sms-template:update', 3, 3, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1104, '鐭俊妯℃澘鍒犻櫎', 'system:sms-template:delete', 3, 4, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1105, '鐭俊妯℃澘瀵煎嚭', 'system:sms-template:export', 3, 5, 1100, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-01 17:35:17', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1106, '鍙戦�佹祴璇曠煭淇�', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-04-11 00:26:40', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1107, '鐭俊鏃ュ織', '', 2, 2, 1093, 'sms-log', 'fa:edit', 'system/sms/log/index', 'SystemSmsLog', 0, '1', '1', '1', '', '2021-04-11 08:37:05', '1', '2024-02-29 08:49:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1108, '鐭俊鏃ュ織鏌ヨ', 'system:sms-log:query', 3, 1, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1109, '鐭俊鏃ュ織瀵煎嚭', 'system:sms-log:export', 3, 5, 1107, '', '', '', NULL, 0, '1', '1', '1', '', '2021-04-11 08:37:05', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1117, '鏀粯绠$悊', '', 1, 30, 0, '/pay', 'ep:money', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-25 16:43:41', '1', '2024-02-29 08:58:38', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1118, '璇峰亣鏌ヨ', '', 2, 0, 5, 'leave', 'fa:leanpub', 'bpm/oa/leave/index', 'BpmOALeave', 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2024-02-29 12:38:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1119, '璇峰亣鐢宠鏌ヨ', 'bpm:oa-leave:query', 3, 1, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1120, '璇峰亣鐢宠鍒涘缓', 'bpm:oa-leave:create', 3, 2, 1118, '', '', '', NULL, 0, '1', '1', '1', '', '2021-09-20 08:51:03', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1126, '搴旂敤淇℃伅', '', 2, 1, 1117, 'app', 'fa:apple', 'pay/app/index', 'PayApp', 0, '1', '1', '1', '', '2021-11-10 01:13:30', '1', '2024-02-29 08:59:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1127, '鏀粯搴旂敤淇℃伅鏌ヨ', 'pay:app:query', 3, 1, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1128, '鏀粯搴旂敤淇℃伅鍒涘缓', 'pay:app:create', 3, 2, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1129, '鏀粯搴旂敤淇℃伅鏇存柊', 'pay:app:update', 3, 3, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1130, '鏀粯搴旂敤淇℃伅鍒犻櫎', 'pay:app:delete', 3, 4, 1126, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:31', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1132, '绉橀挜瑙f瀽', 'pay:channel:parsing', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1133, '鏀粯鍟嗘埛淇℃伅鏌ヨ', 'pay:merchant:query', 3, 1, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1134, '鏀粯鍟嗘埛淇℃伅鍒涘缓', 'pay:merchant:create', 3, 2, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1135, '鏀粯鍟嗘埛淇℃伅鏇存柊', 'pay:merchant:update', 3, 3, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1136, '鏀粯鍟嗘埛淇℃伅鍒犻櫎', 'pay:merchant:delete', 3, 4, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1137, '鏀粯鍟嗘埛淇℃伅瀵煎嚭', 'pay:merchant:export', 3, 5, 1132, '', '', '', NULL, 0, '1', '1', '1', '', '2021-11-10 01:13:41', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1138, '绉熸埛鍒楄〃', '', 2, 0, 1224, 'list', 'ep:house', 'system/tenant/index', 'SystemTenant', 0, '1', '1', '1', '', '2021-12-14 12:31:43', '1', '2024-02-29 01:01:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1139, '绉熸埛鏌ヨ', 'system:tenant:query', 3, 1, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1140, '绉熸埛鍒涘缓', 'system:tenant:create', 3, 2, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1141, '绉熸埛鏇存柊', 'system:tenant:update', 3, 3, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1142, '绉熸埛鍒犻櫎', 'system:tenant:delete', 3, 4, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1143, '绉熸埛瀵煎嚭', 'system:tenant:export', 3, 5, 1138, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-14 12:31:44', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1150, '绉橀挜瑙f瀽', '', 3, 6, 1129, '', '', '', NULL, 0, '1', '1', '1', '1', '2021-11-08 15:15:47', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1161, '閫�娆捐鍗�', '', 2, 3, 1117, 'refund', 'fa:registered', 'pay/refund/index', 'PayRefund', 0, '1', '1', '1', '', '2021-12-25 08:29:07', '1', '2024-02-29 08:59:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1162, '閫�娆捐鍗曟煡璇�', 'pay:refund:query', 3, 1, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1166, '閫�娆捐鍗曞鍑�', 'pay:refund:export', 3, 5, 1161, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:29:07', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1173, '鏀粯璁㈠崟', '', 2, 2, 1117, 'order', 'fa:cc-paypal', 'pay/order/index', 'PayOrder', 0, '1', '1', '1', '', '2021-12-25 08:49:43', '1', '2024-02-29 08:59:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1174, '鏀粯璁㈠崟鏌ヨ', 'pay:order:query', 3, 1, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1178, '鏀粯璁㈠崟瀵煎嚭', 'pay:order:export', 3, 5, 1173, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-25 08:49:43', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1185, '宸ヤ綔娴佺▼', '', 1, 50, 0, '/bpm', 'fa:medium', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:26:36', '1', '2024-02-29 12:43:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1186, '娴佺▼绠$悊', '', 1, 10, 1185, 'manager', 'fa:dedent', NULL, NULL, 0, '1', '1', '1', '1', '2021-12-30 20:28:30', '1', '2024-02-29 12:36:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1187, '娴佺▼琛ㄥ崟', '', 2, 2, 1186, 'form', 'fa:hdd-o', 'bpm/form/index', 'BpmForm', 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2024-03-19 12:25:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1188, '琛ㄥ崟鏌ヨ', 'bpm:form:query', 3, 1, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1189, '琛ㄥ崟鍒涘缓', 'bpm:form:create', 3, 2, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1190, '琛ㄥ崟鏇存柊', 'bpm:form:update', 3, 3, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1191, '琛ㄥ崟鍒犻櫎', 'bpm:form:delete', 3, 4, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1192, '琛ㄥ崟瀵煎嚭', 'bpm:form:export', 3, 5, 1187, '', '', '', NULL, 0, '1', '1', '1', '', '2021-12-30 12:38:22', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1193, '娴佺▼妯″瀷', '', 2, 1, 1186, 'model', 'fa-solid:project-diagram', 'bpm/model/index', 'BpmModel', 0, '1', '1', '1', '1', '2021-12-31 23:24:58', '1', '2024-03-19 12:25:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1194, '妯″瀷鏌ヨ', 'bpm:model:query', 3, 1, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:10', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1195, '妯″瀷鍒涘缓', 'bpm:model:create', 3, 2, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:01:24', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1197, '妯″瀷鏇存柊', 'bpm:model:update', 3, 4, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:28', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1198, '妯″瀷鍒犻櫎', 'bpm:model:delete', 3, 5, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:02:43', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1199, '妯″瀷鍙戝竷', 'bpm:model:deploy', 3, 6, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-03 19:03:24', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1200, '瀹℃壒涓績', '', 2, 20, 1185, 'task', 'fa:tasks', NULL, NULL, 0, '1', '1', '1', '1', '2022-01-07 23:51:48', '1', '2024-03-21 00:33:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1201, '鎴戠殑娴佺▼', '', 2, 1, 1200, 'my', 'fa-solid:book', 'bpm/processInstance/index', 'BpmProcessInstanceMy', 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2024-03-21 23:52:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1202, '娴佺▼瀹炰緥鐨勬煡璇�', 'bpm:process-instance:query', 3, 1, 1201, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-07 15:53:44', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1207, '寰呭姙浠诲姟', '', 2, 10, 1200, 'todo', 'fa:slack', 'bpm/task/todo/index', 'BpmTodoTask', 0, '1', '1', '1', '1', '2022-01-08 10:33:37', '1', '2024-02-29 12:37:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1208, '宸插姙浠诲姟', '', 2, 20, 1200, 'done', 'fa:delicious', 'bpm/task/done/index', 'BpmDoneTask', 0, '1', '1', '1', '1', '2022-01-08 10:34:13', '1', '2024-02-29 12:37:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1209, '鐢ㄦ埛鍒嗙粍', '', 2, 4, 1186, 'user-group', 'fa:user-secret', 'bpm/group/index', 'BpmUserGroup', 0, '1', '1', '1', '', '2022-01-14 02:14:20', '1', '2024-03-21 23:55:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1210, '鐢ㄦ埛缁勬煡璇�', 'bpm:user-group:query', 3, 1, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1211, '鐢ㄦ埛缁勫垱寤�', 'bpm:user-group:create', 3, 2, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1212, '鐢ㄦ埛缁勬洿鏂�', 'bpm:user-group:update', 3, 3, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1213, '鐢ㄦ埛缁勫垹闄�', 'bpm:user-group:delete', 3, 4, 1209, '', '', '', NULL, 0, '1', '1', '1', '', '2022-01-14 02:14:20', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1215, '娴佺▼瀹氫箟鏌ヨ', 'bpm:process-definition:query', 3, 10, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:21:43', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1216, '娴佺▼浠诲姟鍒嗛厤瑙勫垯鏌ヨ', 'bpm:task-assign-rule:query', 3, 20, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:26:53', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1217, '娴佺▼浠诲姟鍒嗛厤瑙勫垯鍒涘缓', 'bpm:task-assign-rule:create', 3, 21, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:15', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1218, '娴佺▼浠诲姟鍒嗛厤瑙勫垯鏇存柊', 'bpm:task-assign-rule:update', 3, 22, 1193, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:28:41', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1219, '娴佺▼瀹炰緥鐨勫垱寤�', 'bpm:process-instance:create', 3, 2, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:15', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1220, '娴佺▼瀹炰緥鐨勫彇娑�', 'bpm:process-instance:cancel', 3, 3, 1201, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:36:33', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1221, '娴佺▼浠诲姟鐨勬煡璇�', 'bpm:task:query', 3, 1, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:38:52', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1222, '娴佺▼浠诲姟鐨勬洿鏂�', 'bpm:task:update', 3, 2, 1207, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-01-23 00:39:24', '1', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1224, '绉熸埛绠$悊', '', 2, 0, 1, 'tenant', 'fa-solid:house-user', NULL, NULL, 0, '1', '1', '1', '1', '2022-02-20 01:41:13', '1', '2024-02-29 00:59:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1225, '绉熸埛濂楅', '', 2, 0, 1224, 'package', 'fa:bars', 'system/tenantPackage/index', 'SystemTenantPackage', 0, '1', '1', '1', '', '2022-02-19 17:44:06', '1', '2024-02-29 01:01:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1226, '绉熸埛濂楅鏌ヨ', 'system:tenant-package:query', 3, 1, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1227, '绉熸埛濂楅鍒涘缓', 'system:tenant-package:create', 3, 2, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1228, '绉熸埛濂楅鏇存柊', 'system:tenant-package:update', 3, 3, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1229, '绉熸埛濂楅鍒犻櫎', 'system:tenant-package:delete', 3, 4, 1225, '', '', '', NULL, 0, '1', '1', '1', '', '2022-02-19 17:44:06', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1237, '鏂囦欢閰嶇疆', '', 2, 0, 1243, 'file-config', 'fa-solid:file-signature', 'infra/fileConfig/index', 'InfraFileConfig', 0, '1', '1', '1', '', '2022-03-15 14:35:28', '1', '2024-02-29 08:52:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1238, '鏂囦欢閰嶇疆鏌ヨ', 'infra:file-config:query', 3, 1, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1239, '鏂囦欢閰嶇疆鍒涘缓', 'infra:file-config:create', 3, 2, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1240, '鏂囦欢閰嶇疆鏇存柊', 'infra:file-config:update', 3, 3, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1241, '鏂囦欢閰嶇疆鍒犻櫎', 'infra:file-config:delete', 3, 4, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1242, '鏂囦欢閰嶇疆瀵煎嚭', 'infra:file-config:export', 3, 5, 1237, '', '', '', NULL, 0, '1', '1', '1', '', '2022-03-15 14:35:28', '', '2022-04-20 17:03:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1243, '鏂囦欢绠$悊', '', 2, 6, 2, 'file', 'ep:files', NULL, '', 0, '1', '1', '1', '1', '2022-03-16 23:47:40', '1', '2024-04-23 00:02:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1254, '浣滆�呭姩鎬�', '', 1, 0, 0, 'https://www.iocoder.cn', 'ep:avatar', NULL, NULL, 0, '1', '1', '1', '1', '2022-04-23 01:03:15', '1', '2025-04-29 17:45:38', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1255, '鏁版嵁婧愰厤缃�', '', 2, 1, 2, 'data-source-config', 'ep:data-analysis', 'infra/dataSourceConfig/index', 'InfraDataSourceConfig', 0, '1', '1', '1', '', '2022-04-27 14:37:32', '1', '2024-02-29 08:51:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1256, '鏁版嵁婧愰厤缃煡璇�', 'infra:data-source-config:query', 3, 1, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1257, '鏁版嵁婧愰厤缃垱寤�', 'infra:data-source-config:create', 3, 2, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1258, '鏁版嵁婧愰厤缃洿鏂�', 'infra:data-source-config:update', 3, 3, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1259, '鏁版嵁婧愰厤缃垹闄�', 'infra:data-source-config:delete', 3, 4, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1260, '鏁版嵁婧愰厤缃鍑�', 'infra:data-source-config:export', 3, 5, 1255, '', '', '', NULL, 0, '1', '1', '1', '', '2022-04-27 14:37:32', '', '2022-04-27 14:37:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1261, 'OAuth 2.0', '', 2, 10, 1, 'oauth2', 'fa:dashcube', NULL, NULL, 0, '1', '1', '1', '1', '2022-05-09 23:38:17', '1', '2024-02-29 01:12:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1263, '搴旂敤绠$悊', '', 2, 0, 1261, 'oauth2/application', 'fa:hdd-o', 'system/oauth2/client/index', 'SystemOAuth2Client', 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2024-02-29 01:13:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1264, '瀹㈡埛绔煡璇�', 'system:oauth2-client:query', 3, 1, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1265, '瀹㈡埛绔垱寤�', 'system:oauth2-client:create', 3, 2, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1266, '瀹㈡埛绔洿鏂�', 'system:oauth2-client:update', 3, 3, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1267, '瀹㈡埛绔垹闄�', 'system:oauth2-client:delete', 3, 4, 1263, '', '', '', NULL, 0, '1', '1', '1', '', '2022-05-10 16:26:33', '1', '2022-05-11 00:31:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1281, '鎶ヨ〃绠$悊', '', 2, 40, 0, '/report', 'ep:pie-chart', NULL, NULL, 0, '1', '1', '1', '1', '2022-07-10 20:22:15', '1', '2024-02-29 12:33:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (1282, '鎶ヨ〃璁捐鍣�', '', 2, 1, 1281, 'jimu-report', 'ep:trend-charts', 'report/jmreport/index', 'JimuReport', 0, '1', '1', '1', '1', '2022-07-10 20:26:36', '1', '2025-05-03 09:57:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2000, '鍟嗗搧涓績', '', 1, 60, 2362, 'product', 'fa:product-hunt', NULL, NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-09-30 11:52:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2002, '鍟嗗搧鍒嗙被', '', 2, 2, 2000, 'category', 'ep:cellphone', 'mall/product/category/index', 'ProductCategory', 0, '1', '1', '1', '', '2022-07-29 15:53:53', '1', '2023-08-21 10:27:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2003, '鍒嗙被鏌ヨ', 'product:category:query', 3, 1, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2004, '鍒嗙被鍒涘缓', 'product:category:create', 3, 2, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2005, '鍒嗙被鏇存柊', 'product:category:update', 3, 3, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2006, '鍒嗙被鍒犻櫎', 'product:category:delete', 3, 4, 2002, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-29 15:53:53', '', '2022-07-29 15:53:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2008, '鍟嗗搧鍝佺墝', '', 2, 3, 2000, 'brand', 'ep:chicken', 'mall/product/brand/index', 'ProductBrand', 0, '1', '1', '1', '', '2022-07-30 13:52:44', '1', '2023-08-21 10:27:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2009, '鍝佺墝鏌ヨ', 'product:brand:query', 3, 1, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2010, '鍝佺墝鍒涘缓', 'product:brand:create', 3, 2, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2011, '鍝佺墝鏇存柊', 'product:brand:update', 3, 3, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2012, '鍝佺墝鍒犻櫎', 'product:brand:delete', 3, 4, 2008, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 13:52:44', '', '2022-07-30 13:52:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2014, '鍟嗗搧鍒楄〃', '', 2, 1, 2000, 'spu', 'ep:apple', 'mall/product/spu/index', 'ProductSpu', 0, '1', '1', '1', '', '2022-07-30 14:22:58', '1', '2025-10-08 10:36:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2015, '鍟嗗搧鏌ヨ', 'product:spu:query', 3, 1, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2016, '鍟嗗搧鍒涘缓', 'product:spu:create', 3, 2, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2017, '鍟嗗搧鏇存柊', 'product:spu:update', 3, 3, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2018, '鍟嗗搧鍒犻櫎', 'product:spu:delete', 3, 4, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2019, '鍟嗗搧灞炴��', '', 2, 4, 2000, 'property', 'ep:cold-drink', 'mall/product/property/index', 'ProductProperty', 0, '1', '1', '1', '', '2022-08-01 14:55:35', '1', '2023-08-26 11:01:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2020, '瑙勬牸鏌ヨ', 'product:property:query', 3, 1, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:24', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2021, '瑙勬牸鍒涘缓', 'product:property:create', 3, 2, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2022, '瑙勬牸鏇存柊', 'product:property:update', 3, 3, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2023, '瑙勬牸鍒犻櫎', 'product:property:delete', 3, 4, 2019, '', '', '', NULL, 0, '1', '1', '1', '', '2022-08-01 14:55:35', '', '2022-12-12 20:26:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2025, 'Banner', '', 2, 100, 2387, 'banner', 'fa:bandcamp', 'mall/promotion/banner/index', NULL, 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2026, 'Banner鏌ヨ', 'promotion:banner:query', 3, 1, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2027, 'Banner鍒涘缓', 'promotion:banner:create', 3, 2, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2028, 'Banner鏇存柊', 'promotion:banner:update', 3, 3, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2029, 'Banner鍒犻櫎', 'promotion:banner:delete', 3, 4, 2025, '', '', '', '', 0, '1', '1', '1', '', '2022-08-01 14:56:14', '1', '2023-10-24 20:20:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2030, '钀ラ攢涓績', '', 1, 70, 2362, 'promotion', 'ep:present', NULL, NULL, 0, '1', '1', '1', '1', '2022-10-31 21:25:09', '1', '2023-09-30 11:54:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2032, '浼樻儬鍔靛垪琛�', '', 2, 1, 2365, 'template', 'ep:discount', 'mall/promotion/coupon/template/index', 'PromotionCouponTemplate', 0, '1', '1', '1', '', '2022-10-31 22:27:14', '1', '2023-10-03 12:40:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2033, '浼樻儬鍔垫ā鏉挎煡璇�', 'promotion:coupon-template:query', 3, 1, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2034, '浼樻儬鍔垫ā鏉垮垱寤�', 'promotion:coupon-template:create', 3, 2, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2035, '浼樻儬鍔垫ā鏉挎洿鏂�', 'promotion:coupon-template:update', 3, 3, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2036, '浼樻儬鍔垫ā鏉垮垹闄�', 'promotion:coupon-template:delete', 3, 4, 2032, '', '', '', NULL, 0, '1', '1', '1', '', '2022-10-31 22:27:14', '', '2022-10-31 22:27:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2038, '棰嗗彇璁板綍', '', 2, 2, 2365, 'list', 'ep:collection-tag', 'mall/promotion/coupon/index', 'PromotionCoupon', 0, '1', '1', '1', '', '2022-11-03 23:21:31', '1', '2023-10-03 12:55:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2039, '浼樻儬鍔垫煡璇�', 'promotion:coupon:query', 3, 1, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2040, '浼樻儬鍔靛垹闄�', 'promotion:coupon:delete', 3, 4, 2038, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-03 23:21:31', '', '2022-11-03 23:21:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2041, '婊″噺閫�', '', 2, 10, 2390, 'reward-activity', 'ep:goblet-square-full', 'mall/promotion/rewardActivity/index', 'PromotionRewardActivity', 0, '1', '1', '1', '', '2022-11-04 23:47:49', '1', '2023-10-21 19:24:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2042, '婊″噺閫佹椿鍔ㄦ煡璇�', 'promotion:reward-activity:query', 3, 1, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2043, '婊″噺閫佹椿鍔ㄥ垱寤�', 'promotion:reward-activity:create', 3, 2, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:49', '', '2022-11-04 23:47:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2044, '婊″噺閫佹椿鍔ㄦ洿鏂�', 'promotion:reward-activity:update', 3, 3, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2045, '婊″噺閫佹椿鍔ㄥ垹闄�', 'promotion:reward-activity:delete', 3, 4, 2041, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-04 23:47:50', '', '2022-11-04 23:47:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2046, '婊″噺閫佹椿鍔ㄥ叧闂�', 'promotion:reward-activity:close', 3, 5, 2041, '', '', '', NULL, 0, '1', '1', '1', '1', '2022-11-05 10:42:53', '1', '2022-11-05 10:42:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2047, '闄愭椂鎶樻墸', '', 2, 7, 2390, 'discount-activity', 'ep:timer', 'mall/promotion/discountActivity/index', 'PromotionDiscountActivity', 0, '1', '1', '1', '', '2022-11-05 17:12:15', '1', '2023-10-21 19:24:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2048, '闄愭椂鎶樻墸娲诲姩鏌ヨ', 'promotion:discount-activity:query', 3, 1, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2049, '闄愭椂鎶樻墸娲诲姩鍒涘缓', 'promotion:discount-activity:create', 3, 2, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:15', '', '2022-11-05 17:12:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2050, '闄愭椂鎶樻墸娲诲姩鏇存柊', 'promotion:discount-activity:update', 3, 3, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2051, '闄愭椂鎶樻墸娲诲姩鍒犻櫎', 'promotion:discount-activity:delete', 3, 4, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2052, '闄愭椂鎶樻墸娲诲姩鍏抽棴', 'promotion:discount-activity:close', 3, 5, 2047, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-05 17:12:16', '', '2022-11-05 17:12:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2059, '绉掓潃鍟嗗搧', '', 2, 2, 2209, 'activity', 'ep:basketball', 'mall/promotion/seckill/activity/index', 'PromotionSeckillActivity', 0, '1', '1', '1', '', '2022-11-06 22:24:49', '1', '2023-06-24 18:57:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2060, '绉掓潃娲诲姩鏌ヨ', 'promotion:seckill-activity:query', 3, 1, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2061, '绉掓潃娲诲姩鍒涘缓', 'promotion:seckill-activity:create', 3, 2, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2062, '绉掓潃娲诲姩鏇存柊', 'promotion:seckill-activity:update', 3, 3, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2063, '绉掓潃娲诲姩鍒犻櫎', 'promotion:seckill-activity:delete', 3, 4, 2059, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-06 22:24:49', '', '2022-11-06 22:24:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2066, '绉掓潃鏃舵', '', 2, 1, 2209, 'config', 'ep:baseball', 'mall/promotion/seckill/config/index', 'PromotionSeckillConfig', 0, '1', '1', '1', '', '2022-11-15 19:46:50', '1', '2023-06-24 18:57:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2067, '绉掓潃鏃舵鏌ヨ', 'promotion:seckill-config:query', 3, 1, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2068, '绉掓潃鏃舵鍒涘缓', 'promotion:seckill-config:create', 3, 2, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:48:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2069, '绉掓潃鏃舵鏇存柊', 'promotion:seckill-config:update', 3, 3, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2070, '绉掓潃鏃舵鍒犻櫎', 'promotion:seckill-config:delete', 3, 4, 2066, '', '', '', '', 0, '1', '1', '1', '', '2022-11-15 19:46:51', '1', '2023-06-24 17:50:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2072, '璁㈠崟涓績', '', 1, 65, 2362, 'trade', 'ep:eleme', NULL, NULL, 0, '1', '1', '1', '1', '2022-11-19 18:57:19', '1', '2023-09-30 11:54:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2073, '鍞悗閫�娆�', '', 2, 2, 2072, 'after-sale', 'ep:refrigerator', 'mall/trade/afterSale/index', 'TradeAfterSale', 0, '1', '1', '1', '', '2022-11-19 20:15:32', '1', '2023-10-01 21:42:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2074, '鍞悗鏌ヨ', 'trade:after-sale:query', 3, 1, 2073, '', '', '', NULL, 0, '1', '1', '1', '', '2022-11-19 20:15:33', '1', '2022-12-10 21:04:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2075, '绉掓潃娲诲姩鍏抽棴', 'promotion:seckill-activity:close', 3, 5, 2059, '', '', '', '', 0, '1', '1', '1', '1', '2022-11-28 20:20:15', '1', '2023-10-03 18:34:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2076, '璁㈠崟鍒楄〃', '', 2, 1, 2072, 'order', 'ep:list', 'mall/trade/order/index', 'TradeOrder', 0, '1', '1', '1', '1', '2022-12-10 21:05:44', '1', '2023-10-01 21:42:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2083, '鍦板尯绠$悊', '', 2, 14, 1, 'area', 'fa:map-marker', 'system/area/index', 'SystemArea', 0, '1', '1', '1', '1', '2022-12-23 17:35:05', '1', '2024-02-29 08:50:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2084, '鍏紬鍙风鐞�', '', 1, 100, 0, '/mp', 'ep:compass', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-01 20:11:04', '1', '2024-02-29 12:39:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2085, '璐﹀彿绠$悊', '', 2, 1, 2084, 'account', 'fa:user', 'mp/account/index', 'MpAccount', 0, '1', '1', '1', '1', '2023-01-01 20:13:31', '1', '2024-02-29 12:42:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2086, '鏂板璐﹀彿', 'mp:account:create', 3, 1, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-01 20:21:40', '1', '2023-01-07 17:32:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2087, '淇敼璐﹀彿', 'mp:account:update', 3, 2, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:32:46', '1', '2023-01-07 17:32:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2088, '鏌ヨ璐﹀彿', 'mp:account:query', 3, 0, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:07', '1', '2023-01-07 17:33:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2089, '鍒犻櫎璐﹀彿', 'mp:account:delete', 3, 3, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:21', '1', '2023-01-07 17:33:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2090, '鐢熸垚浜岀淮鐮�', 'mp:account:qr-code', 3, 4, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 17:33:58', '1', '2023-01-07 17:33:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2091, '娓呯┖ API 閰嶉', 'mp:account:clear-quota', 3, 5, 2085, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-07 18:20:32', '1', '2023-01-07 18:20:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2092, '鏁版嵁缁熻', 'mp:statistics:query', 2, 2, 2084, 'statistics', 'ep:trend-charts', 'mp/statistics/index', 'MpStatistics', 0, '1', '1', '1', '1', '2023-01-07 20:17:36', '1', '2024-02-29 12:42:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2093, '鏍囩绠$悊', '', 2, 3, 2084, 'tag', 'ep:collection-tag', 'mp/tag/index', 'MpTag', 0, '1', '1', '1', '1', '2023-01-08 11:37:32', '1', '2024-02-29 12:42:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2094, '鏌ヨ鏍囩', 'mp:tag:query', 3, 0, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:03', '1', '2023-01-08 11:59:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2095, '鏂板鏍囩', 'mp:tag:create', 3, 1, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:23', '1', '2023-01-08 11:59:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2096, '淇敼鏍囩', 'mp:tag:update', 3, 2, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 11:59:41', '1', '2023-01-08 11:59:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2097, '鍒犻櫎鏍囩', 'mp:tag:delete', 3, 3, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:04', '1', '2023-01-08 12:00:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2098, '鍚屾鏍囩', 'mp:tag:sync', 3, 4, 2093, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 12:00:29', '1', '2023-01-08 12:00:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2099, '绮変笣绠$悊', '', 2, 4, 2084, 'user', 'fa:user-secret', 'mp/user/index', 'MpUser', 0, '1', '1', '1', '1', '2023-01-08 16:51:20', '1', '2024-02-29 12:42:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2100, '鏌ヨ绮変笣', 'mp:user:query', 3, 0, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:16:59', '1', '2023-01-08 17:17:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2101, '淇敼绮変笣', 'mp:user:update', 3, 1, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:11', '1', '2023-01-08 17:17:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2102, '鍚屾绮変笣', 'mp:user:sync', 3, 2, 2099, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-08 17:17:40', '1', '2023-01-08 17:17:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2103, '娑堟伅绠$悊', '', 2, 5, 2084, 'message', 'ep:message', 'mp/message/index', 'MpMessage', 0, '1', '1', '1', '1', '2023-01-08 18:44:19', '1', '2024-02-29 12:42:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2104, '鍥炬枃鍙戣〃璁板綍', '', 2, 10, 2084, 'free-publish', 'ep:edit-pen', 'mp/freePublish/index', 'MpFreePublish', 0, '1', '1', '1', '1', '2023-01-13 00:30:50', '1', '2024-02-29 12:43:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2105, '鏌ヨ鍙戝竷鍒楄〃', 'mp:free-publish:query', 3, 1, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:17', '1', '2023-01-13 07:19:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2106, '鍙戝竷鑽夌', 'mp:free-publish:submit', 3, 2, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:19:46', '1', '2023-01-13 07:19:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2107, '鍒犻櫎鍙戝竷璁板綍', 'mp:free-publish:delete', 3, 3, 2104, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 07:20:01', '1', '2023-01-13 07:20:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2108, '鍥炬枃鑽夌绠�', '', 2, 9, 2084, 'draft', 'ep:edit', 'mp/draft/index', 'MpDraft', 0, '1', '1', '1', '1', '2023-01-13 07:40:21', '1', '2024-02-29 12:43:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2109, '鏂板缓鑽夌', 'mp:draft:create', 3, 1, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-13 23:15:30', '1', '2023-01-13 23:15:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2110, '淇敼鑽夌', 'mp:draft:update', 3, 2, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:08:47', '1', '2023-01-14 10:08:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2111, '鏌ヨ鑽夌', 'mp:draft:query', 3, 0, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:01', '1', '2023-01-14 10:09:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2112, '鍒犻櫎鑽夌', 'mp:draft:delete', 3, 3, 2108, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 10:09:19', '1', '2023-01-14 10:09:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2113, '绱犳潗绠$悊', '', 2, 8, 2084, 'material', 'ep:basketball', 'mp/material/index', 'MpMaterial', 0, '1', '1', '1', '1', '2023-01-14 14:12:07', '1', '2024-02-29 12:43:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2114, '涓婁紶涓存椂绱犳潗', 'mp:material:upload-temporary', 3, 1, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:33:55', '1', '2023-01-14 15:33:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2115, '涓婁紶姘镐箙绱犳潗', 'mp:material:upload-permanent', 3, 2, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:34:14', '1', '2023-01-14 15:34:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2116, '鍒犻櫎绱犳潗', 'mp:material:delete', 3, 3, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:35:37', '1', '2023-01-14 15:35:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2117, '涓婁紶鍥炬枃鍥剧墖', 'mp:material:upload-news-image', 3, 4, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:36:31', '1', '2023-01-14 15:36:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2118, '鏌ヨ绱犳潗', 'mp:material:query', 3, 5, 2113, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-14 15:39:22', '1', '2023-01-14 15:39:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2119, '鑿滃崟绠$悊', '', 2, 6, 2084, 'menu', 'ep:menu', 'mp/menu/index', 'MpMenu', 0, '1', '1', '1', '1', '2023-01-14 17:43:54', '1', '2025-04-01 20:21:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2120, '鑷姩鍥炲', '', 2, 7, 2084, 'auto-reply', 'fa-solid:republican', 'mp/autoReply/index', 'MpAutoReply', 0, '1', '1', '1', '1', '2023-01-15 22:13:09', '1', '2024-02-29 12:43:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2121, '鏌ヨ鍥炲', 'mp:auto-reply:query', 3, 0, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:41', '1', '2023-01-16 22:28:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2122, '鏂板鍥炲', 'mp:auto-reply:create', 3, 1, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:28:54', '1', '2023-01-16 22:28:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2123, '淇敼鍥炲', 'mp:auto-reply:update', 3, 2, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:05', '1', '2023-01-16 22:29:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2124, '鍒犻櫎鍥炲', 'mp:auto-reply:delete', 3, 3, 2120, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-16 22:29:34', '1', '2023-01-16 22:29:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2125, '鏌ヨ鑿滃崟', 'mp:menu:query', 3, 0, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:05:41', '1', '2023-01-17 23:05:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2126, '淇濆瓨鑿滃崟', 'mp:menu:save', 3, 1, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:01', '1', '2023-01-17 23:06:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2127, '鍒犻櫎鑿滃崟', 'mp:menu:delete', 3, 2, 2119, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:06:16', '1', '2023-01-17 23:06:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2128, '鏌ヨ娑堟伅', 'mp:message:query', 3, 0, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:14', '1', '2023-01-17 23:07:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2129, '鍙戦�佹秷鎭�', 'mp:message:send', 3, 1, 2103, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-17 23:07:26', '1', '2023-01-17 23:07:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2130, '閭绠$悊', '', 2, 2, 2739, 'mail', 'fa-solid:mail-bulk', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-25 17:27:44', '1', '2024-04-22 23:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2131, '閭璐﹀彿', '', 2, 0, 2130, 'mail-account', 'fa:universal-access', 'system/mail/account/index', 'SystemMailAccount', 0, '1', '1', '1', '', '2023-01-25 09:33:48', '1', '2024-02-29 08:48:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2132, '璐﹀彿鏌ヨ', 'system:mail-account:query', 3, 1, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2133, '璐﹀彿鍒涘缓', 'system:mail-account:create', 3, 2, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2134, '璐﹀彿鏇存柊', 'system:mail-account:update', 3, 3, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2135, '璐﹀彿鍒犻櫎', 'system:mail-account:delete', 3, 4, 2131, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 09:33:48', '', '2023-01-25 09:33:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2136, '閭欢妯$増', '', 2, 0, 2130, 'mail-template', 'fa:tag', 'system/mail/template/index', 'SystemMailTemplate', 0, '1', '1', '1', '', '2023-01-25 12:05:31', '1', '2024-02-29 08:48:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2137, '妯$増鏌ヨ', 'system:mail-template:query', 3, 1, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2138, '妯$増鍒涘缓', 'system:mail-template:create', 3, 2, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2139, '妯$増鏇存柊', 'system:mail-template:update', 3, 3, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2140, '妯$増鍒犻櫎', 'system:mail-template:delete', 3, 4, 2136, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-25 12:05:31', '', '2023-01-25 12:05:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2141, '閭欢璁板綍', '', 2, 0, 2130, 'mail-log', 'fa:edit', 'system/mail/log/index', 'SystemMailLog', 0, '1', '1', '1', '', '2023-01-26 02:16:50', '1', '2024-02-29 08:48:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2142, '鏃ュ織鏌ヨ', 'system:mail-log:query', 3, 1, 2141, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-26 02:16:50', '', '2023-01-26 02:16:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2143, '鍙戦�佹祴璇曢偖浠�', 'system:mail-template:send-mail', 3, 5, 2136, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-26 23:29:15', '1', '2023-01-26 23:29:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2144, '绔欏唴淇$鐞�', '', 1, 3, 2739, 'notify', 'ep:message-box', NULL, NULL, 0, '1', '1', '1', '1', '2023-01-28 10:25:18', '1', '2024-04-22 23:56:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2145, '妯℃澘绠$悊', '', 2, 0, 2144, 'notify-template', 'fa:archive', 'system/notify/template/index', 'SystemNotifyTemplate', 0, '1', '1', '1', '', '2023-01-28 02:26:42', '1', '2024-02-29 08:49:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2146, '绔欏唴淇℃ā鏉挎煡璇�', 'system:notify-template:query', 3, 1, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2147, '绔欏唴淇℃ā鏉垮垱寤�', 'system:notify-template:create', 3, 2, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2148, '绔欏唴淇℃ā鏉挎洿鏂�', 'system:notify-template:update', 3, 3, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2149, '绔欏唴淇℃ā鏉垮垹闄�', 'system:notify-template:delete', 3, 4, 2145, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 02:26:42', '', '2023-01-28 02:26:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2150, '鍙戦�佹祴璇曠珯鍐呬俊', 'system:notify-template:send-notify', 3, 5, 2145, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-01-28 10:54:43', '1', '2023-01-28 10:54:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2151, '娑堟伅璁板綍', '', 2, 0, 2144, 'notify-message', 'fa:edit', 'system/notify/message/index', 'SystemNotifyMessage', 0, '1', '1', '1', '', '2023-01-28 04:28:22', '1', '2024-02-29 08:49:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2152, '绔欏唴淇℃秷鎭煡璇�', 'system:notify-message:query', 3, 1, 2151, '', '', '', NULL, 0, '1', '1', '1', '', '2023-01-28 04:28:22', '', '2023-01-28 04:28:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2153, '澶у睆璁捐鍣�', '', 2, 2, 1281, 'go-view', 'fa:area-chart', 'report/goview/index', 'GoView', 0, '1', '1', '1', '1', '2023-02-07 00:03:19', '1', '2025-05-03 09:57:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2154, '鍒涘缓椤圭洰', 'report:go-view-project:create', 3, 1, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:14', '1', '2023-02-07 19:25:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2155, '鏇存柊椤圭洰', 'report:go-view-project:update', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2023-02-07 19:25:34', '1', '2024-04-24 20:01:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2156, '鏌ヨ椤圭洰', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:25:53', '1', '2023-02-07 19:25:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2157, '浣跨敤 SQL 鏌ヨ鏁版嵁', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:15', '1', '2023-02-07 19:26:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2158, '浣跨敤 HTTP 鏌ヨ鏁版嵁', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, '1', '1', '1', '1', '2023-02-07 19:26:35', '1', '2023-02-07 19:26:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2159, 'Boot 寮�鍙戞枃妗�', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:46:28', '1', '2026-01-05 19:31:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2160, 'Cloud 寮�鍙戞枃妗�', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'ep:document-copy', NULL, NULL, 0, '1', '1', '1', '1', '2023-02-10 22:47:07', '1', '2023-12-02 21:32:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2161, '鎺ュ叆绀轰緥', '', 1, 99, 1117, 'demo', 'fa-solid:dragon', 'pay/demo/index', NULL, 0, '1', '1', '1', '', '2023-02-11 14:21:42', '1', '2024-01-18 23:50:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2162, '鍟嗗搧瀵煎嚭', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, '1', '1', '1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2164, '閰嶉�佺鐞�', '', 1, 3, 2072, 'delivery', 'ep:shopping-cart', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:18:02', '1', '2023-09-28 10:58:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2165, '蹇�掑彂璐�', '', 1, 0, 2164, 'express', 'ep:bicycle', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:22:06', '1', '2023-08-30 21:02:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2166, '闂ㄥ簵鑷彁', '', 1, 1, 2164, 'pick-up-store', 'ep:add-location', '', '', 0, '1', '1', '1', '1', '2023-05-18 09:23:14', '1', '2023-08-30 21:03:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2167, '蹇�掑叕鍙�', '', 2, 0, 2165, 'express', 'ep:compass', 'mall/trade/delivery/express/index', 'Express', 0, '1', '1', '1', '1', '2023-05-18 09:27:21', '1', '2024-11-29 11:20:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2168, '蹇�掑叕鍙告煡璇�', 'trade:delivery:express:query', 3, 1, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2169, '蹇�掑叕鍙稿垱寤�', 'trade:delivery:express:create', 3, 2, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2170, '蹇�掑叕鍙告洿鏂�', 'trade:delivery:express:update', 3, 3, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2171, '蹇�掑叕鍙稿垹闄�', 'trade:delivery:express:delete', 3, 4, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2172, '蹇�掑叕鍙稿鍑�', 'trade:delivery:express:export', 3, 5, 2167, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-18 09:37:53', '', '2023-05-18 09:37:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2173, '杩愯垂妯$増', 'trade:delivery:express-template:query', 2, 1, 2165, 'express-template', 'ep:coordinate', 'mall/trade/delivery/expressTemplate/index', 'ExpressTemplate', 0, '1', '1', '1', '1', '2023-05-20 06:48:10', '1', '2023-08-30 21:03:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2174, '蹇�掕繍璐规ā鏉挎煡璇�', 'trade:delivery:express-template:query', 3, 1, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2175, '蹇�掕繍璐规ā鏉垮垱寤�', 'trade:delivery:express-template:create', 3, 2, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2176, '蹇�掕繍璐规ā鏉挎洿鏂�', 'trade:delivery:express-template:update', 3, 3, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2177, '蹇�掕繍璐规ā鏉垮垹闄�', 'trade:delivery:express-template:delete', 3, 4, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2178, '蹇�掕繍璐规ā鏉垮鍑�', 'trade:delivery:express-template:export', 3, 5, 2173, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-20 06:49:53', '', '2023-05-20 06:49:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2179, '闂ㄥ簵绠$悊', '', 2, 1, 2166, 'pick-up-store', 'ep:basketball', 'mall/trade/delivery/pickUpStore/index', 'PickUpStore', 0, '1', '1', '1', '1', '2023-05-25 10:50:00', '1', '2023-08-30 21:03:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2180, '鑷彁闂ㄥ簵鏌ヨ', 'trade:delivery:pick-up-store:query', 3, 1, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2181, '鑷彁闂ㄥ簵鍒涘缓', 'trade:delivery:pick-up-store:create', 3, 2, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2182, '鑷彁闂ㄥ簵鏇存柊', 'trade:delivery:pick-up-store:update', 3, 3, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2183, '鑷彁闂ㄥ簵鍒犻櫎', 'trade:delivery:pick-up-store:delete', 3, 4, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2184, '鑷彁闂ㄥ簵瀵煎嚭', 'trade:delivery:pick-up-store:export', 3, 5, 2179, '', '', '', NULL, 0, '1', '1', '1', '', '2023-05-25 10:53:29', '', '2023-05-25 10:53:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2209, '绉掓潃娲诲姩', '', 2, 3, 2030, 'seckill', 'ep:place', '', '', 0, '1', '1', '1', '1', '2023-06-24 17:39:13', '1', '2023-06-24 18:55:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2262, '浼氬憳涓績', '', 1, 55, 0, '/member', 'ep:bicycle', NULL, NULL, 0, '1', '1', '1', '1', '2023-06-10 00:42:03', '1', '2023-08-20 09:23:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2275, '浼氬憳閰嶇疆', '', 2, 0, 2262, 'config', 'fa:archive', 'member/config/index', 'MemberConfig', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2023-10-01 23:41:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2276, '浼氬憳閰嶇疆鏌ヨ', 'member:config:query', 3, 1, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:48:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2277, '浼氬憳閰嶇疆淇濆瓨', 'member:config:save', 3, 2, 2275, '', '', '', '', 0, '1', '1', '1', '', '2023-06-10 02:07:44', '1', '2024-04-24 19:49:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2281, '绛惧埌閰嶇疆', '', 2, 2, 2300, 'config', 'ep:calendar', 'member/signin/config/index', 'SignInConfig', 0, '1', '1', '1', '', '2023-06-10 03:26:12', '1', '2023-08-20 19:25:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2282, '绉垎绛惧埌瑙勫垯鏌ヨ', 'point:sign-in-config:query', 3, 1, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2283, '绉垎绛惧埌瑙勫垯鍒涘缓', 'point:sign-in-config:create', 3, 2, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2284, '绉垎绛惧埌瑙勫垯鏇存柊', 'point:sign-in-config:update', 3, 3, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2285, '绉垎绛惧埌瑙勫垯鍒犻櫎', 'point:sign-in-config:delete', 3, 4, 2281, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 03:26:12', '', '2023-06-10 03:26:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2287, '浼氬憳绉垎', '', 2, 10, 2262, 'record', 'fa:asterisk', 'member/point/record/index', 'PointRecord', 0, '1', '1', '1', '', '2023-06-10 04:18:50', '1', '2023-10-01 23:42:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2288, '鐢ㄦ埛绉垎璁板綍鏌ヨ', 'point:record:query', 3, 1, 2287, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:18:50', '', '2023-06-10 04:18:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2293, '绛惧埌璁板綍', '', 2, 3, 2300, 'record', 'ep:chicken', 'member/signin/record/index', 'SignInRecord', 0, '1', '1', '1', '', '2023-06-10 04:48:22', '1', '2023-08-20 19:26:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2294, '鐢ㄦ埛绛惧埌绉垎鏌ヨ', 'point:sign-in-record:query', 3, 1, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2297, '鐢ㄦ埛绛惧埌绉垎鍒犻櫎', 'point:sign-in-record:delete', 3, 4, 2293, '', '', '', NULL, 0, '1', '1', '1', '', '2023-06-10 04:48:22', '', '2023-06-10 04:48:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2300, '浼氬憳绛惧埌', '', 1, 11, 2262, 'signin', 'ep:alarm-clock', '', '', 0, '1', '1', '1', '1', '2023-06-27 22:49:53', '1', '2023-08-20 09:23:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2301, '鍥炶皟閫氱煡', '', 2, 5, 1117, 'notify', 'ep:mute-notification', 'pay/notify/index', 'PayNotify', 0, '1', '1', '1', '', '2023-07-20 04:41:32', '1', '2024-01-18 23:56:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2302, '鏀粯閫氱煡鏌ヨ', 'pay:notify:query', 3, 1, 2301, '', '', '', NULL, 0, '1', '1', '1', '', '2023-07-20 04:41:32', '', '2023-07-20 04:41:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2303, '鎷煎洟娲诲姩', '', 2, 3, 2030, 'combination', 'fa:group', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:19:54', '1', '2023-08-12 17:20:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2304, '鎷煎洟鍟嗗搧', '', 2, 1, 2303, 'acitivity', 'ep:apple', 'mall/promotion/combination/activity/index', 'PromotionCombinationActivity', 0, '1', '1', '1', '1', '2023-08-12 17:22:03', '1', '2023-08-12 17:22:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2305, '鎷煎洟娲诲姩鏌ヨ', 'promotion:combination-activity:query', 3, 1, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:32', '1', '2023-11-24 11:57:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2306, '鎷煎洟娲诲姩鍒涘缓', 'promotion:combination-activity:create', 3, 2, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:54:49', '1', '2023-08-12 17:54:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2307, '鎷煎洟娲诲姩鏇存柊', 'promotion:combination-activity:update', 3, 3, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:04', '1', '2023-08-12 17:55:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2308, '鎷煎洟娲诲姩鍒犻櫎', 'promotion:combination-activity:delete', 3, 4, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:23', '1', '2023-08-12 17:55:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2309, '鎷煎洟娲诲姩鍏抽棴', 'promotion:combination-activity:close', 3, 5, 2304, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-12 17:55:37', '1', '2023-10-06 10:51:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2310, '鐮嶄环娲诲姩', '', 2, 4, 2030, 'bargain', 'ep:box', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:27:25', '1', '2023-08-13 00:27:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2311, '鐮嶄环鍟嗗搧', '', 2, 1, 2310, 'activity', 'ep:burger', 'mall/promotion/bargain/activity/index', 'PromotionBargainActivity', 0, '1', '1', '1', '1', '2023-08-13 00:28:49', '1', '2023-10-05 01:16:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2312, '鐮嶄环娲诲姩鏌ヨ', 'promotion:bargain-activity:query', 3, 1, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:30', '1', '2023-08-13 00:32:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2313, '鐮嶄环娲诲姩鍒涘缓', 'promotion:bargain-activity:create', 3, 2, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:44', '1', '2023-08-13 00:32:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2314, '鐮嶄环娲诲姩鏇存柊', 'promotion:bargain-activity:update', 3, 3, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:32:55', '1', '2023-08-13 00:32:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2315, '鐮嶄环娲诲姩鍒犻櫎', 'promotion:bargain-activity:delete', 3, 4, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:34:50', '1', '2023-08-13 00:34:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2316, '鐮嶄环娲诲姩鍏抽棴', 'promotion:bargain-activity:close', 3, 5, 2311, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-13 00:35:02', '1', '2023-08-13 00:35:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2317, '浼氬憳绠$悊', '', 2, 0, 2262, 'user', 'ep:avatar', 'member/user/index', 'MemberUser', 0, '1', '1', '1', '', '2023-08-19 04:12:15', '1', '2023-08-24 00:50:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2318, '浼氬憳鐢ㄦ埛鏌ヨ', 'member:user:query', 3, 1, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2319, '浼氬憳鐢ㄦ埛鏇存柊', 'member:user:update', 3, 3, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-19 04:12:15', '', '2023-08-19 04:12:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2320, '浼氬憳鏍囩', '', 2, 1, 2262, 'tag', 'ep:collection-tag', 'member/tag/index', 'MemberTag', 0, '1', '1', '1', '', '2023-08-20 01:03:08', '1', '2023-08-20 09:23:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2321, '浼氬憳鏍囩鏌ヨ', 'member:tag:query', 3, 1, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2322, '浼氬憳鏍囩鍒涘缓', 'member:tag:create', 3, 2, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2323, '浼氬憳鏍囩鏇存柊', 'member:tag:update', 3, 3, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2324, '浼氬憳鏍囩鍒犻櫎', 'member:tag:delete', 3, 4, 2320, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-20 01:03:08', '', '2023-08-20 01:03:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2325, '浼氬憳绛夌骇', '', 2, 2, 2262, 'level', 'fa:level-up', 'member/level/index', 'MemberLevel', 0, '1', '1', '1', '', '2023-08-22 12:41:01', '1', '2023-08-22 21:47:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2326, '浼氬憳绛夌骇鏌ヨ', 'member:level:query', 3, 1, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2327, '浼氬憳绛夌骇鍒涘缓', 'member:level:create', 3, 2, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2328, '浼氬憳绛夌骇鏇存柊', 'member:level:update', 3, 3, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2329, '浼氬憳绛夌骇鍒犻櫎', 'member:level:delete', 3, 4, 2325, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 12:41:02', '', '2023-08-22 12:41:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2330, '浼氬憳鍒嗙粍', '', 2, 3, 2262, 'group', 'fa:group', 'member/group/index', 'MemberGroup', 0, '1', '1', '1', '', '2023-08-22 13:50:06', '1', '2023-10-01 23:42:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2331, '鐢ㄦ埛鍒嗙粍鏌ヨ', 'member:group:query', 3, 1, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2332, '鐢ㄦ埛鍒嗙粍鍒涘缓', 'member:group:create', 3, 2, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2333, '鐢ㄦ埛鍒嗙粍鏇存柊', 'member:group:update', 3, 3, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2334, '鐢ㄦ埛鍒嗙粍鍒犻櫎', 'member:group:delete', 3, 4, 2330, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-22 13:50:06', '', '2023-08-22 13:50:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2335, '鐢ㄦ埛绛夌骇淇敼', 'member:user:update-level', 3, 5, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-08-23 16:49:05', '', '2023-08-23 16:50:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2336, '鍟嗗搧璇勮', '', 2, 5, 2000, 'comment', 'ep:comment', 'mall/product/comment/index', 'ProductComment', 0, '1', '1', '1', '1', '2023-08-26 11:03:00', '1', '2023-08-26 11:03:38', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2337, '璇勮鏌ヨ', 'product:comment:query', 3, 1, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:01', '1', '2023-08-26 11:04:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2338, '娣诲姞鑷瘎', 'product:comment:create', 3, 2, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:23', '1', '2023-08-26 11:08:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2339, '鍟嗗鍥炲', 'product:comment:update', 3, 3, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:37', '1', '2023-08-26 11:04:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2340, '鏄鹃殣璇勮', 'product:comment:update', 3, 4, 2336, '', '', '', '', 0, '1', '1', '1', '1', '2023-08-26 11:04:55', '1', '2023-08-26 11:04:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2341, '浼樻儬鍔靛彂閫�', 'promotion:coupon:send', 3, 2, 2038, '', '', '', '', 0, '1', '1', '1', '1', '2023-09-02 00:03:14', '1', '2023-09-02 00:03:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2342, '浜ゆ槗閰嶇疆', '', 2, 0, 2072, 'config', 'ep:setting', 'mall/trade/config/index', 'TradeConfig', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:30:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2343, '浜ゆ槗涓績閰嶇疆鏌ヨ', 'trade:config:query', 3, 1, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2344, '浜ゆ槗涓績閰嶇疆淇濆瓨', 'trade:config:save', 3, 2, 2342, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2345, '鍒嗛攢绠$悊', '', 1, 4, 2072, 'brokerage', 'fa-solid:project-diagram', '', '', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2023-09-28 10:58:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2346, '鍒嗛攢鐢ㄦ埛', '', 2, 0, 2345, 'brokerage-user', 'fa-solid:user-tie', 'mall/trade/brokerage/user/index', 'TradeBrokerageUser', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2347, '鍒嗛攢鐢ㄦ埛鏌ヨ', 'trade:brokerage-user:query', 3, 1, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2348, '鍒嗛攢鐢ㄦ埛鎺ㄥ箍浜烘煡璇�', 'trade:brokerage-user:user-query', 3, 2, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2349, '鍒嗛攢鐢ㄦ埛鎺ㄥ箍璁㈠崟鏌ヨ', 'trade:brokerage-user:order-query', 3, 3, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2350, '鍒嗛攢鐢ㄦ埛淇敼鎺ㄥ箍璧勬牸', 'trade:brokerage-user:update-brokerage-enable', 3, 4, 2346, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2351, '淇敼鎺ㄥ箍鍛�', 'trade:brokerage-user:update-bind-user', 3, 5, 2346, '', '', '', '', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-12-01 14:33:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2352, '娓呴櫎鎺ㄥ箍鍛�', 'trade:brokerage-user:clear-bind-user', 3, 6, 2346, '', '', '', '', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-12-01 14:33:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2353, '浣i噾璁板綍', '', 2, 1, 2345, 'brokerage-record', 'fa:money', 'mall/trade/brokerage/record/index', 'TradeBrokerageRecord', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2354, '浣i噾璁板綍鏌ヨ', 'trade:brokerage-record:query', 3, 1, 2353, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2355, '浣i噾鎻愮幇', '', 2, 2, 2345, 'brokerage-withdraw', 'fa:credit-card', 'mall/trade/brokerage/withdraw/index', 'TradeBrokerageWithdraw', 0, '1', '1', '1', '', '2023-09-28 02:46:22', '1', '2024-02-26 20:33:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2356, '浣i噾鎻愮幇鏌ヨ', 'trade:brokerage-withdraw:query', 3, 1, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2357, '浣i噾鎻愮幇瀹℃牳', 'trade:brokerage-withdraw:audit', 3, 2, 2355, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-28 02:46:22', '', '2023-09-28 02:46:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2358, '缁熻涓績', '', 1, 75, 2362, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2023-09-30 11:54:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2359, '浜ゆ槗缁熻', '', 2, 4, 2358, 'trade', 'fa-solid:credit-card', 'mall/statistics/trade/index', 'TradeStatistics', 0, '1', '1', '1', '', '2023-09-30 03:22:40', '1', '2024-02-26 20:42:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2360, '浜ゆ槗缁熻鏌ヨ', 'statistics:trade:query', 3, 1, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2361, '浜ゆ槗缁熻瀵煎嚭', 'statistics:trade:export', 3, 2, 2359, '', '', '', NULL, 0, '1', '1', '1', '', '2023-09-30 03:22:40', '', '2023-09-30 03:22:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2362, '鍟嗗煄绯荤粺', '', 1, 59, 0, '/mall', 'ep:shop', '', '', 0, '1', '1', '1', '1', '2023-09-30 11:52:02', '1', '2023-09-30 11:52:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2363, '鐢ㄦ埛绉垎淇敼', 'member:user:update-point', 3, 6, 2317, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-01 14:39:43', '', '2023-10-01 14:39:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2364, '鐢ㄦ埛浣欓淇敼', 'pay:wallet:update-balance', 3, 7, 2317, '', '', '', '', 0, '1', '1', '1', '', '2023-10-01 14:39:43', '1', '2024-10-01 09:42:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2365, '浼樻儬鍔�', '', 1, 2, 2030, 'coupon', 'fa-solid:disease', '', '', 0, '1', '1', '1', '1', '2023-10-03 12:39:15', '1', '2023-10-05 00:16:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2366, '鐮嶄环璁板綍', '', 2, 2, 2310, 'record', 'ep:list', 'mall/promotion/bargain/record/index', 'PromotionBargainRecord', 0, '1', '1', '1', '', '2023-10-05 02:49:06', '1', '2023-10-05 10:50:38', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2367, '鐮嶄环璁板綍鏌ヨ', 'promotion:bargain-record:query', 3, 1, 2366, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-05 02:49:06', '', '2023-10-05 02:49:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2368, '鍔╁姏璁板綍鏌ヨ', 'promotion:bargain-help:query', 3, 2, 2366, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-05 12:27:49', '1', '2023-10-05 12:27:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2369, '鎷煎洟璁板綍', 'promotion:combination-record:query', 2, 2, 2303, 'record', 'ep:avatar', 'mall/promotion/combination/record/index.vue', 'PromotionCombinationRecord', 0, '1', '1', '1', '1', '2023-10-08 07:10:22', '1', '2023-10-08 07:34:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2374, '浼氬憳缁熻', '', 2, 2, 2358, 'member', 'ep:avatar', 'mall/statistics/member/index', 'MemberStatistics', 0, '1', '1', '1', '', '2023-10-11 04:39:24', '1', '2024-02-26 20:41:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2375, '浼氬憳缁熻鏌ヨ', 'statistics:member:query', 3, 1, 2374, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-11 04:39:24', '', '2023-10-11 04:39:24', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2376, '璁㈠崟鏍搁攢', 'trade:order:pick-up', 3, 10, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2023-10-14 17:11:58', '1', '2023-10-14 17:11:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2377, '鏂囩珷鍒嗙被', '', 2, 0, 2387, 'article/category', 'fa:certificate', 'mall/promotion/article/category/index', 'ArticleCategory', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:38:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2378, '鍒嗙被鏌ヨ', 'promotion:article-category:query', 3, 1, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2379, '鍒嗙被鍒涘缓', 'promotion:article-category:create', 3, 2, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2380, '鍒嗙被鏇存柊', 'promotion:article-category:update', 3, 3, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2381, '鍒嗙被鍒犻櫎', 'promotion:article-category:delete', 3, 4, 2377, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2382, '鏂囩珷鍒楄〃', '', 2, 2, 2387, 'article', 'ep:connection', 'mall/promotion/article/index', 'Article', 0, '1', '1', '1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:41:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2383, '鏂囩珷绠$悊鏌ヨ', 'promotion:article:query', 3, 1, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2384, '鏂囩珷绠$悊鍒涘缓', 'promotion:article:create', 3, 2, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2385, '鏂囩珷绠$悊鏇存柊', 'promotion:article:update', 3, 3, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2386, '鏂囩珷绠$悊鍒犻櫎', 'promotion:article:delete', 3, 4, 2382, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2387, '鍐呭绠$悊', '', 1, 1, 2030, 'content', 'ep:collection', '', '', 0, '1', '1', '1', '1', '2023-10-16 09:37:31', '1', '2023-10-16 09:37:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2388, '鍟嗗煄棣栭〉', '', 2, 1, 2362, 'home', 'ep:home-filled', 'mall/home/index', 'MallHome', 0, '1', '1', '1', '', '2023-10-16 12:10:33', '', '2023-10-16 12:10:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2389, '鏍搁攢璁㈠崟', '', 2, 2, 2166, 'pick-up-order', 'ep:list', 'mall/trade/delivery/pickUpOrder/index', 'PickUpOrder', 0, '1', '1', '1', '', '2023-10-19 16:09:51', '', '2023-10-19 16:09:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2390, '浼樻儬娲诲姩', '', 1, 99, 2030, 'youhui', 'ep:aim', '', '', 0, '1', '1', '1', '1', '2023-10-21 19:23:49', '1', '2023-10-21 19:23:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2391, '瀹㈡埛绠$悊', '', 2, 10, 2397, 'customer', 'fa:address-book-o', 'crm/customer/index', 'CrmCustomer', 0, '1', '1', '1', '', '2023-10-29 09:04:21', '1', '2024-02-17 17:13:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2392, '瀹㈡埛鏌ヨ', 'crm:customer:query', 3, 1, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2393, '瀹㈡埛鍒涘缓', 'crm:customer:create', 3, 2, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2394, '瀹㈡埛鏇存柊', 'crm:customer:update', 3, 3, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2395, '瀹㈡埛鍒犻櫎', 'crm:customer:delete', 3, 4, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2396, '瀹㈡埛瀵煎嚭', 'crm:customer:export', 3, 5, 2391, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 09:04:21', '', '2023-10-29 09:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2397, 'CRM 绯荤粺', '', 1, 200, 0, '/crm', 'simple-icons:civicrm', '', '', 0, '1', '1', '1', '1', '2023-10-29 17:08:30', '1', '2025-04-19 18:56:38', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2398, '鍚堝悓绠$悊', '', 2, 50, 2397, 'contract', 'ep:notebook', 'crm/contract/index', 'CrmContract', 0, '1', '1', '1', '', '2023-10-29 10:50:41', '1', '2024-02-17 17:15:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2399, '鍚堝悓鏌ヨ', 'crm:contract:query', 3, 1, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2400, '鍚堝悓鍒涘缓', 'crm:contract:create', 3, 2, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2401, '鍚堝悓鏇存柊', 'crm:contract:update', 3, 3, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2402, '鍚堝悓鍒犻櫎', 'crm:contract:delete', 3, 4, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2403, '鍚堝悓瀵煎嚭', 'crm:contract:export', 3, 5, 2398, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 10:50:41', '', '2023-10-29 10:50:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2404, '绾跨储绠$悊', '', 2, 8, 2397, 'clue', 'fa:pagelines', 'crm/clue/index', 'CrmClue', 0, '1', '1', '1', '', '2023-10-29 11:06:29', '1', '2024-02-17 17:15:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2405, '绾跨储鏌ヨ', 'crm:clue:query', 3, 1, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2406, '绾跨储鍒涘缓', 'crm:clue:create', 3, 2, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2407, '绾跨储鏇存柊', 'crm:clue:update', 3, 3, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2408, '绾跨储鍒犻櫎', 'crm:clue:delete', 3, 4, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2409, '绾跨储瀵煎嚭', 'crm:clue:export', 3, 5, 2404, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:06:29', '', '2023-10-29 11:06:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2410, '鍟嗘満绠$悊', '', 2, 40, 2397, 'business', 'fa:bus', 'crm/business/index', 'CrmBusiness', 0, '1', '1', '1', '', '2023-10-29 11:12:35', '1', '2024-02-17 17:14:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2411, '鍟嗘満鏌ヨ', 'crm:business:query', 3, 1, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2412, '鍟嗘満鍒涘缓', 'crm:business:create', 3, 2, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2413, '鍟嗘満鏇存柊', 'crm:business:update', 3, 3, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2414, '鍟嗘満鍒犻櫎', 'crm:business:delete', 3, 4, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2415, '鍟嗘満瀵煎嚭', 'crm:business:export', 3, 5, 2410, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:12:35', '', '2023-10-29 11:12:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2416, '鑱旂郴浜虹鐞�', '', 2, 20, 2397, 'contact', 'fa:address-book-o', 'crm/contact/index', 'CrmContact', 0, '1', '1', '1', '', '2023-10-29 11:14:56', '1', '2024-02-17 17:13:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2417, '鑱旂郴浜烘煡璇�', 'crm:contact:query', 3, 1, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2418, '鑱旂郴浜哄垱寤�', 'crm:contact:create', 3, 2, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2419, '鑱旂郴浜烘洿鏂�', 'crm:contact:update', 3, 3, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2420, '鑱旂郴浜哄垹闄�', 'crm:contact:delete', 3, 4, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2421, '鑱旂郴浜哄鍑�', 'crm:contact:export', 3, 5, 2416, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:14:56', '', '2023-10-29 11:14:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2422, '鍥炴绠$悊', '', 2, 60, 2397, 'receivable', 'ep:money', 'crm/receivable/index', 'CrmReceivable', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2423, '鍥炴绠$悊鏌ヨ', 'crm:receivable:query', 3, 1, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2424, '鍥炴绠$悊鍒涘缓', 'crm:receivable:create', 3, 2, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2425, '鍥炴绠$悊鏇存柊', 'crm:receivable:update', 3, 3, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2426, '鍥炴绠$悊鍒犻櫎', 'crm:receivable:delete', 3, 4, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2427, '鍥炴绠$悊瀵煎嚭', 'crm:receivable:export', 3, 5, 2422, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2428, '鍥炴璁″垝', '', 2, 61, 2397, 'receivable-plan', 'fa:money', 'crm/receivable/plan/index', 'CrmReceivablePlan', 0, '1', '1', '1', '', '2023-10-29 11:18:09', '1', '2024-02-17 17:16:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2429, '鍥炴璁″垝鏌ヨ', 'crm:receivable-plan:query', 3, 1, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2430, '鍥炴璁″垝鍒涘缓', 'crm:receivable-plan:create', 3, 2, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2431, '鍥炴璁″垝鏇存柊', 'crm:receivable-plan:update', 3, 3, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2432, '鍥炴璁″垝鍒犻櫎', 'crm:receivable-plan:delete', 3, 4, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2433, '鍥炴璁″垝瀵煎嚭', 'crm:receivable-plan:export', 3, 5, 2428, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 11:18:09', '', '2023-10-29 11:18:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2435, '鍟嗗煄瑁呬慨', '', 2, 20, 2030, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', '', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '1', '2025-03-15 21:34:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2436, '瑁呬慨妯℃澘', '', 2, 1, 2435, 'diy-template', 'fa6-solid:brush', 'mall/promotion/diy/template/index', 'DiyTemplate', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2437, '瑁呬慨妯℃澘鏌ヨ', 'promotion:diy-template:query', 3, 1, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2438, '瑁呬慨妯℃澘鍒涘缓', 'promotion:diy-template:create', 3, 2, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2439, '瑁呬慨妯℃澘鏇存柊', 'promotion:diy-template:update', 3, 3, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2440, '瑁呬慨妯℃澘鍒犻櫎', 'promotion:diy-template:delete', 3, 4, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2441, '瑁呬慨妯℃澘浣跨敤', 'promotion:diy-template:use', 3, 5, 2436, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2442, '瑁呬慨椤甸潰', '', 2, 2, 2435, 'diy-page', 'foundation:page-edit', 'mall/promotion/diy/page/index', 'DiyPage', 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2443, '瑁呬慨椤甸潰鏌ヨ', 'promotion:diy-page:query', 3, 1, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:25', '', '2023-10-29 14:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2444, '瑁呬慨椤甸潰鍒涘缓', 'promotion:diy-page:create', 3, 2, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2445, '瑁呬慨椤甸潰鏇存柊', 'promotion:diy-page:update', 3, 3, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2446, '瑁呬慨椤甸潰鍒犻櫎', 'promotion:diy-page:delete', 3, 4, 2442, '', '', '', NULL, 0, '1', '1', '1', '', '2023-10-29 14:19:26', '', '2023-10-29 14:19:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2447, '涓夋柟鐧诲綍', '', 1, 10, 1, 'social', 'fa:rocket', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:12:01', '1', '2024-02-29 01:14:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2448, '涓夋柟搴旂敤', '', 2, 1, 2447, 'client', 'ep:set-up', 'system/social/client/index.vue', 'SocialClient', 0, '1', '1', '1', '1', '2023-11-04 12:17:19', '1', '2024-05-04 19:09:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2449, '涓夋柟搴旂敤鏌ヨ', 'system:social-client:query', 3, 1, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:12', '1', '2023-11-04 12:43:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2450, '涓夋柟搴旂敤鍒涘缓', 'system:social-client:create', 3, 2, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:43:58', '1', '2023-11-04 12:43:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2451, '涓夋柟搴旂敤鏇存柊', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2452, '涓夋柟搴旂敤鍒犻櫎', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, '1', '1', '1', '1', '2023-11-04 12:44:43', '1', '2023-11-04 12:44:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2453, '涓夋柟鐢ㄦ埛', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, '1', '1', '1', '1', '2023-11-04 14:01:05', '1', '2023-11-04 14:01:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2472, '涓诲瓙琛紙鍐呭祵锛�', '', 2, 12, 1070, 'demo03-inner', 'fa:power-off', 'infra/demo/demo03/inner/index', 'Demo03StudentInner', 0, '1', '1', '1', '', '2023-11-13 04:39:51', '1', '2023-11-16 23:53:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2478, '鍗曡〃锛堝鍒犳敼鏌ワ級', '', 2, 1, 1070, 'demo01-contact', 'ep:bicycle', 'infra/demo/demo01/index', 'Demo01Contact', 0, '1', '1', '1', '', '2023-11-15 14:42:30', '1', '2023-11-16 20:34:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2479, '绀轰緥鑱旂郴浜烘煡璇�', 'infra:demo01-contact:query', 3, 1, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2480, '绀轰緥鑱旂郴浜哄垱寤�', 'infra:demo01-contact:create', 3, 2, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2481, '绀轰緥鑱旂郴浜烘洿鏂�', 'infra:demo01-contact:update', 3, 3, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2482, '绀轰緥鑱旂郴浜哄垹闄�', 'infra:demo01-contact:delete', 3, 4, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2483, '绀轰緥鑱旂郴浜哄鍑�', 'infra:demo01-contact:export', 3, 5, 2478, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2484, '鏍戣〃锛堝鍒犳敼鏌ワ級', '', 2, 2, 1070, 'demo02-category', 'fa:tree', 'infra/demo/demo02/index', 'Demo02Category', 0, '1', '1', '1', '', '2023-11-16 12:18:27', '1', '2023-11-16 20:35:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2485, '绀轰緥鍒嗙被鏌ヨ', 'infra:demo02-category:query', 3, 1, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2486, '绀轰緥鍒嗙被鍒涘缓', 'infra:demo02-category:create', 3, 2, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2487, '绀轰緥鍒嗙被鏇存柊', 'infra:demo02-category:update', 3, 3, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2488, '绀轰緥鍒嗙被鍒犻櫎', 'infra:demo02-category:delete', 3, 4, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2489, '绀轰緥鍒嗙被瀵煎嚭', 'infra:demo02-category:export', 3, 5, 2484, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2490, '涓诲瓙琛紙鏍囧噯锛�', '', 2, 10, 1070, 'demo03-normal', 'fa:battery-3', 'infra/demo/demo03/normal/index', 'Demo03StudentNormal', 0, '1', '1', '1', '', '2023-11-16 12:53:37', '1', '2023-11-16 23:10:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2491, '瀛︾敓鏌ヨ', 'infra:demo03-student:query', 3, 1, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2492, '瀛︾敓鍒涘缓', 'infra:demo03-student:create', 3, 2, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2493, '瀛︾敓鏇存柊', 'infra:demo03-student:update', 3, 3, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2494, '瀛︾敓鍒犻櫎', 'infra:demo03-student:delete', 3, 4, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2495, '瀛︾敓瀵煎嚭', 'infra:demo03-student:export', 3, 5, 2490, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2497, '涓诲瓙琛紙ERP锛�', '', 2, 11, 1070, 'demo03-erp', 'ep:calendar', 'infra/demo/demo03/erp/index', 'Demo03StudentERP', 0, '1', '1', '1', '', '2023-11-16 15:50:59', '1', '2023-11-17 13:19:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2516, '瀹㈡埛鍏捣閰嶇疆', '', 2, 0, 2524, 'customer-pool-config', 'ep:data-analysis', 'crm/customer/poolConfig/index', 'CrmCustomerPoolConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:31', '1', '2024-01-03 19:52:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2517, '瀹㈡埛鍏捣閰嶇疆淇濆瓨', 'crm:customer-pool-config:update', 3, 1, 2516, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:31', '', '2023-11-18 13:33:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2518, '瀹㈡埛闄愬埗閰嶇疆', '', 2, 1, 2524, 'customer-limit-config', 'ep:avatar', 'crm/customer/limitConfig/index', 'CrmCustomerLimitConfig', 0, '1', '1', '1', '', '2023-11-18 13:33:53', '1', '2024-02-24 16:43:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2519, '瀹㈡埛闄愬埗閰嶇疆鏌ヨ', 'crm:customer-limit-config:query', 3, 1, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2520, '瀹㈡埛闄愬埗閰嶇疆鍒涘缓', 'crm:customer-limit-config:create', 3, 2, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2521, '瀹㈡埛闄愬埗閰嶇疆鏇存柊', 'crm:customer-limit-config:update', 3, 3, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2522, '瀹㈡埛闄愬埗閰嶇疆鍒犻櫎', 'crm:customer-limit-config:delete', 3, 4, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2523, '瀹㈡埛闄愬埗閰嶇疆瀵煎嚭', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, '1', '1', '1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2524, '绯荤粺閰嶇疆', '', 1, 999, 2397, 'config', 'ep:connection', '', '', 0, '1', '1', '1', '1', '2023-11-18 21:58:00', '1', '2024-02-17 17:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2525, 'WebSocket', '', 2, 5, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, '1', '1', '1', '1', '2023-11-23 19:41:55', '1', '2024-04-23 00:02:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2526, '浜у搧绠$悊', '', 2, 80, 2397, 'product', 'fa:product-hunt', 'crm/product/index', 'CrmProduct', 0, '1', '1', '1', '1', '2023-12-05 22:45:26', '1', '2024-02-20 20:36:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2527, '浜у搧鏌ヨ', 'crm:product:query', 3, 1, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:16', '1', '2023-12-05 22:47:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2528, '浜у搧鍒涘缓', 'crm:product:create', 3, 2, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:47:41', '1', '2023-12-05 22:47:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2529, '浜у搧鏇存柊', 'crm:product:update', 3, 3, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:03', '1', '2023-12-05 22:48:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2530, '浜у搧鍒犻櫎', 'crm:product:delete', 3, 4, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:17', '1', '2023-12-05 22:48:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2531, '浜у搧瀵煎嚭', 'crm:product:export', 3, 5, 2526, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-05 22:48:29', '1', '2023-12-05 22:48:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2532, '浜у搧鍒嗙被閰嶇疆', '', 2, 3, 2524, 'product/category', 'fa-solid:window-restore', 'crm/product/category/index', 'CrmProductCategory', 0, '1', '1', '1', '1', '2023-12-06 12:52:36', '1', '2023-12-06 12:52:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2533, '浜у搧鍒嗙被鏌ヨ', 'crm:product-category:query', 3, 1, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:23', '1', '2023-12-06 12:53:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2534, '浜у搧鍒嗙被鍒涘缓', 'crm:product-category:create', 3, 2, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:41', '1', '2023-12-06 12:53:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2535, '浜у搧鍒嗙被鏇存柊', 'crm:product-category:update', 3, 3, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:53:59', '1', '2023-12-06 12:53:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2536, '浜у搧鍒嗙被鍒犻櫎', 'crm:product-category:delete', 3, 4, 2532, '', '', '', '', 0, '1', '1', '1', '1', '2023-12-06 12:54:14', '1', '2023-12-06 12:54:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2543, '鍏宠仈鍟嗘満', 'crm:contact:create-business', 3, 10, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:25', '1', '2024-01-02 17:28:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2544, '鍙栧叧鍟嗘満', 'crm:contact:delete-business', 3, 11, 2416, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-02 17:28:43', '1', '2024-01-02 17:28:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2545, '鍟嗗搧缁熻', '', 2, 3, 2358, 'product', 'fa:product-hunt', 'mall/statistics/product/index', 'ProductStatistics', 0, '1', '1', '1', '', '2023-12-15 18:54:28', '1', '2024-02-26 20:41:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2546, '瀹㈡埛鍏捣', '', 2, 30, 2397, 'customer/pool', 'fa-solid:swimming-pool', 'crm/customer/pool/index', 'CrmCustomerPool', 0, '1', '1', '1', '1', '2024-01-15 21:29:34', '1', '2024-02-17 17:14:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2547, '璁㈠崟鏌ヨ', 'trade:order:query', 3, 1, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:00', '1', '2024-01-16 08:52:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2548, '璁㈠崟鏇存柊', 'trade:order:update', 3, 2, 2076, '', '', '', '', 0, '1', '1', '1', '1', '2024-01-16 08:52:21', '1', '2024-01-16 08:52:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2549, '鏀粯&閫�娆炬渚�', '', 2, 1, 2161, 'order', 'fa:paypal', 'pay/demo/order/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:45:00', '1', '2024-01-18 23:47:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2550, '鎻愮幇杞处妗堜緥', '', 2, 2, 2161, 'transfer', 'fa:transgender-alt', 'pay/demo/withdraw/index', '', 0, '1', '1', '1', '1', '2024-01-18 23:51:16', '1', '2025-05-08 13:04:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2551, '閽卞寘绠$悊', '', 1, 4, 1117, 'wallet', 'ep:wallet', '', '', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '1', '2024-02-29 08:58:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2552, '鍏呭�煎椁�', '', 2, 2, 2551, 'wallet-recharge-package', 'fa:leaf', 'pay/wallet/rechargePackage/index', 'WalletRechargePackage', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2553, '閽卞寘鍏呭�煎椁愭煡璇�', 'pay:wallet-recharge-package:query', 3, 1, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2554, '閽卞寘鍏呭�煎椁愬垱寤�', 'pay:wallet-recharge-package:create', 3, 2, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2555, '閽卞寘鍏呭�煎椁愭洿鏂�', 'pay:wallet-recharge-package:update', 3, 3, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2556, '閽卞寘鍏呭�煎椁愬垹闄�', 'pay:wallet-recharge-package:delete', 3, 4, 2552, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2557, '閽卞寘浣欓', '', 2, 1, 2551, 'wallet-balance', 'fa:leaf', 'pay/wallet/balance/index', 'WalletBalance', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2558, '閽卞寘浣欓鏌ヨ', 'pay:wallet:query', 3, 1, 2557, '', '', '', NULL, 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2559, '杞处璁㈠崟', '', 2, 3, 1117, 'transfer', 'ep:credit-card', 'pay/transfer/index', 'PayTransfer', 0, '1', '1', '1', '', '2023-12-29 02:32:54', '', '2023-12-29 02:32:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2560, '鏁版嵁缁熻', '', 1, 200, 2397, 'statistics', 'ep:data-line', '', '', 0, '1', '1', '1', '1', '2024-01-26 22:50:35', '1', '2024-02-24 20:10:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2561, '鎺掕姒�', 'crm:statistics-rank:query', 2, 1, 2560, 'ranking', 'fa:area-chart', 'crm/statistics/rank/index', 'CrmStatisticsRank', 0, '1', '1', '1', '1', '2024-01-26 22:52:09', '1', '2024-04-24 19:39:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2562, '瀹㈡埛瀵煎叆', 'crm:customer:import', 3, 6, 2391, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-01 13:09:00', '1', '2024-02-01 13:09:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2563, 'ERP 绯荤粺', '', 1, 300, 0, '/erp', 'simple-icons:erpnext', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:37:25', '1', '2025-04-19 18:56:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2564, '浜у搧绠$悊', '', 1, 40, 2563, 'product', 'fa:product-hunt', '', '', 0, '1', '1', '1', '1', '2024-02-04 15:38:43', '1', '2024-02-04 15:38:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2565, '浜у搧淇℃伅', '', 2, 0, 2564, 'product', 'fa-solid:apple-alt', 'erp/product/product/index', 'ErpProduct', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-05 14:42:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2566, '浜у搧鏌ヨ', 'erp:product:query', 3, 1, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:21:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2567, '浜у搧鍒涘缓', 'erp:product:create', 3, 2, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2568, '浜у搧鏇存柊', 'erp:product:update', 3, 3, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2569, '浜у搧鍒犻櫎', 'erp:product:delete', 3, 4, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2570, '浜у搧瀵煎嚭', 'erp:product:export', 3, 5, 2565, '', '', '', '', 0, '1', '1', '1', '', '2024-02-04 07:52:15', '1', '2024-02-04 17:22:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2571, '浜у搧鍒嗙被', '', 2, 1, 2564, 'product-category', 'fa:certificate', 'erp/product/category/index', 'ErpProductCategory', 0, '1', '1', '1', '', '2024-02-04 09:21:04', '1', '2024-02-04 17:24:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2572, '鍒嗙被鏌ヨ', 'erp:product-category:query', 3, 1, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2573, '鍒嗙被鍒涘缓', 'erp:product-category:create', 3, 2, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2574, '鍒嗙被鏇存柊', 'erp:product-category:update', 3, 3, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2575, '鍒嗙被鍒犻櫎', 'erp:product-category:delete', 3, 4, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2576, '鍒嗙被瀵煎嚭', 'erp:product-category:export', 3, 5, 2571, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 09:21:04', '', '2024-02-04 09:21:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2577, '浜у搧鍗曚綅', '', 2, 2, 2564, 'unit', 'ep:opportunity', 'erp/product/unit/index', 'ErpProductUnit', 0, '1', '1', '1', '', '2024-02-04 11:54:08', '1', '2024-02-04 19:54:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2578, '鍗曚綅鏌ヨ', 'erp:product-unit:query', 3, 1, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2579, '鍗曚綅鍒涘缓', 'erp:product-unit:create', 3, 2, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2580, '鍗曚綅鏇存柊', 'erp:product-unit:update', 3, 3, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2581, '鍗曚綅鍒犻櫎', 'erp:product-unit:delete', 3, 4, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2582, '鍗曚綅瀵煎嚭', 'erp:product-unit:export', 3, 5, 2577, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 11:54:08', '', '2024-02-04 11:54:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2583, '搴撳瓨绠$悊', '', 1, 30, 2563, 'stock', 'fa:window-restore', '', '', 0, '1', '1', '1', '1', '2024-02-05 00:29:37', '1', '2024-02-05 00:29:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2584, '浠撳簱淇℃伅', '', 2, 0, 2583, 'warehouse', 'ep:house', 'erp/stock/warehouse/index', 'ErpWarehouse', 0, '1', '1', '1', '', '2024-02-04 17:12:09', '1', '2024-02-05 01:12:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2585, '浠撳簱鏌ヨ', 'erp:warehouse:query', 3, 1, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2586, '浠撳簱鍒涘缓', 'erp:warehouse:create', 3, 2, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2587, '浠撳簱鏇存柊', 'erp:warehouse:update', 3, 3, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2588, '浠撳簱鍒犻櫎', 'erp:warehouse:delete', 3, 4, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2589, '浠撳簱瀵煎嚭', 'erp:warehouse:export', 3, 5, 2584, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-04 17:12:09', '', '2024-02-04 17:12:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2590, '浜у搧搴撳瓨', '', 2, 1, 2583, 'stock', 'ep:coffee', 'erp/stock/stock/index', 'ErpStock', 0, '1', '1', '1', '', '2024-02-05 06:40:50', '1', '2024-02-05 14:42:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2591, '搴撳瓨鏌ヨ', 'erp:stock:query', 3, 1, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2592, '搴撳瓨瀵煎嚭', 'erp:stock:export', 3, 5, 2590, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 06:40:50', '', '2024-02-05 06:40:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2593, '鍑哄叆搴撴槑缁�', '', 2, 2, 2583, 'record', 'fa-solid:blog', 'erp/stock/record/index', 'ErpStockRecord', 0, '1', '1', '1', '', '2024-02-05 10:27:21', '1', '2024-02-06 17:26:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2594, '搴撳瓨鏄庣粏鏌ヨ', 'erp:stock-record:query', 3, 1, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2595, '搴撳瓨鏄庣粏瀵煎嚭', 'erp:stock-record:export', 3, 5, 2593, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 10:27:21', '', '2024-02-05 10:27:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2596, '鍏跺畠鍏ュ簱', '', 2, 3, 2583, 'in', 'ep:zoom-in', 'erp/stock/in/index', 'ErpStockIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2597, '鍏跺畠鍏ュ簱鍗曟煡璇�', 'erp:stock-in:query', 3, 1, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2598, '鍏跺畠鍏ュ簱鍗曞垱寤�', 'erp:stock-in:create', 3, 2, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2599, '鍏跺畠鍏ュ簱鍗曟洿鏂�', 'erp:stock-in:update', 3, 3, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2600, '鍏跺畠鍏ュ簱鍗曞垹闄�', 'erp:stock-in:delete', 3, 4, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2601, '鍏跺畠鍏ュ簱鍗曞鍑�', 'erp:stock-in:export', 3, 5, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2602, '閲囪喘绠$悊', '', 1, 10, 2563, 'purchase', 'fa:buysellads', '', '', 0, '1', '1', '1', '1', '2024-02-06 16:01:01', '1', '2024-02-06 16:01:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2603, '渚涘簲鍟嗕俊鎭�', '', 2, 4, 2602, 'supplier', 'fa:superpowers', 'erp/purchase/supplier/index', 'ErpSupplier', 0, '1', '1', '1', '', '2024-02-06 08:21:55', '1', '2024-02-06 16:22:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2604, '渚涘簲鍟嗘煡璇�', 'erp:supplier:query', 3, 1, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2605, '渚涘簲鍟嗗垱寤�', 'erp:supplier:create', 3, 2, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2606, '渚涘簲鍟嗘洿鏂�', 'erp:supplier:update', 3, 3, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2607, '渚涘簲鍟嗗垹闄�', 'erp:supplier:delete', 3, 4, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2608, '渚涘簲鍟嗗鍑�', 'erp:supplier:export', 3, 5, 2603, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-06 08:21:55', '', '2024-02-06 08:21:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2609, '鍏跺畠鍏ュ簱鍗曞鎵�', 'erp:stock-in:update-status', 3, 6, 2596, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-05 16:08:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2610, '鍏跺畠鍑哄簱', '', 2, 4, 2583, 'out', 'ep:zoom-out', 'erp/stock/out/index', 'ErpStockOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-07 19:06:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2611, '鍏跺畠鍑哄簱鍗曟煡璇�', 'erp:stock-out:query', 3, 1, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2612, '鍏跺畠鍑哄簱鍗曞垱寤�', 'erp:stock-out:create', 3, 2, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2613, '鍏跺畠鍑哄簱鍗曟洿鏂�', 'erp:stock-out:update', 3, 3, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2614, '鍏跺畠鍑哄簱鍗曞垹闄�', 'erp:stock-out:delete', 3, 4, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2615, '鍏跺畠鍑哄簱鍗曞鍑�', 'erp:stock-out:export', 3, 5, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2616, '鍏跺畠鍑哄簱鍗曞鎵�', 'erp:stock-out:update-status', 3, 6, 2610, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 06:43:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2617, '閿�鍞鐞�', '', 1, 20, 2563, 'sale', 'fa:sellsy', '', '', 0, '1', '1', '1', '1', '2024-02-07 15:12:32', '1', '2024-02-07 15:12:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2618, '瀹㈡埛淇℃伅', '', 2, 4, 2617, 'customer', 'ep:avatar', 'erp/sale/customer/index', 'ErpCustomer', 0, '1', '1', '1', '', '2024-02-07 07:21:45', '1', '2024-02-07 15:22:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2619, '瀹㈡埛鏌ヨ', 'erp:customer:query', 3, 1, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2620, '瀹㈡埛鍒涘缓', 'erp:customer:create', 3, 2, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2621, '瀹㈡埛鏇存柊', 'erp:customer:update', 3, 3, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2622, '瀹㈡埛鍒犻櫎', 'erp:customer:delete', 3, 4, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2623, '瀹㈡埛瀵煎嚭', 'erp:customer:export', 3, 5, 2618, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-07 07:21:45', '', '2024-02-07 07:21:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2624, '搴撳瓨璋冩嫧', '', 2, 5, 2583, 'move', 'ep:folder-remove', 'erp/stock/move/index', 'ErpStockMove', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-16 18:53:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2625, '搴撳瓨璋冨害鍗曟煡璇�', 'erp:stock-move:query', 3, 1, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2626, '搴撳瓨璋冨害鍗曞垱寤�', 'erp:stock-move:create', 3, 2, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2627, '搴撳瓨璋冨害鍗曟洿鏂�', 'erp:stock-move:update', 3, 3, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2628, '搴撳瓨璋冨害鍗曞垹闄�', 'erp:stock-move:delete', 3, 4, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2629, '搴撳瓨璋冨害鍗曞鍑�', 'erp:stock-move:export', 3, 5, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2630, '搴撳瓨璋冨害鍗曞鎵�', 'erp:stock-move:update-status', 3, 6, 2624, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2631, '搴撳瓨鐩樼偣', '', 2, 6, 2583, 'check', 'ep:circle-check-filled', 'erp/stock/check/index', 'ErpStockCheck', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-08 08:31:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2632, '搴撳瓨鐩樼偣鍗曟煡璇�', 'erp:stock-check:query', 3, 1, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2633, '搴撳瓨鐩樼偣鍗曞垱寤�', 'erp:stock-check:create', 3, 2, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2634, '搴撳瓨鐩樼偣鍗曟洿鏂�', 'erp:stock-check:update', 3, 3, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2635, '搴撳瓨鐩樼偣鍗曞垹闄�', 'erp:stock-check:delete', 3, 4, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2636, '搴撳瓨鐩樼偣鍗曞鍑�', 'erp:stock-check:export', 3, 5, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2637, '搴撳瓨鐩樼偣鍗曞鎵�', 'erp:stock-check:update-status', 3, 6, 2631, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2638, '閿�鍞鍗�', '', 2, 1, 2617, 'order', 'fa:first-order', 'erp/sale/order/index', 'ErpSaleOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 21:59:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2639, '閿�鍞鍗曟煡璇�', 'erp:sale-order:query', 3, 1, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2640, '閿�鍞鍗曞垱寤�', 'erp:sale-order:create', 3, 2, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2641, '閿�鍞鍗曟洿鏂�', 'erp:sale-order:update', 3, 3, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2642, '閿�鍞鍗曞垹闄�', 'erp:sale-order:delete', 3, 4, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2643, '閿�鍞鍗曞鍑�', 'erp:sale-order:export', 3, 5, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2644, '閿�鍞鍗曞鎵�', 'erp:sale-order:update-status', 3, 6, 2638, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2645, '璐㈠姟绠$悊', '', 1, 50, 2563, 'finance', 'ep:money', '', '', 0, '1', '1', '1', '1', '2024-02-10 08:05:58', '1', '2024-02-10 08:06:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2646, '缁撶畻璐︽埛', '', 2, 10, 2645, 'account', 'fa:universal-access', 'erp/finance/account/index', 'ErpAccount', 0, '1', '1', '1', '', '2024-02-10 00:15:07', '1', '2024-02-14 08:24:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2647, '缁撶畻璐︽埛鏌ヨ', 'erp:account:query', 3, 1, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2648, '缁撶畻璐︽埛鍒涘缓', 'erp:account:create', 3, 2, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2649, '缁撶畻璐︽埛鏇存柊', 'erp:account:update', 3, 3, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2650, '缁撶畻璐︽埛鍒犻櫎', 'erp:account:delete', 3, 4, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2651, '缁撶畻璐︽埛瀵煎嚭', 'erp:account:export', 3, 5, 2646, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-10 00:15:07', '', '2024-02-10 00:15:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2652, '閿�鍞嚭搴�', '', 2, 2, 2617, 'out', 'ep:sold-out', 'erp/sale/out/index', 'ErpSaleOut', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-10 22:02:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2653, '閿�鍞嚭搴撴煡璇�', 'erp:sale-out:query', 3, 1, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2654, '閿�鍞嚭搴撳垱寤�', 'erp:sale-out:create', 3, 2, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2655, '閿�鍞嚭搴撴洿鏂�', 'erp:sale-out:update', 3, 3, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2656, '閿�鍞嚭搴撳垹闄�', 'erp:sale-out:delete', 3, 4, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2657, '閿�鍞嚭搴撳鍑�', 'erp:sale-out:export', 3, 5, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2658, '閿�鍞嚭搴撳鎵�', 'erp:sale-out:update-status', 3, 6, 2652, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2659, '閿�鍞��璐�', '', 2, 3, 2617, 'return', 'fa-solid:bone', 'erp/sale/return/index', 'ErpSaleReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 06:12:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2660, '閿�鍞��璐ф煡璇�', 'erp:sale-return:query', 3, 1, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2661, '閿�鍞��璐у垱寤�', 'erp:sale-return:create', 3, 2, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2662, '閿�鍞��璐ф洿鏂�', 'erp:sale-return:update', 3, 3, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2663, '閿�鍞��璐у垹闄�', 'erp:sale-return:delete', 3, 4, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2664, '閿�鍞��璐у鍑�', 'erp:sale-return:export', 3, 5, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:12:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2665, '閿�鍞��璐у鎵�', 'erp:sale-return:update-status', 3, 6, 2659, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-07 11:13:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2666, '閲囪喘璁㈠崟', '', 2, 1, 2602, 'order', 'fa-solid:border-all', 'erp/purchase/order/index', 'ErpPurchaseOrder', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 08:51:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2667, '閲囪喘璁㈠崟鏌ヨ', 'erp:purchase-order:query', 3, 1, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2668, '閲囪喘璁㈠崟鍒涘缓', 'erp:purchase-order:create', 3, 2, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2669, '閲囪喘璁㈠崟鏇存柊', 'erp:purchase-order:update', 3, 3, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2670, '閲囪喘璁㈠崟鍒犻櫎', 'erp:purchase-order:delete', 3, 4, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2671, '閲囪喘璁㈠崟瀵煎嚭', 'erp:purchase-order:export', 3, 5, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2672, '閲囪喘璁㈠崟瀹℃壒', 'erp:purchase-order:update-status', 3, 6, 2666, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2673, '閲囪喘鍏ュ簱', '', 2, 2, 2602, 'in', 'fa-solid:gopuram', 'erp/purchase/in/index', 'ErpPurchaseIn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 11:19:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2674, '閲囪喘鍏ュ簱鏌ヨ', 'erp:purchase-in:query', 3, 1, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2675, '閲囪喘鍏ュ簱鍒涘缓', 'erp:purchase-in:create', 3, 2, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2676, '閲囪喘鍏ュ簱鏇存柊', 'erp:purchase-in:update', 3, 3, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2677, '閲囪喘鍏ュ簱鍒犻櫎', 'erp:purchase-in:delete', 3, 4, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2678, '閲囪喘鍏ュ簱瀵煎嚭', 'erp:purchase-in:export', 3, 5, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2679, '閲囪喘鍏ュ簱瀹℃壒', 'erp:purchase-in:update-status', 3, 6, 2673, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2680, '閲囪喘閫�璐�', '', 2, 3, 2602, 'return', 'ep:minus', 'erp/purchase/return/index', 'ErpPurchaseReturn', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-12 20:51:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2681, '閲囪喘閫�璐ф煡璇�', 'erp:purchase-return:query', 3, 1, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2682, '閲囪喘閫�璐у垱寤�', 'erp:purchase-return:create', 3, 2, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2683, '閲囪喘閫�璐ф洿鏂�', 'erp:purchase-return:update', 3, 3, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2684, '閲囪喘閫�璐у垹闄�', 'erp:purchase-return:delete', 3, 4, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2685, '閲囪喘閫�璐у鍑�', 'erp:purchase-return:export', 3, 5, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2686, '閲囪喘閫�璐у鎵�', 'erp:purchase-return:update-status', 3, 6, 2680, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2687, '浠樻鍗�', '', 2, 1, 2645, 'payment', 'ep:caret-right', 'erp/finance/payment/index', 'ErpFinancePayment', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-14 08:24:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2688, '浠樻鍗曟煡璇�', 'erp:finance-payment:query', 3, 1, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2689, '浠樻鍗曞垱寤�', 'erp:finance-payment:create', 3, 2, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2690, '浠樻鍗曟洿鏂�', 'erp:finance-payment:update', 3, 3, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2691, '浠樻鍗曞垹闄�', 'erp:finance-payment:delete', 3, 4, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2692, '浠樻鍗曞鍑�', 'erp:finance-payment:export', 3, 5, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2693, '浠樻鍗曞鎵�', 'erp:finance-payment:update-status', 3, 6, 2687, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2694, '鏀舵鍗�', '', 2, 2, 2645, 'receipt', 'ep:expand', 'erp/finance/receipt/index', 'ErpFinanceReceipt', 0, '1', '1', '1', '', '2024-02-05 16:08:56', '1', '2024-02-15 19:35:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2695, '鏀舵鍗曟煡璇�', 'erp:finance-receipt:query', 3, 1, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2696, '鏀舵鍗曞垱寤�', 'erp:finance-receipt:create', 3, 2, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2697, '鏀舵鍗曟洿鏂�', 'erp:finance-receipt:update', 3, 3, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:44:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2698, '鏀舵鍗曞垹闄�', 'erp:finance-receipt:delete', 3, 4, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2699, '鏀舵鍗曞鍑�', 'erp:finance-receipt:export', 3, 5, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2700, '鏀舵鍗曞鎵�', 'erp:finance-receipt:update-status', 3, 6, 2694, '', '', '', NULL, 0, '1', '1', '1', '', '2024-02-05 16:08:56', '', '2024-02-12 00:45:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2701, '寰呭姙浜嬮」', '', 2, 0, 2397, 'backlog', 'fa-solid:tasks', 'crm/backlog/index', 'CrmBacklog', 0, '1', '1', '1', '1', '2024-02-17 17:17:11', '1', '2024-02-17 17:17:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2702, 'ERP 棣栭〉', 'erp:statistics:query', 2, 0, 2563, 'home', 'ep:home-filled', 'erp/home/index.vue', 'ErpHome', 0, '1', '1', '1', '1', '2024-02-18 16:49:40', '1', '2024-02-26 21:12:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2703, '鍟嗘満鐘舵�侀厤缃�', '', 2, 4, 2524, 'business-status', 'fa-solid:charging-station', 'crm/business/status/index', 'CrmBusinessStatus', 0, '1', '1', '1', '1', '2024-02-21 20:15:17', '1', '2024-02-21 20:15:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2704, '鍟嗘満鐘舵�佹煡璇�', 'crm:business-status:query', 3, 1, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:36', '1', '2024-02-21 20:36:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2705, '鍟嗘満鐘舵�佸垱寤�', 'crm:business-status:create', 3, 2, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:35:57', '1', '2024-02-21 20:35:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2706, '鍟嗘満鐘舵�佹洿鏂�', 'crm:business-status:update', 3, 3, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:21', '1', '2024-02-21 20:36:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2707, '鍟嗘満鐘舵�佸垹闄�', 'crm:business-status:delete', 3, 4, 2703, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-21 20:36:36', '1', '2024-02-21 20:36:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2708, '鍚堝悓閰嶇疆', '', 2, 5, 2524, 'contract-config', 'ep:connection', 'crm/contract/config/index', 'CrmContractConfig', 0, '1', '1', '1', '1', '2024-02-24 16:44:40', '1', '2024-02-24 16:44:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2709, '瀹㈡埛鍏捣閰嶇疆鏌ヨ', 'crm:customer-pool-config:query', 3, 2, 2516, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:19', '1', '2024-02-24 16:45:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2710, '鍚堝悓閰嶇疆鏇存柊', 'crm:contract-config:update', 3, 1, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:45:56', '1', '2024-02-24 16:45:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2711, '鍚堝悓閰嶇疆鏌ヨ', 'crm:contract-config:query', 3, 2, 2708, '', '', '', '', 0, '1', '1', '1', '1', '2024-02-24 16:46:16', '1', '2024-02-24 16:46:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2712, '瀹㈡埛鍒嗘瀽', 'crm:statistics-customer:query', 2, 0, 2560, 'customer', 'ep:avatar', 'crm/statistics/customer/index.vue', 'CrmStatisticsCustomer', 0, '1', '1', '1', '1', '2024-03-09 16:43:56', '1', '2024-05-04 20:38:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2713, '鎶勯�佹垜鐨�', 'bpm:process-instance-cc:query', 2, 30, 1200, 'copy', 'ep:copy-document', 'bpm/task/copy/index', 'BpmProcessInstanceCopy', 0, '1', '1', '1', '1', '2024-03-17 21:50:23', '1', '2024-04-24 19:55:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2714, '娴佺▼鍒嗙被', '', 2, 3, 1186, 'category', 'fa:object-ungroup', 'bpm/category/index', 'BpmCategory', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-21 23:51:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2715, '鍒嗙被鏌ヨ', 'bpm:category:query', 3, 1, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2716, '鍒嗙被鍒涘缓', 'bpm:category:create', 3, 2, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2717, '鍒嗙被鏇存柊', 'bpm:category:update', 3, 3, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2718, '鍒嗙被鍒犻櫎', 'bpm:category:delete', 3, 4, 2714, '', '', '', '', 0, '1', '1', '1', '', '2024-03-08 02:00:51', '1', '2024-03-19 14:36:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2720, '鍙戣捣娴佺▼', '', 2, 0, 1200, 'create', 'fa-solid:grin-stars', 'bpm/processInstance/create/index', 'BpmProcessInstanceCreate', 0, '1', '0', '1', '1', '2024-03-19 19:46:05', '1', '2024-03-23 19:03:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2721, '娴佺▼瀹炰緥', '', 2, 10, 1186, 'process-instance/manager', 'fa:square', 'bpm/processInstance/manager/index', 'BpmProcessInstanceManager', 0, '1', '1', '1', '1', '2024-03-21 23:57:30', '1', '2024-03-21 23:57:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2722, '娴佺▼瀹炰緥鐨勬煡璇紙绠$悊鍛橈級', 'bpm:process-instance:manager-query', 3, 1, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:18:27', '1', '2024-03-22 08:19:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2723, '娴佺▼瀹炰緥鐨勫彇娑堬紙绠$悊鍛橈級', 'bpm:process-instance:cancel-by-admin', 3, 2, 2721, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:19:25', '1', '2024-03-22 08:19:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2724, '娴佺▼浠诲姟', '', 2, 11, 1186, 'process-tasnk', 'ep:collection-tag', 'bpm/task/manager/index', 'BpmManagerTask', 0, '1', '1', '1', '1', '2024-03-22 08:43:22', '1', '2024-03-22 08:43:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2725, '娴佺▼浠诲姟鐨勬煡璇紙绠$悊鍛橈級', 'bpm:task:manager-query', 3, 1, 2724, '', '', '', '', 0, '1', '1', '1', '1', '2024-03-22 08:43:49', '1', '2025-12-23 23:04:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2726, '娴佺▼鐩戝惉鍣�', '', 2, 5, 1186, 'process-listener', 'fa:assistive-listening-systems', 'bpm/processListener/index', 'BpmProcessListener', 0, '1', '1', '1', '', '2024-03-09 16:05:34', '1', '2024-03-23 13:13:38', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2727, '娴佺▼鐩戝惉鍣ㄦ煡璇�', 'bpm:process-listener:query', 3, 1, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2728, '娴佺▼鐩戝惉鍣ㄥ垱寤�', 'bpm:process-listener:create', 3, 2, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2729, '娴佺▼鐩戝惉鍣ㄦ洿鏂�', 'bpm:process-listener:update', 3, 3, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2730, '娴佺▼鐩戝惉鍣ㄥ垹闄�', 'bpm:process-listener:delete', 3, 4, 2726, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 16:05:34', '', '2024-03-09 16:05:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2731, '娴佺▼琛ㄨ揪寮�', '', 2, 6, 1186, 'process-expression', 'fa:wpexplorer', 'bpm/processExpression/index', 'BpmProcessExpression', 0, '1', '1', '1', '', '2024-03-09 22:35:08', '1', '2024-03-23 19:43:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2732, '娴佺▼琛ㄨ揪寮忔煡璇�', 'bpm:process-expression:query', 3, 1, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2733, '娴佺▼琛ㄨ揪寮忓垱寤�', 'bpm:process-expression:create', 3, 2, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2734, '娴佺▼琛ㄨ揪寮忔洿鏂�', 'bpm:process-expression:update', 3, 3, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2735, '娴佺▼琛ㄨ揪寮忓垹闄�', 'bpm:process-expression:delete', 3, 4, 2731, '', '', '', NULL, 0, '1', '1', '1', '', '2024-03-09 22:35:08', '', '2024-03-09 22:35:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2736, '鍛樺伐涓氱哗', 'crm:statistics-performance:query', 2, 3, 2560, 'performance', 'ep:dish-dot', 'crm/statistics/performance/index', 'CrmStatisticsPerformance', 0, '1', '1', '1', '1', '2024-04-05 13:49:20', '1', '2024-04-24 19:42:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2737, '瀹㈡埛鐢诲儚', 'crm:statistics-portrait:query', 2, 4, 2560, 'portrait', 'ep:picture', 'crm/statistics/portrait/index', 'CrmStatisticsPortrait', 0, '1', '1', '1', '1', '2024-04-05 13:57:40', '1', '2024-04-24 19:42:24', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2738, '閿�鍞紡鏂�', 'crm:statistics-funnel:query', 2, 5, 2560, 'funnel', 'ep:grape', 'crm/statistics/funnel/index', 'CrmStatisticsFunnel', 0, '1', '1', '1', '1', '2024-04-13 10:53:26', '1', '2024-04-24 19:39:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2739, '娑堟伅涓績', '', 1, 7, 1, 'messages', 'ep:chat-dot-round', '', '', 0, '1', '1', '1', '1', '2024-04-22 23:54:30', '1', '2024-04-23 09:36:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2740, '鐩戞帶涓績', '', 1, 10, 2, 'monitors', 'ep:monitor', '', '', 0, '1', '1', '1', '1', '2024-04-23 00:04:44', '1', '2024-04-23 00:04:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2741, '棰嗗彇鍏捣瀹㈡埛', 'crm:customer:receive', 3, 1, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:47:45', '1', '2024-04-24 19:47:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2742, '鍒嗛厤鍏捣瀹㈡埛', 'crm:customer:distribute', 3, 2, 2546, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:48:05', '1', '2024-04-24 19:48:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2743, '鍟嗗搧缁熻鏌ヨ', 'statistics:product:query', 3, 1, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:05', '1', '2024-04-24 19:50:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2744, '鍟嗗搧缁熻瀵煎嚭', 'statistics:product:export', 3, 2, 2545, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:50:26', '1', '2024-04-24 19:50:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2745, '鏀粯娓犻亾鏌ヨ', 'pay:channel:query', 3, 10, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:01', '1', '2024-04-24 19:53:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2746, '鏀粯娓犻亾鍒涘缓', 'pay:channel:create', 3, 11, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:18', '1', '2024-04-24 19:53:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2747, '鏀粯娓犻亾鏇存柊', 'pay:channel:update', 3, 12, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:53:32', '1', '2024-04-24 19:53:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2748, '鏀粯娓犻亾鍒犻櫎', 'pay:channel:delete', 3, 13, 1126, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:54:34', '1', '2024-04-24 19:54:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2749, '鍟嗗搧鏀惰棌鏌ヨ', 'product:favorite:query', 3, 10, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:55:47', '1', '2024-04-24 19:55:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2750, '鍟嗗搧娴忚鏌ヨ', 'product:browse-history:query', 3, 20, 2014, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:57:43', '1', '2024-04-24 19:57:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2751, '鍞悗鍚屾剰', 'trade:after-sale:agree', 3, 2, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:58:40', '1', '2024-04-24 19:58:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2752, '鍞悗涓嶅悓鎰�', 'trade:after-sale:disagree', 3, 3, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 19:59:03', '1', '2024-04-24 19:59:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2753, '鍞悗纭閫�璐�', 'trade:after-sale:receive', 3, 4, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:07', '1', '2024-04-24 20:00:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2754, '鍞悗纭閫�娆�', 'trade:after-sale:refund', 3, 5, 2073, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:00:24', '1', '2024-04-24 20:00:24', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2755, '鍒犻櫎椤圭洰', 'report:go-view-project:delete', 3, 2, 2153, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:01:37', '1', '2024-04-24 20:01:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2756, '浼氬憳绛夌骇璁板綍鏌ヨ', 'member:level-record:query', 3, 10, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:32', '1', '2024-04-24 20:02:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2757, '浼氬憳缁忛獙璁板綍鏌ヨ', 'member:experience-record:query', 3, 11, 2325, '', '', '', '', 0, '1', '1', '1', '1', '2024-04-24 20:02:51', '1', '2024-04-24 20:02:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2758, 'AI 澶фā鍨�', '', 1, 400, 0, '/ai', 'tabler:ai', '', '', 0, '1', '1', '1', '1', '2024-05-07 15:07:56', '1', '2025-04-19 18:57:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2759, 'AI 瀵硅瘽', '', 2, 1, 2758, 'chat', 'ep:message', 'ai/chat/index/index.vue', 'AiChat', 0, '1', '1', '1', '1', '2024-05-07 15:09:14', '1', '2024-07-07 17:15:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2760, '鎺у埗鍙�', '', 1, 100, 2758, 'console', 'ep:setting', '', '', 0, '1', '1', '1', '1', '2024-05-09 22:39:09', '1', '2024-05-24 23:34:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2761, 'API 瀵嗛挜', '', 2, 0, 2760, 'api-key', 'ep:key', 'ai/model/apiKey/index.vue', 'AiApiKey', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-10 22:44:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2762, 'API 瀵嗛挜鏌ヨ', 'ai:api-key:query', 3, 1, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2763, 'API 瀵嗛挜鍒涘缓', 'ai:api-key:create', 3, 2, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2764, 'API 瀵嗛挜鏇存柊', 'ai:api-key:update', 3, 3, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2765, 'API 瀵嗛挜鍒犻櫎', 'ai:api-key:delete', 3, 4, 2761, '', '', '', '', 0, '1', '1', '1', '', '2024-05-09 14:52:56', '1', '2024-05-13 20:36:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2767, '妯″瀷閰嶇疆', '', 2, 0, 2760, 'model', 'fa-solid:abacus', 'ai/model/model/index.vue', 'AiModel', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2025-03-03 09:57:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2768, '鑱婂ぉ妯″瀷鏌ヨ', 'ai:model:query', 3, 1, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2025-03-03 09:19:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2769, '鑱婂ぉ妯″瀷鍒涘缓', 'ai:model:create', 3, 2, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2025-03-03 09:20:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2770, '鑱婂ぉ妯″瀷鏇存柊', 'ai:model:update', 3, 3, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2025-03-03 09:20:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2771, '鑱婂ぉ妯″瀷鍒犻櫎', 'ai:model:delete', 3, 4, 2767, '', '', '', '', 0, '1', '1', '1', '', '2024-05-10 14:42:48', '1', '2025-03-03 09:20:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2773, '鑱婂ぉ瑙掕壊', '', 2, 0, 2760, 'chat-role', 'fa:user-secret', 'ai/model/chatRole/index.vue', 'AiChatRole', 0, '1', '1', '1', '', '2024-05-13 12:39:28', '1', '2024-05-13 20:41:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2774, '鑱婂ぉ瑙掕壊鏌ヨ', 'ai:chat-role:query', 3, 1, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2775, '鑱婂ぉ瑙掕壊鍒涘缓', 'ai:chat-role:create', 3, 2, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2776, '鑱婂ぉ瑙掕壊鏇存柊', 'ai:chat-role:update', 3, 3, 2773, '', '', '', NULL, 0, '1', '1', '1', '', '2024-05-13 12:39:28', '', '2024-05-13 12:39:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2777, '鑱婂ぉ瑙掕壊鍒犻櫎', 'ai:chat-role:delete', 3, 4, 2773, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-13 21:43:38', '1', '2024-05-13 21:43:38', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2778, '鑱婂ぉ绠$悊', '', 2, 10, 2760, 'chat-conversation', 'ep:chat-square', 'ai/chat/manager/index.vue', 'AiChatManager', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-06-26 21:36:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2779, '浼氳瘽鏌ヨ', 'ai:chat-conversation:query', 3, 1, 2778, '', '', '', '', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-05-25 08:38:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2780, '浼氳瘽鍒犻櫎', 'ai:chat-conversation:delete', 3, 2, 2778, '', '', '', '', 0, '1', '1', '1', '', '2024-05-24 15:39:18', '1', '2024-05-25 08:38:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2781, '娑堟伅鏌ヨ', 'ai:chat-message:query', 3, 11, 2778, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-25 08:38:56', '1', '2024-05-25 08:38:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2782, '娑堟伅鍒犻櫎', 'ai:chat-message:delete', 3, 12, 2778, '', '', '', '', 0, '1', '1', '1', '1', '2024-05-25 08:39:10', '1', '2024-05-25 08:39:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2783, 'AI 缁樼敾', '', 2, 2, 2758, 'image', 'ep:picture-rounded', 'ai/image/index/index.vue', 'AiImage', 0, '1', '1', '1', '1', '2024-05-26 11:45:17', '1', '2024-07-07 17:18:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2784, '缁樼敾绠$悊', '', 2, 11, 2760, 'image', 'fa:file-image-o', 'ai/image/manager/index.vue', 'AiImageManager', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 21:37:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2785, '缁樼敾鏌ヨ', 'ai:image:query', 3, 1, 2784, '', '', '', '', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 22:21:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2786, '缁樼敾鍒犻櫎', 'ai:image:delete', 3, 4, 2784, '', '', '', '', 0, '1', '1', '1', '', '2024-06-26 13:32:31', '1', '2024-06-26 22:22:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2787, '缁樺浘鏇存柊', 'ai:image:update', 3, 2, 2784, '', '', '', '', 0, '1', '1', '1', '1', '2024-06-26 22:47:56', '1', '2024-08-31 09:21:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2788, '闊充箰绠$悊', '', 2, 12, 2760, 'music', 'fa:music', 'ai/music/manager/index.vue', 'AiMusicManager', 0, '1', '1', '1', '', '2024-06-27 15:03:33', '1', '2024-06-27 23:04:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2789, '闊充箰鏌ヨ', 'ai:music:query', 3, 1, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2790, '闊充箰鏇存柊', 'ai:music:update', 3, 3, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2791, '闊充箰鍒犻櫎', 'ai:music:delete', 3, 4, 2788, '', '', '', NULL, 0, '1', '1', '1', '', '2024-06-27 15:03:33', '', '2024-06-27 15:03:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2792, 'AI 鍐欎綔', '', 2, 3, 2758, 'write', 'fa-solid:book-reader', 'ai/write/index/index.vue', 'AiWrite', 0, '1', '1', '1', '1', '2024-07-08 09:26:44', '1', '2024-07-16 13:03:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2793, '鍐欎綔绠$悊', '', 2, 13, 2760, 'write', 'fa:bookmark-o', 'ai/write/manager/index.vue', 'AiWriteManager', 0, '1', '1', '1', '', '2024-07-10 13:24:34', '1', '2024-07-10 21:31:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2794, 'AI 鍐欎綔鏌ヨ', 'ai:write:query', 3, 1, 2793, '', '', '', NULL, 0, '1', '1', '1', '', '2024-07-10 13:24:34', '', '2024-07-10 13:24:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2795, 'AI 鍐欎綔鍒犻櫎', 'ai:write:delete', 3, 4, 2793, '', '', '', NULL, 0, '1', '1', '1', '', '2024-07-10 13:24:34', '', '2024-07-10 13:24:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2796, 'AI 闊充箰', '', 2, 4, 2758, 'music', 'fa:music', 'ai/music/index/index.vue', 'AiMusic', 0, '1', '1', '1', '1', '2024-07-17 09:21:12', '1', '2024-07-29 21:11:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2797, '瀹㈡湇涓績', '', 2, 100, 2362, 'kefu', 'fa-solid:user-alt', 'mall/promotion/kefu/index', 'KeFu', 0, '1', '1', '1', '1', '2024-07-17 23:49:05', '1', '2024-07-17 23:49:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2798, 'AI 鎬濈淮瀵煎浘', '', 2, 6, 2758, 'mind-map', 'fa:sitemap', 'ai/mindmap/index/index.vue', 'AiMindMap', 0, '1', '1', '1', '1', '2024-07-29 21:31:59', '1', '2025-03-02 18:57:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2799, '瀵煎浘绠$悊', '', 2, 14, 2760, 'mind-map', 'fa:map', 'ai/mindmap/manager/index', 'AiMindMapManager', 0, '1', '1', '1', '', '2024-08-10 09:15:09', '1', '2024-08-10 17:24:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2800, '鎬濈淮瀵煎浘鏌ヨ', 'ai:mind-map:query', 3, 1, 2799, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 09:15:09', '', '2024-08-10 09:15:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2801, '鎬濈淮瀵煎浘鍒犻櫎', 'ai:mind-map:delete', 3, 4, 2799, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 09:15:09', '', '2024-08-10 09:15:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2802, '浼氳瘽鏌ヨ', 'promotion:kefu-conversation:query', 3, 1, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:17:52', '1', '2024-08-31 09:18:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2803, '浼氳瘽鏇存柊', 'promotion:kefu-conversation:update', 3, 2, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:18:15', '1', '2024-08-31 09:19:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2804, '娑堟伅鏌ヨ', 'promotion:kefu-message:query', 3, 10, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:18:42', '1', '2024-08-31 09:18:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2805, '浼氳瘽鍒犻櫎', 'promotion:kefu-conversation:delete', 3, 3, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:19:51', '1', '2024-08-31 09:20:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2806, '娑堟伅鍙戦��', 'promotion:kefu-message:send', 3, 12, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:20:06', '1', '2024-08-31 09:20:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2807, '娑堟伅鏇存柊', 'promotion:kefu-message:update', 3, 11, 2797, '', '', '', '', 0, '1', '1', '1', '1', '2024-08-31 09:20:22', '1', '2024-08-31 09:20:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2808, '绉垎鍟嗗煄', '', 2, 5, 2030, 'point-activity', 'ep:bowl', 'mall/promotion/point/activity/index', 'PointActivity', 0, '1', '1', '1', '', '2024-09-21 05:36:42', '1', '2024-09-23 09:14:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2809, '绉垎鍟嗗煄娲诲姩鏌ヨ', 'promotion:point-activity:query', 3, 1, 2808, '', '', '', '', 0, '1', '1', '1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2810, '绉垎鍟嗗煄娲诲姩鍒涘缓', 'promotion:point-activity:create', 3, 2, 2808, '', '', '', '', 0, '1', '1', '1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2811, '绉垎鍟嗗煄娲诲姩鏇存柊', 'promotion:point-activity:update', 3, 3, 2808, '', '', '', '', 0, '1', '1', '1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2812, '绉垎鍟嗗煄娲诲姩鍒犻櫎', 'promotion:point-activity:delete', 3, 4, 2808, '', '', '', '', 0, '1', '1', '1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2813, '绉垎鍟嗗煄娲诲姩瀵煎嚭', 'promotion:point-activity:export', 3, 5, 2808, '', '', '', '', 0, '1', '1', '1', '', '2024-09-21 05:36:42', '1', '2024-09-22 14:49:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2912, '鍒涘缓鎺ㄥ箍鍛�', 'trade:brokerage-user:create', 3, 7, 2346, '', '', '', '', 0, '1', '1', '1', '1', '2024-12-01 14:32:39', '1', '2024-12-01 14:32:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2913, '娴佺▼娓呯悊', 'bpm:model:clean', 3, 7, 1193, '', '', '', '', 0, '1', '1', '1', '1', '2025-01-17 19:32:06', '1', '2025-01-17 19:32:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2914, '绉垎鍟嗗煄娲诲姩鍏抽棴', 'promotion:point-activity:close', 3, 6, 2808, '', '', '', '', 0, '1', '1', '1', '1', '2025-01-23 20:23:34', '1', '2025-01-23 20:23:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2915, 'AI 鐭ヨ瘑搴�', '', 2, 5, 2758, 'knowledge', 'ep:notebook', 'ai/knowledge/knowledge/index', 'AiKnowledge', 0, '1', '1', '1', '', '2025-02-28 07:04:21', '1', '2025-03-02 18:58:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2916, 'AI 鐭ヨ瘑搴撴煡璇�', 'ai:knowledge:query', 3, 1, 2915, '', '', '', NULL, 0, '1', '1', '1', '', '2025-02-28 07:04:21', '', '2025-02-28 07:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2917, 'AI 鐭ヨ瘑搴撳垱寤�', 'ai:knowledge:create', 3, 2, 2915, '', '', '', NULL, 0, '1', '1', '1', '', '2025-02-28 07:04:21', '', '2025-02-28 07:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2918, 'AI 鐭ヨ瘑搴撴洿鏂�', 'ai:knowledge:update', 3, 3, 2915, '', '', '', NULL, 0, '1', '1', '1', '', '2025-02-28 07:04:21', '', '2025-02-28 07:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2919, 'AI 鐭ヨ瘑搴撳垹闄�', 'ai:knowledge:delete', 3, 4, 2915, '', '', '', NULL, 0, '1', '1', '1', '', '2025-02-28 07:04:21', '', '2025-02-28 07:04:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2920, '宸ュ叿绠$悊', '', 2, 0, 2760, 'tool', 'fa-solid:tools', 'ai/model/tool/index.vue', 'AiTool', 0, '1', '1', '1', '', '2025-03-14 11:19:29', '1', '2025-03-14 19:20:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2921, '宸ュ叿鏌ヨ', 'ai:tool:query', 3, 1, 2920, '', '', '', NULL, 0, '1', '1', '1', '', '2025-03-14 11:19:29', '', '2025-03-14 11:19:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2922, '宸ュ叿鍒涘缓', 'ai:tool:create', 3, 2, 2920, '', '', '', NULL, 0, '1', '1', '1', '', '2025-03-14 11:19:29', '', '2025-03-14 11:19:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2923, '宸ュ叿鏇存柊', 'ai:tool:update', 3, 3, 2920, '', '', '', NULL, 0, '1', '1', '1', '', '2025-03-14 11:19:29', '', '2025-03-14 11:19:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (2924, '宸ュ叿鍒犻櫎', 'ai:tool:delete', 3, 4, 2920, '', '', '', NULL, 0, '1', '1', '1', '', '2025-03-14 11:19:29', '', '2025-03-14 11:19:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4000, 'IoT 鐗╄仈缃�', '', 1, 500, 0, '/iot', 'fa-solid:hdd', '', '', 0, '1', '1', '1', '1', '2024-08-10 09:55:28', '1', '2024-12-07 15:58:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4001, '璁惧鎺ュ叆', '', 1, 2, 4000, 'device', 'ep:platform', '', '', 0, '1', '1', '1', '1', '2024-08-10 09:57:56', '1', '2025-02-27 08:39:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4002, '浜у搧绠$悊', '', 2, 1, 4001, 'product', 'fa-solid:tools', 'iot/product/product/index', 'IoTProduct', 0, '1', '1', '1', '', '2024-08-10 02:38:02', '1', '2025-06-15 20:56:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4003, '浜у搧鏌ヨ', 'iot:product:query', 3, 1, 4002, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4004, '浜у搧鍒涘缓', 'iot:product:create', 3, 2, 4002, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4005, '浜у搧鏇存柊', 'iot:product:update', 3, 3, 4002, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4006, '浜у搧鍒犻櫎', 'iot:product:delete', 3, 4, 4002, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4007, '浜у搧瀵煎嚭', 'iot:product:export', 3, 5, 4002, '', '', '', NULL, 0, '1', '1', '1', '', '2024-08-10 02:38:02', '', '2024-12-07 15:55:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4008, '璁惧绠$悊', '', 2, 2, 4001, 'device', 'fa:mobile', 'iot/device/device/index', 'IoTDevice', 0, '1', '1', '1', '', '2024-09-16 18:48:19', '1', '2025-06-15 20:56:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4009, '璁惧鏌ヨ', 'iot:device:query', 3, 1, 4008, '', '', '', '', 0, '1', '1', '1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4010, '璁惧鍒涘缓', 'iot:device:create', 3, 2, 4008, '', '', '', '', 0, '1', '1', '1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4011, '璁惧鏇存柊', 'iot:device:update', 3, 3, 4008, '', '', '', '', 0, '1', '1', '1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4012, '璁惧鍒犻櫎', 'iot:device:delete', 3, 4, 4008, '', '', '', '', 0, '1', '1', '1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4013, '璁惧瀵煎嚭', 'iot:device:export', 3, 5, 4008, '', '', '', '', 0, '1', '1', '1', '', '2024-09-16 18:48:19', '1', '2024-12-07 15:55:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4014, '浜у搧鍒嗙被', '', 2, 3, 4001, 'product-category', 'ep:notebook', 'iot/product/category/index', 'IotProductCategory', 0, '1', '1', '1', '', '2024-12-07 16:01:35', '1', '2025-06-15 20:56:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4015, '浜у搧鍒嗙被鏌ヨ', 'iot:product-category:query', 3, 1, 4014, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-07 16:01:35', '', '2024-12-07 16:01:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4016, '浜у搧鍒嗙被鍒涘缓', 'iot:product-category:create', 3, 2, 4014, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-07 16:01:35', '', '2024-12-07 16:01:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4017, '浜у搧鍒嗙被鏇存柊', 'iot:product-category:update', 3, 3, 4014, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-07 16:01:35', '', '2024-12-07 16:01:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4018, '浜у搧鍒嗙被鍒犻櫎', 'iot:product-category:delete', 3, 4, 4014, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-07 16:01:35', '', '2024-12-07 16:01:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4031, '璁惧鍒嗙粍', '', 2, 3, 4001, 'device-group', 'fa-solid:layer-group', 'iot/device/group/index', 'IotDeviceGroup', 0, '1', '1', '1', '', '2024-12-14 17:08:29', '1', '2024-12-14 17:09:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4032, '璁惧鍒嗙粍鏌ヨ', 'iot:device-group:query', 3, 1, 4031, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-14 17:08:29', '', '2024-12-14 17:08:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4033, '璁惧鍒嗙粍鍒涘缓', 'iot:device-group:create', 3, 2, 4031, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-14 17:08:29', '', '2024-12-14 17:08:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4034, '璁惧鍒嗙粍鏇存柊', 'iot:device-group:update', 3, 3, 4031, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-14 17:08:29', '', '2024-12-14 17:08:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4035, '璁惧鍒嗙粍鍒犻櫎', 'iot:device-group:delete', 3, 4, 4031, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-14 17:08:29', '', '2024-12-14 17:08:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4036, '璁惧瀵煎叆', 'iot:device:import', 3, 6, 4008, '', '', '', '', 0, '1', '1', '1', '1', '2024-12-15 10:35:47', '1', '2024-12-15 10:35:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4037, '浜у搧鐗╂ā鍨�', '', 2, 99, 4001, 'thing-model', 'ep:mostly-cloudy', 'iot/thingmodel/index', 'IoTThingModel', 0, '0', '0', '0', '', '2024-12-16 17:17:50', '1', '2025-06-15 20:56:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4038, '浜у搧鐗╂ā鍨嬪姛鑳芥煡璇�', 'iot:thing-model:query', 3, 1, 4037, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-16 17:17:51', '', '2025-03-17 09:14:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4039, '浜у搧鐗╂ā鍨嬪姛鑳藉垱寤�', 'iot:thing-model:create', 3, 2, 4037, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-16 17:17:52', '', '2025-03-17 09:14:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4040, '浜у搧鐗╂ā鍨嬪姛鑳芥洿鏂�', 'iot:thing-model:update', 3, 3, 4037, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-16 17:17:52', '', '2025-03-17 09:15:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4041, '浜у搧鐗╂ā鍨嬪姛鑳藉垹闄�', 'iot:thing-model:delete', 3, 4, 4037, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-16 17:17:52', '', '2025-03-17 09:15:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4042, '浜у搧鐗╂ā鍨嬪姛鑳藉鍑�', 'iot:thing-model:export', 3, 5, 4037, '', '', '', NULL, 0, '1', '1', '1', '', '2024-12-16 17:17:53', '', '2025-03-17 09:15:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4043, '璁惧娑堟伅鍙戦��', 'iot:device:message-send', 3, 12, 4008, '', '', '', '', 0, '1', '1', '1', '1', '2025-01-28 04:40:16', '1', '2025-06-14 14:09:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4044, '璁惧灞炴�ф煡璇�', 'iot:device:property-query', 3, 10, 4008, '', '', '', '', 0, '1', '1', '1', '1', '2025-01-28 11:52:54', '1', '2025-01-28 11:52:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4045, '璁惧娑堟伅鏌ヨ', 'iot:device:message-query', 3, 11, 4008, '', '', '', '', 0, '1', '1', '1', '1', '2025-01-28 11:53:22', '1', '2025-06-14 11:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4047, '杩愮淮绠$悊', '', 1, 4, 4000, 'operation', 'fa:align-center', '', '', 0, '1', '1', '1', '1', '2025-02-05 22:21:37', '"1"', '2025-06-30 20:12:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4048, '瑙勫垯寮曟搸', '', 1, 3, 4000, 'rule', 'fa-solid:cogs', '', '', 0, '1', '1', '1', '1', '2025-02-11 14:10:54', '1', '2025-02-11 14:10:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4049, '鍦烘櫙鑱斿姩', '', 2, 1, 4048, 'scene', 'ep:link', 'iot/rule/scene/index', 'IoTSceneRule', 0, '1', '1', '1', '1', '2025-02-11 14:12:44', '"1"', '2025-08-09 15:38:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4050, 'IoT 棣栭〉', '', 2, 1, 4000, 'home', 'ep:home-filled', 'iot/home/index', 'IotHome', 0, '1', '1', '1', '1', '2025-02-27 08:39:35', '1', '2025-06-24 14:22:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4051, '鏁版嵁娴佽浆', '', 2, 2, 4048, 'data-rule', 'ep:guide', 'iot/rule/data/index', 'IoTDataRule', 0, '1', '1', '1', '', '2025-03-09 13:47:11', '"1"', '2025-08-09 15:38:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4052, '鏁版嵁娴佽浆瑙勫垯鏌ヨ', 'iot:data-rule:query', 3, 1, 4051, '', '', '', '', 0, '1', '1', '1', '', '2025-03-09 13:47:11', '1', '2025-06-24 20:48:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4053, '鏁版嵁娴佽浆瑙勫垯鍒涘缓', 'iot:data-rule:create', 3, 2, 4051, '', '', '', '', 0, '1', '1', '1', '', '2025-03-09 13:47:11', '1', '2025-06-24 20:48:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4054, '鏁版嵁娴佽浆瑙勫垯鏇存柊', 'iot:data-rule:update', 3, 3, 4051, '', '', '', '', 0, '1', '1', '1', '', '2025-03-09 13:47:11', '1', '2025-06-24 20:48:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (4055, '鏁版嵁娴佽浆瑙勫垯鍒犻櫎', 'iot:data-rule:delete', 3, 4, 4051, '', '', '', '', 0, '1', '1', '1', '', '2025-03-09 13:47:12', '1', '2025-06-24 20:48:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5000, 'AI 宸ヤ綔娴�', '', 2, 5, 2758, 'workflow', 'fa:hand-grab-o', 'ai/workflow/index.vue', 'AiWorkflow', 0, '1', '1', '1', '1', '2025-03-25 09:50:27', '1', '2025-05-03 18:55:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5001, 'AI 宸ヤ綔娴佹煡璇�', 'ai:workflow:query', 3, 1, 5000, '', '', '', '', 0, '1', '1', '1', '1', '2025-03-25 09:51:11', '1', '2025-03-25 09:51:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5002, 'AI 宸ヤ綔娴佸垱寤�', 'ai:workflow:create', 3, 2, 5000, '', '', '', '', 0, '1', '1', '1', '1', '2025-03-25 09:51:28', '1', '2025-03-25 09:51:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5003, 'AI 宸ヤ綔娴佹洿鏂�', 'ai:workflow:update', 3, 3, 5000, '', '', '', '', 0, '1', '1', '1', '1', '2025-03-25 09:51:42', '1', '2025-03-25 09:51:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5004, 'AI 宸ヤ綔娴佸垹闄�', 'ai:workflow:delete', 3, 4, 5000, '', '', '', '', 0, '1', '1', '1', '1', '2025-03-25 09:51:55', '1', '2025-03-25 09:52:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5005, 'AI 宸ヤ綔娴佹祴璇�', 'ai:workflow:test', 3, 5, 5000, '', '', '', '', 0, '1', '1', '1', '1', '2025-03-30 10:29:41', '1', '2025-03-30 10:29:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5009, '浠〃鐩樿璁″櫒', '', 2, 1, 1281, 'jimu-bi', 'fa:y-combinator', 'report/jmreport/bi', 'JimuBI', 0, '1', '1', '1', '1', '2025-05-03 09:57:15', '1', '2025-05-03 10:02:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5010, '绉熸埛鍒囨崲', 'system:tenant:visit', 3, 999, 1138, '', '', '', '', 0, '1', '1', '1', '1', '2025-05-05 15:25:32', '1', '2025-05-05 15:25:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5011, '杞处璁㈠崟鏌ヨ', 'pay:transfer:query', 3, 1, 2559, '', '', '', '', 0, '1', '1', '1', '1', '2025-05-08 12:46:53', '1', '2025-05-08 12:46:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5012, '杞处璁㈠崟瀵煎嚭', 'pay:transfer:export', 3, 2, 2559, '', '', '', '', 0, '1', '1', '1', '1', '2025-05-10 17:00:28', '1', '2025-05-10 17:00:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5013, '鍦烘櫙鑱斿姩鏌ヨ', 'iot:rule-scene:query', 3, 1, 4049, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-20 16:53:01', '1', '2025-06-20 16:53:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5014, '鍦烘櫙鑱斿姩鍒涘缓', 'iot:rule-scene:create', 3, 2, 4049, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-20 16:54:31', '1', '2025-06-20 16:54:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5015, '鍦烘櫙鑱斿姩鏇存柊', 'iot:rule-scene:update', 3, 3, 4049, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-20 16:54:47', '1', '2025-06-20 16:54:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5016, '鍦烘櫙鑱斿姩鍒犻櫎', 'iot:rule-scene:delete', 3, 4, 4049, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-20 16:55:04', '1', '2025-06-20 16:55:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5017, '鍦烘櫙鑱斿姩瀵煎嚭', 'iot:rule-scene:export', 3, 5, 4049, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-20 16:57:56', '1', '2025-06-20 16:57:56', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5018, '鏁版嵁娴佽浆鐩殑鏌ヨ', 'iot:data-sink:query', 3, 11, 4051, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-24 20:48:40', '1', '2025-06-24 20:48:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5019, '鏁版嵁娴佽浆鐩殑鍒涘缓', 'iot:data-sink:create', 3, 12, 4051, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-24 20:48:57', '1', '2025-06-24 20:48:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5020, '鏁版嵁娴佽浆鐩殑鏇存柊', 'iot:data-sink:update', 3, 13, 4051, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-24 20:49:10', '1', '2025-06-24 20:49:10', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5021, '鏁版嵁娴佽浆鐩殑鍒犻櫎', 'iot:data-sink:delete', 3, 14, 4051, '', '', '', '', 0, '1', '1', '1', '1', '2025-06-24 20:49:23', '1', '2025-06-24 20:49:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5022, '鍛婅閰嶇疆', '', 2, 1, 5028, 'config', 'fa:connectdevelop', 'iot/alert/config/index', 'IotAlertConfig', 0, '1', '1', '1', '', '2025-06-27 14:28:59', '1', '2025-06-27 22:31:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5023, '鍛婅閰嶇疆鏌ヨ', 'iot:alert-config:query', 3, 1, 5022, '', '', '', '', 0, '1', '1', '1', '', '2025-06-27 14:28:59', '1', '2025-06-28 16:00:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5024, '鍛婅閰嶇疆鍒涘缓', 'iot:alert-config:create', 3, 2, 5022, '', '', '', '', 0, '1', '1', '1', '', '2025-06-27 14:28:59', '1', '2025-06-28 16:00:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5025, '鍛婅閰嶇疆鏇存柊', 'iot:alert-config:update', 3, 3, 5022, '', '', '', '', 0, '1', '1', '1', '', '2025-06-27 14:28:59', '1', '2025-06-28 16:00:43', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5026, '鍛婅閰嶇疆鍒犻櫎', 'iot:alert-config:delete', 3, 4, 5022, '', '', '', '', 0, '1', '1', '1', '', '2025-06-27 14:29:00', '1', '2025-06-28 16:00:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5028, '鍛婅涓績', '', 1, 3, 4000, 'alert', 'fa:soundcloud', '', '', 0, '1', '1', '1', '1', '2025-06-27 22:30:04', '1', '2025-06-27 22:30:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5029, '鍛婅璁板綍', '', 2, 2, 5028, 'record', 'fa-solid:record-vinyl', 'iot/alert/record/index', 'IotAlertRecord', 0, '1', '1', '1', '', '2025-06-28 07:59:32', '1', '2025-06-28 16:01:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5030, '鍛婅璁板綍鏌ヨ', 'iot:alert-record:query', 3, 1, 5029, '', '', '', '', 0, '1', '1', '1', '', '2025-06-28 07:59:32', '1', '2025-06-28 16:00:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5031, '鍛婅璁板綍澶勭悊', 'iot:alert-record:process', 3, 2, 5029, '', '', '', '', 0, '1', '1', '1', '', '2025-06-28 07:59:32', '1', '2025-06-28 16:01:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5032, 'OTA 鍥轰欢', '', 2, 1, 4047, 'ota/firmware', 'fa-solid:award', 'iot/ota/firmware/index', 'IoTOtaFirmware', 0, '1', '1', '1', '', '2025-06-30 07:50:29', '"1"', '2025-06-30 20:13:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5033, 'OTA 鍥轰欢鏌ヨ', 'iot:ota-firmware:query', 3, 1, 5032, '', '', '', '', 0, '1', '1', '1', '', '2025-06-30 07:50:29', '"1"', '2025-06-30 17:38:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5034, 'OTA 鍥轰欢鍒涘缓', 'iot:ota-firmware:create', 3, 2, 5032, '', '', '', '', 0, '1', '1', '1', '', '2025-06-30 07:50:29', '"1"', '2025-06-30 17:38:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5035, 'OTA 鍥轰欢鏇存柊', 'iot:ota-firmware:update', 3, 3, 5032, '', '', '', '', 0, '1', '1', '1', '', '2025-06-30 07:50:29', '"1"', '2025-06-30 17:38:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5036, 'OTA 鍥轰欢鍒犻櫎', 'iot:ota-firmware:delete', 3, 4, 5032, '', '', '', '', 0, '1', '1', '1', '', '2025-06-30 07:50:29', '"1"', '2025-06-30 17:38:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5037, 'OTA 鍗囩骇浠诲姟鏌ヨ', 'iot:ota-task:query', 3, 11, 5032, '', '', '', '', 0, '1', '1', '1', '1', '2025-07-02 23:56:56', '1', '2026-05-19 08:48:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5038, 'OTA 鍗囩骇浠诲姟鍙栨秷', 'iot:ota-task:cancel', 3, 13, 5032, '', '', '', '', 0, '1', '1', '1', '1', '2025-07-02 23:57:26', '1', '2025-07-02 23:57:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5039, 'OTA 鍗囩骇浠诲姟鍒涘缓', 'iot:ota-task:create', 3, 12, 5032, '', '', '', '', 0, '1', '1', '1', '1', '2025-07-02 23:57:52', '1', '2025-07-02 23:57:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5040, 'OTA 鍗囩骇璁板綍鏌ヨ', 'iot:ota-task-record:query', 3, 21, 5032, '', '', '', '', 0, '1', '1', '1', '1', '2025-07-02 23:58:30', '1', '2025-07-02 23:58:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5041, 'OTA 鍗囩骇璁板綍鍙栨秷', 'iot:ota-task-record:cancel', 3, 23, 5032, '', '', '', '', 0, '1', '1', '1', '1', '2025-07-02 23:59:18', '1', '2025-07-02 23:59:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5042, '妯$増娑堟伅', '', 2, 5, 2084, 'message-template', 'ep:notebook', 'mp/messageTemplate/index', 'MpMessageTemplate', 0, '1', '1', '1', '1', '2025-11-26 16:45:35', '1', '2025-11-26 18:44:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5043, '鏌ヨ妯$増娑堟伅', 'mp:message-template:query', 3, 1, 5042, '', '', '', '', 0, '1', '1', '1', '1', '2025-11-26 17:00:15', '1', '2025-11-26 18:45:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5044, '鍒犻櫎妯$増娑堟伅', 'mp:message-template:delete', 3, 2, 5042, '', '', '', '', 0, '1', '1', '1', '1', '2025-11-26 17:00:31', '1', '2025-11-26 18:45:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5045, '鍚屾鍏紬鍙锋ā鏉�', 'mp:message-template:sync', 3, 3, 5042, '', '', '', '', 0, '1', '1', '1', '1', '2025-11-26 17:00:55', '1', '2025-11-26 17:00:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5046, '缁欑矇涓濆彂閫佹ā鐗堟秷鎭�', 'mp:message-template:send', 3, 4, 5042, '', '', '', '', 0, '1', '1', '1', '1', '2025-11-26 17:01:11', '1', '2025-11-26 17:01:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5100, 'MES 绯荤粺', '', 1, 320, 0, '/mes', 'ep:cpu', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:39:57', '1', '2026-05-09 16:19:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5101, '鍩虹鏁版嵁', '', 1, 10, 5100, 'md', 'ep:data-analysis', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5110, '鐗╂枡浜у搧鍒嗙被', '', 2, 2, 5101, 'item-type', 'ep:files', 'mes/md/item/type/index', 'MesMdItemType', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 13:58:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5111, '鍒嗙被鏌ヨ', 'mes:md-item-type:query', 3, 1, 5110, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5112, '鍒嗙被鍒涘缓', 'mes:md-item-type:create', 3, 2, 5110, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5113, '鍒嗙被鏇存柊', 'mes:md-item-type:update', 3, 3, 5110, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5114, '鍒嗙被鍒犻櫎', 'mes:md-item-type:delete', 3, 4, 5110, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5120, '鐗╂枡浜у搧绠$悊', '', 2, 1, 5101, 'item', 'ep:box', 'mes/md/item/index', 'MesMdItem', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 13:58:24', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5121, '鐗╂枡鏌ヨ', 'mes:md-item:query', 3, 1, 5120, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5122, '鐗╂枡鍒涘缓', 'mes:md-item:create', 3, 2, 5120, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5123, '鐗╂枡鏇存柊', 'mes:md-item:update', 3, 3, 5120, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5124, '鐗╂枡鍒犻櫎', 'mes:md-item:delete', 3, 4, 5120, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5125, '鐗╂枡瀵煎嚭', 'mes:md-item:export', 3, 5, 5120, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 00:40:13', '1', '2026-02-15 00:40:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5126, '鐗╂枡瀵煎叆', 'mes:md-item:import', 3, 6, 5120, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 14:13:01', '1', '2026-02-15 14:13:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5130, '璁¢噺鍗曚綅', '', 2, 3, 5101, 'unit-measure', 'ep:scale-to-original', 'mes/md/unitmeasure/index', 'MesMdUnitMeasure', 0, '1', '1', '1', '1', '2026-02-15 13:55:01', '1', '2026-02-15 13:55:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5131, '鍗曚綅鏌ヨ', 'mes:md-unit-measure:query', 3, 1, 5130, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 13:55:16', '1', '2026-02-15 13:55:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5132, '鍗曚綅鍒涘缓', 'mes:md-unit-measure:create', 3, 2, 5130, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 13:55:16', '1', '2026-02-15 13:55:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5133, '鍗曚綅鏇存柊', 'mes:md-unit-measure:update', 3, 3, 5130, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 13:55:16', '1', '2026-02-15 13:55:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5134, '鍗曚綅鍒犻櫎', 'mes:md-unit-measure:delete', 3, 4, 5130, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 13:55:16', '1', '2026-02-15 13:55:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5135, '鍗曚綅瀵煎嚭', 'mes:md-unit-measure:export', 3, 5, 5130, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 13:55:16', '1', '2026-02-15 13:55:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5140, '瀹㈡埛绠$悊', '', 2, 4, 5101, 'client', 'ep:user', 'mes/md/client/index', 'MesMdClient', 0, '1', '1', '1', '1', '2026-02-15 15:06:41', '1', '2026-02-15 15:06:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5141, '瀹㈡埛鏌ヨ', 'mes:md-client:query', 3, 1, 5140, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 15:06:41', '1', '2026-02-15 15:06:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5142, '瀹㈡埛鍒涘缓', 'mes:md-client:create', 3, 2, 5140, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 15:06:41', '1', '2026-02-15 15:06:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5143, '瀹㈡埛鏇存柊', 'mes:md-client:update', 3, 3, 5140, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 15:06:41', '1', '2026-02-15 15:06:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5144, '瀹㈡埛鍒犻櫎', 'mes:md-client:delete', 3, 4, 5140, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 15:06:41', '1', '2026-02-15 15:06:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5145, '瀹㈡埛瀵煎嚭', 'mes:md-client:export', 3, 5, 5140, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 15:06:41', '1', '2026-02-15 15:06:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5146, '瀹㈡埛瀵煎叆', 'mes:md-client:import', 3, 6, 5140, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 15:06:41', '1', '2026-02-15 15:06:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5150, '渚涘簲鍟嗙鐞�', '', 2, 5, 5101, 'vendor', 'ep:goods', 'mes/md/vendor/index', 'MesMdVendor', 0, '1', '1', '1', '1', '2026-02-15 16:01:11', '1', '2026-02-15 16:01:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5151, '渚涘簲鍟嗘煡璇�', 'mes:md-vendor:query', 3, 1, 5150, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:01:11', '1', '2026-02-15 16:01:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5152, '渚涘簲鍟嗗垱寤�', 'mes:md-vendor:create', 3, 2, 5150, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:01:11', '1', '2026-02-15 16:01:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5153, '渚涘簲鍟嗘洿鏂�', 'mes:md-vendor:update', 3, 3, 5150, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:01:11', '1', '2026-02-15 16:01:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5154, '渚涘簲鍟嗗垹闄�', 'mes:md-vendor:delete', 3, 4, 5150, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:01:11', '1', '2026-02-15 16:01:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5155, '渚涘簲鍟嗗鍑�', 'mes:md-vendor:export', 3, 5, 5150, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:01:11', '1', '2026-02-15 16:01:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5156, '渚涘簲鍟嗗鍏�', 'mes:md-vendor:import', 3, 6, 5150, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:01:11', '1', '2026-02-15 16:01:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5160, '杞﹂棿璁剧疆', '', 2, 6, 5101, 'workstation/workshop', 'ep:office-building', 'mes/md/workstation/workshop/index', 'MesMdWorkshop', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-16 11:17:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5161, '杞﹂棿鏌ヨ', 'mes:md-workshop:query', 3, 1, 5160, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5162, '杞﹂棿鍒涘缓', 'mes:md-workshop:create', 3, 2, 5160, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5163, '杞﹂棿鏇存柊', 'mes:md-workshop:update', 3, 3, 5160, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5164, '杞﹂棿鍒犻櫎', 'mes:md-workshop:delete', 3, 4, 5160, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5170, '宸ヤ綔绔欒缃�', '', 2, 7, 5101, 'workstation', 'ep:place', 'mes/md/workstation/index', 'MesMdWorkstation', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-16 11:18:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5171, '宸ヤ綅鏌ヨ', 'mes:md-workstation:query', 3, 1, 5170, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5172, '宸ヤ綅鍒涘缓', 'mes:md-workstation:create', 3, 2, 5170, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5173, '宸ヤ綅鏇存柊', 'mes:md-workstation:update', 3, 3, 5170, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5174, '宸ヤ綅鍒犻櫎', 'mes:md-workstation:delete', 3, 4, 5170, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5175, '宸ヤ綅瀵煎嚭', 'mes:md-workstation:export', 3, 5, 5170, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-15 16:47:47', '1', '2026-02-15 16:47:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5190, '缂栫爜瑙勫垯', '', 2, 10, 5101, 'auto-code', 'ep:document', 'mes/md/autocode/index', 'MesAutoCode', 0, '1', '1', '1', '1', '2026-03-04 05:26:04', '1', '2026-04-03 08:31:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5191, '缂栫爜瑙勫垯鏌ヨ', 'mes:auto-code-rule:query', 3, 1, 5190, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-04 05:26:04', '1', '2026-03-04 05:26:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5192, '缂栫爜瑙勫垯鍒涘缓', 'mes:auto-code-rule:create', 3, 2, 5190, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-04 05:26:04', '1', '2026-03-04 05:26:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5193, '缂栫爜瑙勫垯鏇存柊', 'mes:auto-code-rule:update', 3, 3, 5190, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-04 05:26:04', '1', '2026-03-04 05:26:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5194, '缂栫爜瑙勫垯鍒犻櫎', 'mes:auto-code-rule:delete', 3, 4, 5190, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-04 05:26:04', '1', '2026-03-04 05:26:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5195, '缂栫爜瑙勫垯瀵煎嚭', 'mes:auto-code-rule:export', 3, 5, 5190, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-04 05:26:04', '1', '2026-03-04 05:26:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5200, '鎺掔彮绠$悊', '', 1, 70, 5100, 'cal', 'ep:calendar', '', '', 0, '1', '1', '1', '1', '2026-02-16 07:35:50', '1', '2026-02-16 15:37:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5220, '鐝粍璁剧疆', '', 2, 1, 5200, 'team', 'ep:user', 'mes/cal/team/index', 'MesCalTeam', 0, '1', '1', '1', '1', '2026-02-18 01:16:03', '1', '2026-02-18 11:14:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5221, '鐝粍鏌ヨ', 'mes:cal-team:query', 3, 1, 5220, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-18 01:16:03', '1', '2026-02-18 01:16:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5222, '鐝粍鍒涘缓', 'mes:cal-team:create', 3, 2, 5220, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-18 01:16:03', '1', '2026-02-18 01:16:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5223, '鐝粍鏇存柊', 'mes:cal-team:update', 3, 3, 5220, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-18 01:16:03', '1', '2026-02-18 01:16:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5224, '鐝粍鍒犻櫎', 'mes:cal-team:delete', 3, 4, 5220, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-18 01:16:03', '1', '2026-02-18 01:16:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5225, '鐝粍瀵煎嚭', 'mes:cal-team:export', 3, 5, 5220, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-18 01:16:03', '1', '2026-02-18 01:16:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5230, '鎺掔彮璁″垝', '', 2, 3, 5200, 'plan', 'ep:memo', 'mes/cal/plan/index', 'MesCalPlan', 0, '1', '1', '1', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5231, '鎺掔彮璁″垝鏌ヨ', 'mes:cal-plan:query', 3, 1, 5230, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5232, '鎺掔彮璁″垝鍒涘缓', 'mes:cal-plan:create', 3, 2, 5230, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5233, '鎺掔彮璁″垝鏇存柊', 'mes:cal-plan:update', 3, 3, 5230, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5234, '鎺掔彮璁″垝鍒犻櫎', 'mes:cal-plan:delete', 3, 4, 5230, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5235, '鎺掔彮璁″垝瀵煎嚭', 'mes:cal-plan:export', 3, 5, 5230, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5250, '鑺傚亣鏃ヨ缃�', '', 2, 3, 5200, 'holiday', 'ep:sunny', 'mes/cal/holiday/index', 'MesCalHoliday', 0, '1', '1', '1', '1', '2026-02-16 07:35:50', '1', '2026-02-16 15:38:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5251, '鍋囨湡鏌ヨ', 'mes:cal-holiday:query', 3, 1, 5250, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 07:35:50', '1', '2026-02-16 07:35:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5252, '鍋囨湡鍒涘缓', 'mes:cal-holiday:create', 3, 2, 5250, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 07:35:50', '1', '2026-02-16 07:35:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5253, '鍋囨湡鏇存柊', 'mes:cal-holiday:update', 3, 3, 5250, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 07:35:50', '1', '2026-02-16 07:35:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5254, '鍋囨湡鍒犻櫎', 'mes:cal-holiday:delete', 3, 4, 5250, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 07:35:50', '1', '2026-02-16 07:35:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5255, '鍋囨湡瀵煎嚭', 'mes:cal-holiday:export', 3, 5, 5250, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 07:35:50', '1', '2026-02-16 07:35:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5260, '鎺掔彮鏃ュ巻', '', 2, 3, 5200, 'calendar', 'ep:calendar', 'mes/cal/calendar/index', 'MesCalCalendar', 0, '1', '1', '1', '1', '2026-02-19 04:19:33', '1', '2026-02-19 04:19:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5261, '鎺掔彮鏃ュ巻鏌ヨ', 'mes:cal-team-shift:query', 3, 1, 5260, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 04:19:33', '1', '2026-02-19 04:19:33', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5300, '璁惧绠$悊', '', 1, 30, 5100, 'dv', 'ep:cpu', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 09:01:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5310, '璁惧绫诲瀷', '', 2, 1, 5300, 'machinery/type', 'ep:files', 'mes/dv/machinery/type/index', 'MesDvMachineryType', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 09:02:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5311, '绫诲瀷鏌ヨ', 'mes:dv-machinery-type:query', 3, 1, 5310, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5312, '绫诲瀷鍒涘缓', 'mes:dv-machinery-type:create', 3, 2, 5310, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5313, '绫诲瀷鏇存柊', 'mes:dv-machinery-type:update', 3, 3, 5310, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5314, '绫诲瀷鍒犻櫎', 'mes:dv-machinery-type:delete', 3, 4, 5310, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5315, '绫诲瀷瀵煎嚭', 'mes:dv-machinery-type:export', 3, 5, 5310, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5320, '璁惧鍙拌处', '', 2, 2, 5300, 'machinery', 'ep:monitor', 'mes/dv/machinery/index', 'MesDvMachinery', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5321, '璁惧鏌ヨ', 'mes:dv-machinery:query', 3, 1, 5320, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5322, '璁惧鍒涘缓', 'mes:dv-machinery:create', 3, 2, 5320, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5323, '璁惧鏇存柊', 'mes:dv-machinery:update', 3, 3, 5320, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5324, '璁惧鍒犻櫎', 'mes:dv-machinery:delete', 3, 4, 5320, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5325, '璁惧瀵煎嚭', 'mes:dv-machinery:export', 3, 5, 5320, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 00:59:58', '1', '2026-02-17 00:59:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5326, '璁惧瀵煎叆', 'mes:dv-machinery:import', 3, 6, 5320, '', '', '', '', 0, '1', '1', '1', '1', '2026-04-02 15:40:42', '1', '2026-04-02 15:40:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5330, '鐐规淇濆吇椤圭洰', '', 2, 3, 5300, 'subject', 'ep:document-checked', 'mes/dv/subject/index', 'MesDvSubject', 0, '1', '1', '1', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5331, '椤圭洰鏌ヨ', 'mes:dv-subject:query', 3, 1, 5330, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5332, '椤圭洰鍒涘缓', 'mes:dv-subject:create', 3, 2, 5330, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5333, '椤圭洰鏇存柊', 'mes:dv-subject:update', 3, 3, 5330, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5334, '椤圭洰鍒犻櫎', 'mes:dv-subject:delete', 3, 4, 5330, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5335, '椤圭洰瀵煎嚭', 'mes:dv-subject:export', 3, 5, 5330, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5340, '淇濆吇璁板綍', '', 2, 6, 5300, 'mainten-record', 'ep:setting', 'mes/dv/maintenrecord/index', 'MesDvMaintenRecord', 0, '1', '1', '1', '', '2026-02-20 02:59:55', '1', '2026-03-02 11:45:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5341, '淇濆吇璁板綍鏌ヨ', 'mes:dv-mainten-record:query', 3, 1, 5340, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 02:59:55', '', '2026-02-20 02:59:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5342, '淇濆吇璁板綍鍒涘缓', 'mes:dv-mainten-record:create', 3, 2, 5340, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 02:59:55', '', '2026-02-20 02:59:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5343, '淇濆吇璁板綍鏇存柊', 'mes:dv-mainten-record:update', 3, 3, 5340, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 02:59:55', '', '2026-02-20 02:59:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5344, '淇濆吇璁板綍鍒犻櫎', 'mes:dv-mainten-record:delete', 3, 4, 5340, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 02:59:55', '', '2026-02-20 02:59:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5345, '淇濆吇璁板綍瀵煎嚭', 'mes:dv-mainten-record:export', 3, 5, 5340, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 02:59:55', '', '2026-02-20 02:59:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5350, '鐐规淇濆吇鏂规', '', 2, 4, 5300, 'checkplan', 'ep:calendar', 'mes/dv/checkplan/index', 'MesDvCheckPlan', 0, '1', '1', '1', '1', '2026-02-20 07:13:08', '1', '2026-02-20 07:13:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5351, '鏂规鏌ヨ', 'mes:dv-check-plan:query', 3, 1, 5350, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 07:13:08', '1', '2026-02-20 07:13:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5352, '鏂规鍒涘缓', 'mes:dv-check-plan:create', 3, 2, 5350, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 07:13:08', '1', '2026-02-20 07:13:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5353, '鏂规鏇存柊', 'mes:dv-check-plan:update', 3, 3, 5350, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 07:13:08', '1', '2026-02-20 07:13:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5354, '鏂规鍒犻櫎', 'mes:dv-check-plan:delete', 3, 4, 5350, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 07:13:08', '1', '2026-02-20 07:13:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5355, '鏂规瀵煎嚭', 'mes:dv-check-plan:export', 3, 5, 5350, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 07:13:08', '1', '2026-02-20 07:13:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5360, '鐐规璁板綍', '', 2, 5, 5300, 'check-record', 'ep:document-checked', 'mes/dv/checkrecord/index', 'MesDvCheckRecord', 0, '1', '1', '1', '', '2026-02-20 09:46:19', '', '2026-03-02 11:45:39', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5361, '鐐规璁板綍鏌ヨ', 'mes:dv-check-record:query', 3, 1, 5360, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 09:46:19', '', '2026-02-20 09:46:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5362, '鐐规璁板綍鍒涘缓', 'mes:dv-check-record:create', 3, 2, 5360, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 09:46:19', '', '2026-02-20 09:46:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5363, '鐐规璁板綍鏇存柊', 'mes:dv-check-record:update', 3, 3, 5360, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 09:46:19', '', '2026-02-20 09:46:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5364, '鐐规璁板綍鍒犻櫎', 'mes:dv-check-record:delete', 3, 4, 5360, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 09:46:19', '', '2026-02-20 09:46:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5365, '鐐规璁板綍瀵煎嚭', 'mes:dv-check-record:export', 3, 5, 5360, '', '', '', '', 0, '1', '1', '1', '', '2026-02-20 09:46:19', '', '2026-02-20 09:46:19', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5366, '宸ュ崟瀵煎嚭', 'mes:dv-repair:export', 3, 5, 5360, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:07:06', '1', '2026-02-20 11:07:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5370, '缁翠慨鍗�', '', 2, 7, 5300, 'repair', 'ep:tools', 'mes/dv/repair/index', 'MesDvRepair', 0, '1', '1', '1', '1', '2026-02-20 11:06:28', '1', '2026-02-20 19:10:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5371, '宸ュ崟鏌ヨ', 'mes:dv-repair:query', 3, 1, 5370, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:06:28', '1', '2026-02-20 11:06:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5372, '宸ュ崟鍒涘缓', 'mes:dv-repair:create', 3, 2, 5370, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:06:28', '1', '2026-02-20 11:06:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5373, '宸ュ崟鏇存柊', 'mes:dv-repair:update', 3, 3, 5370, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:54:20', '1', '2026-02-20 11:54:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5374, '宸ュ崟鍒犻櫎', 'mes:dv-repair:delete', 3, 4, 5370, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:54:15', '1', '2026-02-20 11:54:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5375, '宸ュ崟瀵煎嚭', 'mes:dv-repair:export', 3, 5, 5370, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:54:04', '1', '2026-02-20 11:54:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5400, '宸ュ叿绠$悊', '', 1, 40, 5100, 'tm', 'ep:scissor', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-03-21 14:20:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5410, '宸ュ叿绫诲瀷璁剧疆', '', 2, 1, 5400, 'tool/type', 'ep:files', 'mes/tm/tool/type/index', 'MesTmToolType', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 21:28:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5411, '绫诲瀷鏌ヨ', 'mes:tm-tool-type:query', 3, 1, 5410, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5412, '绫诲瀷鍒涘缓', 'mes:tm-tool-type:create', 3, 2, 5410, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5413, '绫诲瀷鏇存柊', 'mes:tm-tool-type:update', 3, 3, 5410, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5414, '绫诲瀷鍒犻櫎', 'mes:tm-tool-type:delete', 3, 4, 5410, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5415, '绫诲瀷瀵煎嚭', 'mes:tm-tool-type:export', 3, 5, 5410, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5420, '宸ヨ澶瑰叿鍙拌处', '', 2, 2, 5400, 'tool', 'ep:box', 'mes/tm/tool/index', 'MesTmTool', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 21:29:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5421, '宸ュ叿鏌ヨ', 'mes:tm-tool:query', 3, 1, 5420, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5422, '宸ュ叿鍒涘缓', 'mes:tm-tool:create', 3, 2, 5420, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5423, '宸ュ叿鏇存柊', 'mes:tm-tool:update', 3, 3, 5420, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5424, '宸ュ叿鍒犻櫎', 'mes:tm-tool:delete', 3, 4, 5420, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5425, '宸ュ叿瀵煎嚭', 'mes:tm-tool:export', 3, 5, 5420, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5500, '璐ㄩ噺绠$悊', '', 1, 60, 5100, 'qc', 'ep:check', '', '', 0, '1', '1', '1', '1', '2026-02-17 02:18:18', '1', '2026-02-17 14:36:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5510, '甯歌缂洪櫡', '', 2, 1, 5500, 'defect', 'ep:warning', 'mes/qc/defect/index', 'MesQcDefect', 0, '1', '1', '1', '1', '2026-02-17 02:18:18', '1', '2026-03-04 04:29:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5511, '缂洪櫡绫诲瀷鏌ヨ', 'mes:qc-defect:query', 3, 1, 5510, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 02:18:18', '1', '2026-02-17 02:18:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5512, '缂洪櫡绫诲瀷鍒涘缓', 'mes:qc-defect:create', 3, 2, 5510, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 02:18:18', '1', '2026-02-17 02:18:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5513, '缂洪櫡绫诲瀷鏇存柊', 'mes:qc-defect:update', 3, 3, 5510, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 02:18:18', '1', '2026-02-17 02:18:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5514, '缂洪櫡绫诲瀷鍒犻櫎', 'mes:qc-defect:delete', 3, 4, 5510, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 02:18:18', '1', '2026-02-17 02:18:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5515, '缂洪櫡绫诲瀷瀵煎嚭', 'mes:qc-defect:export', 3, 5, 5510, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 02:18:18', '1', '2026-02-17 02:18:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5530, '鐢熶骇宸ュ崟', '', 2, 1, 5700, 'work-order', 'ep:document-copy', 'mes/pro/workorder/index', 'MesProWorkOrder', 0, '1', '1', '1', '1', '2026-02-17 11:51:44', '1', '2026-02-17 19:54:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5531, '宸ュ崟鏌ヨ', 'mes:pro-work-order:query', 3, 1, 5530, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:51:44', '1', '2026-02-17 11:51:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5532, '宸ュ崟鍒涘缓', 'mes:pro-work-order:create', 3, 2, 5530, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:51:44', '1', '2026-02-17 11:51:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5533, '宸ュ崟鏇存柊', 'mes:pro-work-order:update', 3, 3, 5530, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:51:44', '1', '2026-02-17 11:51:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5534, '宸ュ崟鍒犻櫎', 'mes:pro-work-order:delete', 3, 4, 5530, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:51:44', '1', '2026-02-17 11:51:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5535, '宸ュ崟瀵煎嚭', 'mes:pro-work-order:export', 3, 5, 5530, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:51:44', '1', '2026-02-17 11:51:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5540, '鐢熶骇鎺掍骇', '', 2, 4, 5700, 'task', 'ep:calendar', 'mes/pro/task/index', 'MesProTask', 0, '1', '1', '1', '1', '2026-02-19 15:25:27', '1', '2026-02-20 08:30:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5541, '鎺掍骇鏌ヨ', 'mes:pro-task:query', 3, 1, 5540, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 15:25:27', '1', '2026-02-19 15:25:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5542, '鎺掍骇鍒涘缓', 'mes:pro-task:create', 3, 2, 5540, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 15:25:27', '1', '2026-02-19 15:25:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5543, '鎺掍骇鏇存柊', 'mes:pro-task:update', 3, 3, 5540, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 15:25:27', '1', '2026-02-19 15:25:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5544, '鎺掍骇鍒犻櫎', 'mes:pro-task:delete', 3, 4, 5540, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 15:25:27', '1', '2026-02-19 15:25:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5545, '鎺掍骇瀵煎嚭', 'mes:pro-task:export', 3, 5, 5540, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 15:25:27', '1', '2026-02-19 15:25:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5550, '鐢熶骇鎶ュ伐', '', 2, 5, 5700, 'feedback', 'ep:finished', 'mes/pro/feedback/index', 'MesProFeedback', 0, '1', '1', '1', '1', '2026-02-21 00:50:22', '1', '2026-02-21 08:55:14', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5551, '鎶ュ伐鏌ヨ', 'mes:pro-feedback:query', 3, 1, 5550, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:50:22', '1', '2026-02-21 00:50:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5552, '鎶ュ伐鍒涘缓', 'mes:pro-feedback:create', 3, 2, 5550, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:50:22', '1', '2026-02-21 00:50:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5553, '鎶ュ伐鏇存柊', 'mes:pro-feedback:update', 3, 3, 5550, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:50:22', '1', '2026-02-21 00:50:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5554, '鎶ュ伐鍒犻櫎', 'mes:pro-feedback:delete', 3, 4, 5550, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:50:22', '1', '2026-02-21 00:50:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5555, '鎶ュ伐瀵煎嚭', 'mes:pro-feedback:export', 3, 5, 5550, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:50:22', '1', '2026-02-21 00:50:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5560, '宸ュ簭娴佽浆', '', 2, 6, 5700, 'card', 'ep:postcard', 'mes/pro/card/index', 'MesProCard', 0, '1', '1', '1', '1', '2026-02-21 03:16:35', '1', '2026-02-21 11:18:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5561, '娴佽浆鍗℃煡璇�', 'mes:pro-card:query', 3, 1, 5560, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 03:16:35', '1', '2026-02-21 03:16:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5562, '娴佽浆鍗″垱寤�', 'mes:pro-card:create', 3, 2, 5560, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 03:16:35', '1', '2026-02-21 03:16:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5563, '娴佽浆鍗℃洿鏂�', 'mes:pro-card:update', 3, 3, 5560, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 03:16:35', '1', '2026-02-21 03:16:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5564, '娴佽浆鍗″垹闄�', 'mes:pro-card:delete', 3, 4, 5560, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 03:16:35', '1', '2026-02-21 03:16:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5565, '娴佽浆鍗″鍑�', 'mes:pro-card:export', 3, 5, 5560, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 03:16:35', '1', '2026-02-21 03:16:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5566, '娴佽浆鍗″畬鎴�', 'mes:pro-card:finish', 3, 6, 5560, '', '', '', '', 0, '1', '1', '1', '1', '2026-04-04 12:18:15', '1', '2026-04-04 12:18:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5610, '妫�娴嬮」璁剧疆', '', 2, 2, 5500, 'indicator', 'ep:data-analysis', 'mes/qc/indicator/index', 'MesQcIndicator', 0, '1', '1', '1', '1', '2026-02-17 08:11:31', '1', '2026-02-17 16:16:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5611, '璐ㄦ鎸囨爣鏌ヨ', 'mes:qc-indicator:query', 3, 1, 5610, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:11:31', '1', '2026-02-17 08:11:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5612, '璐ㄦ鎸囨爣鍒涘缓', 'mes:qc-indicator:create', 3, 2, 5610, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:11:31', '1', '2026-02-17 08:11:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5613, '璐ㄦ鎸囨爣鏇存柊', 'mes:qc-indicator:update', 3, 3, 5610, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:11:31', '1', '2026-02-17 08:11:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5614, '璐ㄦ鎸囨爣鍒犻櫎', 'mes:qc-indicator:delete', 3, 4, 5610, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:11:31', '1', '2026-02-17 08:11:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5615, '璐ㄦ鎸囨爣瀵煎嚭', 'mes:qc-indicator:export', 3, 5, 5610, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:11:31', '1', '2026-02-17 08:11:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5630, '璐ㄦ鏂规', '', 2, 3, 5500, 'template', 'ep:document-copy', 'mes/qc/template/index', 'MesQcTemplate', 0, '1', '1', '1', '1', '2026-02-17 08:34:40', '1', '2026-03-04 04:29:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5631, '璐ㄦ鏂规鏌ヨ', 'mes:qc-template:query', 3, 1, 5630, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:34:40', '1', '2026-02-18 14:12:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5632, '璐ㄦ鏂规鍒涘缓', 'mes:qc-template:create', 3, 2, 5630, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:34:40', '1', '2026-02-18 14:12:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5633, '璐ㄦ鏂规鏇存柊', 'mes:qc-template:update', 3, 3, 5630, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:34:40', '1', '2026-02-18 14:12:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5634, '璐ㄦ鏂规鍒犻櫎', 'mes:qc-template:delete', 3, 4, 5630, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:34:40', '1', '2026-02-18 14:12:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5635, '璐ㄦ鏂规瀵煎嚭', 'mes:qc-template:export', 3, 5, 5630, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 08:34:40', '1', '2026-02-18 14:12:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5640, '鏉ユ枡妫�楠�', '', 2, 5, 5500, 'iqc', 'ep:finished', 'mes/qc/iqc/index', 'MesQcIqc', 0, '1', '1', '1', '1', '2026-02-20 11:23:45', '1', '2026-02-24 05:24:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5641, '鏉ユ枡妫�楠屾煡璇�', 'mes:qc-iqc:query', 3, 1, 5640, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:23:45', '1', '2026-02-20 11:23:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5642, '鏉ユ枡妫�楠屽垱寤�', 'mes:qc-iqc:create', 3, 2, 5640, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:23:45', '1', '2026-02-20 11:23:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5643, '鏉ユ枡妫�楠屾洿鏂�', 'mes:qc-iqc:update', 3, 3, 5640, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:23:45', '1', '2026-02-20 11:23:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5644, '鏉ユ枡妫�楠屽垹闄�', 'mes:qc-iqc:delete', 3, 4, 5640, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:23:45', '1', '2026-02-20 11:23:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5645, '鏉ユ枡妫�楠屽鍑�', 'mes:qc-iqc:export', 3, 5, 5640, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 11:23:45', '1', '2026-02-20 11:23:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5650, '杩囩▼妫�楠�', '', 2, 6, 5500, 'ipqc', 'ep:checked', 'mes/qc/ipqc/index', 'MesQcIpqc', 0, '1', '1', '1', '1', '2026-02-22 07:01:08', '1', '2026-02-22 15:02:42', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5651, '杩囩▼妫�楠屾煡璇�', 'mes:qc-ipqc:query', 3, 1, 5650, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 07:01:08', '1', '2026-02-22 07:01:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5652, '杩囩▼妫�楠屽垱寤�', 'mes:qc-ipqc:create', 3, 2, 5650, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 07:01:08', '1', '2026-02-22 07:01:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5653, '杩囩▼妫�楠屾洿鏂�', 'mes:qc-ipqc:update', 3, 3, 5650, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 07:01:08', '1', '2026-02-22 07:01:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5654, '杩囩▼妫�楠屽垹闄�', 'mes:qc-ipqc:delete', 3, 4, 5650, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 07:01:08', '1', '2026-02-22 07:01:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5655, '杩囩▼妫�楠屽鍑�', 'mes:qc-ipqc:export', 3, 5, 5650, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 07:01:08', '1', '2026-02-22 07:01:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5660, '鍑鸿揣妫�楠�', '', 2, 8, 5500, 'oqc', 'ep:sell', 'mes/qc/oqc/index', 'MesQcOqc', 0, '1', '1', '1', '1', '2026-02-22 06:55:53', '1', '2026-02-22 14:58:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5661, '鍑鸿揣妫�楠屾煡璇�', 'mes:qc-oqc:query', 3, 1, 5660, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:55:53', '1', '2026-02-22 06:55:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5662, '鍑鸿揣妫�楠屽垱寤�', 'mes:qc-oqc:create', 3, 2, 5660, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:55:53', '1', '2026-02-22 06:55:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5663, '鍑鸿揣妫�楠屾洿鏂�', 'mes:qc-oqc:update', 3, 3, 5660, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:55:53', '1', '2026-02-22 06:55:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5664, '鍑鸿揣妫�楠屽垹闄�', 'mes:qc-oqc:delete', 3, 4, 5660, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:55:53', '1', '2026-02-22 06:55:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5665, '鍑鸿揣妫�楠屽鍑�', 'mes:qc-oqc:export', 3, 5, 5660, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:55:53', '1', '2026-02-22 06:55:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5670, '閫�鏂欐楠�', '', 2, 7, 5500, 'rqc', 'ep:warning-filled', 'mes/qc/rqc/index', 'MesQcRqc', 0, '1', '1', '1', '1', '2026-02-22 06:43:25', '1', '2026-02-22 14:46:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5671, '閫�璐ф楠屾煡璇�', 'mes:qc-rqc:query', 3, 1, 5670, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:43:25', '1', '2026-02-22 06:43:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5672, '閫�璐ф楠屽垱寤�', 'mes:qc-rqc:create', 3, 2, 5670, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:43:25', '1', '2026-02-22 06:43:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5673, '閫�璐ф楠屾洿鏂�', 'mes:qc-rqc:update', 3, 3, 5670, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:43:25', '1', '2026-02-22 06:43:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5674, '閫�璐ф楠屽垹闄�', 'mes:qc-rqc:delete', 3, 4, 5670, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:43:25', '1', '2026-02-22 06:43:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5675, '閫�璐ф楠屽鍑�', 'mes:qc-rqc:export', 3, 5, 5670, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 06:43:25', '1', '2026-02-22 06:43:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5680, '寰呮浠诲姟', '', 2, 4, 5500, 'pending-inspect', 'ep:clock', 'mes/qc/pendinginspect/index', 'MesQcPendingInspect', 0, '1', '1', '1', '1', '2026-02-23 07:15:41', '1', '2026-02-24 05:24:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5681, '寰呮浠诲姟鏌ヨ', 'mes:qc-pending-inspect:query', 3, 1, 5680, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-23 07:15:41', '1', '2026-02-23 07:15:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5700, '鐢熶骇绠$悊', '', 1, 50, 5100, 'pro', 'ep:management', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:39:58', '1', '2026-02-17 19:53:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5710, '宸ュ簭璁剧疆', '', 2, 2, 5700, 'process', 'ep:operation', 'mes/pro/process/index', 'MesProProcess', 0, '1', '1', '1', '1', '2026-02-17 11:39:58', '1', '2026-02-19 16:23:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5711, '宸ュ簭鏌ヨ', 'mes:pro-process:query', 3, 1, 5710, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:39:58', '1', '2026-02-17 11:39:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5712, '宸ュ簭鍒涘缓', 'mes:pro-process:create', 3, 2, 5710, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:39:58', '1', '2026-02-17 11:39:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5713, '宸ュ簭鏇存柊', 'mes:pro-process:update', 3, 3, 5710, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:39:58', '1', '2026-02-17 11:39:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5714, '宸ュ簭鍒犻櫎', 'mes:pro-process:delete', 3, 4, 5710, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:39:58', '1', '2026-02-17 11:39:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5715, '宸ュ簭瀵煎嚭', 'mes:pro-process:export', 3, 5, 5710, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 11:39:58', '1', '2026-02-17 11:39:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5720, '宸ヨ壓娴佺▼', '', 2, 3, 5700, 'route', 'ep:guide', 'mes/pro/route/index', 'MesProRoute', 0, '1', '1', '1', '1', '2026-02-19 04:24:53', '1', '2026-02-19 16:24:23', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5721, '宸ヨ壓璺嚎鏌ヨ', 'mes:pro-route:query', 3, 1, 5720, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5722, '宸ヨ壓璺嚎鍒涘缓', 'mes:pro-route:create', 3, 2, 5720, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5723, '宸ヨ壓璺嚎鏇存柊', 'mes:pro-route:update', 3, 3, 5720, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5724, '宸ヨ壓璺嚎鍒犻櫎', 'mes:pro-route:delete', 3, 4, 5720, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5725, '宸ヨ壓璺嚎瀵煎嚭', 'mes:pro-route:export', 3, 5, 5720, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5750, '瀹夌伅鍛煎彨', '', 2, 7, 5700, 'andon', 'ep:bell', 'mes/pro/andon/record/index', 'MesProAndonRecord', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 11:35:45', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5751, '瀹夌伅璁板綍鏌ヨ', 'mes:pro-andon-record:query', 3, 1, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5752, '瀹夌伅璁板綍鍒涘缓', 'mes:pro-andon-record:create', 3, 2, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5753, '瀹夌伅璁板綍鏇存柊', 'mes:pro-andon-record:update', 3, 3, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5754, '瀹夌伅璁板綍鍒犻櫎', 'mes:pro-andon-record:delete', 3, 4, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5755, '瀹夌伅璁板綍瀵煎嚭', 'mes:pro-andon-record:export', 3, 5, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5756, '瀹夌伅閰嶇疆鏌ヨ', 'mes:pro-andon-config:query', 3, 6, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5757, '瀹夌伅閰嶇疆鍒涘缓', 'mes:pro-andon-config:create', 3, 7, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5758, '瀹夌伅閰嶇疆鏇存柊', 'mes:pro-andon-config:update', 3, 8, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5759, '瀹夌伅閰嶇疆鍒犻櫎', 'mes:pro-andon-config:delete', 3, 9, 5750, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-21 00:24:18', '1', '2026-02-21 00:24:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5780, '浠撳簱绠$悊', '', 1, 20, 5100, 'wm', 'ep:box', '', '', 0, '1', '1', '1', '1', '2026-02-17 15:37:58', '1', '2026-02-17 23:38:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5781, '浠撳簱璁剧疆', '', 2, 1, 5780, 'warehouse', 'ep:office-building', 'mes/wm/warehouse/index', 'MesWmWarehouse', 0, '1', '1', '1', '1', '2026-02-17 15:37:58', '1', '2026-02-17 15:37:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5782, '浠撳簱鏌ヨ', 'mes:wm-warehouse:query', 3, 1, 5781, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 15:37:58', '1', '2026-02-17 15:37:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5783, '浠撳簱鍒涘缓', 'mes:wm-warehouse:create', 3, 2, 5781, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 15:37:58', '1', '2026-02-17 15:37:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5784, '浠撳簱鏇存柊', 'mes:wm-warehouse:update', 3, 3, 5781, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 15:37:58', '1', '2026-02-17 15:37:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5785, '浠撳簱鍒犻櫎', 'mes:wm-warehouse:delete', 3, 4, 5781, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-17 15:37:58', '1', '2026-02-17 15:37:58', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5786, '搴撳瓨鐜版湁閲�', '', 2, 2, 5780, 'material-stock', 'ep:document', 'mes/wm/materialstock/index', 'MesWmMaterialStock', 0, '1', '1', '1', '1', '2026-02-20 01:02:36', '1', '2026-02-20 09:03:40', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5787, '搴撳瓨鍙拌处鏌ヨ', 'mes:wm-material-stock:query', 3, 1, 5786, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:02:36', '1', '2026-02-20 01:02:36', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5788, '搴撳瓨鍙拌处鍒涘缓', 'mes:wm-material-stock:create', 3, 2, 5786, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:02:37', '1', '2026-02-20 01:02:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5789, '搴撳瓨鍙拌处鏇存柊', 'mes:wm-material-stock:update', 3, 3, 5786, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:02:37', '1', '2026-02-20 01:02:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5790, '搴撳瓨鍙拌处鍒犻櫎', 'mes:wm-material-stock:delete', 3, 4, 5786, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:02:37', '1', '2026-02-20 01:02:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5791, '搴撳瓨鍙拌处瀵煎嚭', 'mes:wm-material-stock:export', 3, 5, 5786, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-20 01:02:37', '1', '2026-02-20 01:02:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5792, '鍒拌揣閫氱煡', '', 2, 4, 5780, 'arrival-notice', 'ep:document-checked', 'mes/wm/arrivalnotice/index', 'MesWmArrivalNotice', 0, '1', '1', '1', '1', '2026-02-22 09:11:05', '1', '2026-02-22 17:13:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5793, '鍒拌揣閫氱煡鍗曟煡璇�', 'mes:wm-arrival-notice:query', 3, 1, 5792, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 09:11:05', '1', '2026-02-22 09:11:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5794, '鍒拌揣閫氱煡鍗曞垱寤�', 'mes:wm-arrival-notice:create', 3, 2, 5792, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 09:11:05', '1', '2026-02-22 09:11:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5795, '鍒拌揣閫氱煡鍗曟洿鏂�', 'mes:wm-arrival-notice:update', 3, 3, 5792, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 09:11:05', '1', '2026-02-22 09:11:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5796, '鍒拌揣閫氱煡鍗曞垹闄�', 'mes:wm-arrival-notice:delete', 3, 4, 5792, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 09:11:05', '1', '2026-02-22 09:11:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5797, '鍒拌揣閫氱煡鍗曞鍑�', 'mes:wm-arrival-notice:export', 3, 5, 5792, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 09:11:05', '1', '2026-02-22 09:11:05', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5798, '閲囪喘鍏ュ簱', '', 2, 3, 5780, 'item-receipt', 'ep:goods', 'mes/wm/itemreceipt/index', 'MesWmItemReceipt', 0, '1', '1', '1', '1', '2026-02-22 10:23:22', '1', '2026-02-22 18:35:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5799, '閲囪喘鍏ュ簱鍗曟煡璇�', 'mes:wm-item-receipt:query', 3, 1, 5798, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 10:23:22', '1', '2026-02-22 10:23:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5800, '閲囪喘鍏ュ簱鍗曞垱寤�', 'mes:wm-item-receipt:create', 3, 2, 5798, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 10:23:22', '1', '2026-02-22 10:23:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5801, '閲囪喘鍏ュ簱鍗曟洿鏂�', 'mes:wm-item-receipt:update', 3, 3, 5798, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 10:23:22', '1', '2026-02-22 10:23:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5802, '閲囪喘鍏ュ簱鍗曞垹闄�', 'mes:wm-item-receipt:delete', 3, 4, 5798, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 10:23:22', '1', '2026-02-22 10:23:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5803, '閲囪喘鍏ュ簱鍗曞鍑�', 'mes:wm-item-receipt:export', 3, 5, 5798, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 10:23:22', '1', '2026-02-22 10:23:22', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5804, '閲囪喘鍏ュ簱鍗曞畬鎴�', 'mes:wm-item-receipt:finish', 3, 6, 5798, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-22 10:23:22', '1', '2026-03-02 11:24:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5805, '鐢熶骇棰嗘枡', '', 2, 6, 5780, 'product-issue', 'ep:sell', 'mes/wm/productissue/index', 'MesWmProductIssue', 0, '1', '1', '1', '1', '2026-02-26 15:53:24', '1', '2026-03-23 12:21:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5806, '棰嗘枡鍑哄簱鍗曟煡璇�', 'mes:wm-product-issue:query', 3, 1, 5805, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-26 15:53:24', '1', '2026-03-23 12:21:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5807, '棰嗘枡鍑哄簱鍗曟柊澧�', 'mes:wm-product-issue:create', 3, 2, 5805, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-26 15:53:24', '1', '2026-03-23 12:21:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5808, '棰嗘枡鍑哄簱鍗曚慨鏀�', 'mes:wm-product-issue:update', 3, 3, 5805, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-26 15:53:24', '1', '2026-03-23 12:21:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5809, '棰嗘枡鍑哄簱鍗曞垹闄�', 'mes:wm-product-issue:delete', 3, 4, 5805, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-26 15:53:24', '1', '2026-03-23 12:21:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5810, '棰嗘枡鍑哄簱鍗曞鍑�', 'mes:wm-product-issue:export', 3, 5, 5805, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-26 15:53:24', '1', '2026-03-23 12:21:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5811, '棰嗘枡鍑哄簱鍗曞畬鎴�', 'mes:wm-product-issue:finish', 3, 6, 5805, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-26 15:53:24', '1', '2026-03-30 03:06:32', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5819, '浜у搧鍏ュ簱', '', 2, 8, 5780, 'product-receipt', 'ep:box', 'mes/wm/productreceipt/index', 'MesWmProductReceipt', 0, '1', '1', '1', '1', '2026-03-01 04:03:25', '1', '2026-03-04 04:29:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5820, '浜у搧鍏ュ簱鍗曟煡璇�', 'mes:wm-product-receipt:query', 3, 1, 5819, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 04:03:25', '1', '2026-03-01 06:03:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5821, '浜у搧鍏ュ簱鍗曟柊澧�', 'mes:wm-product-receipt:create', 3, 2, 5819, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 04:03:25', '1', '2026-03-01 06:03:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5822, '浜у搧鍏ュ簱鍗曚慨鏀�', 'mes:wm-product-receipt:update', 3, 3, 5819, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 04:03:25', '1', '2026-03-01 06:03:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5823, '浜у搧鍏ュ簱鍗曞垹闄�', 'mes:wm-product-receipt:delete', 3, 4, 5819, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 04:03:25', '1', '2026-03-01 06:03:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5824, '浜у搧鍏ュ簱鍗曞鍑�', 'mes:wm-product-receipt:export', 3, 5, 5819, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 04:03:25', '1', '2026-03-01 06:03:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5825, '浜у搧鍏ュ簱鍗曞畬鎴�', 'mes:wm-product-receipt:finish', 3, 6, 5819, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 04:03:25', '1', '2026-03-02 11:24:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5830, '閲囪喘閫�璐�', '', 2, 5, 5780, 'return-vendor', 'ep:box', 'mes/wm/returnvendor/index', 'MesWmReturnVendor', 0, '1', '1', '1', '1', '2026-02-28 09:47:48', '1', '2026-03-29 20:22:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5831, '渚涘簲鍟嗛��璐у崟鏌ヨ', 'mes:wm-return-vendor:query', 3, 1, 5830, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 09:47:48', '1', '2026-02-28 09:47:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5832, '渚涘簲鍟嗛��璐у崟鏂板', 'mes:wm-return-vendor:create', 3, 2, 5830, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 09:47:48', '1', '2026-02-28 09:47:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5833, '渚涘簲鍟嗛��璐у崟淇敼', 'mes:wm-return-vendor:update', 3, 3, 5830, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 09:47:48', '1', '2026-02-28 09:47:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5834, '渚涘簲鍟嗛��璐у崟鍒犻櫎', 'mes:wm-return-vendor:delete', 3, 4, 5830, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 09:47:48', '1', '2026-02-28 09:47:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5835, '渚涘簲鍟嗛��璐у崟瀵煎嚭', 'mes:wm-return-vendor:export', 3, 5, 5830, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 09:47:48', '1', '2026-02-28 09:47:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5836, '渚涘簲鍟嗛��璐у崟鐘舵�佸彉鏇�', 'mes:wm-return-vendor:update-status', 3, 6, 5830, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 09:47:48', '1', '2026-02-28 09:47:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5840, '鐢熶骇閫�鏂�', '', 2, 7, 5780, 'return-issue', 'ep:refresh-left', 'mes/wm/returnissue/index', 'MesWmReturnIssue', 0, '1', '1', '1', '1', '2026-02-28 14:11:04', '1', '2026-03-04 04:29:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5841, '鐢熶骇閫�鏂欏崟鏌ヨ', 'mes:wm-return-issue:query', 3, 1, 5840, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 14:11:04', '1', '2026-02-28 14:11:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5842, '鐢熶骇閫�鏂欏崟鏂板', 'mes:wm-return-issue:create', 3, 2, 5840, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 14:11:04', '1', '2026-02-28 14:11:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5843, '鐢熶骇閫�鏂欏崟淇敼', 'mes:wm-return-issue:update', 3, 3, 5840, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 14:11:04', '1', '2026-02-28 14:11:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5844, '鐢熶骇閫�鏂欏崟鍒犻櫎', 'mes:wm-return-issue:delete', 3, 4, 5840, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 14:11:04', '1', '2026-02-28 14:11:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5845, '鐢熶骇閫�鏂欏崟瀵煎嚭', 'mes:wm-return-issue:export', 3, 5, 5840, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-02-28 14:11:04', '1', '2026-02-28 14:11:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5846, '鐢熶骇閫�鏂欏崟鎵ц', 'mes:wm-return-issue:finish', 3, 6, 5840, '', '', '', '', 0, '1', '1', '1', '1', '2026-02-28 14:11:04', '1', '2026-03-02 11:24:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5847, '閿�鍞��璐�', '', 2, 11, 5780, 'return-sales', 'ep:refresh-left', 'mes/wm/returnsales/index', 'MesWmReturnSales', 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-04 04:29:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5848, '閿�鍞��璐у崟鏌ヨ', 'mes:wm-return-sales:query', 3, 1, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-01 10:31:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5849, '閿�鍞��璐у崟鏂板', 'mes:wm-return-sales:create', 3, 2, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-01 10:31:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5850, '閿�鍞��璐у崟淇敼', 'mes:wm-return-sales:update', 3, 3, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-01 10:31:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5851, '閿�鍞��璐у崟鍒犻櫎', 'mes:wm-return-sales:delete', 3, 4, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-01 10:31:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5852, '閿�鍞��璐у崟瀵煎嚭', 'mes:wm-return-sales:export', 3, 5, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-01 10:31:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5853, '閿�鍞��璐у崟鎻愪氦', 'mes:wm-return-sales:submit', 3, 6, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-01 10:31:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5854, '閿�鍞��璐у崟瀹屾垚閫�璐�', 'mes:wm-return-sales:finish', 3, 7, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-02 11:24:29', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5855, '閿�鍞��璐у崟鎵ц涓婃灦', 'mes:wm-return-sales:stock', 3, 8, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-01 10:31:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5856, '閿�鍞��璐у崟鍙栨秷', 'mes:wm-return-sales:cancel', 3, 9, 5847, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-01 10:31:35', '1', '2026-03-01 10:31:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5857, '鏉傞」鍑哄簱', '', 2, 20, 5780, 'misc-issue', 'ep:sell', 'mes/wm/miscissue/index', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:33:34', '1', '2026-03-03 09:12:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5858, '鏉傞」鍑哄簱鏌ヨ', 'mes:wm-misc-issue:query', 3, 1, 5857, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:33:34', '1', '2026-03-02 14:33:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5859, '鏉傞」鍑哄簱鏂板', 'mes:wm-misc-issue:create', 3, 2, 5857, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:33:34', '1', '2026-03-02 14:33:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5860, '鏉傞」鍑哄簱淇敼', 'mes:wm-misc-issue:update', 3, 3, 5857, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:33:34', '1', '2026-03-02 14:33:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5861, '鏉傞」鍑哄簱鍒犻櫎', 'mes:wm-misc-issue:delete', 3, 4, 5857, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:33:34', '1', '2026-03-02 14:33:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5862, '鏉傞」鍑哄簱瀵煎嚭', 'mes:wm-misc-issue:export', 3, 5, 5857, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:33:34', '1', '2026-03-02 14:33:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5863, '鏉傞」鍑哄簱鎵ц', 'mes:wm-misc-issue:finish', 3, 6, 5857, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:33:34', '1', '2026-03-02 14:33:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5867, '鍙戣揣閫氱煡', '', 2, 9, 5780, 'sales-notice', 'fa-solid:notes-medical', 'mes/wm/salesnotice/index', 'MesWmSalesNotice', 0, '1', '1', '1', '1', '2026-03-30 08:54:30', '1', '2026-03-30 17:09:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5868, '鏌ヨ鍙戣揣閫氱煡', 'mes:wm-sales-notice:query', 3, 1, 5867, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-30 08:54:30', '1', '2026-03-30 16:57:31', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5869, '鍒涘缓鍙戣揣閫氱煡', 'mes:wm-sales-notice:create', 3, 2, 5867, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-30 08:54:30', '1', '2026-03-30 16:57:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5870, '鏇存柊鍙戣揣閫氱煡', 'mes:wm-sales-notice:update', 3, 3, 5867, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-30 08:54:30', '1', '2026-03-30 16:57:49', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5871, '鍒犻櫎鍙戣揣閫氱煡', 'mes:wm-sales-notice:delete', 3, 4, 5867, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-30 08:54:30', '1', '2026-03-30 16:57:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5872, '瀵煎嚭鍙戣揣閫氱煡', 'mes:wm-sales-notice:export', 3, 5, 5867, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-30 08:54:30', '1', '2026-03-30 16:58:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5873, '澶栧崗鍏ュ簱', '', 2, 18, 5780, 'outsource-receipt', 'fa-solid:truck', 'mes/wm/outsourcereceipt/index', 'MesWmOutsourceReceipt', 0, '1', '1', '1', '1', '2026-03-31 15:36:37', '1', '2026-04-01 00:04:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5874, '澶栧崗鍏ュ簱鍗曟煡璇�', 'mes:wm-outsource-receipt:query', 3, 1, 5873, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-31 15:36:37', '1', '2026-03-31 15:36:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5875, '澶栧崗鍏ュ簱鍗曟柊澧�', 'mes:wm-outsource-receipt:create', 3, 2, 5873, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-31 15:36:37', '1', '2026-03-31 15:36:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5876, '澶栧崗鍏ュ簱鍗曚慨鏀�', 'mes:wm-outsource-receipt:update', 3, 3, 5873, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-31 15:36:37', '1', '2026-03-31 15:36:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5877, '澶栧崗鍏ュ簱鍗曞垹闄�', 'mes:wm-outsource-receipt:delete', 3, 4, 5873, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-31 15:36:37', '1', '2026-03-31 15:36:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5878, '澶栧崗鍏ュ簱鍗曞鍑�', 'mes:wm-outsource-receipt:export', 3, 5, 5873, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-31 15:36:37', '1', '2026-03-31 15:36:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5879, '澶栧崗鍏ュ簱鍗曞畬鎴�', 'mes:wm-outsource-receipt:finish', 3, 6, 5873, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-31 15:36:37', '1', '2026-03-31 15:36:37', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5881, '澶栧崗鍙戞枡', '', 2, 17, 5780, 'outsource-issue', 'ep:sell', 'mes/wm/outsourceissue/index', 'MesWmOutsourceIssue', 0, '1', '1', '1', '1', '2026-03-02 14:36:04', '1', '2026-03-03 19:59:38', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5882, '澶栧崗鍙戞枡鍗曟煡璇�', 'mes:wm-outsource-issue:query', 3, 1, 5881, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:36:04', '1', '2026-03-02 14:36:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5883, '澶栧崗鍙戞枡鍗曟柊澧�', 'mes:wm-outsource-issue:create', 3, 2, 5881, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:36:04', '1', '2026-03-02 14:36:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5884, '澶栧崗鍙戞枡鍗曚慨鏀�', 'mes:wm-outsource-issue:update', 3, 3, 5881, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:36:04', '1', '2026-03-02 14:36:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5885, '澶栧崗鍙戞枡鍗曞垹闄�', 'mes:wm-outsource-issue:delete', 3, 4, 5881, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:36:04', '1', '2026-03-02 14:36:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5886, '澶栧崗鍙戞枡鍗曞鍑�', 'mes:wm-outsource-issue:export', 3, 5, 5881, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:36:04', '1', '2026-03-02 14:36:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5887, '澶栧崗鍙戞枡鍗曟墽琛屽嚭搴�', 'mes:wm-outsource-issue:execute', 3, 6, 5881, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-02 14:36:04', '1', '2026-03-02 14:36:04', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5888, '鏉傞」鍏ュ簱', '', 2, 19, 5780, 'misc-receipt', 'ep:bottom', 'mes/wm/miscreceipt/index', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:46:53', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5889, '鏉傞」鍏ュ簱鏌ヨ', 'mes:wm:misc-receipt:query', 3, 1, 5888, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:17:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5890, '鏉傞」鍏ュ簱鍒涘缓', 'mes:wm:misc-receipt:create', 3, 2, 5888, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:17:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5891, '鏉傞」鍏ュ簱鏇存柊', 'mes:wm:misc-receipt:update', 3, 3, 5888, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:17:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5892, '鏉傞」鍏ュ簱鍒犻櫎', 'mes:wm:misc-receipt:delete', 3, 4, 5888, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:17:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5893, '鏉傞」鍏ュ簱鎻愪氦', 'mes:wm:misc-receipt:submit', 3, 5, 5888, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:17:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5894, '鏉傞」鍏ュ簱鎵ц', 'mes:wm:misc-receipt:finish', 3, 6, 5888, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:17:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5895, '鏉傞」鍏ュ簱鍙栨秷', 'mes:wm:misc-receipt:cancel', 3, 7, 5888, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:17:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5896, '鏉傞」鍏ュ簱瀵煎嚭', 'mes:wm:misc-receipt:export', 3, 8, 5888, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-03 07:17:50', '1', '2026-03-03 07:17:50', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5897, 'SN 鐮�', '', 2, 16, 5780, 'sn', 'ep:document', 'mes/wm/sn/index', 'MesWmSn', 0, '1', '1', '1', '1', '2026-03-05 01:30:21', '1', '2026-03-05 13:37:30', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5898, 'SN 鐮佹煡璇�', 'mes:wm-sn:query', 3, 1, 5897, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-05 01:30:21', '1', '2026-03-05 01:30:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5899, 'SN 鐮佺敓鎴�', 'mes:wm-sn:create', 3, 2, 5897, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-05 01:30:21', '1', '2026-03-05 01:30:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5900, 'SN 鐮佸垹闄�', 'mes:wm-sn:delete', 3, 4, 5897, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-05 01:30:21', '1', '2026-03-05 01:30:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5901, 'SN 鐮佸鍑�', 'mes:wm-sn:export', 3, 5, 5897, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-05 01:30:21', '1', '2026-03-05 01:30:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5906, '鏉$爜閰嶇疆', '', 2, 15, 5780, 'barcode/config', 'fa:barcode', 'mes/wm/barcode/config/index', 'MesWmBarcodeConfig', 0, '0', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 21:05:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5907, '鏉$爜閰嶇疆鏌ヨ', 'mes:wm-barcode-config:query', 3, 1, 5906, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 21:09:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5908, '鏉$爜閰嶇疆鍒涘缓', 'mes:wm-barcode-config:create', 3, 2, 5906, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 21:09:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5909, '鏉$爜閰嶇疆鏇存柊', 'mes:wm-barcode-config:update', 3, 3, 5906, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 21:09:21', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5910, '鏉$爜閰嶇疆鍒犻櫎', 'mes:wm-barcode-config:delete', 3, 4, 5906, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 21:09:26', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5911, '璧嬭兘绠$悊', '', 2, 15, 5780, 'barcode', 'fa:qrcode', 'mes/wm/barcode/index', 'MesWmBarcode', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 10:01:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5912, '鏉$爜娓呭崟鏌ヨ', 'mes:wm-barcode:query', 3, 1, 5911, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 09:58:59', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5913, '鏉$爜娓呭崟鍒涘缓', 'mes:wm-barcode:create', 3, 2, 5911, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 09:59:03', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5914, '鏉$爜娓呭崟鏇存柊', 'mes:wm-barcode:update', 3, 3, 5911, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 09:59:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5915, '鏉$爜娓呭崟鍒犻櫎', 'mes:wm-barcode:delete', 3, 4, 5911, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-05 14:37:20', '1', '2026-03-06 09:59:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5916, '鏉$爜娓呭崟瀵煎嚭', 'mes:wm-barcode:export', 3, 5, 5911, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-07 02:08:17', '1', '2026-03-07 02:08:17', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5917, '瑁呯绠$悊', '', 2, 14, 5780, 'packages', 'ep:box', 'mes/wm/packages/index', 'MesWmPackages', 0, '1', '1', '1', '1', '2026-03-08 02:05:46', '1', '2026-03-08 19:16:27', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5918, '瑁呯绠$悊鏌ヨ', 'mes:wm-package:query', 3, 1, 5917, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-08 02:05:46', '1', '2026-03-08 02:05:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5919, '瑁呯绠$悊鏂板', 'mes:wm-package:create', 3, 2, 5917, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-08 02:05:46', '1', '2026-03-08 02:05:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5920, '瑁呯绠$悊淇敼', 'mes:wm-package:update', 3, 3, 5917, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-08 02:05:46', '1', '2026-03-08 02:05:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5921, '瑁呯绠$悊鍒犻櫎', 'mes:wm-package:delete', 3, 4, 5917, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-08 02:05:46', '1', '2026-03-08 02:05:46', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5922, '杞Щ璋冩嫧', '', 2, 12, 5780, 'transfer', 'ep:sort', 'mes/wm/transfer/index', 'MesWmTransfer', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-22 15:22:57', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5923, '璋冩嫧鍗曟煡璇�', 'mes:wm-transfer:query', 3, 1, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5924, '璋冩嫧鍗曟柊澧�', 'mes:wm-transfer:create', 3, 2, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5925, '璋冩嫧鍗曚慨鏀�', 'mes:wm-transfer:update', 3, 3, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5926, '璋冩嫧鍗曞垹闄�', 'mes:wm-transfer:delete', 3, 4, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5927, '璋冩嫧鍗曞鍑�', 'mes:wm-transfer:export', 3, 5, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5928, '璋冩嫧鍗曟彁浜�', 'mes:wm-transfer:submit', 3, 6, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5929, '璋冩嫧鍗曠‘璁�', 'mes:wm-transfer:confirm', 3, 7, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5930, '璋冩嫧鍗曞畬鎴�', 'mes:wm-transfer:finish', 3, 8, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5931, '璋冩嫧鍗曞彇娑�', 'mes:wm-transfer:cancel', 3, 9, 5922, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5950, '搴撳瓨鐩樼偣', '', 1, 13, 5780, 'stock-taking', 'ep:circle-check-filled', '', '', 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 21:19:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5951, '鐩樼偣鏂规', '', 2, 1, 5950, 'plan', 'ep:document', 'mes/wm/stocktaking/plan/index', 'MesWmStockTakingPlan', 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 13:19:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5952, '鐩樼偣鏂规鏌ヨ', 'mes:wm-stock-taking-plan:query', 3, 1, 5951, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 13:35:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5953, '鐩樼偣鏂规鍒涘缓', 'mes:wm-stock-taking-plan:create', 3, 2, 5951, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 13:35:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5954, '鐩樼偣鏂规鏇存柊', 'mes:wm-stock-taking-plan:update', 3, 3, 5951, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 13:35:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5955, '鐩樼偣鏂规鍒犻櫎', 'mes:wm-stock-taking-plan:delete', 3, 4, 5951, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 13:35:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5956, '鐩樼偣鏂规瀵煎嚭', 'mes:wm-stock-taking-plan:export', 3, 5, 5951, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 13:35:13', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5957, '鐩樼偣浠诲姟', '', 2, 2, 5950, 'task', 'ep:list', 'mes/wm/stocktaking/task/index', 'MesWmStockTakingTask', 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 23:00:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5958, '鐩樼偣浠诲姟鏌ヨ', 'mes:wm-stock-taking-task:query', 3, 1, 5957, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5959, '鐩樼偣浠诲姟鍒涘缓', 'mes:wm-stock-taking-task:create', 3, 2, 5957, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5960, '鐩樼偣浠诲姟鏇存柊', 'mes:wm-stock-taking-task:update', 3, 3, 5957, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5961, '鐩樼偣浠诲姟鍒犻櫎', 'mes:wm-stock-taking-task:delete', 3, 4, 5957, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5962, '鐩樼偣浠诲姟瀵煎嚭', 'mes:wm-stock-taking-task:export', 3, 5, 5957, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5966, '鎵规杩芥函', '', 2, 9, 5500, 'batch-trace', 'ep:aim', 'mes/qc/batchtrace/index', 'BatchTrace', 0, '1', '1', '1', '1', '2026-03-14 06:59:25', '1', '2026-04-05 09:39:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5967, '鎵规杩芥函鏌ヨ', 'mes:wm-batch:query', 3, 1, 5966, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-03-14 06:59:25', '1', '2026-03-14 06:59:25', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5969, '鎶ュ憡瀹℃壒', 'mes:pro-feedback:approve', 3, 6, 5550, '', '', '', '', 0, '1', '1', '1', '1', '2026-03-19 08:51:16', '1', '2026-03-19 08:51:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5970, '閿�鍞嚭搴�', '', 2, 10, 5780, 'product-sales', 'ep:sell', 'mes/wm/productsales/index', 'MesWmProductSales', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5971, '鏌ヨ閿�鍞嚭搴�', 'mes:wm-product-sales:query', 3, 1, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5972, '鍒涘缓閿�鍞嚭搴�', 'mes:wm-product-sales:create', 3, 2, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5973, '鏇存柊閿�鍞嚭搴�', 'mes:wm-product-sales:update', 3, 3, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5974, '鍒犻櫎閿�鍞嚭搴�', 'mes:wm-product-sales:delete', 3, 4, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5975, '瀵煎嚭閿�鍞嚭搴�', 'mes:wm-product-sales:export', 3, 5, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5976, '鎻愪氦閿�鍞嚭搴�', 'mes:wm-product-sales:submit', 3, 6, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5977, '鎵ц鎷h揣', 'mes:wm-product-sales:stock', 3, 7, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5978, '濉啓杩愬崟', 'mes:wm-product-sales:shipping', 3, 8, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5979, '鎵ц鍑哄簱', 'mes:wm-product-sales:finish', 3, 9, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5980, '鍙栨秷閿�鍞嚭搴�', 'mes:wm-product-sales:cancel', 3, 10, 5970, '', '', '', '', 0, '1', '1', '1', '', '2026-03-30 10:37:08', '', '2026-03-30 10:37:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5981, '宸ヤ綔璁板綍', '', 2, 99, 5700, 'workrecord', 'ep:timer', 'mes/pro/workrecord/index', 'MesProWorkRecordLog', 0, '1', '1', '1', '1', '2026-04-05 14:08:44', '1', '2026-04-05 14:08:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5982, '宸ヤ綔璁板綍鏌ヨ', 'mes:pro-workrecord:query', 3, 1, 5981, '', '', '', '', 0, '1', '1', '1', '1', '2026-04-05 14:08:44', '1', '2026-04-05 14:08:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5983, '宸ヤ綔璁板綍瀵煎嚭', 'mes:pro-workrecord:export', 3, 2, 5981, '', '', '', '', 0, '1', '1', '1', '1', '2026-04-05 14:08:44', '1', '2026-04-05 14:08:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5984, '涓婂伐涓嬪伐', 'mes:pro-workrecord:clock', 3, 3, 5981, '', '', '', '', 0, '1', '1', '1', '1', '2026-04-05 14:08:44', '1', '2026-04-05 14:08:44', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (5985, 'MES 棣栭〉', 'mes:home:query', 2, 0, 5100, 'mes/home/index', 'ep:home-filled', 'mes/home/index', 'MesHome', 0, '1', '1', '1', '1', '2026-04-05 23:24:03', '1', '2026-04-06 01:20:52', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6400, 'WMS 绯荤粺', '', 1, 310, 0, '/wms', 'ep:box', '', '', 0, '1', '1', '1', '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6401, '鍩虹鏁版嵁', '', 1, 6, 6400, 'md', 'ep:files', '', '', 0, '1', '1', '1', '1', '2026-05-09 16:11:01', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6402, '浠撳簱绠$悊', '', 2, 1, 6401, 'warehouse', 'ep:office-building', 'wms/md/warehouse/index', 'WmsWarehouse', 0, '1', '1', '1', '1', '2026-05-09 16:11:01', '1', '2026-05-10 00:54:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6403, '浠撳簱鏌ヨ', 'wms:warehouse:query', 3, 1, 6402, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6404, '浠撳簱鍒涘缓', 'wms:warehouse:create', 3, 2, 6402, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6405, '浠撳簱鏇存柊', 'wms:warehouse:update', 3, 3, 6402, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6406, '浠撳簱鍒犻櫎', 'wms:warehouse:delete', 3, 4, 6402, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6411, '鍟嗗搧鍝佺墝', '', 2, 3, 6401, 'item/brand', 'ep:price-tag', 'wms/md/item/brand/index', 'WmsItemBrand', 0, '1', '1', '1', '1', '2026-05-10 01:43:12', '1', '2026-05-10 02:12:51', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6412, '鍝佺墝鏌ヨ', 'wms:item-brand:query', 3, 1, 6411, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-10 01:43:12', '1', '2026-05-10 01:43:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6413, '鍝佺墝鍒涘缓', 'wms:item-brand:create', 3, 2, 6411, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-10 01:43:12', '1', '2026-05-10 01:43:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6414, '鍝佺墝鏇存柊', 'wms:item-brand:update', 3, 3, 6411, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-10 01:43:12', '1', '2026-05-10 01:43:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6415, '鍝佺墝鍒犻櫎', 'wms:item-brand:delete', 3, 4, 6411, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-10 01:43:12', '1', '2026-05-10 01:43:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6416, '鍝佺墝瀵煎嚭', 'wms:item-brand:export', 3, 5, 6411, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-10 01:43:12', '1', '2026-05-10 01:43:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6417, '浠撳簱瀵煎嚭', 'wms:warehouse:export', 3, 5, 6402, '', '', '', '', 0, '1', '1', '1', '1', '2026-05-10 02:42:47', '1', '2026-05-10 02:42:47', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6419, '鍟嗗搧鍒嗙被', '', 2, 2, 6401, 'item/category', 'ep:folder', 'wms/md/item/category/index', 'WmsItemCategory', 0, '1', '1', '1', '1', '2026-05-10 07:14:18', '1', '2026-05-10 07:14:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6420, '鍒嗙被鏌ヨ', 'wms:item-category:query', 3, 1, 6419, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 07:14:18', '1', '2026-05-10 07:14:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6421, '鍒嗙被鍒涘缓', 'wms:item-category:create', 3, 2, 6419, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 07:14:18', '1', '2026-05-10 07:14:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6422, '鍒嗙被鏇存柊', 'wms:item-category:update', 3, 3, 6419, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 07:14:18', '1', '2026-05-10 07:14:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6423, '鍒嗙被鍒犻櫎', 'wms:item-category:delete', 3, 4, 6419, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 07:14:18', '1', '2026-05-10 07:14:18', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6424, '鍟嗗搧绠$悊', '', 2, 4, 6401, 'item', 'ep:goods', 'wms/md/item/index', 'WmsItem', 0, '1', '1', '1', '1', '2026-05-10 09:15:34', '1', '2026-05-10 09:15:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6425, '鍟嗗搧鏌ヨ', 'wms:item:query', 3, 1, 6424, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 09:15:34', '1', '2026-05-10 09:15:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6426, '鍟嗗搧鍒涘缓', 'wms:item:create', 3, 2, 6424, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 09:15:34', '1', '2026-05-10 09:15:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6427, '鍟嗗搧鏇存柊', 'wms:item:update', 3, 3, 6424, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 09:15:34', '1', '2026-05-10 09:15:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6428, '鍟嗗搧鍒犻櫎', 'wms:item:delete', 3, 4, 6424, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 09:15:34', '1', '2026-05-10 09:15:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6429, '鍟嗗搧瀵煎嚭', 'wms:item:export', 3, 5, 6424, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 09:15:34', '1', '2026-05-10 09:15:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6430, '寰�鏉ヤ紒涓�', '', 2, 5, 6401, 'merchant', 'ep:office-building', 'wms/md/merchant/index', 'WmsMerchant', 0, '1', '1', '1', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:48:07', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6431, '寰�鏉ヤ紒涓氭煡璇�', 'wms:merchant:query', 3, 1, 6430, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6432, '寰�鏉ヤ紒涓氬垱寤�', 'wms:merchant:create', 3, 2, 6430, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6433, '寰�鏉ヤ紒涓氭洿鏂�', 'wms:merchant:update', 3, 3, 6430, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6434, '寰�鏉ヤ紒涓氬垹闄�', 'wms:merchant:delete', 3, 4, 6430, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6435, '寰�鏉ヤ紒涓氬鍑�', 'wms:merchant:export', 3, 5, 6430, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6440, '搴撳瓨绠$悊', '', 1, 5, 6400, 'inventory', 'ep:box', '', '', 0, '1', '1', '1', '1', '2026-05-10 17:51:46', '1', '2026-05-13 01:23:11', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6441, '搴撳瓨缁熻', '', 2, 1, 6440, 'index', 'ep:data-board', 'wms/inventory/index/index', 'WmsInventory', 0, '1', '1', '1', '1', '2026-05-10 17:51:46', '1', '2026-05-11 02:08:28', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6442, '搴撳瓨缁熻鏌ヨ', 'wms:inventory:query', 3, 1, 6441, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 17:51:46', '1', '2026-05-11 00:30:41', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6445, '搴撳瓨娴佹按', '', 2, 2, 6440, 'history', 'ep:document', 'wms/inventory/history/index', 'WmsInventoryHistory', 0, '1', '1', '1', '1', '2026-05-10 17:51:46', '1', '2026-05-14 07:59:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6446, '搴撳瓨娴佹按鏌ヨ', 'wms:inventory-history:query', 3, 1, 6445, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-10 17:51:46', '1', '2026-05-11 00:29:15', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6451, '鍏ュ簱绠$悊', '', 2, 1, 6400, 'receipt', 'ep:download', 'wms/order/receipt/index', 'WmsReceiptOrder', 0, '1', '1', '1', '1', '2026-05-11 11:58:58', '1', '2026-05-11 16:58:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6452, '鍏ュ簱鍗曟煡璇�', 'wms:receipt-order:query', 3, 1, 6451, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-11 11:58:58', '1', '2026-05-11 16:58:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6453, '鍏ュ簱鍗曞垱寤�', 'wms:receipt-order:create', 3, 2, 6451, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-11 11:58:58', '1', '2026-05-11 16:58:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6454, '鍏ュ簱鍗曟洿鏂�', 'wms:receipt-order:update', 3, 3, 6451, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-11 11:58:58', '1', '2026-05-11 16:58:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6455, '鍏ュ簱鍗曞垹闄�', 'wms:receipt-order:delete', 3, 4, 6451, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-11 11:58:58', '1', '2026-05-11 16:58:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6456, '鍏ュ簱鍗曞畬鎴愬叆搴�', 'wms:receipt-order:complete', 3, 5, 6451, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-11 11:58:58', '1', '2026-05-11 16:58:02', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6457, '鍏ュ簱鍗曚綔搴�', 'wms:receipt-order:cancel', 3, 6, 6451, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-11 11:58:58', '1', '2026-05-12 16:27:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6458, '鍏ュ簱鍗曞鍑�', 'wms:receipt-order:export', 3, 7, 6451, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-11 16:58:02', '1', '2026-05-12 16:27:16', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6461, '鍑哄簱绠$悊', '', 2, 2, 6400, 'shipment', 'ep:upload', 'wms/order/shipment/index', 'WmsShipmentOrder', 0, '1', '1', '1', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6462, '鍑哄簱鍗曟煡璇�', 'wms:shipment-order:query', 3, 1, 6461, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6463, '鍑哄簱鍗曞垱寤�', 'wms:shipment-order:create', 3, 2, 6461, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6464, '鍑哄簱鍗曟洿鏂�', 'wms:shipment-order:update', 3, 3, 6461, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6465, '鍑哄簱鍗曞垹闄�', 'wms:shipment-order:delete', 3, 4, 6461, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6466, '鍑哄簱鍗曞畬鎴愬嚭搴�', 'wms:shipment-order:complete', 3, 5, 6461, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6467, '鍑哄簱鍗曚綔搴�', 'wms:shipment-order:cancel', 3, 6, 6461, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6468, '鍑哄簱鍗曞鍑�', 'wms:shipment-order:export', 3, 7, 6461, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6470, '绉诲簱绠$悊', '', 2, 3, 6400, 'movement', 'ep:sort', 'wms/order/movement/index', 'WmsMovementOrder', 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6471, '绉诲簱鍗曟煡璇�', 'wms:movement-order:query', 3, 1, 6470, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6472, '绉诲簱鍗曞垱寤�', 'wms:movement-order:create', 3, 2, 6470, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6473, '绉诲簱鍗曟洿鏂�', 'wms:movement-order:update', 3, 3, 6470, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6474, '绉诲簱鍗曞垹闄�', 'wms:movement-order:delete', 3, 4, 6470, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6475, '绉诲簱鍗曞畬鎴愮Щ搴�', 'wms:movement-order:complete', 3, 5, 6470, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6476, '绉诲簱鍗曚綔搴�', 'wms:movement-order:cancel', 3, 6, 6470, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6477, '绉诲簱鍗曞鍑�', 'wms:movement-order:export', 3, 7, 6470, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6480, '鐩樺簱绠$悊', '', 2, 4, 6400, 'check', 'ep:circle-check-filled', 'wms/order/check/index', 'WmsCheckOrder', 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6481, '鐩樺簱鍗曟煡璇�', 'wms:check-order:query', 3, 1, 6480, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6482, '鐩樺簱鍗曞垱寤�', 'wms:check-order:create', 3, 2, 6480, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6483, '鐩樺簱鍗曟洿鏂�', 'wms:check-order:update', 3, 3, 6480, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6484, '鐩樺簱鍗曞垹闄�', 'wms:check-order:delete', 3, 4, 6480, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6485, '鐩樺簱鍗曞畬鎴愮洏搴�', 'wms:check-order:complete', 3, 5, 6480, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6486, '鐩樺簱鍗曚綔搴�', 'wms:check-order:cancel', 3, 6, 6480, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6487, '鐩樺簱鍗曞鍑�', 'wms:check-order:export', 3, 7, 6480, '', '#', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-13 01:23:11', '1', '2026-05-14 02:21:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6490, 'WMS 棣栭〉', 'wms:home:query', 2, 0, 6400, 'home', 'ep:home-filled', 'wms/home/index', 'WmsHome', 0, '1', '1', '1', '1', '2026-05-14 09:34:27', '1', '2026-05-14 10:05:06', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6500, 'IM 鍗虫椂閫氳', '', 1, 501, 0, '/im', 'ep:chat-dot-round', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', '1', '2026-05-09 16:19:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6510, '鏁版嵁缁熻', 'im:manager:statistics:query', 2, 10, 6500, 'statistics', 'ep:trend-charts', 'im/manager/statistics/index', 'ImStatistics', 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', '1', '2026-04-30 19:35:54', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6515, '濂藉弸鐢宠', 'im:manager:friend-request:query', 2, 20, 6600, 'friend-request', 'ep:document', 'im/manager/friend/request/index', 'ImFriendRequest', 0, '1', '1', '1', '1', '2026-05-05 11:15:48', '1', '2026-05-07 00:40:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6520, '濂藉弸鍒楄〃', 'im:manager:friend:list', 2, 10, 6600, 'friend', 'ep:user', 'im/manager/friend/index', 'ImFriend', 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', '1', '2026-05-07 00:40:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6521, '濂藉弸鏌ヨ', 'im:manager:friend:query', 3, 10, 6520, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6530, '濂藉弸娑堟伅', 'im:manager:message:private:list', 2, 30, 6600, 'message', 'ep:chat-dot-square', 'im/manager/message/private/index', 'ImPrivateMessage', 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', '1', '2026-05-07 00:40:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6531, '绉佽亰娑堟伅鏌ヨ', 'im:manager:message:query', 3, 10, 6530, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6540, '缇よ亰鍒楄〃', 'im:manager:group:list', 2, 10, 6610, 'list', 'ep:user-filled', 'im/manager/group/index', 'ImGroup', 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', '1', '2026-05-07 00:40:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6541, '缇ょ粍鏌ヨ', 'im:manager:group:query', 3, 10, 6540, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6542, '缇ょ粍灏佺/瑙e皝', 'im:manager:group:ban', 3, 20, 6540, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6545, '缇よ亰鐢宠', 'im:manager:group-request:query', 2, 20, 6610, 'request', 'ep:document', 'im/manager/group/request/index', 'ImGroupRequest', 0, '1', '1', '1', '1', '2026-05-07 00:31:35', '1', '2026-05-07 00:40:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6550, '缇よ亰娑堟伅', 'im:manager:message:group:list', 2, 30, 6610, 'message', 'ep:chat-line-round', 'im/manager/message/group/index', 'ImGroupMessage', 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', '1', '2026-05-07 00:40:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6551, '缇よ亰娑堟伅鏌ヨ', 'im:manager:message:query', 3, 10, 6550, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6560, '鏁忔劅璇嶇鐞�', 'im:manager:sensitive-word:list', 2, 60, 6500, 'sensitive-word', 'ep:warning', 'im/manager/sensitiveword/index', 'ImSensitiveWord', 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', '1', '2026-04-30 22:25:48', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6561, '鏁忔劅璇嶆煡璇�', 'im:manager:sensitive-word:query', 3, 10, 6560, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6562, '鏁忔劅璇嶆柊澧�', 'im:manager:sensitive-word:create', 3, 20, 6560, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6563, '鏁忔劅璇嶄慨鏀�', 'im:manager:sensitive-word:update', 3, 30, 6560, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6564, '鏁忔劅璇嶅垹闄�', 'im:manager:sensitive-word:delete', 3, 40, 6560, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-04-30 09:11:20', 'admin', '2026-04-30 09:11:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6570, '琛ㄦ儏绠$悊', '', 1, 70, 6500, 'face', 'ep:magic-stick', NULL, NULL, 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6571, '绯荤粺琛ㄦ儏', 'im:manager:face-pack:list', 2, 10, 6570, 'pack', 'ep:picture', 'im/manager/face/pack/index', 'ImManagerFacePack', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6572, '琛ㄦ儏鍖呮煡璇�', 'im:manager:face-pack:query', 3, 10, 6571, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6573, '琛ㄦ儏鍖呭垱寤�', 'im:manager:face-pack:create', 3, 20, 6571, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6574, '琛ㄦ儏鍖呬慨鏀�', 'im:manager:face-pack:update', 3, 30, 6571, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6575, '琛ㄦ儏鍖呭垹闄�', 'im:manager:face-pack:delete', 3, 40, 6571, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6576, '琛ㄦ儏鍥炬煡璇�', 'im:manager:face-pack-item:query', 3, 50, 6571, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6577, '琛ㄦ儏鍥惧垱寤�', 'im:manager:face-pack-item:create', 3, 60, 6571, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6578, '琛ㄦ儏鍥句慨鏀�', 'im:manager:face-pack-item:update', 3, 70, 6571, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6579, '琛ㄦ儏鍥惧垹闄�', 'im:manager:face-pack-item:delete', 3, 80, 6571, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6580, '鐢ㄦ埛琛ㄦ儏', 'im:manager:face-user-item:list', 2, 20, 6570, 'user-item', 'ep:user', 'im/manager/face/userItem/index', 'ImManagerFaceUserItem', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 14:24:20', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6581, '鐢ㄦ埛琛ㄦ儏鏌ヨ', 'im:manager:face-user-item:query', 3, 10, 6580, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6582, '鐢ㄦ埛琛ㄦ儏鍒犻櫎', 'im:manager:face-user-item:delete', 3, 20, 6580, '', '', '', '', 0, '1', '1', '1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6600, '绉佽亰绠$悊', '', 1, 20, 6500, 'private', 'ep:chat-round', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-07 00:40:35', '1', '2026-05-07 00:40:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6610, '缇よ亰绠$悊', '', 1, 30, 6500, 'group', 'ep:chat-line-round', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-07 00:40:35', '1', '2026-05-07 00:40:35', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6611, '閫氳瘽璁板綍', '', 2, 40, 6500, 'rtc', 'ep:phone', 'im/manager/rtc/index', 'ImRtcCall', 0, '1', '1', '1', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6612, '閫氳瘽璁板綍鏌ヨ', 'im:manager:rtc:query', 3, 1, 6611, '', '', NULL, NULL, 0, '1', '1', '1', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6700, '棰戦亾绠$悊', '', 1, 90, 6500, 'channel', 'ep:promotion', NULL, NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6710, '棰戦亾鍒楄〃', '', 2, 1, 6700, 'list', 'ep:promotion', 'im/manager/channel/list/index', 'ImChannel', 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6711, '棰戦亾鏌ヨ', 'im:manager:channel:query', 3, 1, 6710, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6712, '棰戦亾鍒涘缓', 'im:manager:channel:create', 3, 2, 6710, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6713, '棰戦亾淇敼', 'im:manager:channel:update', 3, 3, 6710, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6714, '棰戦亾鍒犻櫎', 'im:manager:channel:delete', 3, 4, 6710, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6720, '棰戦亾绱犳潗', '', 2, 2, 6700, 'material', 'ep:document', 'im/manager/channel/material/index', 'ImChannelMaterial', 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6721, '绱犳潗鏌ヨ', 'im:manager:channel-material:query', 3, 1, 6720, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6722, '绱犳潗鍒涘缓', 'im:manager:channel-material:create', 3, 2, 6720, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6723, '绱犳潗淇敼', 'im:manager:channel-material:update', 3, 3, 6720, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6724, '绱犳潗鍒犻櫎', 'im:manager:channel-material:delete', 3, 4, 6720, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6730, '棰戦亾娑堟伅', '', 2, 3, 6700, 'message', 'ep:message', 'im/manager/channel/message/index', 'ImChannelMessage', 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6731, '娑堟伅鏌ヨ', 'im:manager:channel-message:query', 3, 1, 6730, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6732, '绔嬪嵆鎺ㄩ��', 'im:manager:channel-message:send', 3, 2, 6730, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6733, '娑堟伅鍒犻櫎', 'im:manager:channel-message:delete', 3, 3, 6730, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', '0');
+INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted) VALUES (6734, '瑙f暎缇�', 'im:manager:group:dissolve', 3, 21, 6540, '', '', '', NULL, 0, '1', '1', '1', '1', '2026-05-24 12:02:38', '1', '2026-05-24 12:02:38', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_menu_seq;
+CREATE SEQUENCE system_menu_seq
+ START 6735;
+
+-- ----------------------------
+-- Table structure for system_notice
+-- ----------------------------
+DROP TABLE IF EXISTS system_notice;
+CREATE TABLE system_notice (
+ id int8 NOT NULL,
+ title varchar(50) NOT NULL,
+ content text NOT NULL,
+ type int2 NOT NULL,
+ status int2 NOT NULL DEFAULT 0,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_notice ADD CONSTRAINT pk_system_notice PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_notice.id IS '鍏憡ID';
+COMMENT ON COLUMN system_notice.title IS '鍏憡鏍囬';
+COMMENT ON COLUMN system_notice.content IS '鍏憡鍐呭';
+COMMENT ON COLUMN system_notice.type IS '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�';
+COMMENT ON COLUMN system_notice.status IS '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�';
+COMMENT ON COLUMN system_notice.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_notice.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_notice.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_notice.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_notice.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_notice.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_notice IS '閫氱煡鍏憡琛�';
+
+-- ----------------------------
+-- Records of system_notice
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '鑺嬮亾鐨勫叕浼�', '<p>鏂扮増鏈唴瀹�133222</p>', 1, 0, 'admin', '2021-01-05 17:03:48', '"1"', '2025-08-31 09:38:22', '0', 1);
+INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '缁存姢閫氱煡锛�2018-07-01 绯荤粺鍑屾櫒缁存姢', '<p><img src="http://test.yudao.iocoder.cn/b7cb3cf49b4b3258bf7309a09dd2f4e5.jpg" alt="" data-href="">11112222<img src="http://test.yudao.iocoder.cn/fe44fc7bdb82ca421184b2eebbaee9e2148d4a1827479a4eb4521e11d2a062ba.png" alt="image" data-href="http://test.yudao.iocoder.cn/fe44fc7bdb82ca421184b2eebbaee9e2148d4a1827479a4eb4521e11d2a062ba.png">3333</p>\n<p><img src="http://test.yudao.iocoder.cn/20260503/澶囦唤.jpg" alt="" width="258" height="258"><img src="http://test.yudao.iocoder.cn/20260503/钀岃悓鐨勭毊鍗′笜.png"></p>', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2026-05-03 23:07:48', '0', 1);
+INSERT INTO system_notice (id, title, content, type, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '鎴戞槸娴嬭瘯鏍囬', '<p>鍝堝搱鍝堝搱123</p>', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', '0', 121);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_notice_seq;
+CREATE SEQUENCE system_notice_seq
+ START 5;
+
+-- ----------------------------
+-- Table structure for system_notify_message
+-- ----------------------------
+DROP TABLE IF EXISTS system_notify_message;
+CREATE TABLE system_notify_message (
+ id int8 NOT NULL,
+ user_id int8 NOT NULL,
+ user_type int2 NOT NULL,
+ template_id int8 NOT NULL,
+ template_code varchar(64) NOT NULL,
+ template_nickname varchar(63) NOT NULL,
+ template_content varchar(1024) NOT NULL,
+ template_type int4 NOT NULL,
+ template_params varchar(255) NOT NULL,
+ read_status bool NOT NULL,
+ read_time timestamp NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_notify_message ADD CONSTRAINT pk_system_notify_message PRIMARY KEY (id);
+
+CREATE INDEX idx_system_notify_message_01 ON system_notify_message (user_id, user_type, read_status);
+
+COMMENT ON COLUMN system_notify_message.id IS '鐢ㄦ埛ID';
+COMMENT ON COLUMN system_notify_message.user_id IS '鐢ㄦ埛id';
+COMMENT ON COLUMN system_notify_message.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_notify_message.template_id IS '妯$増缂栧彿';
+COMMENT ON COLUMN system_notify_message.template_code IS '妯℃澘缂栫爜';
+COMMENT ON COLUMN system_notify_message.template_nickname IS '妯$増鍙戦�佷汉鍚嶇О';
+COMMENT ON COLUMN system_notify_message.template_content IS '妯$増鍐呭';
+COMMENT ON COLUMN system_notify_message.template_type IS '妯$増绫诲瀷';
+COMMENT ON COLUMN system_notify_message.template_params IS '妯$増鍙傛暟';
+COMMENT ON COLUMN system_notify_message.read_status IS '鏄惁宸茶';
+COMMENT ON COLUMN system_notify_message.read_time IS '闃呰鏃堕棿';
+COMMENT ON COLUMN system_notify_message.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_notify_message.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_notify_message.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_notify_message.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_notify_message.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_notify_message.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_notify_message IS '绔欏唴淇℃秷鎭〃';
+
+-- ----------------------------
+-- Records of system_notify_message
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 1, 2, 1, 'test', '123', '鎴戞槸 1锛屾垜寮�濮� 2 浜�', 1, '{"name":"1","what":"2"}', '1', '2025-12-15 21:24:36', '1', '2023-01-28 11:44:08', '1', '2025-12-15 21:24:36', '0', 1);
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 1, 2, 1, 'test', '123', '鎴戞槸 1锛屾垜寮�濮� 2 浜�', 1, '{"name":"1","what":"2"}', '1', '2025-12-15 21:24:36', '1', '2023-01-28 11:45:04', '1', '2025-12-15 21:24:36', '0', 1);
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 103, 2, 2, 'register', '绯荤粺娑堟伅', '浣犲ソ锛屾杩� 鍝堝搱 鍔犲叆澶у搴紒', 2, '{"name":"鍝堝搱"}', '0', NULL, '1', '2023-01-28 21:02:20', '1', '2023-01-28 21:02:20', '0', 1);
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 1, 2, 1, 'test', '123', '鎴戞槸 鑺嬭壙锛屾垜寮�濮� 鍐欎唬鐮� 浜�', 1, '{"name":"鑺嬭壙","what":"鍐欎唬鐮�"}', '1', '2025-12-08 17:25:28', '1', '2023-01-28 22:21:42', '1', '2025-12-08 17:25:28', '0', 1);
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 1, 2, 1, 'test', '123', '鎴戞槸 鑺嬭壙锛屾垜寮�濮� 鍐欎唬鐮� 浜�', 1, '{"name":"鑺嬭壙","what":"鍐欎唬鐮�"}', '1', '2025-12-08 17:25:30', '1', '2023-01-28 22:22:07', '1', '2025-12-08 17:25:30', '0', 1);
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 1, 2, 1, 'test', '123', '鎴戞槸 2锛屾垜寮�濮� 3 浜�', 1, '{"name":"2","what":"3"}', '1', '2025-12-08 17:25:22', '1', '2023-01-28 23:45:21', '1', '2025-12-08 17:25:22', '0', 1);
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 1, 2, 2, 'register', '绯荤粺娑堟伅', '浣犲ソ锛屾杩� 123 鍔犲叆澶у搴紒', 2, '{"name":"123"}', '1', '2025-12-08 16:46:01', '1', '2023-01-28 23:50:21', '1', '2025-12-08 16:46:01', '0', 1);
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '鎮ㄥ湪2023-09-28 08:35:46鎻愮幇锟�0.09鍏冪殑鐢宠宸查�氳繃瀹℃牳', 2, '{"reason":null,"createTime":"2023-09-28 08:35:46","price":"0.09"}', '0', NULL, '1', '2023-09-28 16:36:22', '1', '2023-09-28 16:36:22', '0', 1);
+INSERT INTO system_notify_message (id, user_id, user_type, template_id, template_code, template_nickname, template_content, template_type, template_params, read_status, read_time, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 247, 1, 4, 'brokerage_withdraw_audit_approve', 'system', '鎮ㄥ湪2023-09-30 20:59:40鎻愮幇锟�1.00鍏冪殑鐢宠宸查�氳繃瀹℃牳', 2, '{"reason":null,"createTime":"2023-09-30 20:59:40","price":"1.00"}', '0', NULL, '1', '2023-10-03 12:11:34', '1', '2023-10-03 12:11:34', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_notify_message_seq;
+CREATE SEQUENCE system_notify_message_seq
+ START 11;
+
+-- ----------------------------
+-- Table structure for system_notify_template
+-- ----------------------------
+DROP TABLE IF EXISTS system_notify_template;
+CREATE TABLE system_notify_template (
+ id int8 NOT NULL,
+ name varchar(63) NOT NULL,
+ code varchar(64) NOT NULL,
+ nickname varchar(255) NOT NULL,
+ content varchar(1024) NOT NULL,
+ type int2 NOT NULL,
+ params varchar(255) NULL DEFAULT NULL,
+ status int2 NOT NULL,
+ remark varchar(255) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_notify_template ADD CONSTRAINT pk_system_notify_template PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_notify_template.id IS '涓婚敭';
+COMMENT ON COLUMN system_notify_template.name IS '妯℃澘鍚嶇О';
+COMMENT ON COLUMN system_notify_template.code IS '妯$増缂栫爜';
+COMMENT ON COLUMN system_notify_template.nickname IS '鍙戦�佷汉鍚嶇О';
+COMMENT ON COLUMN system_notify_template.content IS '妯$増鍐呭';
+COMMENT ON COLUMN system_notify_template.type IS '绫诲瀷';
+COMMENT ON COLUMN system_notify_template.params IS '鍙傛暟鏁扮粍';
+COMMENT ON COLUMN system_notify_template.status IS '鐘舵��';
+COMMENT ON COLUMN system_notify_template.remark IS '澶囨敞';
+COMMENT ON COLUMN system_notify_template.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_notify_template.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_notify_template.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_notify_template.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_notify_template.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_notify_template IS '绔欏唴淇℃ā鏉胯〃';
+
+DROP SEQUENCE IF EXISTS system_notify_template_seq;
+CREATE SEQUENCE system_notify_template_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_oauth2_access_token
+-- ----------------------------
+DROP TABLE IF EXISTS system_oauth2_access_token;
+CREATE TABLE system_oauth2_access_token (
+ id int8 NOT NULL,
+ user_id int8 NOT NULL,
+ user_type int2 NOT NULL,
+ user_info varchar(512) NOT NULL,
+ access_token varchar(255) NOT NULL,
+ refresh_token varchar(32) NOT NULL,
+ client_id varchar(255) NOT NULL,
+ scopes varchar(255) NULL DEFAULT NULL,
+ expires_time timestamp NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_oauth2_access_token ADD CONSTRAINT pk_system_oauth2_access_token PRIMARY KEY (id);
+
+CREATE INDEX idx_system_oauth2_access_token_01 ON system_oauth2_access_token (access_token);
+CREATE INDEX idx_system_oauth2_access_token_02 ON system_oauth2_access_token (refresh_token);
+
+COMMENT ON COLUMN system_oauth2_access_token.id IS '缂栧彿';
+COMMENT ON COLUMN system_oauth2_access_token.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_oauth2_access_token.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_oauth2_access_token.user_info IS '鐢ㄦ埛淇℃伅';
+COMMENT ON COLUMN system_oauth2_access_token.access_token IS '璁块棶浠ょ墝';
+COMMENT ON COLUMN system_oauth2_access_token.refresh_token IS '鍒锋柊浠ょ墝';
+COMMENT ON COLUMN system_oauth2_access_token.client_id IS '瀹㈡埛绔紪鍙�';
+COMMENT ON COLUMN system_oauth2_access_token.scopes IS '鎺堟潈鑼冨洿';
+COMMENT ON COLUMN system_oauth2_access_token.expires_time IS '杩囨湡鏃堕棿';
+COMMENT ON COLUMN system_oauth2_access_token.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_oauth2_access_token.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_oauth2_access_token.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_oauth2_access_token.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_oauth2_access_token.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_oauth2_access_token.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_oauth2_access_token IS 'OAuth2 璁块棶浠ょ墝';
+
+DROP SEQUENCE IF EXISTS system_oauth2_access_token_seq;
+CREATE SEQUENCE system_oauth2_access_token_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_oauth2_approve
+-- ----------------------------
+DROP TABLE IF EXISTS system_oauth2_approve;
+CREATE TABLE system_oauth2_approve (
+ id int8 NOT NULL,
+ user_id int8 NOT NULL,
+ user_type int2 NOT NULL,
+ client_id varchar(255) NOT NULL,
+ scope varchar(255) NOT NULL DEFAULT '',
+ approved bool NOT NULL DEFAULT '0',
+ expires_time timestamp NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_oauth2_approve ADD CONSTRAINT pk_system_oauth2_approve PRIMARY KEY (id);
+
+CREATE INDEX idx_system_oauth2_approve_01 ON system_oauth2_approve (user_id, user_type, client_id);
+
+COMMENT ON COLUMN system_oauth2_approve.id IS '缂栧彿';
+COMMENT ON COLUMN system_oauth2_approve.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_oauth2_approve.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_oauth2_approve.client_id IS '瀹㈡埛绔紪鍙�';
+COMMENT ON COLUMN system_oauth2_approve.scope IS '鎺堟潈鑼冨洿';
+COMMENT ON COLUMN system_oauth2_approve.approved IS '鏄惁鎺ュ彈';
+COMMENT ON COLUMN system_oauth2_approve.expires_time IS '杩囨湡鏃堕棿';
+COMMENT ON COLUMN system_oauth2_approve.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_oauth2_approve.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_oauth2_approve.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_oauth2_approve.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_oauth2_approve.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_oauth2_approve.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_oauth2_approve IS 'OAuth2 鎵瑰噯琛�';
+
+DROP SEQUENCE IF EXISTS system_oauth2_approve_seq;
+CREATE SEQUENCE system_oauth2_approve_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_oauth2_client
+-- ----------------------------
+DROP TABLE IF EXISTS system_oauth2_client;
+CREATE TABLE system_oauth2_client (
+ id int8 NOT NULL,
+ client_id varchar(255) NOT NULL,
+ secret varchar(255) NOT NULL,
+ name varchar(255) NOT NULL,
+ logo varchar(255) NOT NULL,
+ description varchar(255) NULL DEFAULT NULL,
+ status int2 NOT NULL,
+ access_token_validity_seconds int4 NOT NULL,
+ refresh_token_validity_seconds int4 NOT NULL,
+ redirect_uris varchar(255) NOT NULL,
+ authorized_grant_types varchar(255) NOT NULL,
+ scopes varchar(255) NULL DEFAULT NULL,
+ auto_approve_scopes varchar(255) NULL DEFAULT NULL,
+ authorities varchar(255) NULL DEFAULT NULL,
+ resource_ids varchar(255) NULL DEFAULT NULL,
+ additional_information varchar(4096) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_oauth2_client ADD CONSTRAINT pk_system_oauth2_client PRIMARY KEY (id);
+
+CREATE INDEX idx_system_oauth2_client_01 ON system_oauth2_client (client_id);
+
+COMMENT ON COLUMN system_oauth2_client.id IS '缂栧彿';
+COMMENT ON COLUMN system_oauth2_client.client_id IS '瀹㈡埛绔紪鍙�';
+COMMENT ON COLUMN system_oauth2_client.secret IS '瀹㈡埛绔瘑閽�';
+COMMENT ON COLUMN system_oauth2_client.name IS '搴旂敤鍚�';
+COMMENT ON COLUMN system_oauth2_client.logo IS '搴旂敤鍥炬爣';
+COMMENT ON COLUMN system_oauth2_client.description IS '搴旂敤鎻忚堪';
+COMMENT ON COLUMN system_oauth2_client.status IS '鐘舵��';
+COMMENT ON COLUMN system_oauth2_client.access_token_validity_seconds IS '璁块棶浠ょ墝鐨勬湁鏁堟湡';
+COMMENT ON COLUMN system_oauth2_client.refresh_token_validity_seconds IS '鍒锋柊浠ょ墝鐨勬湁鏁堟湡';
+COMMENT ON COLUMN system_oauth2_client.redirect_uris IS '鍙噸瀹氬悜鐨� URI 鍦板潃';
+COMMENT ON COLUMN system_oauth2_client.authorized_grant_types IS '鎺堟潈绫诲瀷';
+COMMENT ON COLUMN system_oauth2_client.scopes IS '鎺堟潈鑼冨洿';
+COMMENT ON COLUMN system_oauth2_client.auto_approve_scopes IS '鑷姩閫氳繃鐨勬巿鏉冭寖鍥�';
+COMMENT ON COLUMN system_oauth2_client.authorities IS '鏉冮檺';
+COMMENT ON COLUMN system_oauth2_client.resource_ids IS '璧勬簮';
+COMMENT ON COLUMN system_oauth2_client.additional_information IS '闄勫姞淇℃伅';
+COMMENT ON COLUMN system_oauth2_client.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_oauth2_client.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_oauth2_client.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_oauth2_client.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_oauth2_client.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_oauth2_client IS 'OAuth2 瀹㈡埛绔〃';
+
+-- ----------------------------
+-- Records of system_oauth2_client
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (1, 'default', 'admin123', '鑺嬮亾婧愮爜', 'http://test.yudao.iocoder.cn/20250502/sort2_1746189740718.png', '鎴戞槸鎻忚堪', 0, 1800, 2592000, '["https://www.iocoder.cn","https://doc.iocoder.cn"]', '["password","authorization_code","implicit","refresh_token","client_credentials"]', '["user.read","user.write"]', '[]', '["user.read","user.write"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2025-12-07 20:07:09', '0');
+INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/20251227/javayuanma_1766829882970.jpg', '鍟﹀暒鍟﹀暒', 0, 1800, 43200, '["https://www.iocoder.cn"]', '["password","authorization_code","implicit"]', '["user_info","projects"]', '["user_info"]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2025-12-27 18:04:44', '0');
+INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (41, 'yudao-sso-demo-by-code', 'test', '鍩轰簬鎺堟潈鐮佹ā寮忥紝濡備綍瀹炵幇 SSO 鍗曠偣鐧诲綍锛�', 'http://test.yudao.iocoder.cn/it/20250502/sign_1746181948685.png', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["authorization_code","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-09-29 13:28:31', '1', '2025-05-02 18:32:30', '0');
+INSERT INTO system_oauth2_client (id, client_id, secret, name, logo, description, status, access_token_validity_seconds, refresh_token_validity_seconds, redirect_uris, authorized_grant_types, scopes, auto_approve_scopes, authorities, resource_ids, additional_information, creator, create_time, updater, update_time, deleted) VALUES (42, 'yudao-sso-demo-by-password', 'test', '鍩轰簬瀵嗙爜妯″紡锛屽浣曞疄鐜� SSO 鍗曠偣鐧诲綍锛�', 'http://test.yudao.iocoder.cn/20251025/images (3)_1761360515810.jpeg', NULL, 0, 1800, 43200, '["http://127.0.0.1:18080"]', '["password","refresh_token"]', '["user.read","user.write"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2025-10-25 10:49:40', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_oauth2_client_seq;
+CREATE SEQUENCE system_oauth2_client_seq
+ START 43;
+
+-- ----------------------------
+-- Table structure for system_oauth2_code
+-- ----------------------------
+DROP TABLE IF EXISTS system_oauth2_code;
+CREATE TABLE system_oauth2_code (
+ id int8 NOT NULL,
+ user_id int8 NOT NULL,
+ user_type int2 NOT NULL,
+ code varchar(32) NOT NULL,
+ client_id varchar(255) NOT NULL,
+ scopes varchar(255) NULL DEFAULT '',
+ expires_time timestamp NOT NULL,
+ redirect_uri varchar(255) NULL DEFAULT NULL,
+ state varchar(255) NOT NULL DEFAULT '',
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_oauth2_code ADD CONSTRAINT pk_system_oauth2_code PRIMARY KEY (id);
+
+CREATE INDEX idx_system_oauth2_code_01 ON system_oauth2_code (code);
+
+COMMENT ON COLUMN system_oauth2_code.id IS '缂栧彿';
+COMMENT ON COLUMN system_oauth2_code.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_oauth2_code.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_oauth2_code.code IS '鎺堟潈鐮�';
+COMMENT ON COLUMN system_oauth2_code.client_id IS '瀹㈡埛绔紪鍙�';
+COMMENT ON COLUMN system_oauth2_code.scopes IS '鎺堟潈鑼冨洿';
+COMMENT ON COLUMN system_oauth2_code.expires_time IS '杩囨湡鏃堕棿';
+COMMENT ON COLUMN system_oauth2_code.redirect_uri IS '鍙噸瀹氬悜鐨� URI 鍦板潃';
+COMMENT ON COLUMN system_oauth2_code.state IS '鐘舵��';
+COMMENT ON COLUMN system_oauth2_code.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_oauth2_code.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_oauth2_code.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_oauth2_code.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_oauth2_code.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_oauth2_code.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_oauth2_code IS 'OAuth2 鎺堟潈鐮佽〃';
+
+DROP SEQUENCE IF EXISTS system_oauth2_code_seq;
+CREATE SEQUENCE system_oauth2_code_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_oauth2_refresh_token
+-- ----------------------------
+DROP TABLE IF EXISTS system_oauth2_refresh_token;
+CREATE TABLE system_oauth2_refresh_token (
+ id int8 NOT NULL,
+ user_id int8 NOT NULL,
+ refresh_token varchar(32) NOT NULL,
+ user_type int2 NOT NULL,
+ client_id varchar(255) NOT NULL,
+ scopes varchar(255) NULL DEFAULT NULL,
+ expires_time timestamp NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_oauth2_refresh_token ADD CONSTRAINT pk_system_oauth2_refresh_token PRIMARY KEY (id);
+
+CREATE INDEX idx_system_oauth2_refresh_token_01 ON system_oauth2_refresh_token (refresh_token);
+
+COMMENT ON COLUMN system_oauth2_refresh_token.id IS '缂栧彿';
+COMMENT ON COLUMN system_oauth2_refresh_token.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_oauth2_refresh_token.refresh_token IS '鍒锋柊浠ょ墝';
+COMMENT ON COLUMN system_oauth2_refresh_token.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_oauth2_refresh_token.client_id IS '瀹㈡埛绔紪鍙�';
+COMMENT ON COLUMN system_oauth2_refresh_token.scopes IS '鎺堟潈鑼冨洿';
+COMMENT ON COLUMN system_oauth2_refresh_token.expires_time IS '杩囨湡鏃堕棿';
+COMMENT ON COLUMN system_oauth2_refresh_token.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_oauth2_refresh_token.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_oauth2_refresh_token.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_oauth2_refresh_token.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_oauth2_refresh_token.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_oauth2_refresh_token.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_oauth2_refresh_token IS 'OAuth2 鍒锋柊浠ょ墝';
+
+DROP SEQUENCE IF EXISTS system_oauth2_refresh_token_seq;
+CREATE SEQUENCE system_oauth2_refresh_token_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_operate_log
+-- ----------------------------
+DROP TABLE IF EXISTS system_operate_log;
+CREATE TABLE system_operate_log (
+ id int8 NOT NULL,
+ trace_id varchar(64) NOT NULL DEFAULT '',
+ user_id int8 NOT NULL,
+ user_type int2 NOT NULL DEFAULT 0,
+ type varchar(50) NOT NULL,
+ sub_type varchar(50) NOT NULL,
+ biz_id int8 NOT NULL,
+ action varchar(2000) NOT NULL DEFAULT '',
+ success bool NOT NULL DEFAULT '1',
+ extra varchar(2000) NOT NULL DEFAULT '',
+ request_method varchar(16) NULL DEFAULT '',
+ request_url varchar(255) NULL DEFAULT '',
+ user_ip varchar(50) NULL DEFAULT NULL,
+ user_agent varchar(512) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_operate_log ADD CONSTRAINT pk_system_operate_log PRIMARY KEY (id);
+
+CREATE INDEX idx_system_operate_log_01 ON system_operate_log (user_id);
+CREATE INDEX idx_system_operate_log_02 ON system_operate_log (create_time);
+
+COMMENT ON COLUMN system_operate_log.id IS '鏃ュ織涓婚敭';
+COMMENT ON COLUMN system_operate_log.trace_id IS '閾捐矾杩借釜缂栧彿';
+COMMENT ON COLUMN system_operate_log.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_operate_log.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_operate_log.type IS '鎿嶄綔妯″潡绫诲瀷';
+COMMENT ON COLUMN system_operate_log.sub_type IS '鎿嶄綔鍚�';
+COMMENT ON COLUMN system_operate_log.biz_id IS '鎿嶄綔鏁版嵁妯″潡缂栧彿';
+COMMENT ON COLUMN system_operate_log.action IS '鎿嶄綔鍐呭';
+COMMENT ON COLUMN system_operate_log.success IS '鎿嶄綔缁撴灉';
+COMMENT ON COLUMN system_operate_log.extra IS '鎷撳睍瀛楁';
+COMMENT ON COLUMN system_operate_log.request_method IS '璇锋眰鏂规硶鍚�';
+COMMENT ON COLUMN system_operate_log.request_url IS '璇锋眰鍦板潃';
+COMMENT ON COLUMN system_operate_log.user_ip IS '鐢ㄦ埛 IP';
+COMMENT ON COLUMN system_operate_log.user_agent IS '娴忚鍣� UA';
+COMMENT ON COLUMN system_operate_log.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_operate_log.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_operate_log.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_operate_log.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_operate_log.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_operate_log.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_operate_log IS '鎿嶄綔鏃ュ織璁板綍 V2 鐗堟湰';
+
+DROP SEQUENCE IF EXISTS system_operate_log_seq;
+CREATE SEQUENCE system_operate_log_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_post
+-- ----------------------------
+DROP TABLE IF EXISTS system_post;
+CREATE TABLE system_post (
+ id int8 NOT NULL,
+ code varchar(64) NOT NULL,
+ name varchar(50) NOT NULL,
+ sort int4 NOT NULL,
+ status int2 NOT NULL,
+ remark varchar(500) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_post ADD CONSTRAINT pk_system_post PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_post.id IS '宀椾綅ID';
+COMMENT ON COLUMN system_post.code IS '宀椾綅缂栫爜';
+COMMENT ON COLUMN system_post.name IS '宀椾綅鍚嶇О';
+COMMENT ON COLUMN system_post.sort IS '鏄剧ず椤哄簭';
+COMMENT ON COLUMN system_post.status IS '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+COMMENT ON COLUMN system_post.remark IS '澶囨敞';
+COMMENT ON COLUMN system_post.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_post.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_post.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_post.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_post.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_post.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_post IS '宀椾綅淇℃伅琛�';
+
+-- ----------------------------
+-- Records of system_post
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 'se', '椤圭洰缁忕悊', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2025-12-15 22:38:43', '0', 1);
+INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, 'user', '鏅�氬憳宸�', 4, 0, '111222', 'admin', '2021-01-05 17:03:48', '1', '2025-03-24 21:32:40', '0', 1);
+INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 'HR', '浜哄姏璧勬簮', 5, 0, '`', '1', '2024-03-24 20:45:40', '1', '2025-03-29 19:08:10', '0', 1);
+INSERT INTO system_post (id, code, name, sort, status, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 'test', '娴嬭瘯', 10, 0, NULL, '1', '2025-09-02 08:45:57', '1', '2025-09-02 08:45:57', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_post_seq;
+CREATE SEQUENCE system_post_seq
+ START 8;
+
+-- ----------------------------
+-- Table structure for system_role
+-- ----------------------------
+DROP TABLE IF EXISTS system_role;
+CREATE TABLE system_role (
+ id int8 NOT NULL,
+ name varchar(30) NOT NULL,
+ code varchar(100) NOT NULL,
+ sort int4 NOT NULL,
+ data_scope int2 NOT NULL DEFAULT 1,
+ data_scope_dept_ids varchar(500) NOT NULL DEFAULT '',
+ status int2 NOT NULL,
+ type int2 NOT NULL,
+ remark varchar(500) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_role ADD CONSTRAINT pk_system_role PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_role.id IS '瑙掕壊ID';
+COMMENT ON COLUMN system_role.name IS '瑙掕壊鍚嶇О';
+COMMENT ON COLUMN system_role.code IS '瑙掕壊鏉冮檺瀛楃涓�';
+COMMENT ON COLUMN system_role.sort IS '鏄剧ず椤哄簭';
+COMMENT ON COLUMN system_role.data_scope IS '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級';
+COMMENT ON COLUMN system_role.data_scope_dept_ids IS '鏁版嵁鑼冨洿(鎸囧畾閮ㄩ棬鏁扮粍)';
+COMMENT ON COLUMN system_role.status IS '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+COMMENT ON COLUMN system_role.type IS '瑙掕壊绫诲瀷';
+COMMENT ON COLUMN system_role.remark IS '澶囨敞';
+COMMENT ON COLUMN system_role.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_role.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_role.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_role.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_role.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_role.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_role IS '瑙掕壊淇℃伅琛�';
+
+-- ----------------------------
+-- Records of system_role
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '瓒呯骇绠$悊鍛�', 'super_admin', 1, 1, '', 0, 1, '瓒呯骇绠$悊鍛�', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:21', '0', 1);
+INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '鏅�氳鑹�', 'common', 2, 2, '', 0, 1, '鏅�氳鑹�', 'admin', '2021-01-05 17:03:48', '', '2022-02-22 05:08:20', '0', 1);
+INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 'CRM 绠$悊鍛�', 'crm_admin', 2, 1, '', 0, 1, 'CRM 涓撳睘瑙掕壊', '1', '2024-02-24 10:51:13', '1', '2024-02-24 02:51:32', '0', 1);
+INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, '绉熸埛绠$悊鍛�', 'tenant_admin', 0, 1, '', 0, 1, '绯荤粺鑷姩鐢熸垚', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121);
+INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, '绉熸埛绠$悊鍛�', 'tenant_admin', 0, 1, '', 0, 1, '绯荤粺鑷姩鐢熸垚', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122);
+INSERT INTO system_role (id, name, code, sort, data_scope, data_scope_dept_ids, status, type, remark, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (155, '娴嬭瘯鏁版嵁鏉冮檺1', 'test-dp', 4, 2, '[112,100,102,103,104,105,107,108]', 0, 2, '1111', '1', '2025-03-31 14:58:06', '1', '2025-12-04 23:29:40', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_role_seq;
+CREATE SEQUENCE system_role_seq
+ START 156;
+
+-- ----------------------------
+-- Table structure for system_role_menu
+-- ----------------------------
+DROP TABLE IF EXISTS system_role_menu;
+CREATE TABLE system_role_menu (
+ id int8 NOT NULL,
+ role_id int8 NOT NULL,
+ menu_id int8 NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_role_menu ADD CONSTRAINT pk_system_role_menu PRIMARY KEY (id);
+
+CREATE INDEX idx_system_role_menu_01 ON system_role_menu (role_id);
+
+COMMENT ON COLUMN system_role_menu.id IS '鑷缂栧彿';
+COMMENT ON COLUMN system_role_menu.role_id IS '瑙掕壊ID';
+COMMENT ON COLUMN system_role_menu.menu_id IS '鑿滃崟ID';
+COMMENT ON COLUMN system_role_menu.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_role_menu.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_role_menu.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_role_menu.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_role_menu.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_role_menu.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_role_menu IS '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+
+-- ----------------------------
+-- Records of system_role_menu
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (263, 109, 1, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (434, 2, 1, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (454, 2, 1093, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (455, 2, 1094, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (460, 2, 1100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (467, 2, 1107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (476, 2, 1117, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (477, 2, 100, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (478, 2, 101, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (479, 2, 102, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (480, 2, 1126, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (481, 2, 103, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (483, 2, 104, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (485, 2, 105, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (488, 2, 107, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (490, 2, 108, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (492, 2, 109, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (498, 2, 1138, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (523, 2, 1224, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (524, 2, 1225, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (541, 2, 500, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (543, 2, 501, '1', '2022-02-22 13:09:12', '1', '2022-02-22 13:09:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (675, 2, 2, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (689, 2, 1077, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (690, 2, 1078, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (692, 2, 1083, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (693, 2, 1084, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (699, 2, 1090, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (703, 2, 106, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (704, 2, 110, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (705, 2, 111, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (706, 2, 112, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (707, 2, 113, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1296, 110, 1, '110', '2022-02-23 00:23:55', '110', '2022-02-23 00:23:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1578, 111, 1, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1729, 109, 100, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1730, 109, 101, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1731, 109, 1063, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1732, 109, 1064, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1733, 109, 1001, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1734, 109, 1065, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1735, 109, 1002, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1736, 109, 1003, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1737, 109, 1004, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1738, 109, 1005, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1739, 109, 1006, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1740, 109, 1007, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1741, 109, 1008, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1742, 109, 1009, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1743, 109, 1010, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1744, 109, 1011, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1745, 109, 1012, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1746, 111, 100, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1747, 111, 101, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1748, 111, 1063, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1749, 111, 1064, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1750, 111, 1001, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1751, 111, 1065, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1752, 111, 1002, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1753, 111, 1003, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1754, 111, 1004, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1755, 111, 1005, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1756, 111, 1006, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1757, 111, 1007, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1758, 111, 1008, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1759, 111, 1009, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1760, 111, 1010, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1761, 111, 1011, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1762, 111, 1012, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1763, 109, 100, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1764, 109, 101, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1765, 109, 1063, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1766, 109, 1064, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1767, 109, 1001, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1768, 109, 1065, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1769, 109, 1002, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1770, 109, 1003, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1771, 109, 1004, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1772, 109, 1005, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1773, 109, 1006, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1774, 109, 1007, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1775, 109, 1008, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1776, 109, 1009, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1777, 109, 1010, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1778, 109, 1011, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1779, 109, 1012, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1780, 111, 100, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1781, 111, 101, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1782, 111, 1063, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1783, 111, 1064, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1784, 111, 1001, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1785, 111, 1065, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1786, 111, 1002, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1787, 111, 1003, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1788, 111, 1004, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1789, 111, 1005, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1790, 111, 1006, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1791, 111, 1007, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1792, 111, 1008, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1793, 111, 1009, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1794, 111, 1010, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1795, 111, 1011, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1796, 111, 1012, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1797, 109, 100, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1798, 109, 101, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1799, 109, 1063, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1800, 109, 1064, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1801, 109, 1001, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1802, 109, 1065, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1803, 109, 1002, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1804, 109, 1003, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1805, 109, 1004, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1806, 109, 1005, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1807, 109, 1006, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1808, 109, 1007, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1809, 109, 1008, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1810, 109, 1009, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1811, 109, 1010, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1812, 109, 1011, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1813, 109, 1012, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1814, 111, 100, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1815, 111, 101, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1816, 111, 1063, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1817, 111, 1064, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1818, 111, 1001, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1819, 111, 1065, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1820, 111, 1002, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1821, 111, 1003, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1822, 111, 1004, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1823, 111, 1005, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1824, 111, 1006, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1825, 111, 1007, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1826, 111, 1008, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1827, 111, 1009, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1828, 111, 1010, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1829, 111, 1011, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1830, 111, 1012, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1831, 109, 103, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1832, 109, 1017, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1833, 109, 1018, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1834, 109, 1019, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1835, 109, 1020, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1836, 111, 103, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1837, 111, 1017, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1838, 111, 1018, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1839, 111, 1019, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1840, 111, 1020, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1841, 109, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1842, 109, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1843, 109, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1844, 109, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1845, 109, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1846, 111, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1847, 111, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1848, 111, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1849, 111, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1850, 111, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1991, 2, 1024, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1992, 2, 1025, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1993, 2, 1026, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1994, 2, 1027, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1995, 2, 1028, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1996, 2, 1029, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1997, 2, 1030, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1998, 2, 1031, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1999, 2, 1032, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2000, 2, 1033, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2001, 2, 1034, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2002, 2, 1035, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2003, 2, 1036, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2004, 2, 1037, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2005, 2, 1038, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2006, 2, 1039, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2007, 2, 1040, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2008, 2, 1042, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2009, 2, 1043, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2010, 2, 1045, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2011, 2, 1046, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2012, 2, 1048, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2013, 2, 1050, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2014, 2, 1051, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2015, 2, 1052, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2016, 2, 1053, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2017, 2, 1054, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2018, 2, 1056, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2019, 2, 1057, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2020, 2, 1058, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2021, 2, 2083, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2022, 2, 1059, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2023, 2, 1060, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2024, 2, 1063, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2025, 2, 1064, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2026, 2, 1065, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2027, 2, 1066, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2028, 2, 1067, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2029, 2, 1070, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2034, 2, 1075, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2036, 2, 1082, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2037, 2, 1085, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2038, 2, 1086, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2039, 2, 1087, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2040, 2, 1088, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2041, 2, 1089, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2042, 2, 1091, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2043, 2, 1092, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2044, 2, 1095, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2045, 2, 1096, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2046, 2, 1097, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2047, 2, 1098, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2048, 2, 1101, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2049, 2, 1102, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2050, 2, 1103, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2051, 2, 1104, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2052, 2, 1105, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2053, 2, 1106, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2054, 2, 1108, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2055, 2, 1109, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2061, 2, 1127, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2062, 2, 1128, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2063, 2, 1129, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2064, 2, 1130, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2066, 2, 1132, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2067, 2, 1133, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2068, 2, 1134, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2069, 2, 1135, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2070, 2, 1136, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2071, 2, 1137, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2072, 2, 114, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2073, 2, 1139, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2074, 2, 115, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2075, 2, 1140, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2076, 2, 116, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2077, 2, 1141, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2078, 2, 1142, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2079, 2, 1143, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2080, 2, 1150, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2081, 2, 1161, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2082, 2, 1162, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2086, 2, 1166, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2087, 2, 1173, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2088, 2, 1174, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2092, 2, 1178, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2099, 2, 1226, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2100, 2, 1227, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2101, 2, 1228, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2102, 2, 1229, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2103, 2, 1237, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2104, 2, 1238, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2105, 2, 1239, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2106, 2, 1240, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2107, 2, 1241, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2108, 2, 1242, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2109, 2, 1243, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2116, 2, 1254, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2117, 2, 1255, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2118, 2, 1256, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2119, 2, 1257, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2120, 2, 1258, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2121, 2, 1259, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2122, 2, 1260, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2123, 2, 1261, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2124, 2, 1263, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2125, 2, 1264, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2126, 2, 1265, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2127, 2, 1266, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2128, 2, 1267, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2129, 2, 1001, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2130, 2, 1002, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2131, 2, 1003, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2132, 2, 1004, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2133, 2, 1005, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2134, 2, 1006, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2135, 2, 1007, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2136, 2, 1008, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2137, 2, 1009, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2138, 2, 1010, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2139, 2, 1011, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2140, 2, 1012, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2141, 2, 1013, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2143, 2, 1015, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2145, 2, 1017, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2146, 2, 1018, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2147, 2, 1019, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2148, 2, 1020, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2149, 2, 1021, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2150, 2, 1022, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2151, 2, 1023, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2152, 2, 1281, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2153, 2, 1282, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2154, 2, 2000, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2155, 2, 2002, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2156, 2, 2003, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2157, 2, 2004, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2158, 2, 2005, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2159, 2, 2006, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2160, 2, 2008, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2161, 2, 2009, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2162, 2, 2010, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2163, 2, 2011, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2164, 2, 2012, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2170, 2, 2019, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2171, 2, 2020, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2172, 2, 2021, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2173, 2, 2022, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2174, 2, 2023, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2175, 2, 2025, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2177, 2, 2027, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2178, 2, 2028, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2179, 2, 2029, '1', '2023-01-25 08:42:58', '1', '2023-01-25 08:42:58', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2180, 2, 2014, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2181, 2, 2015, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2182, 2, 2016, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2183, 2, 2017, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2184, 2, 2018, '1', '2023-01-25 08:43:12', '1', '2023-01-25 08:43:12', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2929, 109, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2930, 109, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2931, 109, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2932, 109, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2933, 109, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2934, 109, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2935, 109, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2936, 109, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2937, 109, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2938, 109, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2939, 109, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2940, 109, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2941, 111, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2942, 111, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2943, 111, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2944, 111, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2945, 111, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2946, 111, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2947, 111, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2948, 111, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2949, 111, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2950, 111, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2951, 111, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2952, 111, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2993, 109, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2994, 109, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2995, 109, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2996, 109, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2997, 109, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2998, 109, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2999, 109, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3000, 109, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3001, 109, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3002, 109, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3003, 109, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3004, 109, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3005, 109, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3006, 109, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3007, 109, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3008, 109, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3009, 109, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3010, 109, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3011, 109, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3012, 109, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3014, 109, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3015, 109, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3016, 109, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3017, 109, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3018, 109, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3019, 109, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3020, 109, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3021, 109, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3022, 109, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3023, 109, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3024, 109, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3025, 109, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3026, 109, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3027, 109, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3028, 109, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3029, 109, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3030, 109, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3031, 109, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3032, 109, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3033, 109, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3034, 109, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3035, 109, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3036, 109, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3037, 109, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3038, 109, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3039, 109, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3040, 109, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3041, 109, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3042, 109, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3043, 109, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3044, 109, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3045, 109, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3046, 109, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3047, 109, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3048, 109, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3049, 109, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3050, 109, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3051, 109, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3052, 109, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3053, 109, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3054, 109, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3055, 109, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3056, 109, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3057, 109, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3058, 109, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3059, 109, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3060, 109, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3061, 109, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3062, 109, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3063, 109, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3064, 109, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3065, 109, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3066, 109, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3067, 109, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3068, 109, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3069, 111, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3070, 111, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3071, 111, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3072, 111, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3073, 111, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3074, 111, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3075, 111, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3076, 111, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3077, 111, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3078, 111, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3079, 111, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3080, 111, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3081, 111, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3082, 111, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3083, 111, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3084, 111, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3085, 111, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3086, 111, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3087, 111, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3088, 111, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3090, 111, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3091, 111, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3092, 111, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3093, 111, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3094, 111, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3095, 111, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3096, 111, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3097, 111, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3098, 111, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3099, 111, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3100, 111, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3101, 111, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3102, 111, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3103, 111, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3104, 111, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3105, 111, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3106, 111, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3107, 111, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3108, 111, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3109, 111, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3110, 111, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3111, 111, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3112, 111, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3113, 111, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3114, 111, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3115, 111, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3116, 111, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3117, 111, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3118, 111, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3119, 111, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3120, 111, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3121, 111, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3122, 111, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3123, 111, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3124, 111, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3125, 111, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3126, 111, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3127, 111, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3128, 111, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3129, 111, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3130, 111, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3131, 111, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3132, 111, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3133, 111, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3134, 111, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3135, 111, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3136, 111, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3137, 111, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3138, 111, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3139, 111, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3140, 111, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3141, 111, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3142, 111, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3143, 111, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3144, 111, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3221, 109, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3222, 109, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3223, 109, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3224, 109, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3225, 109, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3226, 111, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3227, 111, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3228, 111, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3229, 111, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3230, 111, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4163, 109, 5, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4164, 109, 1118, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4165, 109, 1119, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4166, 109, 1120, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4167, 109, 2713, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4168, 109, 2714, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4169, 109, 2715, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4170, 109, 2716, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4171, 109, 2717, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4172, 109, 2718, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4173, 109, 2720, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4174, 109, 1185, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4175, 109, 2721, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4176, 109, 1186, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4177, 109, 2722, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4178, 109, 1187, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4179, 109, 2723, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4180, 109, 1188, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4181, 109, 2724, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4182, 109, 1189, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4183, 109, 2725, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4184, 109, 1190, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4185, 109, 2726, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4186, 109, 1191, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4187, 109, 2727, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4188, 109, 1192, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4189, 109, 2728, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4190, 109, 1193, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4191, 109, 2729, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4192, 109, 1194, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4193, 109, 2730, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4194, 109, 1195, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4195, 109, 2731, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4197, 109, 2732, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4198, 109, 1197, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4199, 109, 2733, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4200, 109, 1198, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4201, 109, 2734, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4202, 109, 1199, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4203, 109, 2735, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4204, 109, 1200, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4205, 109, 1201, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4206, 109, 1202, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4207, 109, 1207, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4208, 109, 1208, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4209, 109, 1209, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4210, 109, 1210, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4211, 109, 1211, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4212, 109, 1212, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4213, 109, 1213, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4214, 109, 1215, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4215, 109, 1216, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4216, 109, 1217, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4217, 109, 1218, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4218, 109, 1219, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4219, 109, 1220, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4220, 109, 1221, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4221, 109, 1222, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4222, 111, 5, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4223, 111, 1118, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4224, 111, 1119, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4225, 111, 1120, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4226, 111, 2713, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4227, 111, 2714, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4228, 111, 2715, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4229, 111, 2716, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4230, 111, 2717, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4231, 111, 2718, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4232, 111, 2720, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4233, 111, 1185, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4234, 111, 2721, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4235, 111, 1186, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4236, 111, 2722, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4237, 111, 1187, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4238, 111, 2723, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4239, 111, 1188, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4240, 111, 2724, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4241, 111, 1189, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4242, 111, 2725, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4243, 111, 1190, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4244, 111, 2726, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4245, 111, 1191, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4246, 111, 2727, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4247, 111, 1192, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4248, 111, 2728, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4249, 111, 1193, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4250, 111, 2729, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4251, 111, 1194, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4252, 111, 2730, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4253, 111, 1195, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4254, 111, 2731, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4256, 111, 2732, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4257, 111, 1197, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4258, 111, 2733, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4259, 111, 1198, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4260, 111, 2734, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4261, 111, 1199, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4262, 111, 2735, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4263, 111, 1200, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4264, 111, 1201, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4265, 111, 1202, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4266, 111, 1207, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4267, 111, 1208, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4268, 111, 1209, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4269, 111, 1210, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4270, 111, 1211, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4271, 111, 1212, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4272, 111, 1213, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4273, 111, 1215, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4274, 111, 1216, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4275, 111, 1217, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4276, 111, 1218, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4277, 111, 1219, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4278, 111, 1220, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4279, 111, 1221, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4280, 111, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5779, 2, 2739, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5780, 2, 2740, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5781, 2, 2758, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5782, 2, 2759, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5783, 2, 2362, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5784, 2, 2387, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5785, 2, 2030, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5789, 109, 2739, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5790, 109, 2740, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5791, 111, 2739, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5792, 111, 2740, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6053, 155, 4000, '1', '2025-04-01 13:48:26', '1', '2025-04-01 13:48:26', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6097, 155, 4050, '1', '2025-04-01 13:48:26', '1', '2025-04-01 13:48:26', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6104, 155, 4032, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6105, 155, 4033, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6106, 155, 4034, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6107, 155, 4035, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6108, 155, 4036, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6109, 155, 4037, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6110, 155, 4038, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6111, 155, 4039, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6112, 155, 4040, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6113, 155, 4041, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6114, 155, 4042, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6115, 155, 4043, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6116, 155, 4044, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6117, 155, 4045, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6119, 155, 4001, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6120, 155, 4002, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6121, 155, 4003, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6122, 155, 4004, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6123, 155, 4005, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6124, 155, 4006, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6125, 155, 4007, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6126, 155, 4008, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6127, 155, 4009, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6128, 155, 4010, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6129, 155, 4011, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6130, 155, 4012, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6131, 155, 4013, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6132, 155, 4014, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6133, 155, 4015, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6134, 155, 4016, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6135, 155, 4017, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6136, 155, 4018, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6137, 155, 4031, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6139, 109, 1117, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6140, 109, 1126, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6141, 109, 1127, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6142, 109, 1128, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6143, 109, 1129, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6144, 109, 1130, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6145, 109, 1132, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6146, 109, 1133, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6147, 109, 1134, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6148, 109, 1135, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6149, 109, 1136, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6150, 109, 1137, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6151, 109, 2161, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6152, 109, 1150, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6153, 109, 1161, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6154, 109, 1162, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6155, 109, 1166, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6156, 109, 1173, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6157, 109, 1174, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6158, 109, 1178, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6159, 109, 2745, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6160, 109, 2746, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6161, 109, 2747, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6162, 109, 2748, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6163, 109, 2301, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6164, 109, 2302, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6165, 109, 5011, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6166, 109, 5012, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6167, 109, 2549, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6168, 109, 2550, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6169, 109, 2551, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6170, 109, 2552, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6171, 109, 2553, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6172, 109, 2554, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6173, 109, 2555, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6174, 109, 2556, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6175, 109, 2557, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6176, 109, 2558, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6177, 109, 2559, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6178, 111, 1117, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6179, 111, 1126, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6180, 111, 1127, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6181, 111, 1128, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6182, 111, 1129, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6183, 111, 1130, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6184, 111, 1132, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6185, 111, 1133, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6186, 111, 1134, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6187, 111, 1135, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6188, 111, 1136, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6189, 111, 1137, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6190, 111, 2161, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6191, 111, 1150, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6192, 111, 1161, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6193, 111, 1162, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6194, 111, 1166, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6195, 111, 1173, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6196, 111, 1174, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6197, 111, 1178, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6198, 111, 2745, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6199, 111, 2746, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6200, 111, 2747, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6201, 111, 2748, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6202, 111, 2301, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6203, 111, 2302, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6204, 111, 5011, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6205, 111, 5012, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6206, 111, 2549, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6207, 111, 2550, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6208, 111, 2551, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6209, 111, 2552, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6210, 111, 2553, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6211, 111, 2554, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6212, 111, 2555, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6213, 111, 2556, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6214, 111, 2557, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6215, 111, 2558, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6216, 111, 2559, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6217, 109, 2756, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6218, 109, 2757, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6219, 109, 2262, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6220, 109, 2275, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6221, 109, 2276, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6222, 109, 2277, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6223, 109, 2281, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6224, 109, 2282, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6225, 109, 2283, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6226, 109, 2284, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6227, 109, 2285, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6228, 109, 2287, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6229, 109, 2288, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6230, 109, 2293, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6231, 109, 2294, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6232, 109, 2297, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6233, 109, 2300, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6234, 109, 2317, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6235, 109, 2318, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6236, 109, 2319, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6237, 109, 2320, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6238, 109, 2321, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6239, 109, 2322, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6240, 109, 2323, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6241, 109, 2324, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6242, 109, 2325, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6243, 109, 2326, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6244, 109, 2327, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6245, 109, 2328, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6246, 109, 2329, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6247, 109, 2330, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6248, 109, 2331, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6249, 109, 2332, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6250, 109, 2333, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6251, 109, 2334, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6252, 109, 2335, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6253, 109, 2363, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6254, 109, 2364, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6255, 111, 2756, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6256, 111, 2757, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6257, 111, 2262, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6258, 111, 2275, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6259, 111, 2276, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6260, 111, 2277, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6261, 111, 2281, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6262, 111, 2282, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6263, 111, 2283, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6264, 111, 2284, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6265, 111, 2285, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6266, 111, 2287, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6267, 111, 2288, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6268, 111, 2293, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6269, 111, 2294, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6270, 111, 2297, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6271, 111, 2300, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6272, 111, 2317, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6273, 111, 2318, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6274, 111, 2319, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6275, 111, 2320, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6276, 111, 2321, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6277, 111, 2322, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6278, 111, 2323, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6279, 111, 2324, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6280, 111, 2325, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6281, 111, 2326, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6282, 111, 2327, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6283, 111, 2328, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6284, 111, 2329, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6285, 111, 2330, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6286, 111, 2331, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6287, 111, 2332, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6288, 111, 2333, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6289, 111, 2334, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6290, 111, 2335, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6291, 111, 2363, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6292, 111, 2364, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6293, 2, 5, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6294, 2, 1118, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6295, 2, 1119, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6296, 2, 1120, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6297, 2, 2713, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6298, 2, 2714, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6299, 2, 2715, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6300, 2, 2716, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6301, 2, 2717, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6302, 2, 2718, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6303, 2, 2720, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6304, 2, 1185, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6305, 2, 2721, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6306, 2, 1186, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6307, 2, 2722, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6308, 2, 1187, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6309, 2, 2723, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6310, 2, 1188, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6311, 2, 2724, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6312, 2, 1189, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6313, 2, 2725, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6314, 2, 1190, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6315, 2, 2726, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6316, 2, 1191, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6317, 2, 2727, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6318, 2, 1192, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6319, 2, 2728, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6320, 2, 1193, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6321, 2, 2729, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6322, 2, 1194, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6323, 2, 2730, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6324, 2, 1195, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6325, 2, 2731, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6326, 2, 2732, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6327, 2, 1197, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6328, 2, 2733, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6329, 2, 1198, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6330, 2, 2734, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6331, 2, 1199, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6332, 2, 2735, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6333, 2, 1200, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6334, 2, 1201, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6335, 2, 1202, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6336, 2, 1207, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6337, 2, 1208, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6338, 2, 1209, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6339, 2, 1210, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6340, 2, 1211, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6341, 2, 1212, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6342, 2, 1213, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6343, 2, 1215, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6344, 2, 1216, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6345, 2, 1217, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6346, 2, 1218, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6347, 2, 1219, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6348, 2, 1220, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6349, 2, 1221, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6350, 2, 1222, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6351, 2, 2913, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6352, 1, 5720, '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6353, 1, 5721, '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6354, 1, 5722, '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6355, 1, 5723, '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6356, 1, 5724, '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6357, 1, 5725, '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6358, 1, 5811, '', '2026-03-30 03:11:59', '', '2026-03-30 03:11:59', '0', 0);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6359, 1, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6360, 2, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6361, 3, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6362, 109, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', '0', 121);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6363, 111, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', '0', 122);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6364, 155, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6365, 2, 6400, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6366, 2, 6401, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6367, 2, 6402, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6368, 2, 6403, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6369, 2, 6404, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6370, 2, 6405, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6371, 2, 6406, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', '0', 1);
+INSERT INTO system_role_menu (id, role_id, menu_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6380, 2, 6490, '1', '2026-05-14 09:36:12', '1', '2026-05-14 09:36:12', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_role_menu_seq;
+CREATE SEQUENCE system_role_menu_seq
+ START 6381;
+
+-- ----------------------------
+-- Table structure for system_sms_channel
+-- ----------------------------
+DROP TABLE IF EXISTS system_sms_channel;
+CREATE TABLE system_sms_channel (
+ id int8 NOT NULL,
+ signature varchar(12) NOT NULL,
+ code varchar(63) NOT NULL,
+ status int2 NOT NULL,
+ remark varchar(255) NULL DEFAULT NULL,
+ api_key varchar(128) NOT NULL,
+ api_secret varchar(128) NULL DEFAULT NULL,
+ callback_url varchar(255) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_sms_channel ADD CONSTRAINT pk_system_sms_channel PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_sms_channel.id IS '缂栧彿';
+COMMENT ON COLUMN system_sms_channel.signature IS '鐭俊绛惧悕';
+COMMENT ON COLUMN system_sms_channel.code IS '娓犻亾缂栫爜';
+COMMENT ON COLUMN system_sms_channel.status IS '寮�鍚姸鎬�';
+COMMENT ON COLUMN system_sms_channel.remark IS '澶囨敞';
+COMMENT ON COLUMN system_sms_channel.api_key IS '鐭俊 API 鐨勮处鍙�';
+COMMENT ON COLUMN system_sms_channel.api_secret IS '鐭俊 API 鐨勭閽�';
+COMMENT ON COLUMN system_sms_channel.callback_url IS '鐭俊鍙戦�佸洖璋� URL';
+COMMENT ON COLUMN system_sms_channel.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_sms_channel.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_sms_channel.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_sms_channel.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_sms_channel.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_sms_channel IS '鐭俊娓犻亾';
+
+-- ----------------------------
+-- Records of system_sms_channel
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (2, 'Ballcat', 'ALIYUN', 0, '浣犺鏀瑰摝锛屽彧鏈夋垜鍙互鐢紒锛侊紒锛�', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2024-08-04 08:53:26', '0');
+INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (4, '娴嬭瘯娓犻亾', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2022-03-27 20:29:49', '0');
+INSERT INTO system_sms_channel (id, signature, code, status, remark, api_key, api_secret, callback_url, creator, create_time, updater, update_time, deleted) VALUES (7, 'mock鑵捐浜�', 'TENCENT', 0, '123', '1 2', '2 3', '', '1', '2024-09-30 08:53:45', '1', '2025-12-20 11:30:18', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_sms_channel_seq;
+CREATE SEQUENCE system_sms_channel_seq
+ START 8;
+
+-- ----------------------------
+-- Table structure for system_sms_code
+-- ----------------------------
+DROP TABLE IF EXISTS system_sms_code;
+CREATE TABLE system_sms_code (
+ id int8 NOT NULL,
+ mobile varchar(11) NOT NULL,
+ code varchar(6) NOT NULL,
+ create_ip varchar(15) NOT NULL,
+ scene int2 NOT NULL,
+ today_index int2 NOT NULL,
+ used int2 NOT NULL,
+ used_time timestamp NULL DEFAULT NULL,
+ used_ip varchar(255) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_sms_code ADD CONSTRAINT pk_system_sms_code PRIMARY KEY (id);
+
+CREATE INDEX idx_system_sms_code_01 ON system_sms_code (mobile);
+
+COMMENT ON COLUMN system_sms_code.id IS '缂栧彿';
+COMMENT ON COLUMN system_sms_code.mobile IS '鎵嬫満鍙�';
+COMMENT ON COLUMN system_sms_code.code IS '楠岃瘉鐮�';
+COMMENT ON COLUMN system_sms_code.create_ip IS '鍒涘缓 IP';
+COMMENT ON COLUMN system_sms_code.scene IS '鍙戦�佸満鏅�';
+COMMENT ON COLUMN system_sms_code.today_index IS '浠婃棩鍙戦�佺殑绗嚑鏉�';
+COMMENT ON COLUMN system_sms_code.used IS '鏄惁浣跨敤';
+COMMENT ON COLUMN system_sms_code.used_time IS '浣跨敤鏃堕棿';
+COMMENT ON COLUMN system_sms_code.used_ip IS '浣跨敤 IP';
+COMMENT ON COLUMN system_sms_code.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_sms_code.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_sms_code.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_sms_code.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_sms_code.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_sms_code.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_sms_code IS '鎵嬫満楠岃瘉鐮�';
+
+DROP SEQUENCE IF EXISTS system_sms_code_seq;
+CREATE SEQUENCE system_sms_code_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_sms_log
+-- ----------------------------
+DROP TABLE IF EXISTS system_sms_log;
+CREATE TABLE system_sms_log (
+ id int8 NOT NULL,
+ channel_id int8 NOT NULL,
+ channel_code varchar(63) NOT NULL,
+ template_id int8 NOT NULL,
+ template_code varchar(63) NOT NULL,
+ template_type int2 NOT NULL,
+ template_content varchar(255) NOT NULL,
+ template_params varchar(255) NOT NULL,
+ api_template_id varchar(63) NOT NULL,
+ mobile varchar(11) NOT NULL,
+ user_id int8 NULL DEFAULT NULL,
+ user_type int2 NULL DEFAULT NULL,
+ send_status int2 NOT NULL DEFAULT 0,
+ send_time timestamp NULL DEFAULT NULL,
+ api_send_code varchar(63) NULL DEFAULT NULL,
+ api_send_msg varchar(255) NULL DEFAULT NULL,
+ api_request_id varchar(255) NULL DEFAULT NULL,
+ api_serial_no varchar(255) NULL DEFAULT NULL,
+ receive_status int2 NOT NULL DEFAULT 0,
+ receive_time timestamp NULL DEFAULT NULL,
+ api_receive_code varchar(63) NULL DEFAULT NULL,
+ api_receive_msg varchar(255) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_sms_log ADD CONSTRAINT pk_system_sms_log PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_sms_log.id IS '缂栧彿';
+COMMENT ON COLUMN system_sms_log.channel_id IS '鐭俊娓犻亾缂栧彿';
+COMMENT ON COLUMN system_sms_log.channel_code IS '鐭俊娓犻亾缂栫爜';
+COMMENT ON COLUMN system_sms_log.template_id IS '妯℃澘缂栧彿';
+COMMENT ON COLUMN system_sms_log.template_code IS '妯℃澘缂栫爜';
+COMMENT ON COLUMN system_sms_log.template_type IS '鐭俊绫诲瀷';
+COMMENT ON COLUMN system_sms_log.template_content IS '鐭俊鍐呭';
+COMMENT ON COLUMN system_sms_log.template_params IS '鐭俊鍙傛暟';
+COMMENT ON COLUMN system_sms_log.api_template_id IS '鐭俊 API 鐨勬ā鏉跨紪鍙�';
+COMMENT ON COLUMN system_sms_log.mobile IS '鎵嬫満鍙�';
+COMMENT ON COLUMN system_sms_log.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_sms_log.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_sms_log.send_status IS '鍙戦�佺姸鎬�';
+COMMENT ON COLUMN system_sms_log.send_time IS '鍙戦�佹椂闂�';
+COMMENT ON COLUMN system_sms_log.api_send_code IS '鐭俊 API 鍙戦�佺粨鏋滅殑缂栫爜';
+COMMENT ON COLUMN system_sms_log.api_send_msg IS '鐭俊 API 鍙戦�佸け璐ョ殑鎻愮ず';
+COMMENT ON COLUMN system_sms_log.api_request_id IS '鐭俊 API 鍙戦�佽繑鍥炵殑鍞竴璇锋眰 ID';
+COMMENT ON COLUMN system_sms_log.api_serial_no IS '鐭俊 API 鍙戦�佽繑鍥炵殑搴忓彿';
+COMMENT ON COLUMN system_sms_log.receive_status IS '鎺ユ敹鐘舵��';
+COMMENT ON COLUMN system_sms_log.receive_time IS '鎺ユ敹鏃堕棿';
+COMMENT ON COLUMN system_sms_log.api_receive_code IS 'API 鎺ユ敹缁撴灉鐨勭紪鐮�';
+COMMENT ON COLUMN system_sms_log.api_receive_msg IS 'API 鎺ユ敹缁撴灉鐨勮鏄�';
+COMMENT ON COLUMN system_sms_log.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_sms_log.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_sms_log.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_sms_log.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_sms_log.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_sms_log IS '鐭俊鏃ュ織';
+
+DROP SEQUENCE IF EXISTS system_sms_log_seq;
+CREATE SEQUENCE system_sms_log_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_sms_template
+-- ----------------------------
+DROP TABLE IF EXISTS system_sms_template;
+CREATE TABLE system_sms_template (
+ id int8 NOT NULL,
+ type int2 NOT NULL,
+ status int2 NOT NULL,
+ code varchar(63) NOT NULL,
+ name varchar(63) NOT NULL,
+ content varchar(255) NOT NULL,
+ params varchar(255) NOT NULL,
+ remark varchar(255) NULL DEFAULT NULL,
+ api_template_id varchar(63) NOT NULL,
+ channel_id int8 NOT NULL,
+ channel_code varchar(63) NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_sms_template ADD CONSTRAINT pk_system_sms_template PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_sms_template.id IS '缂栧彿';
+COMMENT ON COLUMN system_sms_template.type IS '妯℃澘绫诲瀷';
+COMMENT ON COLUMN system_sms_template.status IS '寮�鍚姸鎬�';
+COMMENT ON COLUMN system_sms_template.code IS '妯℃澘缂栫爜';
+COMMENT ON COLUMN system_sms_template.name IS '妯℃澘鍚嶇О';
+COMMENT ON COLUMN system_sms_template.content IS '妯℃澘鍐呭';
+COMMENT ON COLUMN system_sms_template.params IS '鍙傛暟鏁扮粍';
+COMMENT ON COLUMN system_sms_template.remark IS '澶囨敞';
+COMMENT ON COLUMN system_sms_template.api_template_id IS '鐭俊 API 鐨勬ā鏉跨紪鍙�';
+COMMENT ON COLUMN system_sms_template.channel_id IS '鐭俊娓犻亾缂栧彿';
+COMMENT ON COLUMN system_sms_template.channel_code IS '鐭俊娓犻亾缂栫爜';
+COMMENT ON COLUMN system_sms_template.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_sms_template.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_sms_template.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_sms_template.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_sms_template.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_sms_template IS '鐭俊妯℃澘';
+
+-- ----------------------------
+-- Records of system_sms_template
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (2, 1, 0, 'test_01', '娴嬭瘯楠岃瘉鐮佺煭淇�', '姝e湪杩涜鐧诲綍鎿嶄綔{operation}锛屾偍鐨勯獙璇佺爜鏄瘂code}', '["operation","code"]', '娴嬭瘯澶囨敞', '4383920', 4, 'DEBUG_DING_TALK', '', '2021-03-31 10:49:38', '1', '2024-08-18 11:57:18', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (3, 1, 0, 'test_02', '鍏憡閫氱煡', '鎮ㄧ殑楠岃瘉鐮亄code}锛岃楠岃瘉鐮�5鍒嗛挓鍐呮湁鏁堬紝璇峰嬁娉勬紡浜庝粬浜猴紒', '["code"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (6, 3, 0, 'test-01', '娴嬭瘯妯℃澘', '鍝堝搱鍝� {name}', '["name"]', 'f鍝堝搱鍝�', '4383920', 4, 'DEBUG_DING_TALK', '1', '2021-04-10 01:07:21', '1', '2024-08-18 11:57:07', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (7, 3, 0, 'test-04', '娴嬭瘯涓�', '鑰侀浮{name}锛岀墰閫納code}', '["name","code"]', '鍝堝搱鍝堝搱', 'suibian', 7, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2024-09-30 00:56:24', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (8, 1, 0, 'user-sms-login', '鍓嶅彴鐢ㄦ埛鐭俊鐧诲綍', '鎮ㄧ殑楠岃瘉鐮佹槸{code}', '["code"]', NULL, '4372216', 4, 'DEBUG_DING_TALK', '1', '2021-10-11 08:10:00', '1', '2024-08-18 11:57:06', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (9, 2, 0, 'bpm_task_assigned', '銆愬伐浣滄祦銆戜换鍔¤鍒嗛厤', '鎮ㄦ敹鍒颁簡涓�鏉℃柊鐨勫緟鍔炰换鍔★細{processInstanceName}-{taskName}锛岀敵璇蜂汉锛歿startUserNickname}锛屽鐞嗛摼鎺ワ細{detailUrl}', '["processInstanceName","taskName","startUserNickname","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-21 22:31:19', '1', '2022-01-22 00:03:36', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (10, 2, 0, 'bpm_process_instance_reject', '銆愬伐浣滄祦銆戞祦绋嬭涓嶉�氳繃', '鎮ㄧ殑娴佺▼琚鎵逛笉閫氳繃锛歿processInstanceName}锛屽師鍥狅細{reason}锛屾煡鐪嬮摼鎺ワ細{detailUrl}', '["processInstanceName","reason","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:03:31', '1', '2022-05-01 12:33:14', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (11, 2, 0, 'bpm_process_instance_approve', '銆愬伐浣滄祦銆戞祦绋嬭閫氳繃', '鎮ㄧ殑娴佺▼琚鎵归�氳繃锛歿processInstanceName}锛屾煡鐪嬮摼鎺ワ細{detailUrl}', '["processInstanceName","detailUrl"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2022-01-22 00:04:31', '1', '2022-03-27 20:32:21', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (12, 2, 0, 'demo', '婕旂ず妯℃澘', '鎴戝氨鏄祴璇曚竴涓嬩笅', '[]', NULL, 'biubiubiu', 4, 'DEBUG_DING_TALK', '1', '2022-04-10 23:22:49', '1', '2024-08-18 11:57:04', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (14, 1, 0, 'user-update-mobile', '浼氬憳鐢ㄦ埛 - 淇敼鎵嬫満', '鎮ㄧ殑楠岃瘉鐮亄code}锛岃楠岃瘉鐮� 5 鍒嗛挓鍐呮湁鏁堬紝璇峰嬁娉勬紡浜庝粬浜猴紒', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:04', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (15, 1, 0, 'user-update-password', '浼氬憳鐢ㄦ埛 - 淇敼瀵嗙爜', '鎮ㄧ殑楠岃瘉鐮亄code}锛岃楠岃瘉鐮� 5 鍒嗛挓鍐呮湁鏁堬紝璇峰嬁娉勬紡浜庝粬浜猴紒', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-08-19 11:34:18', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (16, 1, 0, 'user-reset-password', '浼氬憳鐢ㄦ埛 - 閲嶇疆瀵嗙爜', '鎮ㄧ殑楠岃瘉鐮亄code}锛岃楠岃瘉鐮� 5 鍒嗛挓鍐呮湁鏁堬紝璇峰嬁娉勬紡浜庝粬浜猴紒', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2023-08-19 18:58:01', '1', '2023-12-02 22:35:27', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (17, 2, 0, 'bpm_task_timeout', '銆愬伐浣滄祦銆戜换鍔″鎵硅秴鏃�', '鎮ㄦ敹鍒颁簡涓�鏉¤秴鏃剁殑寰呭姙浠诲姟锛歿processInstanceName}-{taskName}锛屽鐞嗛摼鎺ワ細{detailUrl}', '["processInstanceName","taskName","detailUrl"]', '', 'X', 4, 'DEBUG_DING_TALK', '1', '2024-08-16 21:59:15', '1', '2024-08-16 21:59:34', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (18, 1, 0, 'admin-reset-password', '鍚庡彴鐢ㄦ埛 - 蹇樿瀵嗙爜', '鎮ㄧ殑楠岃瘉鐮亄code}锛岃楠岃瘉鐮� 5 鍒嗛挓鍐呮湁鏁堬紝璇峰嬁娉勬紡浜庝粬浜猴紒', '["code"]', '', 'null', 4, 'DEBUG_DING_TALK', '1', '2025-03-16 14:19:34', '1', '2025-03-16 14:19:45', '0');
+INSERT INTO system_sms_template (id, type, status, code, name, content, params, remark, api_template_id, channel_id, channel_code, creator, create_time, updater, update_time, deleted) VALUES (19, 1, 0, 'admin-sms-login', '鍚庡彴鐢ㄦ埛鐭俊鐧诲綍', '鎮ㄧ殑楠岃瘉鐮佹槸{code}', '["code"]', '', '4372216', 4, 'DEBUG_DING_TALK', '1', '2025-04-08 09:36:03', '1', '2025-04-08 09:36:17', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_sms_template_seq;
+CREATE SEQUENCE system_sms_template_seq
+ START 20;
+
+-- ----------------------------
+-- Table structure for system_social_client
+-- ----------------------------
+DROP TABLE IF EXISTS system_social_client;
+CREATE TABLE system_social_client (
+ id int8 NOT NULL,
+ name varchar(255) NOT NULL,
+ social_type int2 NOT NULL,
+ user_type int2 NOT NULL,
+ client_id varchar(255) NOT NULL,
+ client_secret varchar(255) NOT NULL,
+ agent_id varchar(255) NULL DEFAULT NULL,
+ public_key varchar(2048) NULL DEFAULT NULL,
+ status int2 NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_social_client ADD CONSTRAINT pk_system_social_client PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_social_client.id IS '缂栧彿';
+COMMENT ON COLUMN system_social_client.name IS '搴旂敤鍚�';
+COMMENT ON COLUMN system_social_client.social_type IS '绀句氦骞冲彴鐨勭被鍨�';
+COMMENT ON COLUMN system_social_client.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_social_client.client_id IS '瀹㈡埛绔紪鍙�';
+COMMENT ON COLUMN system_social_client.client_secret IS '瀹㈡埛绔瘑閽�';
+COMMENT ON COLUMN system_social_client.agent_id IS '浠g悊缂栧彿';
+COMMENT ON COLUMN system_social_client.public_key IS 'publicKey 鍏挜';
+COMMENT ON COLUMN system_social_client.status IS '鐘舵��';
+COMMENT ON COLUMN system_social_client.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_social_client.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_social_client.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_social_client.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_social_client.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_social_client.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_social_client IS '绀句氦瀹㈡埛绔〃';
+
+-- ----------------------------
+-- Records of system_social_client
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, public_key, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '閽夐拤', 20, 2, 'dingvrnreaje3yqvzhxg', 'i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI', NULL, NULL, 0, '', '2023-10-18 11:21:18', '1', '2023-12-20 21:28:26', '1', 1);
+INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, public_key, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '閽夐拤锛堢帇鍦熻眴锛�', 20, 2, 'dingtsu9hpepjkbmthhw', 'FP_bnSq_HAHKCSncmJjw5hxhnzs6vaVDSZZn3egj6rdqTQ_hu5tQVJyLMpgCakdP', NULL, NULL, 0, '', '2023-10-18 11:21:18', '', '2023-12-20 21:28:26', '1', 121);
+INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, public_key, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '寰俊鍏紬鍙�', 31, 1, 'wx5b23ba7a5589ecbb', '2a7b3b20c537e52e74afd395eb85f61f', NULL, NULL, 0, '', '2023-10-18 16:07:46', '1', '2023-12-20 21:28:23', '1', 1);
+INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, public_key, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (43, '寰俊灏忕▼搴�', 34, 1, 'wx63c280fe3248a3e7', '6f270509224a7ae1296bbf1c8cb97aed', NULL, NULL, 0, '', '2023-10-19 13:37:41', '1', '2023-12-20 21:28:25', '1', 1);
+INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, public_key, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (44, '1', 10, 1, '2', '3', NULL, NULL, 0, '1', '2025-04-06 20:36:28', '1', '2025-04-06 20:43:12', '1', 1);
+INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, public_key, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (45, '1', 10, 1, '2', '3', NULL, NULL, 1, '1', '2025-09-06 20:26:15', '1', '2025-09-06 20:27:55', '1', 1);
+INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, public_key, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (46, '1', 10, 1, '2', '3', NULL, NULL, 0, '1', '2025-11-29 16:04:23', '1', '2025-11-29 16:04:26', '1', 1);
+INSERT INTO system_social_client (id, name, social_type, user_type, client_id, client_secret, agent_id, public_key, status, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (47, '123', 10, 1, '1', '2', '3', NULL, 0, '1', '2025-12-21 10:27:02', '1', '2025-12-21 10:27:20', '1', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_social_client_seq;
+CREATE SEQUENCE system_social_client_seq
+ START 48;
+
+-- ----------------------------
+-- Table structure for system_social_user
+-- ----------------------------
+DROP TABLE IF EXISTS system_social_user;
+CREATE TABLE system_social_user (
+ id int8 NOT NULL,
+ type int2 NOT NULL,
+ openid varchar(32) NOT NULL,
+ token varchar(256) NULL DEFAULT NULL,
+ raw_token_info varchar(1024) NOT NULL,
+ nickname varchar(32) NOT NULL,
+ avatar varchar(255) NULL DEFAULT NULL,
+ raw_user_info varchar(1024) NOT NULL,
+ code varchar(256) NOT NULL,
+ state varchar(256) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_social_user ADD CONSTRAINT pk_system_social_user PRIMARY KEY (id);
+
+CREATE INDEX idx_system_social_user_01 ON system_social_user (type, openid);
+CREATE INDEX idx_system_social_user_02 ON system_social_user (type, code, state);
+
+COMMENT ON COLUMN system_social_user.id IS '涓婚敭(鑷绛栫暐)';
+COMMENT ON COLUMN system_social_user.type IS '绀句氦骞冲彴鐨勭被鍨�';
+COMMENT ON COLUMN system_social_user.openid IS '绀句氦 openid';
+COMMENT ON COLUMN system_social_user.token IS '绀句氦 token';
+COMMENT ON COLUMN system_social_user.raw_token_info IS '鍘熷 Token 鏁版嵁锛屼竴鑸槸 JSON 鏍煎紡';
+COMMENT ON COLUMN system_social_user.nickname IS '鐢ㄦ埛鏄电О';
+COMMENT ON COLUMN system_social_user.avatar IS '鐢ㄦ埛澶村儚';
+COMMENT ON COLUMN system_social_user.raw_user_info IS '鍘熷鐢ㄦ埛鏁版嵁锛屼竴鑸槸 JSON 鏍煎紡';
+COMMENT ON COLUMN system_social_user.code IS '鏈�鍚庝竴娆$殑璁よ瘉 code';
+COMMENT ON COLUMN system_social_user.state IS '鏈�鍚庝竴娆$殑璁よ瘉 state';
+COMMENT ON COLUMN system_social_user.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_social_user.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_social_user.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_social_user.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_social_user.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_social_user.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_social_user IS '绀句氦鐢ㄦ埛琛�';
+
+DROP SEQUENCE IF EXISTS system_social_user_seq;
+CREATE SEQUENCE system_social_user_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_social_user_bind
+-- ----------------------------
+DROP TABLE IF EXISTS system_social_user_bind;
+CREATE TABLE system_social_user_bind (
+ id int8 NOT NULL,
+ user_id int8 NOT NULL,
+ user_type int2 NOT NULL,
+ social_type int2 NOT NULL,
+ social_user_id int8 NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_social_user_bind ADD CONSTRAINT pk_system_social_user_bind PRIMARY KEY (id);
+
+CREATE INDEX idx_system_social_user_bind_01 ON system_social_user_bind (user_type, social_user_id);
+
+COMMENT ON COLUMN system_social_user_bind.id IS '涓婚敭(鑷绛栫暐)';
+COMMENT ON COLUMN system_social_user_bind.user_id IS '鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_social_user_bind.user_type IS '鐢ㄦ埛绫诲瀷';
+COMMENT ON COLUMN system_social_user_bind.social_type IS '绀句氦骞冲彴鐨勭被鍨�';
+COMMENT ON COLUMN system_social_user_bind.social_user_id IS '绀句氦鐢ㄦ埛鐨勭紪鍙�';
+COMMENT ON COLUMN system_social_user_bind.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_social_user_bind.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_social_user_bind.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_social_user_bind.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_social_user_bind.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_social_user_bind.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_social_user_bind IS '绀句氦缁戝畾琛�';
+
+DROP SEQUENCE IF EXISTS system_social_user_bind_seq;
+CREATE SEQUENCE system_social_user_bind_seq
+ START 1;
+
+-- ----------------------------
+-- Table structure for system_tenant
+-- ----------------------------
+DROP TABLE IF EXISTS system_tenant;
+CREATE TABLE system_tenant (
+ id int8 NOT NULL,
+ name varchar(30) NOT NULL,
+ contact_user_id int8 NULL DEFAULT NULL,
+ contact_name varchar(30) NOT NULL,
+ contact_mobile varchar(500) NULL DEFAULT NULL,
+ status int2 NOT NULL DEFAULT 0,
+ websites varchar(1024) NULL DEFAULT '',
+ package_id int8 NOT NULL,
+ expire_time timestamp NOT NULL,
+ account_count int4 NOT NULL,
+ creator varchar(64) NOT NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_tenant ADD CONSTRAINT pk_system_tenant PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_tenant.id IS '绉熸埛缂栧彿';
+COMMENT ON COLUMN system_tenant.name IS '绉熸埛鍚�';
+COMMENT ON COLUMN system_tenant.contact_user_id IS '鑱旂郴浜虹殑鐢ㄦ埛缂栧彿';
+COMMENT ON COLUMN system_tenant.contact_name IS '鑱旂郴浜�';
+COMMENT ON COLUMN system_tenant.contact_mobile IS '鑱旂郴鎵嬫満';
+COMMENT ON COLUMN system_tenant.status IS '绉熸埛鐘舵��';
+COMMENT ON COLUMN system_tenant.websites IS '缁戝畾鍩熷悕鏁扮粍';
+COMMENT ON COLUMN system_tenant.package_id IS '绉熸埛濂楅缂栧彿';
+COMMENT ON COLUMN system_tenant.expire_time IS '杩囨湡鏃堕棿';
+COMMENT ON COLUMN system_tenant.account_count IS '璐﹀彿鏁伴噺';
+COMMENT ON COLUMN system_tenant.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_tenant.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_tenant.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_tenant.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_tenant.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_tenant IS '绉熸埛琛�';
+
+-- ----------------------------
+-- Records of system_tenant
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (1, '鑺嬮亾婧愮爜', NULL, '鑺嬭壙', '17321315478', 0, 'www.iocoder.cn,127.0.0.1:3000,wxc4598c446f8a9cb3', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2025-08-19 05:18:41', '0');
+INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (121, '灏忕鎴�', 110, '灏忕帇2', '15601691300', 0, 'zsxq.iocoder.cn,123321', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-08-19 21:19:29', '0');
+INSERT INTO system_tenant (id, name, contact_user_id, contact_name, contact_mobile, status, websites, package_id, expire_time, account_count, creator, create_time, updater, update_time, deleted) VALUES (122, '娴嬭瘯绉熸埛', 113, '鑺嬮亾', '15601691300', 0, 'test.iocoder.cn,222,333', 111, '2023-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2025-12-21 09:50:00', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_tenant_seq;
+CREATE SEQUENCE system_tenant_seq
+ START 123;
+
+-- ----------------------------
+-- Table structure for system_tenant_package
+-- ----------------------------
+DROP TABLE IF EXISTS system_tenant_package;
+CREATE TABLE system_tenant_package (
+ id int8 NOT NULL,
+ name varchar(30) NOT NULL,
+ status int2 NOT NULL DEFAULT 0,
+ remark varchar(256) NULL DEFAULT '',
+ menu_ids varchar(4096) NOT NULL,
+ creator varchar(64) NOT NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_tenant_package ADD CONSTRAINT pk_system_tenant_package PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_tenant_package.id IS '濂楅缂栧彿';
+COMMENT ON COLUMN system_tenant_package.name IS '濂楅鍚�';
+COMMENT ON COLUMN system_tenant_package.status IS '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+COMMENT ON COLUMN system_tenant_package.remark IS '澶囨敞';
+COMMENT ON COLUMN system_tenant_package.menu_ids IS '鍏宠仈鐨勮彍鍗曠紪鍙�';
+COMMENT ON COLUMN system_tenant_package.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_tenant_package.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_tenant_package.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_tenant_package.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_tenant_package.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON TABLE system_tenant_package IS '绉熸埛濂楅琛�';
+
+-- ----------------------------
+-- Records of system_tenant_package
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_tenant_package (id, name, status, remark, menu_ids, creator, create_time, updater, update_time, deleted) VALUES (111, '鏅�氬椁�', 0, '灏忓姛鑳�', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1117,1118,1119,1120,100,101,102,1126,103,1127,1128,1129,106,1130,107,1132,1133,110,1134,111,1135,112,1136,113,1137,2161,114,1138,1139,115,1140,116,1141,1142,1143,1150,1161,1162,1166,1173,1174,2713,2714,1178,2715,2716,2717,2718,2720,2721,1185,2722,1186,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,1192,2728,2729,1193,1194,2730,1195,2731,2732,1197,2733,1198,2734,1199,2735,1200,1201,1202,2739,2740,1207,1208,1209,2745,1210,2746,1211,2747,1212,2748,1213,1215,1216,1217,1218,1219,1220,2756,1221,2757,1222,1224,1225,1226,1227,1228,1229,1237,1238,2262,1239,1240,1241,1242,1243,2275,2276,2277,1255,1256,1257,2281,1258,2282,1259,2283,1260,2284,2285,2287,2288,2293,2294,2297,2300,2301,2302,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2363,2364,5011,5012,2472,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2497,2525,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,2549,1014,2550,1015,2551,1016,2552,1017,2553,1018,2554,1019,2555,1020,2556,2557,2558,2559]', '1', '2022-02-22 00:54:00', '1', '2025-09-06 20:52:25', '0');
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_tenant_package_seq;
+CREATE SEQUENCE system_tenant_package_seq
+ START 112;
+
+-- ----------------------------
+-- Table structure for system_user_post
+-- ----------------------------
+DROP TABLE IF EXISTS system_user_post;
+CREATE TABLE system_user_post (
+ id int8 NOT NULL,
+ user_id int8 NOT NULL DEFAULT 0,
+ post_id int8 NOT NULL DEFAULT 0,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_user_post ADD CONSTRAINT pk_system_user_post PRIMARY KEY (id);
+
+COMMENT ON COLUMN system_user_post.id IS 'id';
+COMMENT ON COLUMN system_user_post.user_id IS '鐢ㄦ埛ID';
+COMMENT ON COLUMN system_user_post.post_id IS '宀椾綅ID';
+COMMENT ON COLUMN system_user_post.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_user_post.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_user_post.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_user_post.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_user_post.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_user_post.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_user_post IS '鐢ㄦ埛宀椾綅琛�';
+
+-- ----------------------------
+-- Records of system_user_post
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 1, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 100, 1, 'admin', '2022-05-02 07:25:24', 'admin', '2022-05-02 07:25:24', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 104, 1, '1', '2022-05-16 19:36:28', '1', '2022-05-16 19:36:28', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (116, 117, 2, '1', '2022-07-09 17:40:26', '1', '2022-07-09 17:40:26', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 118, 1, '1', '2022-07-09 17:44:44', '1', '2022-07-09 17:44:44', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (119, 114, 5, '1', '2024-03-24 20:45:51', '1', '2024-03-24 20:45:51', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (123, 115, 1, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (124, 115, 2, '1', '2024-04-04 09:37:14', '1', '2024-04-04 09:37:14', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (125, 1, 2, '1', '2024-07-13 22:31:39', '1', '2024-07-13 22:31:39', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (128, 139, 2, '1', '2025-12-05 21:43:27', '1', '2025-12-05 21:43:27', '0', 1);
+INSERT INTO system_user_post (id, user_id, post_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (129, 139, 4, '1', '2025-12-05 21:43:27', '1', '2025-12-05 21:43:27', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_user_post_seq;
+CREATE SEQUENCE system_user_post_seq
+ START 130;
+
+-- ----------------------------
+-- Table structure for system_user_role
+-- ----------------------------
+DROP TABLE IF EXISTS system_user_role;
+CREATE TABLE system_user_role (
+ id int8 NOT NULL,
+ user_id int8 NOT NULL,
+ role_id int8 NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_user_role ADD CONSTRAINT pk_system_user_role PRIMARY KEY (id);
+
+CREATE INDEX idx_system_user_role_01 ON system_user_role (user_id);
+
+COMMENT ON COLUMN system_user_role.id IS '鑷缂栧彿';
+COMMENT ON COLUMN system_user_role.user_id IS '鐢ㄦ埛ID';
+COMMENT ON COLUMN system_user_role.role_id IS '瑙掕壊ID';
+COMMENT ON COLUMN system_user_role.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_user_role.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_user_role.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_user_role.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_user_role.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_user_role.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_user_role IS '鐢ㄦ埛鍜岃鑹插叧鑱旇〃';
+
+-- ----------------------------
+-- Records of system_user_role
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 1, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:17', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:13', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, 100, 1, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:12', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 100, 2, '', '2022-01-11 13:19:45', '', '2022-05-12 12:35:11', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 103, 1, '1', '2022-01-11 13:19:45', '1', '2022-01-11 13:19:45', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (14, 110, 109, '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', '0', 121);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (15, 111, 110, '110', '2022-02-23 13:14:38', '110', '2022-02-23 13:14:38', '0', 121);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (16, 113, 111, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', '0', 122);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (18, 1, 2, '1', '2022-05-12 20:39:29', '1', '2022-05-12 20:39:29', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (22, 115, 2, '1', '2022-07-21 22:08:30', '1', '2022-07-21 22:08:30', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (35, 112, 1, '1', '2024-03-15 20:00:24', '1', '2024-03-15 20:00:24', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (36, 118, 1, '1', '2024-03-17 09:12:08', '1', '2024-03-17 09:12:08', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (46, 117, 1, '1', '2024-10-02 10:16:11', '1', '2024-10-02 10:16:11', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (47, 104, 2, '1', '2025-01-04 10:40:33', '1', '2025-01-04 10:40:33', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (48, 100, 155, '1', '2025-04-04 10:41:14', '1', '2025-04-04 10:41:14', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (49, 142, 1, '1', '2025-07-23 09:11:42', '1', '2025-07-23 09:11:42', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (50, 142, 2, '1', '2025-10-07 20:50:37', '1', '2025-10-07 20:50:37', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (51, 139, 1, '1', '2025-12-05 22:36:57', '1', '2025-12-05 22:36:57', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (52, 139, 2, '1', '2025-12-05 22:37:00', '1', '2025-12-05 22:37:00', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (53, 114, 2, '1', '2026-01-04 18:15:40', '1', '2026-01-04 18:15:40', '0', 1);
+INSERT INTO system_user_role (id, user_id, role_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (54, 114, 3, '1', '2026-01-04 18:16:19', '1', '2026-01-04 18:16:19', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_user_role_seq;
+CREATE SEQUENCE system_user_role_seq
+ START 55;
+
+-- ----------------------------
+-- Table structure for system_users
+-- ----------------------------
+DROP TABLE IF EXISTS system_users;
+CREATE TABLE system_users (
+ id int8 NOT NULL,
+ username varchar(30) NOT NULL,
+ password varchar(100) NOT NULL DEFAULT '',
+ nickname varchar(30) NOT NULL,
+ remark varchar(500) NULL DEFAULT NULL,
+ dept_id int8 NULL DEFAULT NULL,
+ post_ids varchar(255) NULL DEFAULT NULL,
+ email varchar(50) NULL DEFAULT '',
+ mobile varchar(11) NULL DEFAULT '',
+ sex int2 NULL DEFAULT 0,
+ avatar varchar(512) NULL DEFAULT '',
+ status int2 NOT NULL DEFAULT 0,
+ login_ip varchar(50) NULL DEFAULT '',
+ login_date timestamp NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE system_users ADD CONSTRAINT pk_system_users PRIMARY KEY (id);
+
+CREATE INDEX idx_system_users_01 ON system_users (username);
+CREATE INDEX idx_system_users_02 ON system_users (mobile);
+CREATE INDEX idx_system_users_03 ON system_users (email);
+CREATE INDEX idx_system_users_04 ON system_users (dept_id);
+
+COMMENT ON COLUMN system_users.id IS '鐢ㄦ埛ID';
+COMMENT ON COLUMN system_users.username IS '鐢ㄦ埛璐﹀彿';
+COMMENT ON COLUMN system_users.password IS '瀵嗙爜';
+COMMENT ON COLUMN system_users.nickname IS '鐢ㄦ埛鏄电О';
+COMMENT ON COLUMN system_users.remark IS '澶囨敞';
+COMMENT ON COLUMN system_users.dept_id IS '閮ㄩ棬ID';
+COMMENT ON COLUMN system_users.post_ids IS '宀椾綅缂栧彿鏁扮粍';
+COMMENT ON COLUMN system_users.email IS '鐢ㄦ埛閭';
+COMMENT ON COLUMN system_users.mobile IS '鎵嬫満鍙风爜';
+COMMENT ON COLUMN system_users.sex IS '鐢ㄦ埛鎬у埆';
+COMMENT ON COLUMN system_users.avatar IS '澶村儚鍦板潃';
+COMMENT ON COLUMN system_users.status IS '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+COMMENT ON COLUMN system_users.login_ip IS '鏈�鍚庣櫥褰旾P';
+COMMENT ON COLUMN system_users.login_date IS '鏈�鍚庣櫥褰曟椂闂�';
+COMMENT ON COLUMN system_users.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN system_users.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN system_users.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN system_users.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN system_users.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN system_users.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE system_users IS '鐢ㄦ埛淇℃伅琛�';
+
+-- ----------------------------
+-- Records of system_users
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, 'admin', '$2a$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '鑺嬮亾婧愮爜', '绠$悊鍛�', 103, '[1,2]', '13aoteman@126.com', '18818260272', 1, 'http://test.yudao.iocoder.cn/20260517/blob_1778998103688.png', 0, '0:0:0:0:0:0:0:1', '2026-05-31 21:54:49', 'admin', '2021-01-05 17:03:47', NULL, '2026-05-31 21:54:49', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (100, 'yudao', '$2a$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '鑺嬮亾', '涓嶈鍚撴垜', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-04-19 17:40:55', '', '2021-01-07 09:07:17', NULL, '2026-04-19 17:40:55', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (103, 'yuanma', '$2a$04$k/d6mc0nySN0i2udwcI8Ee8V5aM5OHixBRbQfXmPuFTUl3Zf/DBs.', '婧愮爜', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2026-04-27 13:19:27', '', '2021-01-13 23:50:35', NULL, '2026-04-27 13:19:27', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (104, 'test', '$2a$04$BrwaYn303hjA/6TnXqdGoOLhyHOAA0bVrAFu6.1dJKycqKUnIoRz2', '娴嬭瘯鍙�', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-05-20 23:37:11', '', '2021-01-21 02:13:53', NULL, '2026-05-20 23:37:11', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '鑺嬭壙', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2025-04-21 14:23:08', '0', 118);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '鑺嬭壙', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2025-04-21 14:23:08', '0', 119);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '鑺嬭壙', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2025-04-21 14:23:08', '0', 120);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '灏忕帇', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2024-07-20 22:23:17', '1', '2022-02-22 00:56:14', NULL, '2025-04-21 14:23:08', '0', 121);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '娴嬭瘯鐢ㄦ埛', NULL, NULL, '[]', '', '', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:42:17', '110', '2022-02-23 13:14:33', NULL, '2025-04-21 14:23:08', '0', 121);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '鏂板璞�', NULL, 100, '[]', '', '15601691235', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-03-16 23:11:38', '1', '2022-02-23 19:08:03', NULL, '2025-04-21 14:23:08', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '鑺嬮亾1', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', '1', '2025-05-05 15:30:53', '0', 122);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 灏忓濮�', NULL, NULL, '[5]', '', '15601691236', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-01-04 18:16:01', '1', '2022-03-19 21:50:58', NULL, '2026-01-04 18:16:01', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '闃垮憜', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, NULL, 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2025-04-21 14:23:08', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (117, 'admin123', '$2a$04$sEtimsHu9YCkYY4/oqElHem2Ijc9ld20eYO6lN.g/21NfLUTDLB9W', '娴嬭瘯鍙�02', '1111', 100, '[2]', '', '15601691234', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-10-02 10:16:20', '1', '2022-07-09 17:40:26', '1', '2025-05-14 09:56:04', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (118, 'goudan', '$2a$04$3suGZjnA6rM5bErf38u1felbgqbsPHGdRG3l9NkxPCEt2ah9Y6aJi', '鐙楄泲', NULL, 103, '[1]', '', '15601691239', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2025-11-23 15:28:25', '1', '2022-07-09 17:44:43', NULL, '2025-11-23 15:28:25', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (139, 'wwbwwb', '$2a$04$FJLIyg8lbPytP29pbZaiU.LesJvCsYfEaHqQfB0pGQhK3e9BeZmLy', '灏忕澶�', '123', 108, '[2,4]', '', '', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-09-10 21:03:58', NULL, '2024-09-10 21:03:58', '1', '2025-12-15 22:38:15', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (141, 'admin1', '$2a$04$oj6F6d7HrZ70kYVD3TNzEu.m3TPUzajOVuC66zdKna8KRerK1FmVa', '鏂扮敤鎴�', NULL, NULL, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2025-04-08 13:09:07', '1', '2025-04-08 13:09:07', '1', '2025-05-14 19:11:48', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (142, 'test01', '$2a$04$4bCYWZkjxxOC4QE0LY2M9uEEKWeJbLfs489NFtQoyidL5I0FndRaO', 'test01', '', NULL, '[]', '', '19021719925', 1, '', 0, '0:0:0:0:0:0:0:1', '2025-07-29 19:47:17', '1', '2025-07-09 21:07:10', NULL, '2025-12-02 13:23:11', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (143, 'a00001', '$2a$04$GhVHFviOw/SsTmiQtifHJesDYFlHMeGK7OWh7aGCCjGGVCmbHVAwa', 'a00001', NULL, 104, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2025-12-01 16:10:13', NULL, '2025-12-01 16:10:13', '1', '2025-12-05 21:34:05', '0', 1);
+INSERT INTO system_users (id, username, password, nickname, remark, dept_id, post_ids, email, mobile, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (144, 'aoteman001', '$2a$04$omQOmhz8OyUFBKw77nr8KOtMp6xdvoQ1gWStjk9r8.OYT3Bv6oEYe', 'aoteman001', NULL, 104, NULL, '', '', 0, '', 1, '0:0:0:0:0:0:0:1', '2025-12-01 17:05:27', '1', '2025-12-01 17:05:27', '1', '2026-05-31 21:52:48', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS system_users_seq;
+CREATE SEQUENCE system_users_seq
+ START 145;
+
+-- ----------------------------
+-- Table structure for yudao_demo01_contact
+-- ----------------------------
+DROP TABLE IF EXISTS yudao_demo01_contact;
+CREATE TABLE yudao_demo01_contact (
+ id int8 NOT NULL,
+ name varchar(100) NOT NULL DEFAULT '',
+ sex int2 NOT NULL,
+ birthday timestamp NOT NULL,
+ description varchar(255) NOT NULL,
+ avatar varchar(512) NULL DEFAULT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE yudao_demo01_contact ADD CONSTRAINT pk_yudao_demo01_contact PRIMARY KEY (id);
+
+COMMENT ON COLUMN yudao_demo01_contact.id IS '缂栧彿';
+COMMENT ON COLUMN yudao_demo01_contact.name IS '鍚嶅瓧';
+COMMENT ON COLUMN yudao_demo01_contact.sex IS '鎬у埆';
+COMMENT ON COLUMN yudao_demo01_contact.birthday IS '鍑虹敓骞�';
+COMMENT ON COLUMN yudao_demo01_contact.description IS '绠�浠�';
+COMMENT ON COLUMN yudao_demo01_contact.avatar IS '澶村儚';
+COMMENT ON COLUMN yudao_demo01_contact.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN yudao_demo01_contact.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN yudao_demo01_contact.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN yudao_demo01_contact.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN yudao_demo01_contact.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN yudao_demo01_contact.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE yudao_demo01_contact IS '绀轰緥鑱旂郴浜鸿〃';
+
+-- ----------------------------
+-- Records of yudao_demo01_contact
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO yudao_demo01_contact (id, name, sex, birthday, description, avatar, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '鍦熻眴', 2, '2023-11-07 00:00:00', '<p>澶╄殨鍦熻眴锛佸憖</p>', 'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', '1', '2023-11-15 23:34:30', '1', '2023-11-15 23:47:39', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS yudao_demo01_contact_seq;
+CREATE SEQUENCE yudao_demo01_contact_seq
+ START 2;
+
+-- ----------------------------
+-- Table structure for yudao_demo02_category
+-- ----------------------------
+DROP TABLE IF EXISTS yudao_demo02_category;
+CREATE TABLE yudao_demo02_category (
+ id int8 NOT NULL,
+ name varchar(100) NOT NULL DEFAULT '',
+ parent_id int8 NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE yudao_demo02_category ADD CONSTRAINT pk_yudao_demo02_category PRIMARY KEY (id);
+
+COMMENT ON COLUMN yudao_demo02_category.id IS '缂栧彿';
+COMMENT ON COLUMN yudao_demo02_category.name IS '鍚嶅瓧';
+COMMENT ON COLUMN yudao_demo02_category.parent_id IS '鐖剁骇缂栧彿';
+COMMENT ON COLUMN yudao_demo02_category.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN yudao_demo02_category.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN yudao_demo02_category.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN yudao_demo02_category.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN yudao_demo02_category.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN yudao_demo02_category.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE yudao_demo02_category IS '绀轰緥鍒嗙被琛�';
+
+-- ----------------------------
+-- Records of yudao_demo02_category
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (1, '鍦熻眴', 0, '1', '2023-11-15 23:34:30', '1', '2023-11-16 20:24:23', '0', 1);
+INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '鐣寗', 0, '1', '2023-11-16 20:24:00', '1', '2023-11-16 20:24:15', '0', 1);
+INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, '鎬��', 0, '1', '2023-11-16 20:24:32', '1', '2023-11-16 20:24:32', '0', 1);
+INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (4, '灏忕暘鑼�', 2, '1', '2023-11-16 20:24:39', '1', '2023-11-16 20:24:39', '0', 1);
+INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '澶х暘鑼�', 2, '1', '2023-11-16 20:24:46', '1', '2023-11-16 20:24:46', '0', 1);
+INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, '11', 3, '1', '2023-11-24 19:29:34', '1', '2023-11-24 19:29:34', '0', 1);
+INSERT INTO yudao_demo02_category (id, name, parent_id, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, '1', 0, '1', '2025-10-01 09:19:20', '1', '2025-10-01 09:19:20', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS yudao_demo02_category_seq;
+CREATE SEQUENCE yudao_demo02_category_seq
+ START 8;
+
+-- ----------------------------
+-- Table structure for yudao_demo03_course
+-- ----------------------------
+DROP TABLE IF EXISTS yudao_demo03_course;
+CREATE TABLE yudao_demo03_course (
+ id int8 NOT NULL,
+ student_id int8 NOT NULL,
+ name varchar(100) NOT NULL DEFAULT '',
+ score int2 NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE yudao_demo03_course ADD CONSTRAINT pk_yudao_demo03_course PRIMARY KEY (id);
+
+COMMENT ON COLUMN yudao_demo03_course.id IS '缂栧彿';
+COMMENT ON COLUMN yudao_demo03_course.student_id IS '瀛︾敓缂栧彿';
+COMMENT ON COLUMN yudao_demo03_course.name IS '鍚嶅瓧';
+COMMENT ON COLUMN yudao_demo03_course.score IS '鍒嗘暟';
+COMMENT ON COLUMN yudao_demo03_course.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN yudao_demo03_course.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN yudao_demo03_course.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN yudao_demo03_course.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN yudao_demo03_course.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN yudao_demo03_course.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE yudao_demo03_course IS '瀛︾敓璇剧▼琛�';
+
+-- ----------------------------
+-- Records of yudao_demo03_course
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, 2, '璇枃', 66, '1', '2023-11-16 23:21:49', '1', '2024-09-17 10:55:30', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (3, 2, '鏁板', 22, '1', '2023-11-16 23:21:49', '1', '2024-09-17 10:55:30', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (6, 5, '浣撹偛', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 5, '璁$畻鏈�', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '浣撹偛', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 5, '璁$畻鏈�', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (10, 5, '浣撹偛', 23, '1', '2023-11-16 23:22:46', '1', '2024-09-17 10:55:28', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (11, 5, '璁$畻鏈�', 11, '1', '2023-11-16 23:22:46', '1', '2024-09-17 10:55:28', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (12, 2, '鐢佃剳', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (13, 9, '婊戦洩', 12, '1', '2023-11-17 13:13:20', '1', '2024-09-17 10:55:26', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (14, 9, '婊戦洩', 12, '1', '2023-11-17 13:13:20', '1', '2024-09-17 10:55:49', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (15, 5, '浣撹偛', 23, '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', '0', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (16, 5, '璁$畻鏈�', 11, '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', '0', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (17, 2, '璇枃', 66, '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', '0', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (18, 2, '鏁板', 22, '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', '0', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (19, 9, '婊戦洩', 12, '1', '2023-11-17 13:13:20', '1', '2025-04-19 02:49:03', '1', 1);
+INSERT INTO yudao_demo03_course (id, student_id, name, score, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (20, 9, '婊戦洩', 12, '1', '2023-11-17 13:13:20', '1', '2025-04-19 10:49:04', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS yudao_demo03_course_seq;
+CREATE SEQUENCE yudao_demo03_course_seq
+ START 21;
+
+-- ----------------------------
+-- Table structure for yudao_demo03_grade
+-- ----------------------------
+DROP TABLE IF EXISTS yudao_demo03_grade;
+CREATE TABLE yudao_demo03_grade (
+ id int8 NOT NULL,
+ student_id int8 NOT NULL,
+ name varchar(100) NOT NULL DEFAULT '',
+ teacher varchar(255) NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE yudao_demo03_grade ADD CONSTRAINT pk_yudao_demo03_grade PRIMARY KEY (id);
+
+COMMENT ON COLUMN yudao_demo03_grade.id IS '缂栧彿';
+COMMENT ON COLUMN yudao_demo03_grade.student_id IS '瀛︾敓缂栧彿';
+COMMENT ON COLUMN yudao_demo03_grade.name IS '鍚嶅瓧';
+COMMENT ON COLUMN yudao_demo03_grade.teacher IS '鐝富浠�';
+COMMENT ON COLUMN yudao_demo03_grade.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN yudao_demo03_grade.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN yudao_demo03_grade.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN yudao_demo03_grade.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN yudao_demo03_grade.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN yudao_demo03_grade.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE yudao_demo03_grade IS '瀛︾敓鐝骇琛�';
+
+-- ----------------------------
+-- Records of yudao_demo03_grade
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (7, 2, '涓夊勾 2 鐝�', '鍛ㄦ澃浼�', '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', '0', 1);
+INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (8, 5, '鍗庝负', '閬ラ仴棰嗗厛', '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', '0', 1);
+INSERT INTO yudao_demo03_grade (id, student_id, name, teacher, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, 9, '灏忓浘', '灏忓▋111', '1', '2023-11-17 13:10:23', '1', '2025-04-19 10:49:04', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS yudao_demo03_grade_seq;
+CREATE SEQUENCE yudao_demo03_grade_seq
+ START 10;
+
+-- ----------------------------
+-- Table structure for yudao_demo03_student
+-- ----------------------------
+DROP TABLE IF EXISTS yudao_demo03_student;
+CREATE TABLE yudao_demo03_student (
+ id int8 NOT NULL,
+ name varchar(100) NOT NULL DEFAULT '',
+ sex int2 NOT NULL,
+ birthday timestamp NOT NULL,
+ description varchar(255) NOT NULL,
+ creator varchar(64) NULL DEFAULT '',
+ create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updater varchar(64) NULL DEFAULT '',
+ update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ deleted int2 NOT NULL DEFAULT 0,
+ tenant_id int8 NOT NULL DEFAULT 0
+);
+
+ALTER TABLE yudao_demo03_student ADD CONSTRAINT pk_yudao_demo03_student PRIMARY KEY (id);
+
+COMMENT ON COLUMN yudao_demo03_student.id IS '缂栧彿';
+COMMENT ON COLUMN yudao_demo03_student.name IS '鍚嶅瓧';
+COMMENT ON COLUMN yudao_demo03_student.sex IS '鎬у埆';
+COMMENT ON COLUMN yudao_demo03_student.birthday IS '鍑虹敓鏃ユ湡';
+COMMENT ON COLUMN yudao_demo03_student.description IS '绠�浠�';
+COMMENT ON COLUMN yudao_demo03_student.creator IS '鍒涘缓鑰�';
+COMMENT ON COLUMN yudao_demo03_student.create_time IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN yudao_demo03_student.updater IS '鏇存柊鑰�';
+COMMENT ON COLUMN yudao_demo03_student.update_time IS '鏇存柊鏃堕棿';
+COMMENT ON COLUMN yudao_demo03_student.deleted IS '鏄惁鍒犻櫎';
+COMMENT ON COLUMN yudao_demo03_student.tenant_id IS '绉熸埛缂栧彿';
+COMMENT ON TABLE yudao_demo03_student IS '瀛︾敓琛�';
+
+-- ----------------------------
+-- Records of yudao_demo03_student
+-- ----------------------------
+-- @formatter:off
+BEGIN;
+INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (2, '灏忕櫧', 1, '2023-11-16 00:00:00', '<p>鍘夊</p>', '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', '0', 1);
+INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (5, '澶ч粦', 2, '2023-11-13 00:00:00', '<p>浣犲湪鏁欐垜鍋氫簨?</p>', '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', '0', 1);
+INSERT INTO yudao_demo03_student (id, name, sex, birthday, description, creator, create_time, updater, update_time, deleted, tenant_id) VALUES (9, '灏忚姳', 1, '2023-11-07 00:00:00', '<p>鍝堝搱鍝�</p>', '1', '2023-11-17 00:04:47', '1', '2025-04-19 10:49:04', '0', 1);
+COMMIT;
+-- @formatter:on
+
+DROP SEQUENCE IF EXISTS yudao_demo03_student_seq;
+CREATE SEQUENCE yudao_demo03_student_seq
+ START 10;
+
diff --git a/sql/kingbase/ruoyi-vue-pro.sql b/sql/kingbase/ruoyi-vue-pro.sql
index ec0251a..b0e0ed0 100644
--- a/sql/kingbase/ruoyi-vue-pro.sql
+++ b/sql/kingbase/ruoyi-vue-pro.sql
@@ -1371,6 +1371,8 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '鏀粯瀹濆皬绋嬪簭', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3036, 60, 'Admin Uniapp 绉诲姩绔�', '60', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-12-16 19:25:51', '1', '2025-12-17 09:46:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3037, 42, 'Vben5.0 Antdv Next Schema 妯$増', '42', 'infra_codegen_front_type', 0, '', '', '', '1', NOW(), '1', NOW(), '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3038, 43, 'Vben5.0 Antdv Next 鏍囧噯妯$増', '43', 'infra_codegen_front_type', 0, '', '', '', '1', NOW(), '1', NOW(), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3040, 1, 'UDP', 'udp', 'iot_protocol_type', 0, '', '', 'UDP 鍗忚', '1', '2026-02-04 00:32:47', '1', '2026-02-04 00:32:47', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3041, 2, 'WebSocket', 'websocket', 'iot_protocol_type', 0, '', '', 'WebSocket 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3042, 3, 'HTTP', 'http', 'iot_protocol_type', 0, '', '', 'HTTP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
@@ -1653,9 +1655,9 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3443, 1, '鑽夌', '0', 'mes_wm_product_produce_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3444, 2, '宸插畬鎴�', '4', 'mes_wm_product_produce_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3445, 3, '宸插彇娑�', '5', 'mes_wm_product_produce_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '猫聧鈥懊�', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '氓路虏氓庐艗忙藛聬', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '氓路虏氓聫鈥撁β端�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '鑽夌', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '宸插畬鎴�', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '宸插彇娑�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
COMMIT;
-- @formatter:on
@@ -5943,4 +5945,3 @@
DROP SEQUENCE IF EXISTS yudao_demo03_student_seq;
CREATE SEQUENCE yudao_demo03_student_seq
START 10;
-
diff --git a/sql/mdm_migration.sql b/sql/mdm_migration.sql
deleted file mode 100644
index 54402b2..0000000
--- a/sql/mdm_migration.sql
+++ /dev/null
@@ -1,405 +0,0 @@
--- =============================================
--- MDM 鏁版嵁杩佺Щ SQL 鑴氭湰
--- 鍒涘缓鏃ユ湡: 2026-06-29
--- 璇存槑: 灏� MES/ERP/WMS 鐨勭墿鏂欐暟鎹縼绉诲埌缁熶竴涓绘暟鎹〃 md_item
--- 娉ㄦ剰: 鎵ц鍓嶈澶囦唤鏁版嵁搴擄紒
--- =============================================
-
--- ---------------------------------------------
--- 绗竴闃舵锛氳縼绉诲熀纭�鏁版嵁锛堝垎绫汇�佸崟浣嶃�佸搧鐗岋級
--- ---------------------------------------------
-
--- 1. 杩佺Щ MES 璁¢噺鍗曚綅鍒� md_unit_measure
-INSERT INTO `md_unit_measure` (`id`, `code`, `name`, `primary_flag`, `primary_id`, `change_rate`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id,
- LOWER(REPLACE(name, ' ', '_')) AS code, -- 浣跨敤鍚嶇О鐢熸垚缂栫爜
- name,
- COALESCE(primary_flag, 0) AS primary_flag,
- primary_id,
- change_rate,
- COALESCE(status, 0) AS status,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `mes_md_unit_measure`
-WHERE deleted = 0
-ON DUPLICATE KEY UPDATE name = VALUES(name);
-
--- 2. 杩佺Щ ERP 璁¢噺鍗曚綅鍒� md_unit_measure锛堜娇鐢ㄦ柊ID鑼冨洿 10000-19999锛�
-INSERT INTO `md_unit_measure` (`id`, `code`, `name`, `primary_flag`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id + 10000, -- ERP 鍗曚綅 ID 鍋忕Щ 10000
- LOWER(REPLACE(name, ' ', '_')) AS code,
- name,
- 0 AS primary_flag,
- COALESCE(status, 0) AS status,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `erp_product_unit`
-WHERE deleted = 0
-ON DUPLICATE KEY UPDATE name = VALUES(name);
-
--- 3. 杩佺Щ MES 鐗╂枡鍒嗙被鍒� md_item_category
-INSERT INTO `md_item_category` (`id`, `parent_id`, `code`, `name`, `item_type`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id,
- parent_id,
- code,
- name,
- CASE item_or_product
- WHEN 'ITEM' THEN 1 -- 鍘熸枡
- WHEN 'PRODUCT' THEN 3 -- 鎴愬搧
- ELSE NULL
- END AS item_type,
- sort,
- COALESCE(status, 0) AS status,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `mes_md_item_type`
-WHERE deleted = 0
-ON DUPLICATE KEY UPDATE name = VALUES(name);
-
--- 4. 杩佺Щ ERP 浜у搧鍒嗙被鍒� md_item_category锛堜娇鐢ㄦ柊ID鑼冨洿 10000-19999锛�
-INSERT INTO `md_item_category` (`id`, `parent_id`, `code`, `name`, `item_type`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id + 10000,
- CASE WHEN parent_id = 0 THEN 0 ELSE parent_id + 10000 END,
- CONCAT('ERP_', code) AS code, -- 娣诲姞鍓嶇紑閬垮厤鍐茬獊
- name,
- 3 AS item_type, -- ERP 浜у搧榛樿涓烘垚鍝�
- COALESCE(sort, 0) AS sort,
- COALESCE(status, 0) AS status,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `erp_product_category`
-WHERE deleted = 0
-ON DUPLICATE KEY UPDATE name = VALUES(name);
-
--- 5. 杩佺Щ WMS 鍟嗗搧鍒嗙被鍒� md_item_category锛堜娇鐢ㄦ柊ID鑼冨洿 20000-29999锛�
-INSERT INTO `md_item_category` (`id`, `parent_id`, `code`, `name`, `item_type`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id + 20000,
- CASE WHEN parent_id = 0 THEN 0 ELSE parent_id + 20000 END,
- CONCAT('WMS_', code) AS code,
- name,
- NULL AS item_type, -- WMS 鍒嗙被涓嶅尯鍒嗙被鍨�
- COALESCE(sort, 0) AS sort,
- COALESCE(status, 0) AS status,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `wms_item_category`
-WHERE deleted = 0
-ON DUPLICATE KEY UPDATE name = VALUES(name);
-
--- 6. 杩佺Щ WMS 鍝佺墝鍒� md_brand
-INSERT INTO `md_brand` (`id`, `code`, `name`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id,
- code,
- name,
- 0 AS status,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `wms_item_brand`
-WHERE deleted = 0
-ON DUPLICATE KEY UPDATE name = VALUES(name);
-
--- ---------------------------------------------
--- 绗簩闃舵锛氳縼绉荤墿鏂欎富鏁版嵁
--- ---------------------------------------------
-
--- 7. 杩佺Щ MES 鐗╂枡鍒� md_item
-INSERT INTO `md_item` (
- `id`, `code`, `name`, `bar_code`, `specification`,
- `category_id`, `unit_measure_id`, `brand_id`, `item_type`, `status`,
- `purchase_price`, `sales_price`, `cost_price`, `min_price`,
- `safety_stock`, `min_stock`, `max_stock`, `min_order_qty`, `lead_time`,
- `is_batch_managed`, `is_serial_managed`, `barcode_rule_id`,
- `expiry_day`, `high_value`, `weight`, `remark`,
- `creator`, `create_time`, `updater`, `update_time`, `deleted`
-)
-SELECT
- id,
- code,
- name,
- NULL AS bar_code, -- MES 娌℃湁鏉$爜
- specification,
- itemTypeId,
- unitMeasureId,
- NULL AS brand_id,
- 1 AS item_type, -- MES 鐗╂枡榛樿涓哄師鏂�
- COALESCE(status, 0),
- NULL, NULL, NULL, NULL, -- 浠锋牸淇℃伅 MES 娌℃湁
- NULL AS safety_stock,
- min_stock,
- max_stock,
- NULL, NULL, -- 鏈�灏忚璐ч噺銆佹彁鍓嶆湡 MES 娌℃湁
- COALESCE(batchFlag, 0),
- 0 AS is_serial_managed,
- NULL AS barcode_rule_id,
- NULL AS expiry_day,
- COALESCE(highValue, 0),
- NULL AS weight,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `mes_md_item`
-WHERE deleted = 0;
-
--- 8. 璁板綍 MES 鐗╂枡杩佺Щ鏄犲皠
-INSERT INTO `md_item_migration_map` (`source_module`, `source_table`, `source_id`, `target_item_id`, `create_time`)
-SELECT 'MES', 'mes_md_item', id, id, NOW()
-FROM `mes_md_item`
-WHERE deleted = 0;
-
--- 9. 杩佺Щ ERP 浜у搧鍒� md_item锛堜娇鐢ㄦ柊ID鑼冨洿 100000-199999锛�
-INSERT INTO `md_item` (
- `id`, `code`, `name`, `bar_code`, `specification`,
- `category_id`, `unit_measure_id`, `brand_id`, `item_type`, `status`,
- `purchase_price`, `sales_price`, `cost_price`, `min_price`,
- `safety_stock`, `min_stock`, `max_stock`, `min_order_qty`, `lead_time`,
- `is_batch_managed`, `is_serial_managed`, `barcode_rule_id`,
- `expiry_day`, `high_value`, `weight`, `remark`,
- `creator`, `create_time`, `updater`, `update_time`, `deleted`
-)
-SELECT
- id + 100000, -- ERP 浜у搧 ID 鍋忕Щ 100000
- COALESCE(bar_code, CONCAT('ERP_', id)) AS code, -- 浣跨敤鏉$爜浣滀负缂栫爜锛屾病鏈夊垯鐢熸垚
- name,
- bar_code,
- standard AS specification,
- categoryId + 10000, -- 浣跨敤 ERP 鍒嗙被鏄犲皠鍚庣殑ID
- unitId + 10000, -- 浣跨敤 ERP 鍗曚綅鏄犲皠鍚庣殑ID
- NULL AS brand_id,
- 3 AS item_type, -- ERP 浜у搧榛樿涓烘垚鍝�
- COALESCE(status, 0),
- purchase_price,
- sale_price,
- NULL AS cost_price,
- min_price,
- NULL, NULL, NULL, NULL, NULL, -- 搴撳瓨绠$悊 ERP 娌℃湁
- 0 AS is_batch_managed,
- 0 AS is_serial_managed,
- NULL AS barcode_rule_id,
- expiry_day,
- 0 AS high_value,
- weight,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `erp_product`
-WHERE deleted = 0;
-
--- 10. 璁板綍 ERP 浜у搧杩佺Щ鏄犲皠
-INSERT INTO `md_item_migration_map` (`source_module`, `source_table`, `source_id`, `target_item_id`, `create_time`)
-SELECT 'ERP', 'erp_product', id, id + 100000, NOW()
-FROM `erp_product`
-WHERE deleted = 0;
-
--- 11. 杩佺Щ WMS 鍟嗗搧鍒� md_item锛堜娇鐢ㄦ柊ID鑼冨洿 200000-299999锛�
-INSERT INTO `md_item` (
- `id`, `code`, `name`, `bar_code`, `specification`,
- `category_id`, `unit_measure_id`, `brand_id`, `item_type`, `status`,
- `purchase_price`, `sales_price`, `cost_price`, `min_price`,
- `safety_stock`, `min_stock`, `max_stock`, `min_order_qty`, `lead_time`,
- `is_batch_managed`, `is_serial_managed`, `barcode_rule_id`,
- `expiry_day`, `high_value`, `weight`, `remark`,
- `creator`, `create_time`, `updater`, `update_time`, `deleted`
-)
-SELECT
- id + 200000, -- WMS 鍟嗗搧 ID 鍋忕Щ 200000
- code,
- name,
- NULL AS bar_code, -- WMS 鏉$爜鍦� SKU 灞�
- NULL AS specification,
- categoryId + 20000, -- 浣跨敤 WMS 鍒嗙被鏄犲皠鍚庣殑ID
- NULL AS unit_measure_id, -- WMS 鍗曚綅鏄瓧绗︿覆锛岄渶瑕佸悗缁鐞�
- brandId,
- 1 AS item_type, -- WMS 鍟嗗搧榛樿涓哄師鏂�
- 0 AS status,
- NULL, NULL, NULL, NULL, -- 浠锋牸鍦� SKU 灞�
- NULL, NULL, NULL, NULL, NULL,
- 0, 0, NULL,
- NULL, 0, NULL,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `wms_item`
-WHERE deleted = 0;
-
--- 12. 璁板綍 WMS 鍟嗗搧杩佺Щ鏄犲皠
-INSERT INTO `md_item_migration_map` (`source_module`, `source_table`, `source_id`, `target_item_id`, `create_time`)
-SELECT 'WMS', 'wms_item', id, id + 200000, NOW()
-FROM `wms_item`
-WHERE deleted = 0;
-
--- ---------------------------------------------
--- 绗笁闃舵锛氳縼绉绘壒娆″睘鎬ч厤缃�
--- ---------------------------------------------
-
--- 13. 杩佺Щ MES 鎵规灞炴�ч厤缃埌 md_item_batch_config
-INSERT INTO `md_item_batch_config` (
- `id`, `item_id`,
- `produce_date_flag`, `expire_date_flag`, `receipt_date_flag`,
- `vendor_flag`, `client_flag`, `sales_order_code_flag`, `purchase_order_code_flag`,
- `work_order_flag`, `task_flag`, `workstation_flag`, `tool_flag`, `mold_flag`,
- `lot_number_flag`, `quality_status_flag`,
- `creator`, `create_time`, `updater`, `update_time`, `deleted`
-)
-SELECT
- id,
- itemId,
- COALESCE(produce_date_flag, 0),
- COALESCE(expire_date_flag, 0),
- COALESCE(receipt_date_flag, 0),
- COALESCE(vendor_flag, 0),
- COALESCE(client_flag, 0),
- COALESCE(sales_order_code_flag, 0),
- COALESCE(purchase_order_code_flag, 0),
- COALESCE(work_order_flag, 0),
- COALESCE(task_flag, 0),
- COALESCE(workstation_flag, 0),
- COALESCE(tool_flag, 0),
- COALESCE(mold_flag, 0),
- COALESCE(lot_number_flag, 0),
- COALESCE(quality_status_flag, 0),
- creator, create_time, updater, update_time, deleted
-FROM `mes_md_item_batch_config`
-WHERE deleted = 0;
-
--- ---------------------------------------------
--- 绗洓闃舵锛氳縼绉讳粨搴撴暟鎹�
--- ---------------------------------------------
-
--- 14. 杩佺Щ MES 浠撳簱鍒� md_warehouse
-INSERT INTO `md_warehouse` (`id`, `code`, `name`, `address`, `area`, `type`, `charge_user_id`, `status`, `frozen`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id,
- code,
- name,
- address,
- area,
- NULL AS type, -- MES 浠撳簱娌℃湁绫诲瀷
- chargeUserId,
- 0 AS status,
- COALESCE(frozen, 0),
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `mes_wm_warehouse`
-WHERE deleted = 0;
-
--- 15. 杩佺Щ ERP 浠撳簱鍒� md_warehouse锛堜娇鐢ㄦ柊ID鑼冨洿 10000-19999锛�
-INSERT INTO `md_warehouse` (`id`, `code`, `name`, `address`, `area`, `type`, `charge_user_id`, `status`, `frozen`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id + 10000,
- CONCAT('ERP_', id) AS code, -- ERP 浠撳簱娌℃湁缂栫爜锛岀敓鎴愪竴涓�
- name,
- address,
- NULL AS area,
- NULL AS type,
- NULL AS charge_user_id, -- ERP 浣跨敤 principal 瀛楃涓诧紝鏃犳硶鏄犲皠
- COALESCE(status, 0),
- 0 AS frozen,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `erp_warehouse`
-WHERE deleted = 0;
-
--- 16. 杩佺Щ WMS 浠撳簱鍒� md_warehouse锛堜娇鐢ㄦ柊ID鑼冨洿 20000-29999锛�
-INSERT INTO `md_warehouse` (`id`, `code`, `name`, `address`, `area`, `type`, `charge_user_id`, `status`, `frozen`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- id + 20000,
- code,
- name,
- address,
- area,
- NULL AS type,
- chargeUserId,
- COALESCE(status, 0),
- 0 AS frozen,
- remark,
- creator, create_time, updater, update_time, deleted
-FROM `wms_warehouse`
-WHERE deleted = 0;
-
--- ---------------------------------------------
--- 绗簲闃舵锛氳縼绉诲簱瀛樻暟鎹�
--- ---------------------------------------------
-
--- 17. 杩佺Щ MES 搴撳瓨鍒� wms_stock
-INSERT INTO `wms_stock` (`item_id`, `warehouse_id`, `location_id`, `batch_code`, `quantity`, `quantity_locked`, `quantity_available`, `unit_measure_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- m.target_item_id AS item_id, -- 浣跨敤鏄犲皠鍚庣殑鐗╂枡ID
- s.warehouseId AS warehouse_id,
- s.locationId AS location_id,
- s.batchCode AS batch_code,
- s.quantity,
- 0 AS quantity_locked,
- s.quantity AS quantity_available,
- i.unitMeasureId AS unit_measure_id,
- s.creator, s.create_time, s.updater, s.update_time, s.deleted
-FROM `mes_wm_material_stock` s
-LEFT JOIN `mes_md_item` i ON i.id = s.itemId
-LEFT JOIN `md_item_migration_map` m ON m.source_module = 'MES' AND m.source_table = 'mes_md_item' AND m.source_id = s.itemId
-WHERE s.deleted = 0 AND m.target_item_id IS NOT NULL;
-
--- 18. 杩佺Щ ERP 搴撳瓨鍒� wms_stock
-INSERT INTO `wms_stock` (`item_id`, `warehouse_id`, `batch_code`, `quantity`, `quantity_locked`, `quantity_available`, `unit_measure_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- m.target_item_id AS item_id,
- s.warehouseId + 10000 AS warehouse_id, -- 浣跨敤 ERP 浠撳簱鏄犲皠鍚庣殑ID
- NULL AS batch_code,
- s.count AS quantity,
- 0 AS quantity_locked,
- s.count AS quantity_available,
- p.unitId + 10000 AS unit_measure_id, -- 浣跨敤 ERP 鍗曚綅鏄犲皠鍚庣殑ID
- s.creator, s.create_time, s.updater, s.update_time, s.deleted
-FROM `erp_stock` s
-LEFT JOIN `erp_product` p ON p.id = s.productId
-LEFT JOIN `md_item_migration_map` m ON m.source_module = 'ERP' AND m.source_table = 'erp_product' AND m.source_id = s.productId
-WHERE s.deleted = 0 AND m.target_item_id IS NOT NULL;
-
--- 19. 杩佺Щ WMS 搴撳瓨鍒� wms_stock
-INSERT INTO `wms_stock` (`item_id`, `warehouse_id`, `batch_code`, `quantity`, `quantity_locked`, `quantity_available`, `unit_measure_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
-SELECT
- m.target_item_id AS item_id,
- s.warehouseId + 20000 AS warehouse_id, -- 浣跨敤 WMS 浠撳簱鏄犲皠鍚庣殑ID
- NULL AS batch_code,
- s.quantity,
- 0 AS quantity_locked,
- s.quantity AS quantity_available,
- NULL AS unit_measure_id, -- WMS 搴撳瓨娌℃湁鍗曚綅
- s.creator, s.create_time, s.updater, s.update_time, s.deleted
-FROM `wms_inventory` s
-LEFT JOIN `md_item_migration_map` m ON m.source_module = 'WMS' AND m.source_table = 'wms_item' AND m.source_id = s.skuId -- 娉ㄦ剰锛歐MS 搴撳瓨鍏宠仈鐨勬槸 SKU
-WHERE s.deleted = 0 AND m.target_item_id IS NOT NULL;
-
--- =============================================
--- 杩佺Щ瀹屾垚
--- =============================================
-
--- 鏌ヨ杩佺Щ缁撴灉缁熻
-SELECT
- 'md_item' AS table_name,
- (SELECT COUNT(*) FROM md_item WHERE deleted = 0) AS count
-UNION ALL
-SELECT
- 'md_item_category',
- (SELECT COUNT(*) FROM md_item_category WHERE deleted = 0)
-UNION ALL
-SELECT
- 'md_unit_measure',
- (SELECT COUNT(*) FROM md_unit_measure WHERE deleted = 0)
-UNION ALL
-SELECT
- 'md_brand',
- (SELECT COUNT(*) FROM md_brand WHERE deleted = 0)
-UNION ALL
-SELECT
- 'md_warehouse',
- (SELECT COUNT(*) FROM md_warehouse WHERE deleted = 0)
-UNION ALL
-SELECT
- 'wms_stock',
- (SELECT COUNT(*) FROM wms_stock WHERE deleted = 0)
-UNION ALL
-SELECT
- 'md_item_migration_map',
- (SELECT COUNT(*) FROM md_item_migration_map);
diff --git a/sql/mdm_tables.sql b/sql/mdm_tables.sql
deleted file mode 100644
index 6efdc42..0000000
--- a/sql/mdm_tables.sql
+++ /dev/null
@@ -1,334 +0,0 @@
--- =============================================
--- 缁熶竴鐗╂枡涓绘暟鎹ā鍧� (MDM) 寤鸿〃 SQL
--- 鍒涘缓鏃ユ湡: 2026-06-29
--- 璇存槑: 鏁村悎 MES/ERP/WMS 鐨勭墿鏂欐暟鎹紝瀹炵幇璺ㄦā鍧楁暟鎹墦閫�
--- 娉ㄦ剰: 涓嶅紑鍚绉熸埛妯″紡
--- =============================================
-
--- ---------------------------------------------
--- 1. 鐗╂枡涓绘暟鎹〃 (md_item)
--- 鏍稿績琛紝鎵�鏈夋ā鍧楀叡鐢ㄥ敮涓�浜у搧缂栫爜
--- ---------------------------------------------
-DROP TABLE IF EXISTS `md_item`;
-CREATE TABLE `md_item` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐗╂枡ID锛堝叏灞�鍞竴锛�',
- `code` varchar(64) NOT NULL COMMENT '鐗╂枡缂栫爜锛堝叏灞�鍞竴锛�',
- `name` varchar(255) NOT NULL COMMENT '鐗╂枡鍚嶇О',
- `bar_code` varchar(64) DEFAULT NULL COMMENT '鐗╂枡鏉$爜',
- `specification` varchar(500) DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
-
- -- 鍒嗙被涓庡崟浣�
- `category_id` bigint NOT NULL COMMENT '鐗╂枡鍒嗙被缂栧彿',
- `unit_measure_id` bigint NOT NULL COMMENT '涓昏閲忓崟浣嶇紪鍙�',
- `brand_id` bigint DEFAULT NULL COMMENT '鍝佺墝缂栧彿',
-
- -- 鐗╂枡绫诲瀷
- `item_type` tinyint NOT NULL DEFAULT 1 COMMENT '鐗╂枡绫诲瀷(1:鍘熸枡, 2:鍗婃垚鍝�, 3:鎴愬搧, 4:杈呮枡)',
-
- -- 鐘舵��
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��(0:鍚敤, 1:绂佺敤)',
-
- -- 浠锋牸淇℃伅
- `purchase_price` decimal(24,6) DEFAULT NULL COMMENT '閲囪喘浠�',
- `sales_price` decimal(24,6) DEFAULT NULL COMMENT '閿�鍞环',
- `cost_price` decimal(24,6) DEFAULT NULL COMMENT '鎴愭湰浠�',
- `min_price` decimal(24,6) DEFAULT NULL COMMENT '鏈�浣庝环',
-
- -- 搴撳瓨绠$悊
- `safety_stock` decimal(24,6) DEFAULT NULL COMMENT '瀹夊叏搴撳瓨',
- `min_stock` decimal(24,6) DEFAULT NULL COMMENT '鏈�浣庡簱瀛橀噺',
- `max_stock` decimal(24,6) DEFAULT NULL COMMENT '鏈�楂樺簱瀛橀噺',
- `min_order_qty` decimal(24,6) DEFAULT NULL COMMENT '鏈�灏忚璐ч噺',
- `lead_time` int DEFAULT NULL COMMENT '閲囪喘鎻愬墠鏈燂紙澶╋級',
-
- -- 鎵规涓庡簭鍒楀彿绠$悊
- `is_batch_managed` bit(1) DEFAULT b'0' COMMENT '鏄惁鎵规绠$悊',
- `is_serial_managed` bit(1) DEFAULT b'0' COMMENT '鏄惁搴忓垪鍙风鐞�',
- `barcode_rule_id` bigint DEFAULT NULL COMMENT '鏉$爜瑙勫垯ID',
-
- -- 璐ㄩ噺绠$悊
- `expiry_day` int DEFAULT NULL COMMENT '淇濊川鏈熷ぉ鏁�',
- `high_value` bit(1) DEFAULT b'0' COMMENT '鏄惁楂樺�肩墿鏂�',
-
- -- 鐗╃悊灞炴��
- `weight` decimal(24,6) DEFAULT NULL COMMENT '閲嶉噺(kg)',
-
- -- 澶囨敞
- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-
- -- 绯荤粺瀛楁
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
-
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_code` (`code`),
- KEY `idx_category_id` (`category_id`),
- KEY `idx_unit_measure_id` (`unit_measure_id`),
- KEY `idx_brand_id` (`brand_id`),
- KEY `idx_item_type` (`item_type`),
- KEY `idx_status` (`status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鐗╂枡涓绘暟鎹〃';
-
--- ---------------------------------------------
--- 2. 鐗╂枡鍒嗙被琛� (md_item_category)
--- 缁熶竴鍒嗙被锛屾敮鎸佹爲褰㈢粨鏋�
--- ---------------------------------------------
-DROP TABLE IF EXISTS `md_item_category`;
-CREATE TABLE `md_item_category` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍒嗙被缂栧彿',
- `parent_id` bigint NOT NULL DEFAULT 0 COMMENT '鐖跺垎绫荤紪鍙�(鏍硅妭鐐�=0)',
- `code` varchar(64) NOT NULL COMMENT '鍒嗙被缂栫爜',
- `name` varchar(255) NOT NULL COMMENT '鍒嗙被鍚嶇О',
- `item_type` tinyint DEFAULT NULL COMMENT '閫傜敤鐗╂枡绫诲瀷(1:鍘熸枡, 2:鍗婃垚鍝�, 3:鎴愬搧, 4:杈呮枡, NULL:鍏ㄩ儴)',
- `sort` int NOT NULL DEFAULT 0 COMMENT '鎺掑簭',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��(0:鍚敤, 1:绂佺敤)',
- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-
- -- 绯荤粺瀛楁
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
-
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_code` (`code`),
- KEY `idx_parent_id` (`parent_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鐗╂枡鍒嗙被琛�';
-
--- ---------------------------------------------
--- 3. 璁¢噺鍗曚綅琛� (md_unit_measure)
--- 缁熶竴璁¢噺鍗曚綅
--- ---------------------------------------------
-DROP TABLE IF EXISTS `md_unit_measure`;
-CREATE TABLE `md_unit_measure` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍗曚綅缂栧彿',
- `code` varchar(64) NOT NULL COMMENT '鍗曚綅缂栫爜',
- `name` varchar(64) NOT NULL COMMENT '鍗曚綅鍚嶇О',
- `primary_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁涓诲崟浣�',
- `primary_id` bigint DEFAULT NULL COMMENT '涓诲崟浣嶇紪鍙�',
- `change_rate` decimal(24,6) DEFAULT NULL COMMENT '涓庝富鍗曚綅鎹㈢畻姣斾緥',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��(0:鍚敤, 1:绂佺敤)',
- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-
- -- 绯荤粺瀛楁
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
-
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_code` (`code`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='璁¢噺鍗曚綅琛�';
-
--- ---------------------------------------------
--- 4. 鍝佺墝琛� (md_brand)
--- 缁熶竴鍝佺墝鏁版嵁
--- ---------------------------------------------
-DROP TABLE IF EXISTS `md_brand`;
-CREATE TABLE `md_brand` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍝佺墝缂栧彿',
- `code` varchar(64) NOT NULL COMMENT '鍝佺墝缂栫爜',
- `name` varchar(255) NOT NULL COMMENT '鍝佺墝鍚嶇О',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��(0:鍚敤, 1:绂佺敤)',
- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-
- -- 绯荤粺瀛楁
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
-
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_code` (`code`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鍝佺墝琛�';
-
--- ---------------------------------------------
--- 5. 鐗╂枡鎵规灞炴�ч厤缃〃 (md_item_batch_config)
--- 鏉ヨ嚜 MES 鐨勬壒娆$鐞嗛厤缃�
--- ---------------------------------------------
-DROP TABLE IF EXISTS `md_item_batch_config`;
-CREATE TABLE `md_item_batch_config` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `item_id` bigint NOT NULL COMMENT '鐗╂枡缂栧彿',
-
- -- 鎵规灞炴�у紑鍏�
- `produce_date_flag` bit(1) DEFAULT b'0' COMMENT '鐢熶骇鏃ユ湡',
- `expire_date_flag` bit(1) DEFAULT b'0' COMMENT '鏈夋晥鏈�',
- `receipt_date_flag` bit(1) DEFAULT b'0' COMMENT '鍏ュ簱鏃ユ湡',
- `vendor_flag` bit(1) DEFAULT b'0' COMMENT '渚涘簲鍟�',
- `client_flag` bit(1) DEFAULT b'0' COMMENT '瀹㈡埛',
- `sales_order_code_flag` bit(1) DEFAULT b'0' COMMENT '閿�鍞鍗曠紪鍙�',
- `purchase_order_code_flag` bit(1) DEFAULT b'0' COMMENT '閲囪喘璁㈠崟缂栧彿',
- `work_order_flag` bit(1) DEFAULT b'0' COMMENT '鐢熶骇宸ュ崟',
- `task_flag` bit(1) DEFAULT b'0' COMMENT '鐢熶骇浠诲姟',
- `workstation_flag` bit(1) DEFAULT b'0' COMMENT '宸ヤ綔绔�',
- `tool_flag` bit(1) DEFAULT b'0' COMMENT '宸ュ叿',
- `mold_flag` bit(1) DEFAULT b'0' COMMENT '妯″叿',
- `lot_number_flag` bit(1) DEFAULT b'0' COMMENT '鐢熶骇鎵瑰彿',
- `quality_status_flag` bit(1) DEFAULT b'0' COMMENT '璐ㄩ噺鐘舵��',
-
- -- 绯荤粺瀛楁
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
-
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_item_id` (`item_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鐗╂枡鎵规灞炴�ч厤缃〃';
-
--- ---------------------------------------------
--- 6. 浠撳簱涓绘暟鎹〃 (md_warehouse)
--- 缁熶竴浠撳簱鏁版嵁锛學MS 涓轰富鏁版嵁婧�
--- ---------------------------------------------
-DROP TABLE IF EXISTS `md_warehouse`;
-CREATE TABLE `md_warehouse` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浠撳簱ID',
- `code` varchar(64) NOT NULL COMMENT '浠撳簱缂栫爜',
- `name` varchar(255) NOT NULL COMMENT '浠撳簱鍚嶇О',
- `address` varchar(500) DEFAULT NULL COMMENT '浠撳簱鍦板潃',
- `area` decimal(24,6) DEFAULT NULL COMMENT '闈㈢Н(骞虫柟绫�)',
- `type` tinyint DEFAULT NULL COMMENT '浠撳簱绫诲瀷(1:鍘熸枡浠�, 2:鎴愬搧浠�, 3:鍗婃垚鍝佷粨, 4:绾胯竟浠�)',
- `charge_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴稩D',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��(0:鍚敤, 1:绂佺敤)',
- `frozen` bit(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-
- -- 绯荤粺瀛楁
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
-
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_code` (`code`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='浠撳簱涓绘暟鎹〃';
-
--- ---------------------------------------------
--- 7. 搴撳瓨琛� (wms_stock)
--- WMS 浣滀负鍞竴搴撳瓨绠$悊鑰�
--- ---------------------------------------------
-DROP TABLE IF EXISTS `wms_stock`;
-CREATE TABLE `wms_stock` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '搴撳瓨ID',
- `item_id` bigint NOT NULL COMMENT '鐗╂枡ID锛堝叧鑱� md_item锛�',
- `warehouse_id` bigint NOT NULL COMMENT '浠撳簱ID锛堝叧鑱� md_warehouse锛�',
- `location_id` bigint DEFAULT NULL COMMENT '搴撲綅ID',
- `batch_code` varchar(64) DEFAULT NULL COMMENT '鎵规鍙�',
-
- -- 搴撳瓨鏁伴噺
- `quantity` decimal(24,6) NOT NULL DEFAULT 0 COMMENT '褰撳墠搴撳瓨鏁伴噺',
- `quantity_locked` decimal(24,6) NOT NULL DEFAULT 0 COMMENT '閿佸畾鏁伴噺',
- `quantity_available` decimal(24,6) NOT NULL DEFAULT 0 COMMENT '鍙敤鏁伴噺 = quantity - quantity_locked',
-
- `unit_measure_id` bigint NOT NULL COMMENT '璁¢噺鍗曚綅ID',
-
- -- 绯荤粺瀛楁
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
-
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_item_warehouse_batch` (`item_id`, `warehouse_id`, `batch_code`),
- KEY `idx_item_id` (`item_id`),
- KEY `idx_warehouse_id` (`warehouse_id`),
- KEY `idx_batch_code` (`batch_code`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='搴撳瓨琛�';
-
--- ---------------------------------------------
--- 8. 搴撳瓨浜嬪姟娴佹按琛� (wms_stock_transaction)
--- 璁板綍鎵�鏈夊簱瀛樺彉鍔�
--- ---------------------------------------------
-DROP TABLE IF EXISTS `wms_stock_transaction`;
-CREATE TABLE `wms_stock_transaction` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '娴佹按ID',
- `item_id` bigint NOT NULL COMMENT '鐗╂枡ID',
- `warehouse_id` bigint NOT NULL COMMENT '浠撳簱ID',
- `location_id` bigint DEFAULT NULL COMMENT '搴撲綅ID',
- `batch_code` varchar(64) DEFAULT NULL COMMENT '鎵规鍙�',
-
- -- 鍙樺姩淇℃伅
- `quantity` decimal(24,6) NOT NULL COMMENT '鍙樺姩鏁伴噺(姝f暟鍏ュ簱,璐熸暟鍑哄簱)',
- `biz_type` tinyint NOT NULL COMMENT '涓氬姟绫诲瀷(瑙佹灇涓�)',
- `biz_id` bigint DEFAULT NULL COMMENT '涓氬姟鍗曟嵁ID',
- `biz_no` varchar(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁鍙�',
-
- -- 鍏宠仈搴撳瓨璁板綍
- `stock_id` bigint DEFAULT NULL COMMENT '鍏宠仈搴撳瓨璁板綍ID',
-
- `remark` varchar(500) DEFAULT NULL COMMENT '澶囨敞',
-
- -- 绯荤粺瀛楁
- `creator` varchar(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
-
- PRIMARY KEY (`id`),
- KEY `idx_item_id` (`item_id`),
- KEY `idx_warehouse_id` (`warehouse_id`),
- KEY `idx_biz_type` (`biz_type`),
- KEY `idx_biz_id` (`biz_id`),
- KEY `idx_create_time` (`create_time`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='搴撳瓨浜嬪姟娴佹按琛�';
-
--- ---------------------------------------------
--- 9. 鐗╂枡杩佺Щ鏄犲皠琛� (md_item_migration_map)
--- 鐢ㄤ簬璁板綍鏃ц〃鏁版嵁鍒版柊琛ㄧ殑鏄犲皠鍏崇郴
--- ---------------------------------------------
-DROP TABLE IF EXISTS `md_item_migration_map`;
-CREATE TABLE `md_item_migration_map` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏄犲皠ID',
- `source_module` varchar(20) NOT NULL COMMENT '鏉ユ簮妯″潡(ERP/MES/WMS)',
- `source_table` varchar(64) NOT NULL COMMENT '鏉ユ簮琛ㄥ悕',
- `source_id` bigint NOT NULL COMMENT '鍘烮D',
- `target_item_id` bigint NOT NULL COMMENT 'MDM鐗╂枡ID',
-
- -- 绯荤粺瀛楁
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
-
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_source` (`source_module`, `source_table`, `source_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='鐗╂枡杩佺Щ鏄犲皠琛�';
-
--- ---------------------------------------------
--- 10. 搴撳瓨鍙樺姩涓氬姟绫诲瀷鏋氫妇鍊�
--- ---------------------------------------------
--- 涓氬姟绫诲瀷璇存槑锛�
--- 10: 閲囪喘鍏ュ簱 (ERP)
--- 11: 閲囪喘鍏ュ簱浣滃簾 (ERP)
--- 20: 閿�鍞嚭搴� (ERP)
--- 21: 閿�鍞嚭搴撲綔搴� (ERP)
--- 30: 鐢熶骇鍏ュ簱 (MES)
--- 31: 鐢熶骇鍏ュ簱浣滃簾 (MES)
--- 40: 鐢熶骇棰嗘枡 (MES)
--- 41: 鐢熶骇棰嗘枡浣滃簾 (MES)
--- 50: 鐢熶骇閫�鏂� (MES)
--- 51: 鐢熶骇閫�鏂欎綔搴� (MES)
--- 60: 閲囪喘閫�璐у嚭搴� (ERP)
--- 61: 閲囪喘閫�璐у嚭搴撲綔搴� (ERP)
--- 70: 閿�鍞��璐у叆搴� (ERP)
--- 71: 閿�鍞��璐у叆搴撲綔搴� (ERP)
--- 80: 璋冩嫧鍏ュ簱 (WMS)
--- 81: 璋冩嫧鍏ュ簱浣滃簾 (WMS)
--- 90: 璋冩嫧鍑哄簱 (WMS)
--- 91: 璋冩嫧鍑哄簱浣滃簾 (WMS)
--- 100: 鐩樼泩鍏ュ簱 (WMS)
--- 101: 鐩樼泩鍏ュ簱浣滃簾 (WMS)
--- 110: 鐩樹簭鍑哄簱 (WMS)
--- 111: 鐩樹簭鍑哄簱浣滃簾 (WMS)
-
--- =============================================
--- 瀹屾垚寤鸿〃 SQL
--- =============================================
\ No newline at end of file
diff --git a/sql/mysql/ai.sql b/sql/mysql/ai.sql
deleted file mode 100644
index 7e97bf7..0000000
--- a/sql/mysql/ai.sql
+++ /dev/null
@@ -1,332 +0,0 @@
--- AI 澶фā鍨嬫ā鍧楀缓琛� SQL
-
--- ----------------------------
--- 1. AI API 绉橀挜琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_api_key`;
-CREATE TABLE `ai_api_key` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍚嶇О',
- `api_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀵嗛挜',
- `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
- `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'API 鍦板潃',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI API 绉橀挜琛�';
-
--- ----------------------------
--- 2. AI 妯″瀷琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_model`;
-CREATE TABLE `ai_model` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `key_id` bigint NOT NULL COMMENT 'API 绉橀挜缂栧彿',
- `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '妯″瀷鍚嶇О',
- `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '妯″瀷鏍囧織',
- `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
- `type` tinyint NOT NULL COMMENT '绫诲瀷',
- `sort` int NOT NULL DEFAULT 0 COMMENT '鎺掑簭鍊�',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��',
- `temperature` double DEFAULT NULL COMMENT '娓╁害鍙傛暟',
- `max_tokens` int DEFAULT NULL COMMENT '鍗曟潯鍥炲鐨勬渶澶� Token 鏁伴噺',
- `max_contexts` int DEFAULT NULL COMMENT '涓婁笅鏂囩殑鏈�澶� Message 鏁伴噺',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 妯″瀷琛�';
-
--- ----------------------------
--- 3. AI 鑱婂ぉ瑙掕壊琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_chat_role`;
-CREATE TABLE `ai_chat_role` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瑙掕壊鍚嶇О',
- `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊澶村儚',
- `category` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瑙掕壊鍒嗙被',
- `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊鎻忚堪',
- `system_message` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊璁惧畾',
- `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
- `knowledge_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮曠敤鐨勭煡璇嗗簱缂栧彿鍒楄〃',
- `tool_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮曠敤鐨勫伐鍏风紪鍙峰垪琛�',
- `mcp_client_names` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮曠敤鐨� MCP Client 鍚嶅瓧鍒楄〃',
- `public_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏紑',
- `sort` int NOT NULL DEFAULT 0 COMMENT '鎺掑簭鍊�',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 鑱婂ぉ瑙掕壊琛�';
-
--- ----------------------------
--- 4. AI 宸ュ叿琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_tool`;
-CREATE TABLE `ai_tool` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '宸ュ叿缂栧彿',
- `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '宸ュ叿鍚嶇О',
- `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ叿鎻忚堪',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 宸ュ叿琛�';
-
--- ----------------------------
--- 5. AI Chat 瀵硅瘽琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_chat_conversation`;
-CREATE TABLE `ai_chat_conversation` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID 缂栧彿',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '鏂板璇�' COMMENT '瀵硅瘽鏍囬',
- `pinned` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁缃《',
- `pinned_time` datetime DEFAULT NULL COMMENT '缃《鏃堕棿',
- `role_id` bigint DEFAULT NULL COMMENT '瑙掕壊缂栧彿',
- `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
- `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷鏍囧織',
- `system_message` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊璁惧畾',
- `temperature` double DEFAULT NULL COMMENT '娓╁害鍙傛暟',
- `max_tokens` int DEFAULT NULL COMMENT '鍗曟潯鍥炲鐨勬渶澶� Token 鏁伴噺',
- `max_contexts` int DEFAULT NULL COMMENT '涓婁笅鏂囩殑鏈�澶� Message 鏁伴噺',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI Chat 瀵硅瘽琛�';
-
--- ----------------------------
--- 6. AI Chat 娑堟伅琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_chat_message`;
-CREATE TABLE `ai_chat_message` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `conversation_id` bigint NOT NULL COMMENT '瀵硅瘽缂栧彿',
- `reply_id` bigint DEFAULT NULL COMMENT '鍥炲娑堟伅缂栧彿',
- `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娑堟伅绫诲瀷',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `role_id` bigint DEFAULT NULL COMMENT '瑙掕壊缂栧彿',
- `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷鏍囧織',
- `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
- `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鑱婂ぉ鍐呭',
- `reasoning_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鎺ㄧ悊鍐呭',
- `use_context` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鎼哄甫涓婁笅鏂�',
- `segment_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭ヨ瘑搴撴钀界紪鍙锋暟缁�',
- `web_search_pages` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鑱旂綉鎼滅储鐨勭綉椤靛唴瀹规暟缁�',
- `attachment_urls` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闄勪欢 URL 鏁扮粍',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI Chat 娑堟伅琛�';
-
--- ----------------------------
--- 7. AI 缁樼敾琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_image`;
-CREATE TABLE `ai_image` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `prompt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鎻愮ず璇�',
- `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
- `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
- `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷鏍囪瘑',
- `width` int DEFAULT NULL COMMENT '鍥剧墖瀹藉害',
- `height` int DEFAULT NULL COMMENT '鍥剧墖楂樺害',
- `status` tinyint NOT NULL COMMENT '鐢熸垚鐘舵��',
- `finish_time` datetime DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
- `error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁樼敾閿欒淇℃伅',
- `pic_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥剧墖鍦板潃',
- `public_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏紑',
- `options` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '缁樺埗鍙傛暟',
- `buttons` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'mj buttons 鎸夐挳',
- `task_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠诲姟缂栧彿',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 缁樼敾琛�';
-
--- ----------------------------
--- 8. AI 鐭ヨ瘑搴撹〃
--- ----------------------------
-DROP TABLE IF EXISTS `ai_knowledge`;
-CREATE TABLE `ai_knowledge` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鐭ヨ瘑搴撳悕绉�',
- `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭ヨ瘑搴撴弿杩�',
- `embedding_model_id` bigint DEFAULT NULL COMMENT '鍚戦噺妯″瀷缂栧彿',
- `embedding_model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷鏍囪瘑',
- `top_k` int DEFAULT NULL COMMENT 'topK',
- `similarity_threshold` double DEFAULT NULL COMMENT '鐩镐技搴﹂槇鍊�',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 鐭ヨ瘑搴撹〃';
-
--- ----------------------------
--- 9. AI 鐭ヨ瘑搴撴枃妗h〃
--- ----------------------------
-DROP TABLE IF EXISTS `ai_knowledge_document`;
-CREATE TABLE `ai_knowledge_document` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `knowledge_id` bigint NOT NULL COMMENT '鐭ヨ瘑搴撶紪鍙�',
- `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鏂囨。鍚嶇О',
- `url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂囦欢 URL',
- `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鍐呭',
- `content_length` int DEFAULT NULL COMMENT '鏂囨。闀垮害',
- `tokens` int DEFAULT NULL COMMENT '鏂囨。 token 鏁伴噺',
- `segment_max_tokens` int DEFAULT NULL COMMENT '鍒嗙墖鏈�澶� Token 鏁�',
- `retrieval_count` int NOT NULL DEFAULT 0 COMMENT '鍙洖娆℃暟',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 鐭ヨ瘑搴撴枃妗h〃';
-
--- ----------------------------
--- 10. AI 鐭ヨ瘑搴撴枃妗e垎娈佃〃
--- ----------------------------
-DROP TABLE IF EXISTS `ai_knowledge_segment`;
-CREATE TABLE `ai_knowledge_segment` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `knowledge_id` bigint NOT NULL COMMENT '鐭ヨ瘑搴撶紪鍙�',
- `document_id` bigint NOT NULL COMMENT '鏂囨。缂栧彿',
- `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鍒囩墖鍐呭',
- `content_length` int DEFAULT NULL COMMENT '鍒囩墖鍐呭闀垮害',
- `vector_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍚戦噺搴撶殑缂栧彿',
- `tokens` int DEFAULT NULL COMMENT 'token 鏁伴噺',
- `retrieval_count` int NOT NULL DEFAULT 0 COMMENT '鍙洖娆℃暟',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 鐭ヨ瘑搴撴枃妗e垎娈佃〃';
-
--- ----------------------------
--- 11. AI 鎬濈淮瀵煎浘琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_mind_map`;
-CREATE TABLE `ai_mind_map` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
- `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
- `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷',
- `prompt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鐢熸垚鍐呭鎻愮ず',
- `generated_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鐢熸垚鐨勫唴瀹�',
- `error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿欒淇℃伅',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 鎬濈淮瀵煎浘琛�';
-
--- ----------------------------
--- 12. AI 闊充箰琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_music`;
-CREATE TABLE `ai_music` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闊充箰鍚嶇О',
- `lyric` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '姝岃瘝',
- `image_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥剧墖鍦板潃',
- `audio_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闊抽鍦板潃',
- `video_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙嗛鍦板潃',
- `status` tinyint NOT NULL COMMENT '闊充箰鐘舵��',
- `generate_mode` tinyint NOT NULL COMMENT '鐢熸垚妯″紡',
- `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎻忚堪璇�',
- `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
- `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷',
- `tags` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闊充箰椋庢牸鏍囩',
- `duration` double DEFAULT NULL COMMENT '闊充箰鏃堕暱',
- `public_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏紑',
- `task_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠诲姟缂栧彿',
- `error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿欒淇℃伅',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 闊充箰琛�';
-
--- ----------------------------
--- 13. AI 鍐欎綔琛�
--- ----------------------------
-DROP TABLE IF EXISTS `ai_write`;
-CREATE TABLE `ai_write` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
- `type` tinyint NOT NULL COMMENT '鍐欎綔绫诲瀷',
- `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
- `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
- `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷',
- `prompt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鐢熸垚鍐呭鎻愮ず',
- `generated_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鐢熸垚鐨勫唴瀹�',
- `original_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鍘熸枃',
- `length` tinyint DEFAULT NULL COMMENT '闀垮害鎻愮ず璇�',
- `format` tinyint DEFAULT NULL COMMENT '鏍煎紡鎻愮ず璇�',
- `tone` tinyint DEFAULT NULL COMMENT '璇皵鎻愮ず璇�',
- `language` tinyint DEFAULT NULL COMMENT '璇█鎻愮ず璇�',
- `error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿欒淇℃伅',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 鍐欎綔琛�';
-
--- ----------------------------
--- 14. AI 宸ヤ綔娴佽〃
--- ----------------------------
-DROP TABLE IF EXISTS `ai_workflow`;
-CREATE TABLE `ai_workflow` (
- `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
- `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '宸ヤ綔娴佸悕绉�',
- `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '宸ヤ綔娴佹爣璇�',
- `graph` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '宸ヤ綔娴佹ā鍨� JSON 鏁版嵁',
- `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
- `status` tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵��',
- `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
- `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
- `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AI 宸ヤ綔娴佽〃';
\ No newline at end of file
diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql
index 3f498b3..4d34a54 100644
--- a/sql/mysql/ruoyi-vue-pro.sql
+++ b/sql/mysql/ruoyi-vue-pro.sql
@@ -11,7 +11,7 @@
Target Server Version : 80200 (8.2.0)
File Encoding : 65001
- Date: 16/05/2026 06:24:32
+ Date: 29/06/2026 17:18:58
*/
SET NAMES utf8mb4;
@@ -49,7 +49,7 @@
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛缂栧彿',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 36301 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 璁块棶鏃ュ織琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 36346 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'API 璁块棶鏃ュ織琛�';
-- ----------------------------
-- Records of infra_api_access_log
@@ -92,7 +92,7 @@
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛缂栧彿',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 23883 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '绯荤粺寮傚父鏃ュ織';
+) ENGINE = InnoDB AUTO_INCREMENT = 24453 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '绯荤粺寮傚父鏃ュ織';
-- ----------------------------
-- Records of infra_api_error_log
@@ -253,7 +253,7 @@
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2216 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鏂囦欢琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 2260 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鏂囦欢琛�';
-- ----------------------------
-- Records of infra_file
@@ -284,17 +284,17 @@
-- Records of infra_file_config
-- ----------------------------
BEGIN;
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '鏁版嵁搴擄紙绀轰緥锛�', 1, '鎴戞槸鏁版嵁搴�', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '涓冪墰瀛樺偍鍣紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鑷繁鐨勫瘑閽ワ紒锛侊紒', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-01-13 22:11:12', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '鑵捐浜戝瓨鍌紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鐨勫瘑閽ワ紒锛侊紒', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:03:22', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '闃块噷浜戝瓨鍌紙绀轰緥锛�', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:47:08', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '鐏北浜戝瓨鍌紙绀轰緥锛�', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:56:42', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '鍗庝负浜戝瓨鍌紙绀轰緥锛�', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:18:41', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 瀛樺偍锛堢ず渚嬶級', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:43:10', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (29, '鏈湴瀛樺偍锛堢ず渚嬶級', 10, 'mac/linux 浣跨敤 /锛寃indows 浣跨敤 \\', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig\",\"basePath\":\"/Users/yunai/tmp/file\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2025-05-02 11:25:45', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (30, 'SFTP 瀛樺偍锛堢ず渚嬶級', 12, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig\",\"basePath\":\"/upload\",\"domain\":\"http://127.0.0.1:48080\",\"host\":\"127.0.0.1\",\"port\":2222,\"username\":\"foo\",\"password\":\"pass\"}', '1', '2025-05-02 16:34:10', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (34, '涓冪墰浜戝瓨鍌ㄣ�愮鏈夈�戯紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鑷繁鐨勫瘑閽ワ紒锛侊紒', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://t151glocd.hn-bkt.clouddn.com\",\"bucket\":\"ruoyi-vue-pro-private\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false}', '1', '2025-08-17 21:22:00', '1', '2025-11-24 20:57:14', b'0');
-INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (35, '1', 20, '1', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://www.baidu.com\",\"domain\":\"http://www.xxx.com\",\"bucket\":\"1\",\"accessKey\":\"2\",\"accessSecret\":\"3\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false,\"region\":\"1\"}', '1', '2025-10-02 14:32:12', '1', '2025-11-29 15:59:39', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '鏁版嵁搴擄紙绀轰緥锛�', 1, '鎴戞槸鏁版嵁搴�', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2022-03-15 23:56:24', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (22, '涓冪墰瀛樺偍鍣紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鑷繁鐨勫瘑閽ワ紒锛侊紒', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://test.yudao.iocoder.cn\",\"bucket\":\"ruoyi-vue-pro\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-01-13 22:11:12', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (24, '鑵捐浜戝瓨鍌紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鐨勫瘑閽ワ紒锛侊紒', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"https://cos.ap-shanghai.myqcloud.com\",\"domain\":\"http://tengxun-oss.iocoder.cn\",\"bucket\":\"aoteman-1255880240\",\"accessKey\":\"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:03:22', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (25, '闃块噷浜戝瓨鍌紙绀轰緥锛�', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"http://ali-oss.iocoder.cn\",\"bucket\":\"yunai-aoteman\",\"accessKey\":\"LTAI5tEQLgnDyjh3WpNcdMKA\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:47:08', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (26, '鐏北浜戝瓨鍌紙绀轰緥锛�', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"tos-s3-cn-beijing.volces.com\",\"domain\":null,\"bucket\":\"yunai\",\"accessKey\":\"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE\",\"accessSecret\":\"X==\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 16:56:42', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (27, '鍗庝负浜戝瓨鍌紙绀轰緥锛�', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"obs.cn-east-3.myhuaweicloud.com\",\"domain\":\"\",\"bucket\":\"yudao\",\"accessKey\":\"PVDONDEIOTW88LF8DC4U\",\"accessSecret\":\"X\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:18:41', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (28, 'MinIO 瀛樺偍锛堢ず渚嬶級', 20, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://127.0.0.1:9000\",\"domain\":\"http://127.0.0.1:9000/yudao\",\"bucket\":\"yudao\",\"accessKey\":\"admin\",\"accessSecret\":\"password\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":true}', '1', '2024-11-09 17:43:10', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (29, '鏈湴瀛樺偍锛堢ず渚嬶級', 10, 'mac/linux 浣跨敤 /锛寃indows 浣跨敤 \\', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig\",\"basePath\":\"/Users/yunai/tmp/file\",\"domain\":\"http://127.0.0.1:48080\"}', '1', '2025-05-02 11:25:45', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (30, 'SFTP 瀛樺偍锛堢ず渚嬶級', 12, '', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig\",\"basePath\":\"/upload\",\"domain\":\"http://127.0.0.1:48080\",\"host\":\"127.0.0.1\",\"port\":2222,\"username\":\"foo\",\"password\":\"pass\"}', '1', '2025-05-02 16:34:10', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (34, '涓冪墰浜戝瓨鍌ㄣ�愮鏈夈�戯紙绀轰緥锛�', 20, '璇锋崲鎴愪綘鑷繁鐨勫瘑閽ワ紒锛侊紒', b'0', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"s3.cn-south-1.qiniucs.com\",\"domain\":\"http://t151glocd.hn-bkt.clouddn.com\",\"bucket\":\"ruoyi-vue-pro-private\",\"accessKey\":\"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS\",\"accessSecret\":\"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false}', '1', '2025-08-17 21:22:00', '1', '2026-06-26 12:23:25', b'0');
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (35, '1', 20, '1', b'1', '{\"@class\":\"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig\",\"endpoint\":\"http://www.baidu.com\",\"domain\":\"http://www.xxx.com\",\"bucket\":\"1\",\"accessKey\":\"2\",\"accessSecret\":\"3\",\"enablePathStyleAccess\":false,\"enablePublicAccess\":false,\"region\":\"1\"}', '1', '2025-10-02 14:32:12', '1', '2026-06-26 12:23:25', b'0');
COMMIT;
-- ----------------------------
@@ -313,7 +313,7 @@
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_config_id_path`(`config_id` ASC, `path` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 286 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鏂囦欢琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 288 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鏂囦欢琛�';
-- ----------------------------
-- Records of infra_file_content
@@ -462,7 +462,7 @@
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1061096 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '瀛楀吀鏁版嵁琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 1061137 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '瀛楀吀鏁版嵁琛�';
-- ----------------------------
-- Records of system_dict_data
@@ -1095,6 +1095,8 @@
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3035, 40, '鏀粯瀹濆皬绋嬪簭', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3036, 60, 'Admin Uniapp 绉诲姩绔�', '60', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-12-16 19:25:51', '1', '2025-12-17 09:46:15', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3037, 42, 'Vben5.0 Antdv Next Schema 妯$増', '42', 'infra_codegen_front_type', 0, '', '', '', '1', '2026-05-23 13:52:25', '1', '2026-05-23 13:52:25', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3038, 43, 'Vben5.0 Antdv Next 鏍囧噯妯$増', '43', 'infra_codegen_front_type', 0, '', '', '', '1', '2026-05-23 13:52:25', '1', '2026-05-23 13:52:25', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3040, 1, 'UDP', 'udp', 'iot_protocol_type', 0, '', '', 'UDP 鍗忚', '1', '2026-02-04 00:32:47', '1', '2026-02-04 00:32:47', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3041, 2, 'WebSocket', 'websocket', 'iot_protocol_type', 0, '', '', 'WebSocket 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3042, 3, 'HTTP', 'http', 'iot_protocol_type', 0, '', '', 'HTTP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', b'0');
@@ -1372,17 +1374,14 @@
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3443, 1, '鑽夌', '0', 'mes_wm_product_produce_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3444, 2, '宸插畬鎴�', '4', 'mes_wm_product_produce_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3445, 3, '宸插彇娑�', '5', 'mes_wm_product_produce_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3446, 0, '猫聧鈥懊�', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3447, 1, '氓路虏氓庐艗忙藛聬', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3448, 2, '氓路虏氓聫鈥撁β端�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3520, 1, '鏈', '0', 'im_private_message_status', 0, 'warning', '', '绉佽亰=鏈锛岀兢鑱�=姝e父', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 15:14:36', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3521, 2, '宸叉挙鍥�', '2', 'im_private_message_status', 0, 'danger', '', 'RECALL', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 15:14:36', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3522, 3, '宸茶', '3', 'im_private_message_status', 0, 'success', '', 'READ锛堜粎绉佽亰锛�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 15:14:36', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3525, 1, '姝e父', '0', 'im_group_message_status', 0, 'success', '', '缇よ亰姝e父锛堝垵濮嬬姸鎬侊級', 'admin', '2026-04-30 15:14:36', 'admin', '2026-04-30 15:14:36', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3526, 2, '宸叉挙鍥�', '2', 'im_group_message_status', 0, 'danger', '', '缇よ亰宸叉挙鍥�', 'admin', '2026-04-30 15:14:36', 'admin', '2026-04-30 15:14:36', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3530, 1, '涓嶉渶瑕佸洖鎵�', '0', 'im_group_message_receipt_status', 0, 'info', '', 'NO_RECEIPT', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3531, 2, '寰呭畬鎴�', '1', 'im_group_message_receipt_status', 0, 'warning', '', 'PENDING', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3532, 3, '宸插畬鎴�', '2', 'im_group_message_receipt_status', 0, 'success', '', 'DONE', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3446, 0, '鑽夌', '0', 'mes_pro_task_status', 0, 'default', '', 'PREPARE', '1', '2026-04-16 09:47:00', '1', '2026-06-13 10:32:58', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3447, 1, '宸插畬鎴�', '4', 'mes_pro_task_status', 0, 'success', '', 'FINISHED', '1', '2026-04-16 09:47:00', '1', '2026-06-13 10:32:58', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3448, 2, '宸插彇娑�', '5', 'mes_pro_task_status', 0, 'danger', '', 'CANCELED', '1', '2026-04-16 09:47:00', '1', '2026-06-13 10:32:58', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3525, 1, '姝e父', '0', 'im_message_status', 0, 'success', '', '姝e父锛堝垵濮嬬姸鎬侊級', 'admin', '2026-04-30 15:14:36', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3526, 2, '宸叉挙鍥�', '2', 'im_message_status', 0, 'danger', '', '宸叉挙鍥�', 'admin', '2026-04-30 15:14:36', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3530, 1, '涓嶉渶瑕佸洖鎵�', '0', 'im_message_receipt_status', 0, 'info', '', 'NO_RECEIPT', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-14 00:32:47', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3531, 2, '寰呭畬鎴�', '1', 'im_message_receipt_status', 0, 'warning', '', 'PENDING', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-14 00:32:47', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3532, 3, '宸插畬鎴�', '2', 'im_message_receipt_status', 0, 'success', '', 'DONE', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-14 00:32:47', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3540, 1, '姝e父', '0', 'im_friend_status', 0, 'success', '', '姝e父濂藉弸鍏崇郴', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3541, 2, '宸插垹闄�', '1', 'im_friend_status', 0, 'danger', '', '宸插垹闄ゅソ鍙嬪叧绯�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3550, 1, '姝e父', '0', 'im_group_status', 0, 'success', '', '缇ゆ甯�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0');
@@ -1397,39 +1396,39 @@
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3559, 1, '绛夊緟楠岃瘉', '0', 'im_friend_request_handle_result', 0, 'warning', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3560, 2, '宸叉坊鍔�', '1', 'im_friend_request_handle_result', 0, 'success', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3561, 3, '宸叉嫆缁�', '2', 'im_friend_request_handle_result', 0, 'info', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3562, 101, '鏂囨湰', '101', 'im_message_type', 0, '', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3563, 102, '鍥剧墖', '102', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3564, 103, '璇煶', '103', 'im_message_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3565, 104, '瑙嗛', '104', 'im_message_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3566, 105, '鏂囦欢', '105', 'im_message_type', 0, 'info', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3568, 2101, '鎾ゅ洖', '2101', 'im_message_type', 0, 'danger', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3569, 2200, '鍥炴墽', '2200', 'im_message_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3570, 2201, '宸茶', '2201', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3571, 1501, '缇ゅ垱寤�', '1501', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3572, 1502, '缇や俊鎭彉鏇�', '1502', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3573, 1503, '鍏ョ兢鐢宠', '1503', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3574, 1504, '鎴愬憳閫�缇�', '1504', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3575, 1505, '鍏ョ兢鐢宠閫氳繃', '1505', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3576, 1506, '鍏ョ兢鐢宠鎷掔粷', '1506', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3577, 1507, '缇や富杞', '1507', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3578, 1508, '鎴愬憳琚Щ鍑�', '1508', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3579, 1509, '鎴愬憳鍔犲叆', '1509', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3580, 1510, '鑷敱杩涚兢', '1510', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3581, 1511, '缇よВ鏁�', '1511', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3582, 1512, '鎴愬憳绂佽█', '1512', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3583, 1513, '鎴愬憳鍙栨秷绂佽█', '1513', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3584, 1514, '鍏ㄧ兢绂佽█', '1514', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3585, 1515, '鍏ㄧ兢鍙栨秷绂佽█', '1515', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3586, 1516, '鎴愬憳鏄电О鍙樻洿', '1516', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3587, 1517, '娣诲姞绠$悊鍛�', '1517', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3588, 1518, '鎾ら攢绠$悊鍛�', '1518', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3589, 1519, '缇ゅ叕鍛婂彉鏇�', '1519', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3590, 1520, '缇ゅ悕鍙樻洿', '1520', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3591, 1531, '缇ゆ秷鎭疆椤�', '1531', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3592, 1532, '缇ゆ秷鎭彇娑堢疆椤�', '1532', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3593, 1533, '缇ゅ皝绂佸彉鏇�', '1533', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-05-05 11:52:30', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3594, 1204, '鏂板濂藉弸', '1204', 'im_message_type', 0, 'success', '', NULL, 'admin', '2026-05-05 13:26:53', 'admin', '2026-05-05 13:26:53', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3595, 1205, '濂藉弸琚垹闄�', '1205', 'im_message_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 13:26:53', 'admin', '2026-05-05 13:26:53', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3562, 101, '鏂囨湰', '101', 'im_content_type', 0, '', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3563, 102, '鍥剧墖', '102', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3564, 103, '璇煶', '103', 'im_content_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3565, 104, '瑙嗛', '104', 'im_content_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3566, 105, '鏂囦欢', '105', 'im_content_type', 0, 'info', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3568, 2101, '鎾ゅ洖', '2101', 'im_content_type', 0, 'danger', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3569, 2200, '鍥炴墽', '2200', 'im_content_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3570, 2201, '宸茶', '2201', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3571, 1501, '缇ゅ垱寤�', '1501', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3572, 1502, '缇や俊鎭彉鏇�', '1502', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3573, 1503, '鏀跺埌鏂扮殑鍏ョ兢鐢宠', '1503', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3574, 1504, '鎴愬憳閫�缇�', '1504', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3575, 1505, '鍏ョ兢鐢宠琚悓鎰�', '1505', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3576, 1506, '鍏ョ兢鐢宠琚嫆缁�', '1506', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3577, 1507, '缇や富杞', '1507', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3578, 1508, '鎴愬憳琚Щ鍑�', '1508', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3579, 1509, '鎴愬憳鍔犲叆', '1509', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3580, 1510, '鑷敱杩涚兢', '1510', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3581, 1511, '缇よВ鏁�', '1511', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3582, 1512, '鎴愬憳绂佽█', '1512', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3583, 1513, '鎴愬憳鍙栨秷绂佽█', '1513', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3584, 1514, '鍏ㄧ兢绂佽█', '1514', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3585, 1515, '鍏ㄧ兢鍙栨秷绂佽█', '1515', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3586, 1516, '鎴愬憳鏄电О鍙樻洿', '1516', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3587, 1517, '娣诲姞绠$悊鍛�', '1517', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3588, 1518, '鎾ら攢绠$悊鍛�', '1518', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3589, 1519, '缇ゅ叕鍛婂彉鏇�', '1519', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3590, 1520, '缇ゅ悕鍙樻洿', '1520', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3591, 1531, '缇ゆ秷鎭疆椤�', '1531', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3592, 1532, '缇ゆ秷鎭彇娑堢疆椤�', '1532', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3593, 1533, '缇ゅ皝绂佸彉鏇�', '1533', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3594, 1204, '鏂板濂藉弸', '1204', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-05-05 13:26:53', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3595, 1205, '濂藉弸琚垹闄�', '1205', 'im_content_type', 0, 'warning', '', NULL, 'admin', '2026-05-05 13:26:53', 'admin', '2026-06-16 03:41:55', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3596, 1, '鎼滅储', '1', 'im_group_add_source', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3597, 2, '閭�璇�', '2', 'im_group_add_source', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3598, 3, '鎵爜', '3', 'im_group_add_source', 0, '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', b'0');
@@ -1454,8 +1453,47 @@
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061091, 1, '閫�璐у嚭搴�', '200', 'wms_shipment_order_type', 0, 'warning', '', '閫�璐у嚭搴�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061092, 2, '閿�鍞嚭搴�', '201', 'wms_shipment_order_type', 0, 'primary', '', '閿�鍞嚭搴�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', b'0');
INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061093, 3, '鐢熶骇鍑哄簱', '202', 'wms_shipment_order_type', 0, 'success', '', '鐢熶骇鍑哄簱', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061094, 1, '猫炉颅茅鸥鲁', '1', 'im_rtc_call_media_type', 0, '', '', '猫炉颅茅鸥鲁茅鈧∶�', 'admin', '2026-05-14 13:48:31', 'admin', '2026-05-14 13:48:31', b'0');
-INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061095, 2, '猫搂鈥犆┞⑩��', '2', 'im_rtc_call_media_type', 0, '', '', '猫搂鈥犆┞⑩�樏┾偓拧猫炉聺', 'admin', '2026-05-14 13:48:31', 'admin', '2026-05-14 13:48:31', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061096, 1, '璇煶', '1', 'im_rtc_call_media_type', 0, '', '', '璇煶閫氳瘽', 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061097, 2, '瑙嗛', '2', 'im_rtc_call_media_type', 0, '', '', '瑙嗛閫氳瘽', 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061098, 1, '绉佽亰', '1', 'im_rtc_call_conversation_type', 0, 'primary', '', '涓�瀵逛竴绉佽亰閫氳瘽', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061099, 2, '缇よ亰', '2', 'im_rtc_call_conversation_type', 0, 'success', '', '缇ゅ唴澶氫汉閫氳瘽', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061100, 1, '鍒涘缓', '10', 'im_rtc_call_status', 0, 'info', '', '閫氳瘽宸插垱寤猴紝绛夊緟鎺ラ��', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061101, 2, '杩涜涓�', '20', 'im_rtc_call_status', 0, 'primary', '', '宸叉湁浜烘帴閫氾紝閫氳瘽涓�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061102, 3, '宸茬粨鏉�', '30', 'im_rtc_call_status', 0, 'success', '', '閫氳瘽缁撴潫', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061103, 1, '閫氳瘽缁撴潫', '1', 'im_rtc_call_end_reason', 0, 'success', '', '鎺ラ�氬悗浠讳竴鏂逛富鍔ㄦ寕鏂�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061104, 2, '宸叉嫆缁�', '2', 'im_rtc_call_end_reason', 0, 'warning', '', '琚彨鎺ラ�氬墠鐐规嫆鎺�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061105, 3, '宸插彇娑�', '3', 'im_rtc_call_end_reason', 0, 'info', '', '涓诲彨鎺ラ�氬墠涓诲姩鍙栨秷', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061106, 4, '鏃犱汉鎺ュ惉', '4', 'im_rtc_call_end_reason', 0, 'info', '', '鎸搩瓒呮椂鏈帴閫�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061107, 5, '瀵规柟姝e繖', '5', 'im_rtc_call_end_reason', 0, 'warning', '', '瀵规柟鍦ㄥ彟涓�閫氳瘽涓�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061108, 6, '閫氳瘽寮傚父', '9', 'im_rtc_call_end_reason', 0, 'danger', '', '缃戠粶涓柇銆佽澶囧け璐ョ瓑', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061109, 1, '鍙戣捣浜�', '1', 'im_rtc_participant_role', 0, 'primary', '', '閫氳瘽鍙戣捣鑰�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061110, 2, '琚個璇疯��', '2', 'im_rtc_participant_role', 0, 'info', '', '琚個璇峰姞鍏�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061111, 3, '涓诲姩鍔犲叆鑰�', '3', 'im_rtc_participant_role', 0, 'success', '', '缇ら�氳瘽鍦烘櫙锛屾梺瑙傝�呬富鍔ㄥ姞鍏�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061112, 1, '閭�璇蜂腑', '10', 'im_rtc_participant_status', 0, 'info', '', '宸插彂鍑� invite锛岀瓑寰呭搷搴�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061113, 2, '宸插姞鍏�', '20', 'im_rtc_participant_status', 0, 'primary', '', '宸叉帴閫氬苟杩涘叆鎴块棿', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061114, 3, '宸叉嫆缁�', '30', 'im_rtc_participant_status', 0, 'warning', '', '鎺ラ�氬墠鐐规嫆鎺�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061115, 4, '鏈簲绛�', '40', 'im_rtc_participant_status', 0, 'info', '', '閫氳瘽宸茬粨鏉熶粛鏈簲绛�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061116, 5, '宸茬寮�', '50', 'im_rtc_participant_status', 0, 'success', '', '鎺ラ�氬悗鎸傛柇 / 绂诲紑', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061117, 1610, '閫氳瘽寮�濮�', '1610', 'im_content_type', 0, 'info', '', '鍏ユ秷鎭祦锛涚鑱婂畾鍚戦�氱煡锛岀兢鑱婂叏鍛樺箍鎾�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061118, 1611, '閫氳瘽缁撴潫', '1611', 'im_content_type', 0, 'info', '', '鍏ユ秷鎭祦锛涚鑱婂噯姘旀场锛岀兢鑱婄郴缁� tip', 'admin', '2026-05-18 03:36:12', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061119, 125, '绱犳潗', '125', 'im_content_type', 0, 'success', '', '棰戦亾杩愯惀鎺ㄩ�佺殑鍥炬枃鍗$墖娑堟伅', '1', '2026-05-18 13:14:34', 'admin', '2026-06-16 03:41:55', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061120, 1, '瀵屾枃鏈�', '1', 'im_channel_material_type', 0, 'primary', '', '', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061121, 2, '澶栭摼', '2', 'im_channel_material_type', 0, 'info', '', '', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061122, 7, 'SN 鐮�', '109', 'mes_wm_barcode_biz_type', 0, 'default', '', 'SN', '1', '2026-06-13 10:30:30', '1', '2026-06-13 10:30:30', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061123, 107, '鍚堝苟杞彂', '107', 'im_content_type', 0, '', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061124, 108, '鍚嶇墖', '108', 'im_content_type', 0, '', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061125, 115, '琛ㄦ儏', '115', 'im_content_type', 0, '', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061126, 1201, '濂藉弸鐢宠琚悓鎰�', '1201', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061127, 1202, '濂藉弸鐢宠琚嫆缁�', '1202', 'im_content_type', 0, 'warning', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061128, 1203, '鏀跺埌鏂扮殑濂藉弸鐢宠', '1203', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061129, 1207, '鍔犲叆榛戝悕鍗�', '1207', 'im_content_type', 0, 'danger', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061130, 1208, '绉诲嚭榛戝悕鍗�', '1208', 'im_content_type', 0, 'success', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061131, 1209, '濂藉弸璧勬枡鍙樻洿', '1209', 'im_content_type', 0, 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061132, 1210, '濂藉弸淇℃伅鎵归噺鏇存柊', '1210', 'im_content_type', 0, 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061133, 1530, '缇ゆ垚鍛樹釜浜鸿缃彉鏇�', '1530', 'im_content_type', 0, 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061134, 1601, '閫氳瘽淇′护', '1601', 'im_content_type', 0, 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061135, 1602, '閫氳瘽鍙備笌鑰呭姞鍏�', '1602', 'im_content_type', 0, 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061136, 1603, '閫氳瘽鍙備笌鑰呯寮�', '1603', 'im_content_type', 0, 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', b'0');
COMMIT;
-- ----------------------------
@@ -1475,7 +1513,7 @@
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
`deleted_time` datetime NULL DEFAULT NULL COMMENT '鍒犻櫎鏃堕棿',
PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1061092 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '瀛楀吀绫诲瀷琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 1061099 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '瀛楀吀绫诲瀷琛�';
-- ----------------------------
-- Records of system_dict_type
@@ -1613,7 +1651,7 @@
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2029, 'MES 宸ュ崟绫诲瀷', 'mes_pro_work_order_type', 0, 'MES 鐢熶骇绠$悊 - 宸ュ崟绫诲瀷锛�1=鑷鐢熶骇锛�2=浠e伐锛�3=閲囪喘锛�', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2036, 'MES 宸ュ簭鍏崇郴绫诲瀷', 'mes_pro_link_type', 0, '宸ヨ壓璺嚎涓伐搴忎箣闂寸殑鍏崇郴绫诲瀷', '1', '2026-02-19 04:24:53', '1', '2026-04-05 15:05:07', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2037, 'MES 鏃堕棿鍗曚綅', 'mes_time_unit_type', 0, '鐢熶骇鏃堕棿鐨勮閲忓崟浣�', '1', '2026-02-19 04:24:53', '1', '2026-04-05 15:04:57', b'0', NULL);
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2038, 'MES 鐢熶骇浠诲姟鐘舵��', 'mes_pro_task_status', 0, 'MES 鐢熶骇绠$悊 - 浠诲姟鐘舵�侊紙0=鑽夌锛�1=杩涜涓紝2=鏆傚仠锛�3=宸插畬鎴愶紝4=宸插彇娑堬級', '1', '2026-02-19 15:25:27', '1', '2026-02-19 15:25:27', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2038, 'MES 鐢熶骇浠诲姟鐘舵��', 'mes_pro_task_status', 0, 'MES 鐢熶骇绠$悊 - 浠诲姟鐘舵�侊紙0=鑽夌锛�4=宸插畬鎴愶紝5=宸插彇娑堬級', '1', '2026-02-19 15:25:27', '1', '2026-06-13 10:32:58', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2039, 'MES 鐐规淇濆吇椤圭洰绫诲瀷', 'mes_dv_subject_type', 0, 'MES 璁惧绠$悊 - 鐐规淇濆吇椤圭洰绫诲瀷锛�1=璁惧鐐规锛�2=璁惧淇濆吇锛�', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2040, 'MES 淇濆吇璁板綍鐘舵��', 'mes_mainten_record_status', 0, NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2041, 'MES 淇濆吇缁撴灉', 'mes_mainten_status', 0, NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', b'0', NULL);
@@ -1666,12 +1704,11 @@
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2133, 'MES 閿�鍞��璐у崟鐘舵��', 'mes_wm_return_sales_status', 0, 'MES 閿�鍞��璐у崟鐘舵�佹灇涓�', '1', '2026-04-03 17:20:25', '1', '2026-04-05 15:05:39', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2135, 'MES 涓婁笅宸ョ姸鎬佺被鍨�', 'mes_pro_work_record_type', 0, 'MES 涓婁笅宸ョ姸鎬佺被鍨�', '1', '2026-04-05 14:07:27', '1', '2026-04-05 14:07:27', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2138, 'MES 鐢熶骇鍏ュ簱鍗曠姸鎬�', 'mes_wm_product_produce_status', 0, 'MES 鐢熶骇鍏ュ簱鍗曠姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', b'0', '1970-01-01 00:00:00');
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2200, 'IM 娑堟伅绫诲瀷', 'im_message_type', 0, '瀵瑰簲 ImMessageTypeEnum', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0', NULL);
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2201, 'IM 绉佽亰娑堟伅鐘舵��', 'im_private_message_status', 0, '瀵瑰簲 ImMessageStatusEnum锛涚鑱� 0=鏈 / 2=宸叉挙鍥� / 3=宸茶', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 15:14:36', b'0', NULL);
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2202, 'IM 缇ゆ秷鎭洖鎵х姸鎬�', 'im_group_message_receipt_status', 0, '瀵瑰簲 ImGroupMessageReceiptStatusEnum', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2200, 'IM 鍐呭绫诲瀷', 'im_content_type', 0, '瀵瑰簲 ImContentTypeEnum', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-16 03:41:55', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2202, 'IM 娑堟伅鍥炴墽鐘舵��', 'im_message_receipt_status', 0, '瀵瑰簲 ImMessageReceiptStatusEnum', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-16 03:41:55', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2203, 'IM 濂藉弸鐘舵��', 'im_friend_status', 0, '0=姝e父 / 1=宸插垹闄�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2204, 'IM 缇ょ姸鎬�', 'im_group_status', 0, '0=姝e父 / 1=宸茶В鏁�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', b'0', NULL);
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2205, 'IM 缇よ亰娑堟伅鐘舵��', 'im_group_message_status', 0, '瀵瑰簲 ImMessageStatusEnum锛涚兢鑱� 0=姝e父 / 2=宸叉挙鍥烇紙鏃犳湭璇绘蹇碉級', 'admin', '2026-04-30 15:14:36', 'admin', '2026-04-30 15:14:36', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2205, 'IM 娑堟伅鐘舵��', 'im_message_status', 0, '瀵瑰簲 ImMessageStatusEnum锛�0=姝e父 / 2=宸叉挙鍥烇紙绉佽亰 / 缇よ亰鍏辩敤锛�', 'admin', '2026-04-30 15:14:36', 'admin', '2026-06-16 03:41:55', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2206, 'IM 缇ゆ垚鍛樿鑹�', 'im_group_member_role', 0, NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2207, 'IM 濂藉弸娣诲姞鏉ユ簮', 'im_friend_add_source', 0, NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (2208, 'IM 濂藉弸鐢宠澶勭悊缁撴灉', 'im_friend_request_handle_result', 0, NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', b'0', NULL);
@@ -1682,7 +1719,13 @@
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061070, 'WMS 鍗曟嵁鐘舵��', 'wms_order_status', 0, 'WMS 鍗曟嵁鐘舵��', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061080, '鍏ュ簱鍗曠被鍨�', 'wms_receipt_order_type', 0, 'WMS 鍏ュ簱鍗曠被鍨�', '1', '2026-05-11 11:21:49', '1', '2026-05-12 13:40:29', b'0', NULL);
INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061090, '鍑哄簱鍗曠被鍨�', 'wms_shipment_order_type', 0, 'WMS 鍑哄簱鍗曠被鍨�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', b'0', NULL);
-INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061091, 'IM 茅鈧∶澝ヂ�櫭ぢ解�溍甭幻ヅ锯��', 'im_rtc_call_media_type', 0, NULL, 'admin', '2026-05-14 13:48:31', 'admin', '2026-05-14 13:48:31', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061092, 'IM 閫氳瘽濯掍綋绫诲瀷', 'im_rtc_call_media_type', 0, NULL, 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061093, 'IM 閫氳瘽浼氳瘽绫诲瀷', 'im_rtc_call_conversation_type', 0, '1=绉佽亰锛�2=缇よ亰', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061094, 'IM 閫氳瘽鐘舵��', 'im_rtc_call_status', 0, '10=鍒涘缓锛�20=杩涜涓紱30=宸茬粨鏉�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061095, 'IM 閫氳瘽缁撴潫鍘熷洜', 'im_rtc_call_end_reason', 0, '1=閫氳瘽缁撴潫锛�2=宸叉嫆缁濓紱3=宸插彇娑堬紱4=鏃犱汉鎺ュ惉锛�5=瀵规柟姝e繖锛�9=閫氳瘽寮傚父', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061096, 'IM 閫氳瘽鍙備笌瑙掕壊', 'im_rtc_participant_role', 0, '1=鍙戣捣浜猴紱2=琚個璇疯�咃紱3=涓诲姩鍔犲叆鑰�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061097, 'IM 閫氳瘽鍙備笌鐘舵��', 'im_rtc_participant_status', 0, '10=閭�璇蜂腑锛�20=宸插姞鍏ワ紱30=宸叉嫆缁濓紱40=鏈簲绛旓紱50=宸茬寮�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL);
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061098, 'IM 棰戦亾绱犳潗鍐呭绫诲瀷', 'im_channel_material_type', 0, '1=绔欏唴瀵屾枃鏈� / 2=澶栭摼', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', b'0', NULL);
COMMIT;
-- ----------------------------
@@ -1708,7 +1751,7 @@
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_username`(`username` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 4557 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '绯荤粺璁块棶璁板綍';
+) ENGINE = InnoDB AUTO_INCREMENT = 5367 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '绯荤粺璁块棶璁板綍';
-- ----------------------------
-- Records of system_login_log
@@ -1841,7 +1884,7 @@
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 6611 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鑿滃崟鏉冮檺琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 6735 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鑿滃崟鏉冮檺琛�';
-- ----------------------------
-- Records of system_menu
@@ -2186,7 +2229,7 @@
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2156, '鏌ヨ椤圭洰', 'report:go-view-project:query', 3, 0, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:25:53', '1', '2023-02-07 19:25:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2157, '浣跨敤 SQL 鏌ヨ鏁版嵁', 'report:go-view-data:get-by-sql', 3, 3, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:26:15', '1', '2023-02-07 19:26:15', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2158, '浣跨敤 HTTP 鏌ヨ鏁版嵁', 'report:go-view-data:get-by-http', 3, 4, 2153, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2023-02-07 19:26:35', '1', '2023-02-07 19:26:35', b'0');
-INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2159, 'Boot 寮�鍙戞枃妗�', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-02-10 22:46:28', '1', '2026-01-05 19:31:07', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2159, 'Boot 寮�鍙戞枃妗�', '', 1, 1, 0, 'https://doc.iocoder.cn/', 'ep:document', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-02-10 22:46:28', '1', '2026-06-12 00:05:19', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2160, 'Cloud 寮�鍙戞枃妗�', '', 1, 2, 0, 'https://cloud.iocoder.cn', 'ep:document-copy', NULL, NULL, 0, b'1', b'1', b'1', '1', '2023-02-10 22:47:07', '1', '2023-12-02 21:32:29', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2161, '鎺ュ叆绀轰緥', '', 1, 99, 1117, 'demo', 'fa-solid:dragon', 'pay/demo/index', NULL, 0, b'1', b'1', b'1', '', '2023-02-11 14:21:42', '1', '2024-01-18 23:50:00', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2162, '鍟嗗搧瀵煎嚭', 'product:spu:export', 3, 5, 2014, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2022-07-30 14:22:58', '', '2022-07-30 14:22:58', b'0');
@@ -2773,7 +2816,7 @@
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5034, 'OTA 鍥轰欢鍒涘缓', 'iot:ota-firmware:create', 3, 2, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:21', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5035, 'OTA 鍥轰欢鏇存柊', 'iot:ota-firmware:update', 3, 3, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:29', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5036, 'OTA 鍥轰欢鍒犻櫎', 'iot:ota-firmware:delete', 3, 4, 5032, '', '', '', '', 0, b'1', b'1', b'1', '', '2025-06-30 07:50:29', '\"1\"', '2025-06-30 17:38:37', b'0');
-INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5037, 'OTA 鍗囩骇浠诲姟鏌ヨ', 'iot:ota-task:create', 3, 11, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:56:56', '1', '2025-07-02 23:56:56', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5037, 'OTA 鍗囩骇浠诲姟鏌ヨ', 'iot:ota-task:query', 3, 11, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:56:56', '1', '2026-05-19 08:48:53', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5038, 'OTA 鍗囩骇浠诲姟鍙栨秷', 'iot:ota-task:cancel', 3, 13, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:57:26', '1', '2025-07-02 23:57:26', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5039, 'OTA 鍗囩骇浠诲姟鍒涘缓', 'iot:ota-task:create', 3, 12, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:57:52', '1', '2025-07-02 23:57:52', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (5040, 'OTA 鍗囩骇璁板綍鏌ヨ', 'iot:ota-task-record:query', 3, 21, 5032, '', '', '', '', 0, b'1', b'1', b'1', '1', '2025-07-02 23:58:30', '1', '2025-07-02 23:58:30', b'0');
@@ -3270,6 +3313,24 @@
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6582, '鐢ㄦ埛琛ㄦ儏鍒犻櫎', 'im:manager:face-user-item:delete', 3, 20, 6580, '', '', '', '', 0, b'1', b'1', b'1', '', '2026-05-06 13:56:08', '', '2026-05-06 13:56:08', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6600, '绉佽亰绠$悊', '', 1, 20, 6500, 'private', 'ep:chat-round', NULL, NULL, 0, b'1', b'1', b'1', '1', '2026-05-07 00:40:35', '1', '2026-05-07 00:40:35', b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6610, '缇よ亰绠$悊', '', 1, 30, 6500, 'group', 'ep:chat-line-round', NULL, NULL, 0, b'1', b'1', b'1', '1', '2026-05-07 00:40:35', '1', '2026-05-07 00:40:35', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6611, '閫氳瘽璁板綍', '', 2, 40, 6500, 'rtc', 'ep:phone', 'im/manager/rtc/index', 'ImRtcCall', 0, b'1', b'1', b'1', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6612, '閫氳瘽璁板綍鏌ヨ', 'im:manager:rtc:query', 3, 1, 6611, '', '', NULL, NULL, 0, b'1', b'1', b'1', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6700, '棰戦亾绠$悊', '', 1, 90, 6500, 'channel', 'ep:promotion', NULL, NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6710, '棰戦亾鍒楄〃', '', 2, 1, 6700, 'list', 'ep:promotion', 'im/manager/channel/list/index', 'ImChannel', 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6711, '棰戦亾鏌ヨ', 'im:manager:channel:query', 3, 1, 6710, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6712, '棰戦亾鍒涘缓', 'im:manager:channel:create', 3, 2, 6710, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6713, '棰戦亾淇敼', 'im:manager:channel:update', 3, 3, 6710, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6714, '棰戦亾鍒犻櫎', 'im:manager:channel:delete', 3, 4, 6710, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6720, '棰戦亾绱犳潗', '', 2, 2, 6700, 'material', 'ep:document', 'im/manager/channel/material/index', 'ImChannelMaterial', 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6721, '绱犳潗鏌ヨ', 'im:manager:channel-material:query', 3, 1, 6720, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6722, '绱犳潗鍒涘缓', 'im:manager:channel-material:create', 3, 2, 6720, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6723, '绱犳潗淇敼', 'im:manager:channel-material:update', 3, 3, 6720, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6724, '绱犳潗鍒犻櫎', 'im:manager:channel-material:delete', 3, 4, 6720, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6730, '棰戦亾娑堟伅', '', 2, 3, 6700, 'message', 'ep:message', 'im/manager/channel/message/index', 'ImChannelMessage', 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-19 09:44:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6731, '娑堟伅鏌ヨ', 'im:manager:channel-message:query', 3, 1, 6730, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6732, '绔嬪嵆鎺ㄩ��', 'im:manager:channel-message:send', 3, 2, 6730, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6733, '娑堟伅鍒犻櫎', 'im:manager:channel-message:delete', 3, 3, 6730, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-18 13:14:34', '1', '2026-05-18 13:14:34', b'0');
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (6734, '瑙f暎缇�', 'im:manager:group:dissolve', 3, 21, 6540, '', '', '', NULL, 0, b'1', b'1', b'1', '1', '2026-05-24 12:02:38', '1', '2026-05-24 12:02:38', b'0');
COMMIT;
-- ----------------------------
@@ -3392,7 +3453,7 @@
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_access_token`(`access_token` ASC) USING BTREE,
INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 54457 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 璁块棶浠ょ墝';
+) ENGINE = InnoDB AUTO_INCREMENT = 108473 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 璁块棶浠ょ墝';
-- ----------------------------
-- Records of system_oauth2_access_token
@@ -3465,7 +3526,7 @@
INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 'default', 'admin123', '鑺嬮亾婧愮爜', 'http://test.yudao.iocoder.cn/20250502/sort2_1746189740718.png', '鎴戞槸鎻忚堪', 0, 1800, 2592000, '[\"https://www.iocoder.cn\",\"https://doc.iocoder.cn\"]', '[\"password\",\"authorization_code\",\"implicit\",\"refresh_token\",\"client_credentials\"]', '[\"user.read\",\"user.write\"]', '[]', '[\"user.read\",\"user.write\"]', '[]', '{}', '1', '2022-05-11 21:47:12', '1', '2025-12-07 20:07:09', b'0');
INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (40, 'test', 'test2', 'biubiu', 'http://test.yudao.iocoder.cn/20251227/javayuanma_1766829882970.jpg', '鍟﹀暒鍟﹀暒', 0, 1800, 43200, '[\"https://www.iocoder.cn\"]', '[\"password\",\"authorization_code\",\"implicit\"]', '[\"user_info\",\"projects\"]', '[\"user_info\"]', '[]', '[]', '{}', '1', '2022-05-12 00:28:20', '1', '2025-12-27 18:04:44', b'0');
INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (41, 'yudao-sso-demo-by-code', 'test', '鍩轰簬鎺堟潈鐮佹ā寮忥紝濡備綍瀹炵幇 SSO 鍗曠偣鐧诲綍锛�', 'http://test.yudao.iocoder.cn/it/20250502/sign_1746181948685.png', NULL, 0, 1800, 43200, '[\"http://127.0.0.1:18080\"]', '[\"authorization_code\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[]', '[]', NULL, '1', '2022-09-29 13:28:31', '1', '2025-05-02 18:32:30', b'0');
-INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (42, 'yudao-sso-demo-by-password', 'test', '鍩轰簬瀵嗙爜妯″紡锛屽浣曞疄鐜� SSO 鍗曠偣鐧诲綍锛�', 'http://test.yudao.iocoder.cn/20251025/images (3)_1761360515810.jpeg', NULL, 0, 1800, 43200, '[\"http://127.0.0.1:18080\"]', '[\"password\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2025-10-25 10:49:40', b'0');
+INSERT INTO `system_oauth2_client` (`id`, `client_id`, `secret`, `name`, `logo`, `description`, `status`, `access_token_validity_seconds`, `refresh_token_validity_seconds`, `redirect_uris`, `authorized_grant_types`, `scopes`, `auto_approve_scopes`, `authorities`, `resource_ids`, `additional_information`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (42, 'yudao-sso-demo-by-password', 'test', '鍩轰簬瀵嗙爜妯″紡锛屽浣曞疄鐜� SSO 鍗曠偣鐧诲綍锛�', 'http://test.yudao.iocoder.cn/oauth2/20260615/iShot_2026-05-31_23.18.10.png', NULL, 0, 1800, 43200, '[\"http://127.0.0.1:18080\"]', '[\"password\",\"refresh_token\"]', '[\"user.read\",\"user.write\"]', '[]', '[]', '[]', NULL, '1', '2022-10-04 17:40:16', '1', '2026-06-15 18:58:30', b'0');
COMMIT;
-- ----------------------------
@@ -3518,7 +3579,7 @@
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛缂栧彿',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 2590 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 鍒锋柊浠ょ墝';
+) ENGINE = InnoDB AUTO_INCREMENT = 3382 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 鍒锋柊浠ょ墝';
-- ----------------------------
-- Records of system_oauth2_refresh_token
@@ -3554,7 +3615,7 @@
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 9194 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鎿嶄綔鏃ュ織璁板綍 V2 鐗堟湰';
+) ENGINE = InnoDB AUTO_INCREMENT = 9208 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鎿嶄綔鏃ュ織璁板綍 V2 鐗堟湰';
-- ----------------------------
-- Records of system_operate_log
@@ -3580,7 +3641,7 @@
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛缂栧彿',
PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '宀椾綅淇℃伅琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '宀椾綅淇℃伅琛�';
-- ----------------------------
-- Records of system_post
@@ -3624,7 +3685,7 @@
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 'CRM 绠$悊鍛�', 'crm_admin', 2, 1, '', 0, 1, 'CRM 涓撳睘瑙掕壊', '1', '2024-02-24 10:51:13', '1', '2024-02-24 02:51:32', b'0', 1);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, '绉熸埛绠$悊鍛�', 'tenant_admin', 0, 1, '', 0, 1, '绯荤粺鑷姩鐢熸垚', '1', '2022-02-22 00:56:14', '1', '2022-02-22 00:56:14', b'0', 121);
INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, '绉熸埛绠$悊鍛�', 'tenant_admin', 0, 1, '', 0, 1, '绯荤粺鑷姩鐢熸垚', '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122);
-INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (155, '娴嬭瘯鏁版嵁鏉冮檺1', 'test-dp', 4, 2, '[112,100,102,103,104,105,107,108]', 0, 2, '1111', '1', '2025-03-31 14:58:06', '1', '2025-12-04 23:29:40', b'0', 1);
+INSERT INTO `system_role` (`id`, `name`, `code`, `sort`, `data_scope`, `data_scope_dept_ids`, `status`, `type`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (155, '娴嬭瘯鏁版嵁鏉冮檺12', 'test-dp', 4, 2, '[112,100,102,103,104,105,107,108]', 0, 2, '1111', '1', '2025-03-31 14:58:06', '1', '2026-06-26 10:42:44', b'0', 1);
COMMIT;
-- ----------------------------
@@ -3643,7 +3704,7 @@
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛缂栧彿',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_role_id`(`role_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 6381 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+) ENGINE = InnoDB AUTO_INCREMENT = 6692 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
-- ----------------------------
-- Records of system_role_menu
@@ -3683,7 +3744,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (706, 2, 112, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (707, 2, 113, '1', '2022-02-22 13:16:57', '1', '2022-02-22 13:16:57', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1296, 110, 1, '110', '2022-02-23 00:23:55', '110', '2022-02-23 00:23:55', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1578, 111, 1, '1', '2022-03-07 21:37:58', '1', '2022-03-07 21:37:58', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1729, 109, 100, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1730, 109, 101, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1731, 109, 1063, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
@@ -3701,23 +3761,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1743, 109, 1010, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1744, 109, 1011, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1745, 109, 1012, '1', '2022-09-21 22:08:51', '1', '2022-09-21 22:08:51', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1746, 111, 100, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1747, 111, 101, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1748, 111, 1063, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1749, 111, 1064, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1750, 111, 1001, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1751, 111, 1065, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1752, 111, 1002, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1753, 111, 1003, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1754, 111, 1004, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1755, 111, 1005, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1756, 111, 1006, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1757, 111, 1007, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1758, 111, 1008, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1759, 111, 1009, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1760, 111, 1010, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1761, 111, 1011, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1762, 111, 1012, '1', '2022-09-21 22:08:52', '1', '2022-09-21 22:08:52', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1763, 109, 100, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1764, 109, 101, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1765, 109, 1063, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121);
@@ -3735,23 +3778,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1777, 109, 1010, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1778, 109, 1011, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1779, 109, 1012, '1', '2022-09-21 22:08:53', '1', '2022-09-21 22:08:53', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1780, 111, 100, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1781, 111, 101, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1782, 111, 1063, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1783, 111, 1064, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1784, 111, 1001, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1785, 111, 1065, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1786, 111, 1002, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1787, 111, 1003, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1788, 111, 1004, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1789, 111, 1005, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1790, 111, 1006, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1791, 111, 1007, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1792, 111, 1008, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1793, 111, 1009, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1794, 111, 1010, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1795, 111, 1011, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1796, 111, 1012, '1', '2022-09-21 22:08:54', '1', '2022-09-21 22:08:54', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1797, 109, 100, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1798, 109, 101, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1799, 109, 1063, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121);
@@ -3769,43 +3795,16 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1811, 109, 1010, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1812, 109, 1011, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1813, 109, 1012, '1', '2022-09-21 22:08:55', '1', '2022-09-21 22:08:55', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1814, 111, 100, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1815, 111, 101, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1816, 111, 1063, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1817, 111, 1064, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1818, 111, 1001, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1819, 111, 1065, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1820, 111, 1002, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1821, 111, 1003, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1822, 111, 1004, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1823, 111, 1005, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1824, 111, 1006, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1825, 111, 1007, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1826, 111, 1008, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1827, 111, 1009, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1828, 111, 1010, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1829, 111, 1011, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1830, 111, 1012, '1', '2022-09-21 22:08:56', '1', '2022-09-21 22:08:56', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1831, 109, 103, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1832, 109, 1017, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1833, 109, 1018, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1834, 109, 1019, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1835, 109, 1020, '1', '2022-09-21 22:43:23', '1', '2022-09-21 22:43:23', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1836, 111, 103, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1837, 111, 1017, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1838, 111, 1018, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1839, 111, 1019, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1840, 111, 1020, '1', '2022-09-21 22:43:24', '1', '2022-09-21 22:43:24', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1841, 109, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1842, 109, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1843, 109, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1844, 109, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1845, 109, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1846, 111, 1036, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1847, 111, 1037, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1848, 111, 1038, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1849, 111, 1039, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1850, 111, 107, '1', '2022-09-21 22:48:13', '1', '2022-09-21 22:48:13', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1991, 2, 1024, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1992, 2, 1025, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1993, 2, 1026, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
@@ -3975,18 +3974,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2938, 109, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2939, 109, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2940, 109, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2941, 111, 1224, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2942, 111, 1225, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2943, 111, 1226, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2944, 111, 1227, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2945, 111, 1228, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2946, 111, 1229, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2947, 111, 1138, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2948, 111, 1139, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2949, 111, 1140, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2950, 111, 1141, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2951, 111, 1142, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2952, 111, 1143, '1', '2023-12-02 23:19:40', '1', '2023-12-02 23:19:40', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2993, 109, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2994, 109, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2995, 109, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121);
@@ -4062,91 +4049,11 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3066, 109, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3067, 109, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3068, 109, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3069, 111, 2, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3070, 111, 1031, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3071, 111, 1032, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3072, 111, 1033, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3073, 111, 1034, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3074, 111, 1035, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3075, 111, 1050, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3076, 111, 1051, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3077, 111, 1052, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3078, 111, 1053, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3079, 111, 1054, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3080, 111, 1056, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3081, 111, 1057, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3082, 111, 1058, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3083, 111, 1059, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3084, 111, 1060, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3085, 111, 1066, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3086, 111, 1067, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3087, 111, 1070, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3088, 111, 1075, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3090, 111, 1077, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3091, 111, 1078, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3092, 111, 1082, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3093, 111, 1083, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3094, 111, 1084, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3095, 111, 1085, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3096, 111, 1086, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3097, 111, 1087, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3098, 111, 1088, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3099, 111, 1089, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3100, 111, 1090, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3101, 111, 1091, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3102, 111, 1092, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3103, 111, 106, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3104, 111, 110, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3105, 111, 111, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3106, 111, 112, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3107, 111, 113, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3108, 111, 114, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3109, 111, 115, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3110, 111, 116, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3111, 111, 2472, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3112, 111, 2478, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3113, 111, 2479, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3114, 111, 2480, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3115, 111, 2481, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3116, 111, 2482, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3117, 111, 2483, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3118, 111, 2484, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3119, 111, 2485, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3120, 111, 2486, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3121, 111, 2487, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3122, 111, 2488, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3123, 111, 2489, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3124, 111, 2490, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3125, 111, 2491, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3126, 111, 2492, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3127, 111, 2493, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3128, 111, 2494, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3129, 111, 2495, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3130, 111, 2497, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3131, 111, 1237, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3132, 111, 1238, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3133, 111, 1239, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3134, 111, 1240, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3135, 111, 1241, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3136, 111, 1242, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3137, 111, 1243, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3138, 111, 2525, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3139, 111, 1255, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3140, 111, 1256, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3141, 111, 1257, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3142, 111, 1258, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3143, 111, 1259, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3144, 111, 1260, '1', '2023-12-02 23:41:02', '1', '2023-12-02 23:41:02', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3221, 109, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3222, 109, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3223, 109, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3224, 109, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3225, 109, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3226, 111, 102, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3227, 111, 1013, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3228, 111, 1014, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3229, 111, 1015, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3230, 111, 1016, '1', '2023-12-30 11:42:36', '1', '2023-12-30 11:42:36', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4163, 109, 5, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4164, 109, 1118, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4165, 109, 1119, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
@@ -4205,64 +4112,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4219, 109, 1220, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4220, 109, 1221, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4221, 109, 1222, '1', '2024-03-30 17:53:17', '1', '2024-03-30 17:53:17', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4222, 111, 5, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4223, 111, 1118, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4224, 111, 1119, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4225, 111, 1120, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4226, 111, 2713, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4227, 111, 2714, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4228, 111, 2715, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4229, 111, 2716, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4230, 111, 2717, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4231, 111, 2718, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4232, 111, 2720, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4233, 111, 1185, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4234, 111, 2721, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4235, 111, 1186, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4236, 111, 2722, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4237, 111, 1187, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4238, 111, 2723, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4239, 111, 1188, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4240, 111, 2724, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4241, 111, 1189, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4242, 111, 2725, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4243, 111, 1190, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4244, 111, 2726, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4245, 111, 1191, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4246, 111, 2727, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4247, 111, 1192, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4248, 111, 2728, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4249, 111, 1193, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4250, 111, 2729, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4251, 111, 1194, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4252, 111, 2730, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4253, 111, 1195, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4254, 111, 2731, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4256, 111, 2732, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4257, 111, 1197, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4258, 111, 2733, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4259, 111, 1198, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4260, 111, 2734, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4261, 111, 1199, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4262, 111, 2735, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4263, 111, 1200, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4264, 111, 1201, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4265, 111, 1202, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4266, 111, 1207, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4267, 111, 1208, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4268, 111, 1209, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4269, 111, 1210, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4270, 111, 1211, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4271, 111, 1212, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4272, 111, 1213, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4273, 111, 1215, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4274, 111, 1216, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4275, 111, 1217, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4276, 111, 1218, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4277, 111, 1219, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4278, 111, 1220, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4279, 111, 1221, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4280, 111, 1222, '1', '2024-03-30 17:53:18', '1', '2024-03-30 17:53:18', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5779, 2, 2739, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5780, 2, 2740, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5781, 2, 2758, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
@@ -4272,8 +4121,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5785, 2, 2030, '1', '2024-07-07 20:39:38', '1', '2024-07-07 20:39:38', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5789, 109, 2739, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5790, 109, 2740, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5791, 111, 2739, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5792, 111, 2740, '1', '2024-07-13 22:37:24', '1', '2024-07-13 22:37:24', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6053, 155, 4000, '1', '2025-04-01 13:48:26', '1', '2025-04-01 13:48:26', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6097, 155, 4050, '1', '2025-04-01 13:48:26', '1', '2025-04-01 13:48:26', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6104, 155, 4032, '1', '2025-04-01 13:49:30', '1', '2025-04-01 13:49:30', b'0', 1);
@@ -4348,45 +4195,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6175, 109, 2557, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6176, 109, 2558, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6177, 109, 2559, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6178, 111, 1117, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6179, 111, 1126, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6180, 111, 1127, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6181, 111, 1128, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6182, 111, 1129, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6183, 111, 1130, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6184, 111, 1132, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6185, 111, 1133, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6186, 111, 1134, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6187, 111, 1135, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6188, 111, 1136, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6189, 111, 1137, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6190, 111, 2161, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6191, 111, 1150, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6192, 111, 1161, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6193, 111, 1162, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6194, 111, 1166, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6195, 111, 1173, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6196, 111, 1174, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6197, 111, 1178, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6198, 111, 2745, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6199, 111, 2746, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6200, 111, 2747, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6201, 111, 2748, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6202, 111, 2301, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6203, 111, 2302, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6204, 111, 5011, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6205, 111, 5012, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6206, 111, 2549, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6207, 111, 2550, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6208, 111, 2551, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6209, 111, 2552, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6210, 111, 2553, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6211, 111, 2554, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6212, 111, 2555, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6213, 111, 2556, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6214, 111, 2557, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6215, 111, 2558, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6216, 111, 2559, '1', '2025-09-06 20:52:12', '1', '2025-09-06 20:52:12', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6217, 109, 2756, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6218, 109, 2757, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6219, 109, 2262, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 121);
@@ -4425,44 +4233,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6252, 109, 2335, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6253, 109, 2363, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 121);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6254, 109, 2364, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6255, 111, 2756, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6256, 111, 2757, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6257, 111, 2262, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6258, 111, 2275, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6259, 111, 2276, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6260, 111, 2277, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6261, 111, 2281, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6262, 111, 2282, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6263, 111, 2283, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6264, 111, 2284, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6265, 111, 2285, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6266, 111, 2287, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6267, 111, 2288, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6268, 111, 2293, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6269, 111, 2294, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6270, 111, 2297, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6271, 111, 2300, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6272, 111, 2317, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6273, 111, 2318, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6274, 111, 2319, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6275, 111, 2320, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6276, 111, 2321, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6277, 111, 2322, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6278, 111, 2323, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6279, 111, 2324, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6280, 111, 2325, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6281, 111, 2326, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6282, 111, 2327, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6283, 111, 2328, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6284, 111, 2329, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6285, 111, 2330, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6286, 111, 2331, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6287, 111, 2332, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6288, 111, 2333, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6289, 111, 2334, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6290, 111, 2335, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6291, 111, 2363, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6292, 111, 2364, '1', '2025-09-06 20:52:25', '1', '2025-09-06 20:52:25', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6293, 2, 5, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6294, 2, 1118, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6295, 2, 1119, '1', '2026-01-04 18:09:41', '1', '2026-01-04 18:09:41', b'0', 1);
@@ -4533,7 +4303,6 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6360, 2, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6361, 3, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6362, 109, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', b'0', 121);
-INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6363, 111, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', b'0', 122);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6364, 155, 5811, '', '2026-03-30 03:13:05', '', '2026-03-30 03:13:05', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6365, 2, 6400, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6366, 2, 6401, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', b'0', 1);
@@ -4543,6 +4312,317 @@
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6370, 2, 6405, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6371, 2, 6406, '1', '2026-05-09 16:11:01', '1', '2026-05-09 16:11:01', b'0', 1);
INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6380, 2, 6490, '1', '2026-05-14 09:36:12', '1', '2026-05-14 09:36:12', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6381, 111, 1, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6382, 111, 2, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6383, 111, 5, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6384, 111, 1031, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6385, 111, 1032, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6386, 111, 1033, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6387, 111, 1034, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6388, 111, 1035, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6389, 111, 1036, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6390, 111, 1037, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6391, 111, 1038, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6392, 111, 1039, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6393, 111, 1050, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6394, 111, 1051, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6395, 111, 1052, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6396, 111, 1053, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6397, 111, 1054, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6398, 111, 1056, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6399, 111, 1057, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6400, 111, 1058, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6401, 111, 1059, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6402, 111, 1060, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6403, 111, 1063, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6404, 111, 1064, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6405, 111, 1065, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6406, 111, 1066, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6407, 111, 1067, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6408, 111, 1070, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6409, 111, 1075, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6410, 111, 1077, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6411, 111, 1078, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6412, 111, 1082, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6413, 111, 1083, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6414, 111, 1084, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6415, 111, 1085, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6416, 111, 1086, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6417, 111, 1087, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6418, 111, 1088, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6419, 111, 1089, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6420, 111, 1090, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6421, 111, 1091, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6422, 111, 1092, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6423, 111, 1117, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6424, 111, 1118, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6425, 111, 1119, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6426, 111, 1120, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6427, 111, 100, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6428, 111, 101, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6429, 111, 102, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6430, 111, 1126, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6431, 111, 103, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6432, 111, 1127, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6433, 111, 1128, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6434, 111, 1129, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6435, 111, 106, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6436, 111, 1130, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6437, 111, 107, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6438, 111, 1132, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6439, 111, 1133, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6440, 111, 110, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6441, 111, 1134, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6442, 111, 111, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6443, 111, 1135, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6444, 111, 112, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6445, 111, 1136, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6446, 111, 113, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6447, 111, 1137, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6448, 111, 2161, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6449, 111, 114, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6450, 111, 1138, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6451, 111, 1139, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6452, 111, 115, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6453, 111, 1140, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6454, 111, 116, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6455, 111, 1141, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6456, 111, 1142, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6457, 111, 1143, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6458, 111, 1150, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6459, 111, 1161, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6460, 111, 1162, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6461, 111, 1166, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6462, 111, 1173, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6463, 111, 1174, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6464, 111, 2713, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6465, 111, 2714, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6466, 111, 1178, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6467, 111, 2715, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6468, 111, 2716, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6469, 111, 2717, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6470, 111, 2718, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6471, 111, 2720, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6472, 111, 2721, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6473, 111, 1185, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6474, 111, 2722, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6475, 111, 1186, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6476, 111, 1187, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6477, 111, 2723, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6478, 111, 1188, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6479, 111, 2724, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6480, 111, 1189, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6481, 111, 2725, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6482, 111, 1190, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6483, 111, 2726, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6484, 111, 1191, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6485, 111, 2727, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6486, 111, 1192, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6487, 111, 2728, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6488, 111, 2729, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6489, 111, 1193, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6490, 111, 1194, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6491, 111, 2730, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6492, 111, 1195, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6493, 111, 2731, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6494, 111, 2732, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6495, 111, 1197, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6496, 111, 2733, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6497, 111, 1198, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6498, 111, 2734, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6499, 111, 1199, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6500, 111, 2735, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6501, 111, 1200, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6502, 111, 1201, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6503, 111, 1202, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6504, 111, 2739, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6505, 111, 2740, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6506, 111, 1207, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6507, 111, 1208, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6508, 111, 1209, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6509, 111, 2745, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6510, 111, 1210, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6511, 111, 2746, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6512, 111, 1211, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6513, 111, 2747, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6514, 111, 1212, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6515, 111, 2748, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6516, 111, 1213, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6517, 111, 1215, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6518, 111, 1216, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6519, 111, 1217, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6520, 111, 1218, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6521, 111, 1219, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6522, 111, 1220, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6523, 111, 2756, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6524, 111, 1221, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6525, 111, 2757, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6526, 111, 1222, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6527, 111, 1224, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6528, 111, 1225, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6529, 111, 1226, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6530, 111, 1227, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6531, 111, 1228, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6532, 111, 1229, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6533, 111, 1237, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6534, 111, 1238, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6535, 111, 2262, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6536, 111, 1239, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6537, 111, 1240, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6538, 111, 1241, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6539, 111, 1242, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6540, 111, 1243, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6541, 111, 2275, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6542, 111, 2276, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6543, 111, 2277, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6544, 111, 1255, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6545, 111, 1256, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6546, 111, 1257, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6547, 111, 2281, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6548, 111, 1258, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6549, 111, 2282, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6550, 111, 1259, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6551, 111, 2283, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6552, 111, 1260, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6553, 111, 2284, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6554, 111, 2285, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6555, 111, 2287, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6556, 111, 2288, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6557, 111, 2293, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6558, 111, 2294, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6559, 111, 2297, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6560, 111, 2300, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6561, 111, 2301, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6562, 111, 2302, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6563, 111, 2317, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6564, 111, 2318, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6565, 111, 2319, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6566, 111, 2320, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6567, 111, 2321, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6568, 111, 2322, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6569, 111, 2323, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6570, 111, 2324, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6571, 111, 2325, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6572, 111, 2326, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6573, 111, 2327, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6574, 111, 2328, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6575, 111, 2329, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6576, 111, 2330, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6577, 111, 2331, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6578, 111, 2332, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6579, 111, 2333, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6580, 111, 2334, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6581, 111, 2335, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6582, 111, 2363, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6583, 111, 2364, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6584, 111, 5011, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6585, 111, 5012, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6586, 111, 2472, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6587, 111, 2478, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6588, 111, 2479, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6589, 111, 2480, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6590, 111, 2481, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6591, 111, 2482, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6592, 111, 2483, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6593, 111, 2484, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6594, 111, 2485, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6595, 111, 2486, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6596, 111, 2487, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6597, 111, 2488, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6598, 111, 2489, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6599, 111, 2490, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6600, 111, 2491, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6601, 111, 2492, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6602, 111, 2493, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6603, 111, 2494, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6604, 111, 2495, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6605, 111, 2497, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6606, 111, 2525, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6607, 111, 1001, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6608, 111, 1002, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6609, 111, 1003, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6610, 111, 1004, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6611, 111, 1005, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6612, 111, 1006, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6613, 111, 1007, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6614, 111, 1008, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6615, 111, 1009, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6616, 111, 1010, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6617, 111, 1011, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6618, 111, 1012, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6619, 111, 1013, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6620, 111, 2549, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6621, 111, 1014, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6622, 111, 2550, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6623, 111, 1015, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6624, 111, 2551, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6625, 111, 1016, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6626, 111, 2552, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6627, 111, 1017, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6628, 111, 2553, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6629, 111, 1018, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6630, 111, 2554, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6631, 111, 1019, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6632, 111, 2555, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6633, 111, 1020, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6634, 111, 2556, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6635, 111, 2557, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6636, 111, 2558, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6637, 111, 2559, '1', '2026-06-01 23:29:35', '1', '2026-06-01 23:29:35', b'0', 122);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6638, 155, 5780, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6639, 155, 2084, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6640, 155, 2085, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6641, 155, 2086, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6642, 155, 2087, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6643, 155, 2088, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6644, 155, 2089, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6645, 155, 2090, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6646, 155, 2091, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6647, 155, 2092, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6648, 155, 2093, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6649, 155, 5805, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6650, 155, 2094, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6651, 155, 2095, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6652, 155, 2096, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6653, 155, 2097, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6654, 155, 2098, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6655, 155, 5042, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6656, 155, 2099, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6657, 155, 5043, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6658, 155, 2100, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6659, 155, 5044, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6660, 155, 2101, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6661, 155, 5045, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6662, 155, 2102, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6663, 155, 5046, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6664, 155, 2103, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6665, 155, 2104, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6666, 155, 2105, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6667, 155, 2106, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6668, 155, 2107, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6669, 155, 2108, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6670, 155, 2109, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6671, 155, 2110, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6672, 155, 2111, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6673, 155, 2112, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6674, 155, 2113, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6675, 155, 2114, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6676, 155, 2115, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6677, 155, 2116, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6678, 155, 2117, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6679, 155, 2118, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6680, 155, 2119, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6681, 155, 2120, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6682, 155, 2121, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6683, 155, 2122, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6684, 155, 2123, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6685, 155, 2124, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6686, 155, 2125, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6687, 155, 2126, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6688, 155, 2127, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6689, 155, 2128, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6690, 155, 2129, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
+INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6691, 155, 5100, '1', '2026-06-10 09:04:18', '1', '2026-06-10 09:04:18', b'0', 1);
COMMIT;
-- ----------------------------
@@ -4597,7 +4677,7 @@
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '绉熸埛缂栧彿',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_mobile`(`mobile` ASC) USING BTREE COMMENT '鎵嬫満鍙�'
-) ENGINE = InnoDB AUTO_INCREMENT = 690 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鎵嬫満楠岃瘉鐮�';
+) ENGINE = InnoDB AUTO_INCREMENT = 694 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鎵嬫満楠岃瘉鐮�';
-- ----------------------------
-- Records of system_sms_code
@@ -4638,7 +4718,7 @@
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 1553 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鐭俊鏃ュ織';
+) ENGINE = InnoDB AUTO_INCREMENT = 1568 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鐭俊鏃ュ織';
-- ----------------------------
-- Records of system_sms_log
@@ -4815,7 +4895,7 @@
BEGIN;
INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `websites`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '鑺嬮亾婧愮爜', NULL, '鑺嬭壙', '17321315478', 0, 'www.iocoder.cn,127.0.0.1:3000,wxc4598c446f8a9cb3', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2025-08-19 05:18:41', b'0');
INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `websites`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '灏忕鎴�', 110, '灏忕帇2', '15601691300', 0, 'zsxq.iocoder.cn,123321', 111, '2026-07-10 00:00:00', 30, '1', '2022-02-22 00:56:14', '1', '2025-08-19 21:19:29', b'0');
-INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `websites`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '娴嬭瘯绉熸埛', 113, '鑺嬮亾', '15601691300', 0, 'test.iocoder.cn,222,333', 111, '2023-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2025-12-21 09:50:00', b'0');
+INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `websites`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '娴嬭瘯绉熸埛', 113, '鑺嬮亾', '15601691300', 0, 'test.iocoder.cn,222,333', 111, '2023-04-29 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2026-06-01 23:29:35', b'0');
COMMIT;
-- ----------------------------
@@ -4834,13 +4914,14 @@
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 113 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '绉熸埛濂楅琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 114 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '绉熸埛濂楅琛�';
-- ----------------------------
-- Records of system_tenant_package
-- ----------------------------
BEGIN;
INSERT INTO `system_tenant_package` (`id`, `name`, `status`, `remark`, `menu_ids`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (111, '鏅�氬椁�', 0, '灏忓姛鑳�', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1117,1118,1119,1120,100,101,102,1126,103,1127,1128,1129,106,1130,107,1132,1133,110,1134,111,1135,112,1136,113,1137,2161,114,1138,1139,115,1140,116,1141,1142,1143,1150,1161,1162,1166,1173,1174,2713,2714,1178,2715,2716,2717,2718,2720,2721,1185,2722,1186,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,1192,2728,2729,1193,1194,2730,1195,2731,2732,1197,2733,1198,2734,1199,2735,1200,1201,1202,2739,2740,1207,1208,1209,2745,1210,2746,1211,2747,1212,2748,1213,1215,1216,1217,1218,1219,1220,2756,1221,2757,1222,1224,1225,1226,1227,1228,1229,1237,1238,2262,1239,1240,1241,1242,1243,2275,2276,2277,1255,1256,1257,2281,1258,2282,1259,2283,1260,2284,2285,2287,2288,2293,2294,2297,2300,2301,2302,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2363,2364,5011,5012,2472,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2497,2525,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,2549,1014,2550,1015,2551,1016,2552,1017,2553,1018,2554,1019,2555,1020,2556,2557,2558,2559]', '1', '2022-02-22 00:54:00', '1', '2025-09-06 20:52:25', b'0');
+INSERT INTO `system_tenant_package` (`id`, `name`, `status`, `remark`, `menu_ids`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (113, '娴嬭瘯濂楅锛堝暐閮芥病鏈夛級', 0, '', '[2160,1254,2159]', '1', '2026-06-01 23:22:39', '1', '2026-06-09 14:44:00', b'0');
COMMIT;
-- ----------------------------
@@ -4952,32 +5033,32 @@
INDEX `idx_mobile`(`mobile` ASC) USING BTREE,
INDEX `idx_email`(`email` ASC) USING BTREE,
INDEX `idx_dept_id`(`dept_id` ASC) USING BTREE
-) ENGINE = InnoDB AUTO_INCREMENT = 145 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鐢ㄦ埛淇℃伅琛�';
+) ENGINE = InnoDB AUTO_INCREMENT = 225 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '鐢ㄦ埛淇℃伅琛�';
-- ----------------------------
-- Records of system_users
-- ----------------------------
BEGIN;
-INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '鑺嬮亾婧愮爜', '绠$悊鍛�', 103, '[1,2]', '13aoteman@126.com', '18818260272', 1, 'http://test.yudao.iocoder.cn/user/avatar/20251220/blob_1766215463801.jpg', 0, '0:0:0:0:0:0:0:1', '2026-05-15 22:24:39', 'admin', '2021-01-05 17:03:47', NULL, '2026-05-15 22:24:39', b'0', 1);
-INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '鑺嬮亾', '涓嶈鍚撴垜', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-04-19 17:40:55', '', '2021-01-07 09:07:17', NULL, '2026-04-19 17:40:55', b'0', 1);
+INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '鑺嬮亾婧愮爜', '绠$悊鍛�', 103, '[1,2]', '13aoteman@126.com', '18818260272', 1, 'http://test.yudao.iocoder.cn/20260517/blob_1778998103688.png', 0, '0:0:0:0:0:0:0:1', '2026-06-28 03:39:52', 'admin', '2021-01-05 17:03:47', NULL, '2026-06-28 03:39:52', b'0', 1);
+INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$04$.vd8nPeLwxt6hnSzmAoAyul8BOLX7Cib6QhcxRe30rfvrIPQHH1OG', '鑺嬮亾', '涓嶈鍚撴垜', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, NULL, 0, '127.0.0.1', '2026-06-17 09:37:17', '', '2021-01-07 09:07:17', NULL, '2026-06-17 09:37:17', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$04$k/d6mc0nySN0i2udwcI8Ee8V5aM5OHixBRbQfXmPuFTUl3Zf/DBs.', '婧愮爜', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2026-04-27 13:19:27', '', '2021-01-13 23:50:35', NULL, '2026-04-27 13:19:27', b'0', 1);
-INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$BrwaYn303hjA/6TnXqdGoOLhyHOAA0bVrAFu6.1dJKycqKUnIoRz2', '娴嬭瘯鍙�', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-05-09 09:57:13', '', '2021-01-21 02:13:53', NULL, '2026-05-09 09:57:13', b'0', 1);
+INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$04$BrwaYn303hjA/6TnXqdGoOLhyHOAA0bVrAFu6.1dJKycqKUnIoRz2', '娴嬭瘯鍙�', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-06-16 11:37:56', '', '2021-01-21 02:13:53', NULL, '2026-06-16 11:37:56', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (107, 'admin107', '$2a$10$dYOOBKMO93v/.ReCqzyFg.o67Tqk.bbc2bhrpyBGkIw9aypCtr2pm', '鑺嬭壙', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 22:59:33', '1', '2025-04-21 14:23:08', b'0', 118);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (108, 'admin108', '$2a$10$y6mfvKoNYL1GXWak8nYwVOH.kCWqjactkzdoIDgiKl93WN3Ejg.Lu', '鑺嬭壙', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 23:00:50', '1', '2025-04-21 14:23:08', b'0', 119);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (109, 'admin109', '$2a$10$JAqvH0tEc0I7dfDVBI7zyuB4E3j.uH6daIjV53.vUS6PknFkDJkuK', '鑺嬭壙', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '', NULL, '1', '2022-02-20 23:11:50', '1', '2025-04-21 14:23:08', b'0', 120);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (110, 'admin110', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '灏忕帇', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2024-07-20 22:23:17', '1', '2022-02-22 00:56:14', NULL, '2025-04-21 14:23:08', b'0', 121);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (111, 'test', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '娴嬭瘯鐢ㄦ埛', NULL, NULL, '[]', '', '', 0, NULL, 0, '0:0:0:0:0:0:0:1', '2023-12-30 11:42:17', '110', '2022-02-23 13:14:33', NULL, '2025-04-21 14:23:08', b'0', 121);
-INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '鏂板璞�', NULL, 100, '[]', '', '15601691235', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-03-16 23:11:38', '1', '2022-02-23 19:08:03', NULL, '2025-04-21 14:23:08', b'0', 1);
+INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (112, 'newobject', '$2a$04$dB0z8Q819fJWz0hbaLe6B.VfHCjYgWx6LFfET5lyz3JwcqlyCkQ4C', '鏂板璞�', NULL, 100, '[]', '', '15601691235', 1, NULL, 0, '127.0.0.1', '2026-06-17 09:07:20', '1', '2022-02-23 19:08:03', NULL, '2026-06-17 09:07:20', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (113, 'aoteman', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '鑺嬮亾1', NULL, NULL, NULL, '', '15601691300', 0, NULL, 0, '127.0.0.1', '2022-03-19 18:38:51', '1', '2022-03-07 21:37:58', '1', '2025-05-05 15:30:53', b'0', 122);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (114, 'hrmgr', '$2a$10$TR4eybBioGRhBmDBWkqWLO6NIh3mzYa8KBKDDB5woiGYFVlRAi.fu', 'hr 灏忓濮�', NULL, NULL, '[5]', '', '15601691236', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2026-01-04 18:16:01', '1', '2022-03-19 21:50:58', NULL, '2026-01-04 18:16:01', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (115, 'aotemane', '$2a$04$GcyP0Vyzb2F2Yni5PuIK9ueGxM0tkZGMtDwVRwrNbtMvorzbpNsV2', '闃垮憜', '11222', 102, '[1,2]', '7648@qq.com', '15601691229', 2, NULL, 0, '', NULL, '1', '2022-04-30 02:55:43', '1', '2025-04-21 14:23:08', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (117, 'admin123', '$2a$04$sEtimsHu9YCkYY4/oqElHem2Ijc9ld20eYO6lN.g/21NfLUTDLB9W', '娴嬭瘯鍙�02', '1111', 100, '[2]', '', '15601691234', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-10-02 10:16:20', '1', '2022-07-09 17:40:26', '1', '2025-05-14 09:56:04', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (118, 'goudan', '$2a$04$3suGZjnA6rM5bErf38u1felbgqbsPHGdRG3l9NkxPCEt2ah9Y6aJi', '鐙楄泲', NULL, 103, '[1]', '', '15601691239', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2025-11-23 15:28:25', '1', '2022-07-09 17:44:43', NULL, '2025-11-23 15:28:25', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (139, 'wwbwwb', '$2a$04$FJLIyg8lbPytP29pbZaiU.LesJvCsYfEaHqQfB0pGQhK3e9BeZmLy', '灏忕澶�', '123', 108, '[2,4]', '', '', 1, NULL, 0, '0:0:0:0:0:0:0:1', '2024-09-10 21:03:58', NULL, '2024-09-10 21:03:58', '1', '2025-12-15 22:38:15', b'0', 1);
-INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (141, 'admin1', '$2a$04$oj6F6d7HrZ70kYVD3TNzEu.m3TPUzajOVuC66zdKna8KRerK1FmVa', '鏂扮敤鎴�', NULL, NULL, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2025-04-08 13:09:07', '1', '2025-04-08 13:09:07', '1', '2025-05-14 19:11:48', b'0', 1);
-INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (142, 'test01', '$2a$04$4bCYWZkjxxOC4QE0LY2M9uEEKWeJbLfs489NFtQoyidL5I0FndRaO', 'test01', '', NULL, '[]', '', '19021719925', 1, '', 0, '0:0:0:0:0:0:0:1', '2025-07-29 19:47:17', '1', '2025-07-09 21:07:10', NULL, '2025-12-02 13:23:11', b'0', 1);
+INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (141, 'admin1', '$2a$04$oj6F6d7HrZ70kYVD3TNzEu.m3TPUzajOVuC66zdKna8KRerK1FmVa', '鏂扮敤鎴�', NULL, NULL, NULL, '', '', 0, '', 0, '127.0.0.1', '2026-06-17 09:37:18', '1', '2025-04-08 13:09:07', NULL, '2026-06-17 09:37:18', b'0', 1);
+INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (142, 'test01', '$2a$04$4bCYWZkjxxOC4QE0LY2M9uEEKWeJbLfs489NFtQoyidL5I0FndRaO', 'test01', '', NULL, '[]', '', '19021719925', 1, '', 0, '0:0:0:0:0:0:0:1', '2026-06-17 10:44:58', '1', '2025-07-09 21:07:10', NULL, '2026-06-17 10:44:58', b'0', 1);
INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (143, 'a00001', '$2a$04$GhVHFviOw/SsTmiQtifHJesDYFlHMeGK7OWh7aGCCjGGVCmbHVAwa', 'a00001', NULL, 104, NULL, '', '', 0, '', 0, '0:0:0:0:0:0:0:1', '2025-12-01 16:10:13', NULL, '2025-12-01 16:10:13', '1', '2025-12-05 21:34:05', b'0', 1);
-INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (144, 'aoteman001', '$2a$04$omQOmhz8OyUFBKw77nr8KOtMp6xdvoQ1gWStjk9r8.OYT3Bv6oEYe', 'aoteman001', NULL, 116, NULL, '', '', 0, '', 1, '0:0:0:0:0:0:0:1', '2025-12-01 17:05:27', '1', '2025-12-01 17:05:27', '1', '2025-12-15 15:55:54', b'0', 1);
+INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (144, 'aoteman001', '$2a$04$omQOmhz8OyUFBKw77nr8KOtMp6xdvoQ1gWStjk9r8.OYT3Bv6oEYe', 'aoteman00112', NULL, 104, NULL, '', '', 0, '', 1, '0:0:0:0:0:0:0:1', '2025-12-01 17:05:27', '1', '2025-12-01 17:05:27', '1', '2026-06-15 18:58:56', b'0', 1);
COMMIT;
-- ----------------------------
@@ -5075,7 +5156,7 @@
INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (17, 2, '璇枃', 66, '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1);
INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (18, 2, '鏁板', 22, '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1);
INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (19, 9, '婊戦洩', 12, '1', '2023-11-17 13:13:20', '1', '2025-04-19 02:49:03', b'1', 1);
-INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (20, 9, '婊戦洩', 12, '1', '2023-11-17 13:13:20', '1', '2025-04-19 10:49:04', b'0', 1);
+INSERT INTO `yudao_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (20, 9, '婊戦洩', 12, '1', '2023-11-17 13:13:20', '1', '2026-06-27 08:42:44', b'0', 1);
COMMIT;
-- ----------------------------
@@ -5102,7 +5183,7 @@
BEGIN;
INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 2, '涓夊勾 2 鐝�', '鍛ㄦ澃浼�', '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1);
INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '鍗庝负', '閬ラ仴棰嗗厛', '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1);
-INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 9, '灏忓浘', '灏忓▋111', '1', '2023-11-17 13:10:23', '1', '2025-04-19 10:49:04', b'0', 1);
+INSERT INTO `yudao_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 9, '灏忓浘', '灏忓▋111', '1', '2023-11-17 13:10:23', '1', '2026-06-27 08:42:44', b'0', 1);
COMMIT;
-- ----------------------------
@@ -5130,7 +5211,7 @@
BEGIN;
INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '灏忕櫧', 1, '2023-11-16 00:00:00', '<p>鍘夊</p>', '1', '2023-11-16 23:21:49', '1', '2024-09-17 18:55:31', b'0', 1);
INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '澶ч粦', 2, '2023-11-13 00:00:00', '<p>浣犲湪鏁欐垜鍋氫簨?</p>', '1', '2023-11-16 23:22:46', '1', '2024-09-17 18:55:29', b'0', 1);
-INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, '灏忚姳', 1, '2023-11-07 00:00:00', '<p>鍝堝搱鍝�</p>', '1', '2023-11-17 00:04:47', '1', '2025-04-19 10:49:04', b'0', 1);
+INSERT INTO `yudao_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, '灏忚姳', 1, '2023-11-07 00:00:00', '<p>鍝堝搱鍝�</p>', '1', '2023-11-17 00:04:47', '1', '2026-06-27 08:42:44', b'0', 1);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
diff --git a/sql/opengauss/ruoyi-vue-pro.sql b/sql/opengauss/ruoyi-vue-pro.sql
index 926ffe6..443705e 100644
--- a/sql/opengauss/ruoyi-vue-pro.sql
+++ b/sql/opengauss/ruoyi-vue-pro.sql
@@ -1371,6 +1371,8 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '鏀粯瀹濆皬绋嬪簭', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3036, 60, 'Admin Uniapp 绉诲姩绔�', '60', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-12-16 19:25:51', '1', '2025-12-17 09:46:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3037, 42, 'Vben5.0 Antdv Next Schema 妯$増', '42', 'infra_codegen_front_type', 0, '', '', '', '1', NOW(), '1', NOW(), '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3038, 43, 'Vben5.0 Antdv Next 鏍囧噯妯$増', '43', 'infra_codegen_front_type', 0, '', '', '', '1', NOW(), '1', NOW(), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3040, 1, 'UDP', 'udp', 'iot_protocol_type', 0, '', '', 'UDP 鍗忚', '1', '2026-02-04 00:32:47', '1', '2026-02-04 00:32:47', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3041, 2, 'WebSocket', 'websocket', 'iot_protocol_type', 0, '', '', 'WebSocket 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3042, 3, 'HTTP', 'http', 'iot_protocol_type', 0, '', '', 'HTTP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
@@ -1653,9 +1655,9 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3443, 1, '鑽夌', '0', 'mes_wm_product_produce_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3444, 2, '宸插畬鎴�', '4', 'mes_wm_product_produce_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3445, 3, '宸插彇娑�', '5', 'mes_wm_product_produce_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '猫聧鈥懊�', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '氓路虏氓庐艗忙藛聬', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '氓路虏氓聫鈥撁β端�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '鑽夌', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '宸插畬鎴�', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '宸插彇娑�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
COMMIT;
-- @formatter:on
@@ -5943,4 +5945,3 @@
DROP SEQUENCE IF EXISTS yudao_demo03_student_seq;
CREATE SEQUENCE yudao_demo03_student_seq
START 10;
-
diff --git a/sql/oracle/ruoyi-vue-pro.sql b/sql/oracle/ruoyi-vue-pro.sql
index 12f8e40..b731aab 100644
--- a/sql/oracle/ruoyi-vue-pro.sql
+++ b/sql/oracle/ruoyi-vue-pro.sql
@@ -1323,6 +1323,8 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', to_date('2025-09-06 00:02:21', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-09-06 00:02:31', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '鏀粯瀹濆皬绋嬪簭', '40', 'system_social_type', 0, '', '', '', '1', to_date('2023-11-04 13:05:38', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2023-11-04 13:07:16', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3036, 60, 'Admin Uniapp 绉诲姩绔�', '60', 'infra_codegen_front_type', 0, '', '', NULL, '1', to_date('2025-12-16 19:25:51', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2025-12-17 09:46:15', 'SYYYY-MM-DD HH24:MI:SS'), '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3037, 42, 'Vben5.0 Antdv Next Schema 妯$増', '42', 'infra_codegen_front_type', 0, '', '', '', '1', SYSDATE, '1', SYSDATE, '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3038, 43, 'Vben5.0 Antdv Next 鏍囧噯妯$増', '43', 'infra_codegen_front_type', 0, '', '', '', '1', SYSDATE, '1', SYSDATE, '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3040, 1, 'UDP', 'udp', 'iot_protocol_type', 0, '', '', 'UDP 鍗忚', '1', to_date('2026-02-04 00:32:47', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-02-04 00:32:47', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3041, 2, 'WebSocket', 'websocket', 'iot_protocol_type', 0, '', '', 'WebSocket 鍗忚', '1', to_date('2026-02-04 00:32:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-02-04 00:32:55', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3042, 3, 'HTTP', 'http', 'iot_protocol_type', 0, '', '', 'HTTP 鍗忚', '1', to_date('2026-02-04 00:32:55', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-02-04 00:32:55', 'SYYYY-MM-DD HH24:MI:SS'), '0');
@@ -1605,9 +1607,9 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3443, 1, '鑽夌', '0', 'mes_wm_product_produce_status', 0, 'info', '', '鑽夌鐘舵��', '1', to_date('2026-04-05 15:53:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-05 15:53:46', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3444, 2, '宸插畬鎴�', '4', 'mes_wm_product_produce_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', to_date('2026-04-05 15:53:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-05 15:53:46', 'SYYYY-MM-DD HH24:MI:SS'), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3445, 3, '宸插彇娑�', '5', 'mes_wm_product_produce_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', to_date('2026-04-05 15:53:46', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-05 15:53:46', 'SYYYY-MM-DD HH24:MI:SS'), '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '猫聧鈥懊�', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '氓路虏氓庐艗忙藛聬', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '氓路虏氓聫鈥撁β端�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '鑽夌', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '宸插畬鎴�', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '宸插彇娑�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '1', to_date('2026-04-16 09:47:00', 'SYYYY-MM-DD HH24:MI:SS'), '0');
COMMIT;
-- @formatter:on
@@ -5801,4 +5803,3 @@
CREATE SEQUENCE yudao_demo03_student_seq
START WITH 10;
-
diff --git a/sql/postgresql/ruoyi-vue-pro.sql b/sql/postgresql/ruoyi-vue-pro.sql
index d52f015..7bceebd 100644
--- a/sql/postgresql/ruoyi-vue-pro.sql
+++ b/sql/postgresql/ruoyi-vue-pro.sql
@@ -1371,6 +1371,8 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3034, 1, 'ttt', 'tt', 'iot_ota_task_record_status', 0, 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3035, 40, '鏀粯瀹濆皬绋嬪簭', '40', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3036, 60, 'Admin Uniapp 绉诲姩绔�', '60', 'infra_codegen_front_type', 0, '', '', NULL, '1', '2025-12-16 19:25:51', '1', '2025-12-17 09:46:15', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3037, 42, 'Vben5.0 Antdv Next Schema 妯$増', '42', 'infra_codegen_front_type', 0, '', '', '', '1', NOW(), '1', NOW(), '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3038, 43, 'Vben5.0 Antdv Next 鏍囧噯妯$増', '43', 'infra_codegen_front_type', 0, '', '', '', '1', NOW(), '1', NOW(), '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3040, 1, 'UDP', 'udp', 'iot_protocol_type', 0, '', '', 'UDP 鍗忚', '1', '2026-02-04 00:32:47', '1', '2026-02-04 00:32:47', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3041, 2, 'WebSocket', 'websocket', 'iot_protocol_type', 0, '', '', 'WebSocket 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3042, 3, 'HTTP', 'http', 'iot_protocol_type', 0, '', '', 'HTTP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', '0');
@@ -1653,9 +1655,9 @@
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3443, 1, '鑽夌', '0', 'mes_wm_product_produce_status', 0, 'info', '', '鑽夌鐘舵��', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3444, 2, '宸插畬鎴�', '4', 'mes_wm_product_produce_status', 0, 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3445, 3, '宸插彇娑�', '5', 'mes_wm_product_produce_status', 0, 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '猫聧鈥懊�', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '氓路虏氓庐艗忙藛聬', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '氓路虏氓聫鈥撁β端�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, '鑽夌', '0', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, '宸插畬鎴�', '4', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, '宸插彇娑�', '5', 'mes_pro_task_status', 0, '', '', NULL, '1', '2026-04-16 09:47:00', '1', '2026-04-16 09:47:00', '0');
COMMIT;
-- @formatter:on
@@ -5943,4 +5945,3 @@
DROP SEQUENCE IF EXISTS yudao_demo03_student_seq;
CREATE SEQUENCE yudao_demo03_student_seq
START 10;
-
diff --git a/sql/sqlserver/ruoyi-vue-pro.sql b/sql/sqlserver/ruoyi-vue-pro.sql
index 82c4896..9a237d5 100644
--- a/sql/sqlserver/ruoyi-vue-pro.sql
+++ b/sql/sqlserver/ruoyi-vue-pro.sql
@@ -3367,6 +3367,10 @@
GO
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3036, 60, N'Admin Uniapp 绉诲姩绔�', N'60', N'infra_codegen_front_type', 0, N'', N'', NULL, N'1', N'2025-12-16 19:25:51', N'1', N'2025-12-17 09:46:15', N'0')
GO
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3037, 42, N'Vben5.0 Antdv Next Schema 妯$増', N'42', N'infra_codegen_front_type', 0, N'', N'', N'', N'1', N'2026-05-16 00:00:00', N'1', N'2026-05-16 00:00:00', N'0')
+GO
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3038, 43, N'Vben5.0 Antdv Next 鏍囧噯妯$増', N'43', N'infra_codegen_front_type', 0, N'', N'', N'', N'1', N'2026-05-16 00:00:00', N'1', N'2026-05-16 00:00:00', N'0')
+GO
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3040, 1, N'UDP', N'udp', N'iot_protocol_type', 0, N'', N'', N'UDP 鍗忚', N'1', N'2026-02-04 00:32:47', N'1', N'2026-02-04 00:32:47', N'0')
GO
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3041, 2, N'WebSocket', N'websocket', N'iot_protocol_type', 0, N'', N'', N'WebSocket 鍗忚', N'1', N'2026-02-04 00:32:55', N'1', N'2026-02-04 00:32:55', N'0')
@@ -3931,11 +3935,11 @@
GO
INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3445, 3, N'宸插彇娑�', N'5', N'mes_wm_product_produce_status', 0, N'danger', N'', N'宸插彇娑堢姸鎬�', N'1', N'2026-04-05 15:53:46', N'1', N'2026-04-05 15:53:46', N'0')
GO
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, N'猫聧鈥懊�', N'0', N'mes_pro_task_status', 0, N'', N'', NULL, N'1', N'2026-04-16 09:47:00', N'1', N'2026-04-16 09:47:00', N'0')
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3446, 0, N'鑽夌', N'0', N'mes_pro_task_status', 0, N'', N'', NULL, N'1', N'2026-04-16 09:47:00', N'1', N'2026-04-16 09:47:00', N'0')
GO
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, N'氓路虏氓庐艗忙藛聬', N'4', N'mes_pro_task_status', 0, N'', N'', NULL, N'1', N'2026-04-16 09:47:00', N'1', N'2026-04-16 09:47:00', N'0')
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3447, 1, N'宸插畬鎴�', N'4', N'mes_pro_task_status', 0, N'', N'', NULL, N'1', N'2026-04-16 09:47:00', N'1', N'2026-04-16 09:47:00', N'0')
GO
-INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, N'氓路虏氓聫鈥撁β端�', N'5', N'mes_pro_task_status', 0, N'', N'', NULL, N'1', N'2026-04-16 09:47:00', N'1', N'2026-04-16 09:47:00', N'0')
+INSERT INTO system_dict_data (id, sort, label, value, dict_type, status, color_type, css_class, remark, creator, create_time, updater, update_time, deleted) VALUES (3448, 2, N'宸插彇娑�', N'5', N'mes_pro_task_status', 0, N'', N'', NULL, N'1', N'2026-04-16 09:47:00', N'1', N'2026-04-16 09:47:00', N'0')
GO
SET IDENTITY_INSERT system_dict_data OFF
GO
@@ -13915,4 +13919,3 @@
COMMIT
GO
-- @formatter:on
-
diff --git a/sql/tools/README.md b/sql/tools/README.md
index 94c5300..da1d3f9 100644
--- a/sql/tools/README.md
+++ b/sql/tools/README.md
@@ -57,9 +57,11 @@
```Bash
docker compose up -d dm8
# 娉ㄦ剰锛氬惎鍔ㄥ畬 dm 鍚庯紝闇�瑕佹墜鍔ㄥ啀鎵ц濡備笅鍛戒护锛屽洜涓� dm 涓嶆敮鎸佸垵濮嬪寲鑴氭湰
-docker compose exec dm8 bash -c '/opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema.sql'
+docker compose exec dm8 bash -c 'printf "SET DEFINE OFF;\n" > /tmp/schema-with-define-off.sql && cat /tmp/schema.sql >> /tmp/schema-with-define-off.sql && /opt/dmdbms/bin/disql SYSDBA/SYSDBA001 \`/tmp/schema-with-define-off.sql'
exit
```
+
+> 娉ㄦ剰锛氶」鐩� DM8 鑴氭湰浣跨敤 `varchar(n char)` 淇濇寔鍜� MySQL `varchar(n)` 涓�鑷寸殑瀛楃闀垮害璇箟锛屽缓璁垵濮嬪寲 DM8 鏃朵娇鐢� `PAGE_SIZE=16`銆乣UNICODE_FLAG=1`銆俙sql/tools/docker-compose.yaml` 宸叉寜璇ラ厤缃彁渚涚ず渚嬨�備娇鐢� `disql` 瀵煎叆鏃堕渶瑕佸厛鎵ц `SET DEFINE OFF;`锛岄伩鍏嶆暟鎹噷鐨� `&` 琚綋浣滃彉閲忔浛鎹€��
### 1.6 KingbaseES 浜哄ぇ閲戜粨
@@ -90,6 +92,25 @@
docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql'
```
+### 1.8 HighGo 鐎氶珮鏁版嵁搴�
+
+鈶� 涓嬭浇鐎氶珮瀹樻柟 Docker 闀滃儚锛屽苟鍔犺浇闀滃儚鏂囦欢銆傚姞杞藉悗锛屽皢闀滃儚鎵撴垚鏈湴鏍囩锛�
+
+```Bash
+docker load -i <highgo-image>.tar
+docker tag <image>:<tag> highgo:local
+```
+
+鈶� 鍦ㄩ」鐩� `sql/tools` 鐩綍涓嬭繍琛岋細
+
+```Bash
+docker compose up -d highgo
+```
+
+> 娉ㄦ剰锛氫笉鍚岀�氶珮闀滃儚鐨勬暟鎹洰褰曞彲鑳戒笉鍚岋紝濡傛灉瀹瑰櫒鏃犳硶鍚姩锛岃鎸夐暅鍍忓疄闄� `PGDATA` 淇敼 `docker-compose.yaml` 涓殑 `highgo` 鏁版嵁鍗锋寕杞界洰褰曘��
+
+鈶� 鍚姩瀹屾垚鍚庯紝闇�瑕佹墜鍔ㄥ鍏� Quartz 鍜岄」鐩� SQL銆傜�氶珮鍏煎 PostgreSQL锛屽叿浣撳鎴风鍛戒护浠ュ綋鍓嶉暅鍍忎负鍑嗭紝鍙娇鐢� `psql` 鎴栫�氶珮闀滃儚鍐呯疆鐨勫吋瀹瑰鎴风鎵ц `/tmp/quartz.sql`銆乣/tmp/schema.sql`銆�
+
## 1.X 瀹瑰櫒鐨勯攢姣侀噸寤�
寮�鍙戞祴璇曡繃绋嬩腑锛屾湁鏃跺�欓渶瑕佸垱寤哄叏鏂板共鍑�鐨勬暟鎹簱銆傜敱浜庢祴璇曟暟鎹� Docker 瀹瑰櫒閲囩敤鏁版嵁鍗� Volume 鎸傝浇鏁版嵁搴撳疄渚嬬殑鏁版嵁鐩綍锛屽洜姝ら攢姣佹暟鎹渶瑕佸仠姝㈠鍣ㄥ悗锛屽垹闄ゆ暟鎹嵎锛岀劧鍚庡啀閲嶆柊鍒涘缓瀹瑰櫒銆�
@@ -103,7 +124,7 @@
## 2. MySQL 杞崲鍏跺畠鏁版嵁搴�
-椤圭洰鎻愪緵浜� `sql/tools/convertor.py` 鑴氭湰锛屾敮鎸佸皢 MySQL 杞崲涓� Oracle銆丳ostgreSQL銆丼QL Server銆佽揪姊︺�佷汉澶ч噾浠撱�丱penGauss 绛夋暟鎹簱鐨勮剼鏈��
+椤圭洰鎻愪緵浜� `sql/tools/convertor.py` 鑴氭湰锛屾敮鎸佸皢 MySQL 杞崲涓� Oracle銆丳ostgreSQL銆丼QL Server銆佽揪姊︺�佷汉澶ч噾浠撱�丱penGauss銆佺�氶珮绛夋暟鎹簱鐨勮剼鏈��
### 2.1 瀹炵幇鍘熺悊
@@ -118,11 +139,12 @@
# pip3 install simple-ddl-parser
```
-鈶� 鍦� `sql/tools/` 鐩綍涓嬶紝鎵ц濡備笅鍛戒护鎵撳嵃鐢熸垚 postgres 鐨勮剼鏈唴瀹癸紝鍏朵粬鍙�夊弬鏁版湁锛歚oracle`銆乣sqlserver`銆乣dm8`銆乣kingbase`銆乣opengauss`锛�
+鈶� 鍦� `sql/tools/` 鐩綍涓嬶紝鎵ц濡備笅鍛戒护鎵撳嵃鐢熸垚 postgres 鐨勮剼鏈唴瀹癸紝鍏朵粬鍙�夊弬鏁版湁锛歚oracle`銆乣sqlserver`銆乣dm8`銆乣kingbase`銆乣opengauss`銆乣highgo`锛�
```Bash
python3 convertor.py postgres
# python3 convertor.py postgres > tmp.sql
+# python3 convertor.py highgo ../mysql/ruoyi-vue-pro.sql > ../highgo/ruoyi-vue-pro.sql
```
绋嬪簭灏� SQL 鑴氭湰鎵撳嵃鍒扮粓绔紝鍙互閲嶅畾鍚戝埌涓存椂鏂囦欢 `tmp.sql`銆�
diff --git a/sql/tools/convertor.py b/sql/tools/convertor.py
index 3a8b9f3..f4509fd 100644
--- a/sql/tools/convertor.py
+++ b/sql/tools/convertor.py
@@ -10,6 +10,7 @@
uv run --with simple-ddl-parser convertor.py sqlserver ../mysql/ruoyi-vue-pro.sql > ../sqlserver/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py kingbase ../mysql/ruoyi-vue-pro.sql > ../kingbase/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py opengauss ../mysql/ruoyi-vue-pro.sql > ../opengauss/ruoyi-vue-pro.sql
+uv run --with simple-ddl-parser convertor.py highgo ../mysql/ruoyi-vue-pro.sql > ../highgo/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py oracle ../mysql/ruoyi-vue-pro.sql > ../oracle/ruoyi-vue-pro.sql
uv run --with simple-ddl-parser convertor.py dm8 ../mysql/ruoyi-vue-pro.sql > ../dm/ruoyi-vue-pro-dm8.sql
"""
@@ -77,6 +78,9 @@
class Convertor(ABC):
+ # 涓嶅悓鏁版嵁搴撶殑鍏抽敭瀛椾笉瀹屽叏涓�鑷达紱瀛愮被鎸夐渶澹版槑闇�瑕佽浆涔夌殑鍒楀悕銆�
+ reserved_column_names = set()
+
def __init__(self, src: str, db_type) -> None:
self.src = src
self.db_type = db_type
@@ -179,6 +183,31 @@
"""
return ""
+ def escape_column_name(self, name: str) -> str:
+ """杞箟鐩爣搴撲繚鐣欏瓧鍒楀悕锛屼緥濡� Oracle / Kingbase 鐨� level銆�"""
+
+ column_name = name.lower()
+ if column_name in self.reserved_column_names:
+ return f'"{column_name}"'
+ return column_name
+
+ def escape_insert_columns(self, insert_script: str) -> str:
+ """INSERT 鏄惧紡鍒楁竻鍗曢渶瑕佸拰 CREATE / COMMENT 浣跨敤鍚屼竴濂楀垪鍚嶈浆涔夈��"""
+
+ match = re.match(
+ r"(INSERT INTO\s+\S+\s*\()([^)]+)(\)\s+VALUES\s+[\s\S]*)",
+ insert_script,
+ flags=re.IGNORECASE,
+ )
+ if not match:
+ return insert_script
+
+ columns = [
+ self.escape_column_name(column.strip())
+ for column in match.group(2).split(",")
+ ]
+ return f"{match.group(1)}{', '.join(columns)}{match.group(3)}"
+
@staticmethod
def inserts(table_name: str, script_content: str) -> Generator:
PREFIX = f"INSERT INTO `{table_name}`"
@@ -204,17 +233,54 @@
Generator[str]: create index 璇彞
"""
- def generate_columns(columns):
- keys = [
- f"{col['name'].lower()}{' ' + col['order'].lower() if col['order'] != 'ASC' else ''}"
- for col in columns[0]
- ]
- return ", ".join(keys)
-
- for no, index in enumerate(ddl["index"], 1):
- columns = generate_columns(index["columns"])
+ for no, index in enumerate(ddl.get("index", []), 1):
+ columns = ", ".join(Convertor.index_columns(index.get("columns", [])))
+ if not columns:
+ continue
table_name = ddl["table_name"].lower()
yield f"CREATE INDEX idx_{table_name}_{no:02d} ON {table_name} ({columns})"
+
+ @staticmethod
+ def index_columns(columns) -> list:
+ """鍏煎 simple-ddl-parser 涓嶅悓鐗堟湰鐨勭储寮曞垪缁撴瀯銆�"""
+
+ keys = []
+
+ def append(name, order="ASC"):
+ if not name:
+ return
+ column_name = str(name).strip("`").lower()
+ column_order = str(order or "ASC").upper()
+ if column_order == "DESC":
+ keys.append(f"{column_name} desc")
+ else:
+ keys.append(column_name)
+
+ def visit(value):
+ # 鏅�氱储寮曞父瑙佺粨鏋勶細[[{'name': 'user_id', 'order': 'ASC'}]]
+ if isinstance(value, (list, tuple)):
+ for item in value:
+ visit(item)
+ return
+ if isinstance(value, dict):
+ name = value.get("name")
+ if isinstance(name, (dict, list, tuple)):
+ visit(name)
+ return
+ append(name, value.get("order", "ASC"))
+ return
+ # 鍞竴绱㈠紩鍦ㄩ儴鍒嗙増鏈腑浼氳瑙f瀽鎴� ['mobile', 'ASC', 'tenant_id', 'ASC']銆�
+ if isinstance(value, str):
+ token = value.strip("`")
+ order = token.upper()
+ if order in ("ASC", "DESC"):
+ if order == "DESC" and keys and not keys[-1].endswith(" desc"):
+ keys[-1] = f"{keys[-1]} desc"
+ return
+ append(token)
+
+ visit(columns)
+ return keys
@staticmethod
def unique_index(ddl: Dict) -> Generator:
@@ -223,7 +289,9 @@
for uk in uk_list:
table_name = ddl["table_name"]
uk_name = uk["constraint_name"]
- uk_columns = uk["columns"]
+ uk_columns = Convertor.index_columns(uk["columns"])
+ if not uk_columns:
+ continue
yield table_name, uk_name, uk_columns
@staticmethod
@@ -381,7 +449,7 @@
)
nullable = "NULL" if col["nullable"] else "NOT NULL"
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
- return f"{name} {full_type} {nullable} {default}"
+ return f"{self.escape_column_name(name)} {full_type} {nullable} {default}"
table_name = ddl["table_name"].lower()
columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]]
@@ -406,7 +474,7 @@
for column in table_ddl["columns"]:
table_comment = column["comment"]
script += (
- f"COMMENT ON COLUMN {table_ddl['table_name']}.{column['name']} IS '{table_comment}';"
+ f"COMMENT ON COLUMN {table_ddl['table_name']}.{self.escape_column_name(column['name'])} IS '{table_comment}';"
+ "\n"
)
@@ -435,6 +503,7 @@
"""鐢熸垚 insert 璇彞锛屼互鍙婃牴鎹渶鍚庣殑 insert id+1 鐢熸垚 Sequence"""
inserts = list(Convertor.inserts(table_name, self.content))
+ inserts = [self.escape_insert_columns(s) for s in inserts]
# 杞崲 MySQL 瀛楃涓茶浆涔変负 PostgreSQL 鏍煎紡锛歕\ -> \锛孿' -> ''
inserts = [re.sub(r"\\\\|\\'", lambda m: "\\" if m.group() == "\\\\" else "''", s) for s in inserts]
## 鐢熸垚 insert 鑴氭湰
@@ -482,6 +551,8 @@
class OracleConvertor(Convertor):
+ reserved_column_names = {"level", "size"}
+
def __init__(self, src):
super().__init__(src, "Oracle")
@@ -526,10 +597,8 @@
# Oracle鐨� INSERT '' 涓嶈兘閫氳繃NOT NULL鏍¢獙锛屽洜姝ゅ鏂囧瓧绫诲瀷瀛楁瑕嗗啓涓� NULL
nullable = "NULL" if type in ("varchar", "text", "longtext") else nullable
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
- # Oracle 涓� size 涓嶈兘浣滀负瀛楁鍚�
- field_name = '"size"' if name == "size" else name
# Oracle DEFAULT 瀹氫箟鍦� NULLABLE 涔嬪墠
- return f"{field_name} {full_type} {default} {nullable}"
+ return f"{self.escape_column_name(name)} {full_type} {default} {nullable}"
table_name = ddl["table_name"].lower()
columns = [f"{generate_column(col).strip()}" for col in ddl["columns"]]
@@ -554,7 +623,7 @@
for column in table_ddl["columns"]:
table_comment = column["comment"]
script += (
- f"COMMENT ON COLUMN {table_ddl['table_name']}.{column['name']} IS '{table_comment}';"
+ f"COMMENT ON COLUMN {table_ddl['table_name']}.{self.escape_column_name(column['name'])} IS '{table_comment}';"
+ "\n"
)
@@ -586,6 +655,7 @@
"""鎷疯礉 INSERT 璇彞"""
inserts = []
for insert_script in Convertor.inserts(table_name, self.content):
+ insert_script = self.escape_insert_columns(insert_script)
# 瀵规棩鏈熸暟鎹坊鍔� TO_DATE 杞崲
insert_script = re.sub(
r"('\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}')",
@@ -801,7 +871,9 @@
type = type.lower()
if type == "varchar":
- return f"varchar({size})"
+ # MySQL varchar(n) is character-oriented. DM8 may treat varchar(n)
+ # as bytes, so use explicit CHAR semantics for generated scripts.
+ return f"varchar({size} char)"
if type in ("int", "int unsigned"):
return "int"
if type in ("bigint", "bigint unsigned"):
@@ -907,6 +979,8 @@
class KingbaseConvertor(PostgreSQLConvertor):
+ reserved_column_names = {"level"}
+
def __init__(self, src):
super().__init__(src)
self.db_type = "Kingbase"
@@ -925,7 +999,7 @@
if full_type == "text":
nullable = "NULL"
default = f"DEFAULT {col['default']}" if col["default"] is not None else ""
- return f"{name} {full_type} {nullable} {default}"
+ return f"{self.escape_column_name(name)} {full_type} {nullable} {default}"
table_name = ddl["table_name"].lower()
columns = [f"{_generate_column(col).strip()}" for col in ddl["columns"]]
@@ -945,9 +1019,17 @@
class OpengaussConvertor(KingbaseConvertor):
+ reserved_column_names = set()
+
def __init__(self, src):
super().__init__(src)
self.db_type = "OpenGauss"
+
+
+class HighGoConvertor(PostgreSQLConvertor):
+ def __init__(self, src):
+ super().__init__(src)
+ self.db_type = "HighGo"
def main():
@@ -956,12 +1038,13 @@
"type",
type=str,
help="鐩爣鏁版嵁搴撶被鍨�",
- choices=["postgres", "oracle", "sqlserver", "dm8", "kingbase", "opengauss"],
+ choices=["postgres", "oracle", "sqlserver", "dm8", "kingbase", "opengauss", "highgo"],
)
parser.add_argument(
"path",
type=str,
help="婧愭暟鎹簱鑴氭湰璺緞",
+ nargs="?",
default="../mysql/ruoyi-vue-pro.sql"
)
args = parser.parse_args()
@@ -980,6 +1063,8 @@
convertor = KingbaseConvertor(sql_file)
elif args.type == "opengauss":
convertor = OpengaussConvertor(sql_file)
+ elif args.type == "highgo":
+ convertor = HighGoConvertor(sql_file)
else:
raise NotImplementedError(f"涓嶆敮鎸佺洰鏍囨暟鎹簱绫诲瀷: {args.type}")
diff --git a/sql/tools/docker-compose.yaml b/sql/tools/docker-compose.yaml
index 0fa9513..de25dfa 100644
--- a/sql/tools/docker-compose.yaml
+++ b/sql/tools/docker-compose.yaml
@@ -7,6 +7,7 @@
dm8: { }
kingbase: { }
opengauss: { }
+ highgo: { }
services:
mysql:
@@ -131,4 +132,16 @@
volumes:
- opengauss:/var/lib/opengauss
- ../opengauss/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
- # docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql'
\ No newline at end of file
+ # docker compose exec opengauss bash -c '/usr/local/opengauss/bin/gsql -U $GS_USERNAME -W $GS_PASSWORD -d postgres -f /tmp/schema.sql'
+
+ highgo:
+ # 浣跨敤鐎氶珮瀹樻柟鎻愪緵鐨� Docker 闀滃儚锛屽姞杞藉悗鎵撴垚鏈湴鏍囩锛�
+ # docker tag <image>:<tag> highgo:local
+ image: highgo:local
+ restart: unless-stopped
+ ports:
+ - "5866:5866"
+ volumes:
+ - highgo:/home/highgo/hgdb/data
+ - ../highgo/quartz.sql:/tmp/quartz.sql:ro
+ - ../highgo/ruoyi-vue-pro.sql:/tmp/schema.sql:ro
diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index 7599892..32e82e5 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -14,10 +14,10 @@
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
- <revision>2026.04-SNAPSHOT</revision>
+ <revision>2026.06-jdk25-SNAPSHOT</revision>
<flatten-maven-plugin.version>1.7.2</flatten-maven-plugin.version>
<!-- 缁熶竴渚濊禆绠$悊 -->
- <spring.boot.version>4.0.6</spring.boot.version>
+ <spring.boot.version>4.1.0</spring.boot.version>
<!-- Web 鐩稿叧 -->
<springdoc.version>3.0.3</springdoc.version>
<knife4j.version>4.5.0</knife4j.version>
@@ -28,13 +28,13 @@
<mybatis-plus-join.version>1.5.7</mybatis-plus-join.version>
<dynamic-datasource.version>4.5.0</dynamic-datasource.version>
<easy-trans.version>3.1.5</easy-trans.version>
- <redisson.version>4.3.1</redisson.version>
+ <redisson.version>4.6.1</redisson.version>
<dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
<kingbase.jdbc.version>9.0.1.jre7</kingbase.jdbc.version>
<opengauss.jdbc.version>7.0.0-RC3-og</opengauss.jdbc.version>
- <taos.version>3.8.3</taos.version>
+ <taos.version>3.8.4</taos.version>
<!-- 娑堟伅闃熷垪 -->
- <rocketmq-spring.version>2.3.5</rocketmq-spring.version>
+ <rocketmq-spring.version>2.3.6</rocketmq-spring.version>
<!-- 鏈嶅姟淇濋殰鐩稿叧 -->
<lock4j.version>2.2.7</lock4j.version>
<!-- 鐩戞帶鐩稿叧 -->
@@ -43,42 +43,46 @@
<opentracing.version>0.33.0</opentracing.version>
<!-- Test 娴嬭瘯鐩稿叧 -->
<podam.version>8.0.2.RELEASE</podam.version>
- <jedis-mock.version>1.1.12</jedis-mock.version>
+ <jedis-mock.version>1.1.15</jedis-mock.version>
<mockito-inline.version>5.2.0</mockito-inline.version>
<!-- Bpm 宸ヤ綔娴佺浉鍏� -->
- <flowable.version>7.2.0</flowable.version>
+ <flowable.version>8.0.0</flowable.version>
<!-- 宸ュ叿绫荤浉鍏� -->
<anji-plus-captcha.version>1.4.0</anji-plus-captcha.version>
<jsoup.version>1.22.2</jsoup.version>
+ <sensitive-word.version>0.29.5</sensitive-word.version>
+ <pinyin4j.version>2.5.1</pinyin4j.version>
<lombok.version>1.18.46</lombok.version>
<mapstruct.version>1.6.3</mapstruct.version>
- <hutool-5.version>5.8.44</hutool-5.version>
+ <hutool-5.version>5.8.46</hutool-5.version>
<hutool-6.version>6.0.0-M22</hutool-6.version>
<fastexcel.version>1.3.0</fastexcel.version>
<velocity.version>2.4.1</velocity.version>
<fastjson.version>1.2.83</fastjson.version>
+ <fastjson2.version>2.0.62</fastjson2.version>
<guava.version>33.6.0-jre</guava.version>
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
<commons-net.version>3.13.0</commons-net.version>
<commons-lang3.version>3.20.0</commons-lang3.version>
- <jsch.version>2.28.2</jsch.version>
- <tika-core.version>3.3.0</tika-core.version>
+ <jsch.version>2.28.3</jsch.version>
+ <tika-core.version>3.3.1</tika-core.version>
<ip2region.version>2.7.0</ip2region.version>
<bizlog-sdk.version>3.0.6</bizlog-sdk.version>
- <netty.version>4.2.12.Final</netty.version>
+ <netty.version>4.2.15.Final</netty.version>
<mqtt.version>1.2.5</mqtt.version>
<vertx.version>4.5.26</vertx.version>
<okhttp.version>4.12.0</okhttp.version>
<californium.version>3.14.0</californium.version>
<j2mod.version>3.3.0</j2mod.version>
<!-- 涓夋柟浜戞湇鍔$浉鍏� -->
- <awssdk.version>2.44.0</awssdk.version>
+ <awssdk.version>2.46.17</awssdk.version>
<justauth.version>1.16.7</justauth.version>
<justauth-starter.version>1.4.0</justauth-starter.version>
- <jimureport.version>2.3.2</jimureport.version>
+ <jimureport.version>2.3.4</jimureport.version>
<jimubi.version>2.3.2</jimubi.version>
- <weixin-java.version>4.8.2-20260501.180637</weixin-java.version>
- <alipay-sdk-java.version>4.40.771.ALL</alipay-sdk-java.version>
+ <weixin-java.version>4.8.4-20260623.211820</weixin-java.version>
+ <bouncycastle.version>1.80</bouncycastle.version>
+ <alipay-sdk-java.version>4.40.865.ALL</alipay-sdk-java.version>
</properties>
<dependencyManagement>
@@ -521,6 +525,11 @@
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.alibaba.fastjson2</groupId>
+ <artifactId>fastjson2</artifactId>
+ <version>${fastjson2.version}</version>
+ </dependency>
<dependency>
<groupId>com.google.guava</groupId>
@@ -567,6 +576,18 @@
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.github.houbb</groupId>
+ <artifactId>sensitive-word</artifactId> <!-- 鏁忔劅璇嶆娴嬶細trie 鏍戦珮鏁堝尮閰� -->
+ <version>${sensitive-word.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.belerweb</groupId>
+ <artifactId>pinyin4j</artifactId> <!-- 姹夊瓧杞嫾闊筹細浣滀负 hutool PinyinUtil 鐨勫簳灞傚紩鎿� -->
+ <version>${pinyin4j.version}</version>
</dependency>
<!-- Vert.x -->
@@ -657,6 +678,24 @@
</exclusions>
</dependency>
+ <!-- 閿佸畾 weixin-java 浼犻�掍緷璧栵紝閬垮厤 Maven 鐗堟湰鑼冨洿鑷姩鍗囩骇鍒� 1.80.2 鍚� Fat Jar 鍚姩澶辫触銆�
+ 鍙嶉锛歨ttps://t.zsxq.com/pCVBo -->
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk18on</artifactId>
+ <version>${bouncycastle.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcutil-jdk18on</artifactId>
+ <version>${bouncycastle.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk18on</artifactId>
+ <version>${bouncycastle.version}</version>
+ </dependency>
+
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
index 28265a5..b2db78b 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
@@ -124,6 +124,22 @@
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
}
+ public static <T, U> Set<U> convertLinkedSet(Collection<T> from, Function<T, U> func) {
+ if (CollUtil.isEmpty(from)) {
+ return new LinkedHashSet<>();
+ }
+ return from.stream().map(func).filter(Objects::nonNull)
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+ }
+
+ public static <T, U> Set<U> convertLinkedSet(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
+ if (CollUtil.isEmpty(from)) {
+ return new LinkedHashSet<>();
+ }
+ return from.stream().filter(filter).map(func).filter(Objects::nonNull)
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+ }
+
public static <T, K> Map<K, T> convertMapByFilter(Collection<T> from, Predicate<T> filter, Function<T, K> keyFunc) {
if (CollUtil.isEmpty(from)) {
return new HashMap<>();
@@ -372,4 +388,14 @@
return false;
}
+ /**
+ * 鎶婂崟鍏冪礌 head 涓庨泦鍚� tail 鍚堝苟鎴愭柊 List锛坔ead 鍦ㄥ墠锛宼ail 椤哄簭淇濈暀锛�
+ */
+ public static <T> List<T> of(T head, Collection<T> tail) {
+ List<T> list = new ArrayList<>();
+ list.add(head);
+ CollUtil.addAll(list, tail);
+ return list;
+ }
+
}
\ No newline at end of file
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
index 34e4d85..f942d6e 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
@@ -3,7 +3,6 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
-import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
@@ -16,6 +15,7 @@
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
+import java.util.TimeZone;
import static cn.hutool.core.date.DatePattern.*;
@@ -32,6 +32,11 @@
public static LocalDateTime EMPTY = buildTime(1970, 1, 1);
public static DateTimeFormatter UTC_MS_WITH_XXX_OFFSET_FORMATTER = createFormatter(UTC_MS_WITH_XXX_OFFSET_PATTERN);
+
+ /**
+ * 榛樿鏃跺尯
+ */
+ private static final ZoneId DEFAULT_ZONE_ID = TimeZone.getTimeZone(DateUtils.TIME_ZONE_DEFAULT).toZoneId();
/**
* 瑙f瀽鏃堕棿
@@ -63,6 +68,27 @@
public static boolean afterNow(LocalDateTime date) {
return date.isAfter(LocalDateTime.now());
+ }
+
+ /**
+ * 灏� Unix 绉掓椂闂存埑杞崲涓洪粯璁ゆ椂鍖虹殑鏈湴鏃堕棿
+ *
+ * @param epochSecond Unix 绉掓椂闂存埑
+ * @return 鏈湴鏃堕棿
+ */
+ public static LocalDateTime ofEpochSecond(long epochSecond) {
+ return ofEpochSecond(epochSecond, DEFAULT_ZONE_ID);
+ }
+
+ /**
+ * 灏� Unix 绉掓椂闂存埑杞崲涓烘寚瀹氭椂鍖虹殑鏈湴鏃堕棿
+ *
+ * @param epochSecond Unix 绉掓椂闂存埑
+ * @param zoneId 鏃跺尯缂栧彿
+ * @return 鏈湴鏃堕棿
+ */
+ public static LocalDateTime ofEpochSecond(long epochSecond, ZoneId zoneId) {
+ return LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), zoneId);
}
/**
@@ -236,6 +262,23 @@
return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
}
+ /**
+ * 鑾峰彇鏈�杩� N 澶╃殑 0 鐐规椂鍒诲簭鍒楋紙鍗囧簭锛屽惈浠婂ぉ锛�
+ * <p>
+ * 渚嬶細getLatestDays(3) 杩斿洖 [鍓嶅ぉ 00:00, 鏄ㄥぉ 00:00, 浠婂ぉ 00:00]
+ *
+ * @param days 澶╂暟锛堝惈浠婂ぉ锛�
+ * @return 鍗囧簭鐨� LocalDateTime 鍒楄〃
+ */
+ public static List<LocalDateTime> getLatestDays(int days) {
+ LocalDateTime today = getToday();
+ List<LocalDateTime> dates = new ArrayList<>(days);
+ for (int i = days - 1; i >= 0; i--) {
+ dates.add(today.minusDays(i));
+ }
+ return dates;
+ }
+
public static List<LocalDateTime[]> getDateRangeList(LocalDateTime startTime,
LocalDateTime endTime,
Integer interval) {
@@ -376,7 +419,18 @@
* @throws DateTimeException 濡傛灉杞崲杩囩▼涓彂鐢熸椂闂磋秴鍑鸿寖鍥存垨鍏朵粬鏃堕棿澶勭悊寮傚父
*/
public static Long toEpochSecond(LocalDateTime sourceDateTime) {
- return TemporalAccessorUtil.toInstant(sourceDateTime).getEpochSecond();
+ return toEpochSecond(sourceDateTime, DEFAULT_ZONE_ID);
+ }
+
+ /**
+ * 灏嗙粰瀹氱殑 {@link LocalDateTime} 鎸夋寚瀹氭椂鍖鸿浆鎹负鑷� Unix 绾厓鏃堕棿锛�1970-01-01T00:00:00Z锛変互鏉ョ殑绉掓暟銆�
+ *
+ * @param sourceDateTime 闇�瑕佽浆鎹㈢殑鏈湴鏃ユ湡鏃堕棿锛屼笉鑳戒负绌�
+ * @param zoneId 鏃跺尯缂栧彿
+ * @return 鑷� 1970-01-01T00:00:00Z 璧风殑绉掓暟锛坋poch second锛�
+ */
+ public static Long toEpochSecond(LocalDateTime sourceDateTime, ZoneId zoneId) {
+ return sourceDateTime.atZone(zoneId).toEpochSecond();
}
}
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java
index d274981..95220a9 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java
@@ -9,6 +9,7 @@
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
+import org.springframework.web.util.UriUtils;
import java.net.URI;
import java.net.URLDecoder;
@@ -55,9 +56,59 @@
* @return 瑙g爜鍚庣殑璺緞
*/
public static String decodeUrlPath(String path) {
+ if (StrUtil.isEmpty(path)) {
+ return path;
+ }
// 鍏堝皢 + 鏇挎崲涓� %2B锛岄伩鍏嶈 URLDecoder 瑙g爜涓虹┖鏍�
String encoded = path.replace("+", "%2B");
return URLDecoder.decode(encoded, StandardCharsets.UTF_8);
+ }
+
+ /**
+ * 缂栫爜 URL 璺緞锛屾寜璺緞娈电紪鐮侊紝淇濈暀 / 鍒嗛殧绗�
+ *
+ * @param path URL 璺緞锛屼緥濡� 20250602/xxx.pdf
+ * @return 缂栫爜鍚庣殑璺緞
+ */
+ public static String encodeUrlPath(String path) {
+ if (StrUtil.isEmpty(path)) {
+ return path;
+ }
+ String[] segments = path.split(StrUtil.SLASH, -1);
+ StringBuilder result = new StringBuilder(path.length());
+ for (int i = 0; i < segments.length; i++) {
+ if (i > 0) {
+ result.append(StrUtil.SLASH);
+ }
+ result.append(encodeUrlPathSegment(segments[i]));
+ }
+ return result.toString();
+ }
+
+ /**
+ * 缂栫爜 URL 璺緞娈�
+ *
+ * @param segment URL 璺緞娈�
+ * @return 缂栫爜鍚庣殑璺緞娈�
+ */
+ public static String encodeUrlPathSegment(String segment) {
+ return UriUtils.encodePathSegment(segment, StandardCharsets.UTF_8);
+ }
+
+ public static String removeUrlPathQueryAndFragment(String path) {
+ if (StrUtil.isEmpty(path)) {
+ return path;
+ }
+ int endIndex = path.length();
+ int queryIndex = path.indexOf('?');
+ if (queryIndex >= 0) {
+ endIndex = queryIndex;
+ }
+ int fragmentIndex = path.indexOf('#');
+ if (fragmentIndex >= 0 && fragmentIndex < endIndex) {
+ endIndex = fragmentIndex;
+ }
+ return path.substring(0, endIndex);
}
public static String replaceUrlQuery(String url, String key, String value) {
@@ -200,4 +251,14 @@
}
}
+ /**
+ * WebSocket URL 鍒囨崲鎴� HTTP URL锛歸s:// 鈫� http://锛泈ss:// 鈫� https://锛涘叾瀹冩牸寮忓師鏍蜂繚鐣�
+ *
+ * @param url 鍘熷 URL
+ * @return 鍒囨崲鍗忚鍚庣殑 URL
+ */
+ public static String wsUrlToHttp(String url) {
+ return StrUtil.startWithIgnoreCase(url, "ws") ? "http" + url.substring(2) : url;
+ }
+
}
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
index c12e262..558c8d2 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
@@ -22,6 +22,7 @@
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* JSON 宸ュ叿绫�
@@ -36,13 +37,12 @@
private static ObjectMapper buildObjectMapper() {
SimpleModule simpleModule = new SimpleModule()
+ // 瑙e喅 LocalDateTime 鐨勫簭鍒楀寲
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
return JsonMapper.builder()
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
- // 寮哄埗灏嗘暣鏁板弽搴忓垪鍖栦负 Long锛岃В鍐� Redis 缂撳瓨鍙嶅簭鍒楀寲鏃� Integer 杞� Long 鐨勯棶棰�
- .enable(DeserializationFeature.USE_LONG_FOR_INTS)
.changeDefaultPropertyInclusion(value -> JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL))
.addModule(simpleModule)
.build();
@@ -177,6 +177,23 @@
}
/**
+ * 瑙f瀽 JSON 瀛楃涓叉垚 Map锛岀┖瀛楃涓叉垨瑙f瀽澶辫触杩斿洖 null
+ *
+ * @param text JSON 瀛楃涓�
+ * @return Map 瀵硅薄
+ */
+ public static Map<String, Object> parseMap(String text) {
+ if (StrUtil.isEmpty(text)) {
+ return null;
+ }
+ try {
+ return objectMapper.readValue(text, new TypeReference<Map<String, Object>>() {});
+ } catch (JacksonException e) {
+ return null;
+ }
+ }
+
+ /**
* 瑙f瀽 JSON 瀛楃涓叉垚鎸囧畾绫诲瀷鐨勫璞★紝濡傛灉瑙f瀽澶辫触锛屽垯杩斿洖 null
*
* @param text 瀛楃涓�
@@ -238,6 +255,14 @@
}
}
+ public static String getText(JsonNode node, String fieldName) {
+ if (node == null) {
+ return null;
+ }
+ JsonNode value = node.get(fieldName);
+ return value != null && !value.isNull() ? value.asText() : null;
+ }
+
public static boolean isJson(String text) {
return JSONUtil.isTypeJSON(text);
}
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java
index c2898ea..0e7d052 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/NumberSerializer.java
@@ -4,10 +4,6 @@
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.annotation.JacksonStdImpl;
-import tools.jackson.databind.ser.std.StdScalarSerializer;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
/**
* Long 搴忓垪鍖栬鍒�
@@ -17,41 +13,24 @@
* @author 鏄熻
*/
@JacksonStdImpl
-public class NumberSerializer extends StdScalarSerializer<Number> {
+public class NumberSerializer extends tools.jackson.databind.ser.jdk.NumberSerializer {
private static final long MAX_SAFE_INTEGER = 9007199254740991L;
private static final long MIN_SAFE_INTEGER = -9007199254740991L;
public static final NumberSerializer INSTANCE = new NumberSerializer(Number.class);
- @SuppressWarnings("unchecked")
public NumberSerializer(Class<? extends Number> rawType) {
- super((Class<Number>) rawType);
+ super(rawType);
}
@Override
public void serialize(Number value, JsonGenerator gen, SerializationContext serializers) throws JacksonException {
// 瓒呭嚭鑼冨洿 搴忓垪鍖栦綅瀛楃涓�
if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
- writeNumber(value, gen);
+ super.serialize(value, gen, serializers);
} else {
gen.writeString(value.toString());
- }
- }
-
- private static void writeNumber(Number value, JsonGenerator gen) throws JacksonException {
- if (value instanceof BigDecimal decimal) {
- gen.writeNumber(decimal);
- } else if (value instanceof BigInteger integer) {
- gen.writeNumber(integer);
- } else if (value instanceof Double doubleValue) {
- gen.writeNumber(doubleValue);
- } else if (value instanceof Float floatValue) {
- gen.writeNumber(floatValue);
- } else if (value instanceof Long longValue) {
- gen.writeNumber(longValue);
- } else {
- gen.writeNumber(value.intValue());
}
}
}
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java
index 47a53a5..f0e423e 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java
@@ -3,6 +3,7 @@
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.pinyin.PinyinUtil;
import org.aspectj.lang.JoinPoint;
import java.util.Arrays;
@@ -79,6 +80,25 @@
}
/**
+ * 杞皬鍐欐嫾闊筹紝瀛椾箣闂翠互绌烘牸鍒嗛殧锛屼究浜庤皟鐢ㄦ柟鎸夐渶鎷兼帴 / 鍙栭瀛楁瘝 / 鎷奸煶鎼滅储
+ *
+ * 渚嬶細銆岃�佸紶銆嶁啋 "lao zhang"銆併�孼hangSan銆嶁啋 "zhangsan"
+ * 鑻辨枃 / 鏁板瓧 / 绗﹀彿鍘熸牱杩斿洖锛岀┖鍊艰繑鍥� null
+ *
+ * 娉ㄦ剰锛氬簳灞備緷璧� hutool-extra 鐨� {@link PinyinUtil}锛岄渶瑕佷笟鍔℃ā鍧楄嚜琛屽紩鍏ユ嫾闊冲紩鎿庝緷璧�
+ * 锛坧inyin4j / TinyPinyin / Bopomofo4j 浠婚�夊叾涓�锛夛紝鍚﹀垯杩愯鏃朵細鎶� NoClassDefFoundError
+ *
+ * @param str 瀛楃涓�
+ * @return 鎷奸煶涓诧紙淇濈暀绌烘牸鍒嗛殧锛�
+ */
+ public static String toPinyin(String str) {
+ if (StrUtil.isBlank(str)) {
+ return null;
+ }
+ return PinyinUtil.getPinyin(str);
+ }
+
+ /**
* 鎷兼帴鏂规硶鐨勫弬鏁�
*
* 鐗规畩锛氭帓闄や竴浜涙棤娉曞簭鍒楀寲鐨勫弬鏁帮紝濡� ServletRequest銆丼ervletResponse銆丮ultipartFile
diff --git a/yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/http/HttpUtilsTest.java b/yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/http/HttpUtilsTest.java
index a42874f..e2b6120 100644
--- a/yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/http/HttpUtilsTest.java
+++ b/yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/http/HttpUtilsTest.java
@@ -10,6 +10,36 @@
public class HttpUtilsTest {
@Test
+ public void testEncodeUrlPath() {
+ // 鍑嗗鍙傛暟
+ String path = "avatar/涓枃 100%+鏂囦欢.jpg";
+
+ // 璋冪敤
+ String result = HttpUtils.encodeUrlPath(path);
+
+ // 鏂█
+ assertEquals("avatar/%E4%B8%AD%E6%96%87%20100%25+%E6%96%87%E4%BB%B6.jpg", result);
+ }
+
+ @Test
+ public void testDecodeUrlPath() {
+ // 鍑嗗鍙傛暟锛�+ 鏄矾寰勫瓧绗︼紝涓嶅簲璇ユ寜 query parameter 璇箟瑙g爜涓虹┖鏍�
+ String path = "avatar/%E4%B8%AD%E6%96%87%20100%25+%E6%96%87%E4%BB%B6.jpg";
+
+ // 璋冪敤
+ String result = HttpUtils.decodeUrlPath(path);
+
+ // 鏂█
+ assertEquals("avatar/涓枃 100%+鏂囦欢.jpg", result);
+ }
+
+ @Test
+ public void testRemoveUrlPathQueryAndFragment() {
+ assertEquals("avatar/test.jpg", HttpUtils.removeUrlPathQueryAndFragment("avatar/test.jpg?token=1#preview"));
+ assertEquals("avatar/test.jpg", HttpUtils.removeUrlPathQueryAndFragment("avatar/test.jpg#preview?token=1"));
+ }
+
+ @Test
public void testReplaceUrlQuery_replace() {
// 鍑嗗鍙傛暟
String url = "https://www.iocoder.cn/path?a=1&b=2";
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
index fa252c4..b5f70aa 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java
@@ -30,6 +30,7 @@
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.BatchStrategies;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
@@ -42,8 +43,11 @@
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import org.springframework.web.util.pattern.PathPattern;
import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@AutoConfiguration
@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true) // 鍏佽浣跨敤 yudao.tenant.enable=false 绂佺敤澶氱鎴�
@@ -125,6 +129,7 @@
*
* @return 蹇界暐绉熸埛鐨� URL 闆嗗悎
*/
+ @SuppressWarnings("removal")
private Set<String> getTenantIgnoreUrls() {
Set<String> ignoreUrls = new HashSet<>();
// 鑾峰緱鎺ュ彛瀵瑰簲鐨� HandlerMethod 闆嗗悎
@@ -139,35 +144,50 @@
continue;
}
// 娣诲姞鍒板拷鐣ョ殑 URL 涓�
- ignoreUrls.addAll(entry.getKey().getPatternValues());
+ if (entry.getKey().getPatternsCondition() != null) {
+ ignoreUrls.addAll(entry.getKey().getPatternsCondition().getPatterns());
+ }
+ if (entry.getKey().getPathPatternsCondition() != null) {
+ ignoreUrls.addAll(
+ convertList(entry.getKey().getPathPatternsCondition().getPatterns(), PathPattern::getPatternString));
+ }
}
return ignoreUrls;
}
// ========== MQ ==========
- @Bean
- public TenantRedisMessageInterceptor tenantRedisMessageInterceptor() {
- return new TenantRedisMessageInterceptor();
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(name = "cn.iocoder.yudao.framework.mq.redis.core.interceptor.RedisMessageInterceptor")
+ public static class TenantRedisMQConfiguration {
+
+ @Bean
+ public TenantRedisMessageInterceptor tenantRedisMessageInterceptor() {
+ return new TenantRedisMessageInterceptor();
+ }
+
}
- @Bean
+ @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate")
- public TenantRabbitMQInitializer tenantRabbitMQInitializer() {
- return new TenantRabbitMQInitializer();
+ public static class TenantRabbitMQConfiguration {
+
+ @Bean
+ public TenantRabbitMQInitializer tenantRabbitMQInitializer() {
+ return new TenantRabbitMQInitializer();
+ }
+
}
- @Bean
+ @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "org.apache.rocketmq.spring.core.RocketMQTemplate")
- public TenantRocketMQInitializer tenantRocketMQInitializer() {
- return new TenantRocketMQInitializer();
- }
+ public static class TenantRocketMQConfiguration {
- // ========== Job ==========
+ @Bean
+ public TenantRocketMQInitializer tenantRocketMQInitializer() {
+ return new TenantRocketMQInitializer();
+ }
- @Bean
- public TenantJobAspect tenantJobAspect(TenantFrameworkService tenantFrameworkService) {
- return new TenantJobAspect(tenantFrameworkService);
}
// ========== Redis ==========
@@ -183,7 +203,25 @@
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory,
BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize()));
// 鍒涘缓 TenantRedisCacheManager 瀵硅薄
- return new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration, tenantProperties.getIgnoreCaches());
+ TenantRedisCacheManager cacheManager = new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration,
+ tenantProperties.getIgnoreCaches());
+ // 寮�鍚簨鍔℃劅鐭ワ細@Transactional 鏂规硶鍐呯殑 @CacheEvict / @CachePut 鑷姩寤惰繜鍒� afterCommit锛�
+ // 閬垮厤浜嬪姟鏈彁浜ゅ氨娓呯紦瀛樿骞跺彂璇荤┛鍐欒剰鍊硷紱鏃犱簨鍔℃椂绔嬪嵆鐢熸晥锛岃涓轰笉鍙�
+ cacheManager.setTransactionAware(true);
+ return cacheManager;
+ }
+
+ // ========== Job ==========
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(name = "cn.iocoder.yudao.framework.quartz.core.handler.JobHandler")
+ public static class TenantJobConfiguration {
+
+ @Bean
+ public TenantJobAspect tenantJobAspect(TenantFrameworkService tenantFrameworkService) {
+ return new TenantJobAspect(tenantFrameworkService);
+ }
+
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java
index b802444..5b0d886 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/config/YudaoRedisMQConsumerAutoConfiguration.java
@@ -12,7 +12,6 @@
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
@@ -70,7 +69,8 @@
public RedisPendingMessageResendJob redisPendingMessageResendJob(List<AbstractRedisStreamMessageListener<?>> listeners,
RedisMQTemplate redisTemplate,
RedissonClient redissonClient) {
- return new RedisPendingMessageResendJob(listeners, redisTemplate, redissonClient);
+ return new RedisPendingMessageResendJob(listeners, redisTemplate, redissonClient,
+ RedisPendingMessageResendJob.DEFAULT_RESEND_LOCK_KEY);
}
/**
@@ -81,7 +81,8 @@
public RedisStreamMessageCleanupJob redisStreamMessageCleanupJob(List<AbstractRedisStreamMessageListener<?>> listeners,
RedisMQTemplate redisTemplate,
RedissonClient redissonClient) {
- return new RedisStreamMessageCleanupJob(listeners, redisTemplate, redissonClient);
+ return new RedisStreamMessageCleanupJob(listeners, redisTemplate, redissonClient,
+ RedisStreamMessageCleanupJob.DEFAULT_CLEANUP_LOCK_KEY);
}
/**
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
index bb16be0..d0b7ae3 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisPendingMessageResendJob.java
@@ -23,7 +23,9 @@
@AllArgsConstructor
public class RedisPendingMessageResendJob {
- private static final String LOCK_KEY = "redis:stream:pending-message-resend:lock";
+ public static final String DEFAULT_RESEND_LOCK_KEY = "redis:stream:pending-message-resend:lock";
+
+ public static final String IOT_RESEND_LOCK_KEY = "redis:stream:pending-message-resend:lock:iot";
/**
* 娑堟伅瓒呮椂鏃堕棿锛岄粯璁� 5 鍒嗛挓
@@ -36,22 +38,26 @@
private final List<AbstractRedisStreamMessageListener<?>> listeners;
private final RedisMQTemplate redisTemplate;
private final RedissonClient redissonClient;
+ private final String resendLockKey;
/**
* 涓�鍒嗛挓鎵ц涓�娆�,杩欓噷閫夋嫨姣忓垎閽熺殑 35 绉掓墽琛岋紝鏄负浜嗛伩鍏嶆暣鐐逛换鍔¤繃澶氱殑闂
*/
@Scheduled(cron = "35 * * * * ?")
public void messageResend() {
- RLock lock = redissonClient.getLock(LOCK_KEY);
- // 灏濊瘯鍔犻攣
+ RLock lock = redissonClient.getLock(resendLockKey);
if (lock.tryLock()) {
try {
execute();
} catch (Exception ex) {
- log.error("[messageResend][鎵ц寮傚父]", ex);
+ log.error("[messageResend][鎵ц寮傚父][lockKey={}]", resendLockKey, ex);
} finally {
- lock.unlock();
+ if (lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
}
+ } else {
+ log.debug("[messageResend][鏈幏鍙栧埌閿侊紝璺宠繃鏈疆][lockKey={}]", resendLockKey);
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisStreamMessageCleanupJob.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisStreamMessageCleanupJob.java
index 19da845..eff64fd 100644
--- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisStreamMessageCleanupJob.java
+++ b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/redis/core/job/RedisStreamMessageCleanupJob.java
@@ -23,7 +23,16 @@
@AllArgsConstructor
public class RedisStreamMessageCleanupJob {
- private static final String LOCK_KEY = "redis:stream:message-cleanup:lock";
+ /**
+ * 涓氬姟 MQ锛圫pring 瀹瑰櫒鍐� AbstractRedisStreamMessageListener锛夋竻鐞嗕换鍔′娇鐢ㄧ殑鍒嗗竷寮忛攣
+ */
+ public static final String DEFAULT_CLEANUP_LOCK_KEY = "redis:stream:message-cleanup:lock";
+
+ /**
+ * IoT Redis 鎬荤嚎娓呯悊浠诲姟浣跨敤鐨勫垎甯冨紡閿侊紙椤讳笌 {@link #DEFAULT_CLEANUP_LOCK_KEY} 鍖哄垎锛屽惁鍒欎細鍏辨姠涓�鎶婇攣锛�
+ * 鍚屼竴鏃跺埢鍙湁涓�渚ц兘鎵ц XTRIM锛屽彟涓�渚� Stream 鍙兘鏃犻檺绉帇锛�
+ */
+ public static final String IOT_CLEANUP_LOCK_KEY = "redis:stream:message-cleanup:lock:iot";
/**
* 淇濈暀鐨勬秷鎭暟閲忥紝榛樿淇濈暀鏈�杩� 10000 鏉℃秷鎭�
@@ -33,22 +42,29 @@
private final List<AbstractRedisStreamMessageListener<?>> listeners;
private final RedisMQTemplate redisTemplate;
private final RedissonClient redissonClient;
+ /**
+ * Redisson 閿侀敭锛堝 Bean 娉ㄥ唽娓呯悊浠诲姟鏃跺繀椤诲悇涓嶇浉鍚岋級
+ */
+ private final String cleanupLockKey;
/**
* 姣忓皬鏃舵墽琛屼竴娆℃竻鐞嗕换鍔�
*/
@Scheduled(cron = "0 0 * * * ?")
public void cleanup() {
- RLock lock = redissonClient.getLock(LOCK_KEY);
- // 灏濊瘯鍔犻攣
+ RLock lock = redissonClient.getLock(cleanupLockKey);
if (lock.tryLock()) {
try {
execute();
} catch (Exception ex) {
- log.error("[cleanup][鎵ц寮傚父]", ex);
+ log.error("[cleanup][鎵ц寮傚父][lockKey={}]", cleanupLockKey, ex);
} finally {
- lock.unlock();
+ if (lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
}
+ } else {
+ log.debug("[cleanup][鏈幏鍙栧埌閿侊紝璺宠繃鏈疆][lockKey={}]", cleanupLockKey);
}
}
@@ -59,8 +75,8 @@
StreamOperations<String, Object, Object> ops = redisTemplate.getRedisTemplate().opsForStream();
listeners.forEach(listener -> {
try {
- // 浣跨敤 XTRIM 鍛戒护娓呯悊娑堟伅锛屽彧淇濈暀鏈�杩戠殑 MAX_LEN 鏉℃秷鎭�
- Long trimCount = ops.trim(listener.getStreamKey(), MAX_COUNT, true);
+ // 浣跨敤 XTRIM MAXLEN 绮剧‘瑁佸壀锛坅pproximate=false锛夛紝閬垮厤 ~ 妯″紡涓嬮暱鏈熸槑鏄鹃珮浜庝笂闄�
+ Long trimCount = ops.trim(listener.getStreamKey(), MAX_COUNT, false);
if (trimCount != null && trimCount > 0) {
log.info("[execute][Stream({}) 娓呯悊娑堟伅鏁伴噺({})]", listener.getStreamKey(), trimCount);
}
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
index 2e6875b..bd16132 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
@@ -84,12 +84,6 @@
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot4-starter</artifactId> <!-- 澶氭暟鎹簮 -->
- <exclusions>
- <exclusion>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-undertow</artifactId>
- </exclusion>
- </exclusions>
</dependency>
<dependency>
@@ -105,6 +99,13 @@
<groupId>org.dromara</groupId>
<artifactId>easy-trans-mybatis-plus-extend</artifactId>
</dependency>
+
+ <!-- Test 娴嬭瘯鐩稿叧 -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java
index 460ea78..62a5b08 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/enums/DbTypeEnum.java
@@ -20,51 +20,49 @@
/**
* H2
- *
- * 娉ㄦ剰锛欻2 涓嶆敮鎸� find_in_set 鍑芥暟
*/
- H2(DbType.H2, "H2", ""),
+ H2(DbType.H2, "H2", "POSITION(',' || CAST(#{value} AS VARCHAR) || ',' IN ',' || #{column} || ',') > 0"),
/**
* MySQL
*/
- MY_SQL(DbType.MYSQL, "MySQL", "FIND_IN_SET('#{value}', #{column}) <> 0"),
+ MY_SQL(DbType.MYSQL, "MySQL", "FIND_IN_SET(#{value}, #{column}) <> 0"),
/**
* Oracle
*/
- ORACLE(DbType.ORACLE, "Oracle", "FIND_IN_SET('#{value}', #{column}) <> 0"),
+ ORACLE(DbType.ORACLE, "Oracle", "INSTR(',' || #{column} || ',', ',' || #{value} || ',') > 0"),
/**
* PostgreSQL
*
* 鍗庝负 openGauss 浣跨敤 ProductName 涓� PostgreSQL 鐩稿悓
*/
- POSTGRE_SQL(DbType.POSTGRE_SQL,"PostgreSQL", "POSITION('#{value}' IN #{column}) <> 0"),
+ POSTGRE_SQL(DbType.POSTGRE_SQL, "PostgreSQL", "POSITION(',' || CAST(#{value} AS VARCHAR) || ',' IN ',' || #{column} || ',') > 0"),
/**
* SQL Server
*/
- SQL_SERVER(DbType.SQL_SERVER, "Microsoft SQL Server", "CHARINDEX(',' + #{value} + ',', ',' + #{column} + ',') <> 0"),
+ SQL_SERVER(DbType.SQL_SERVER, "Microsoft SQL Server", "CHARINDEX(',' + CAST(#{value} AS varchar(255)) + ',', ',' + #{column} + ',') > 0"),
/**
* SQL Server 2005
*/
- SQL_SERVER2005(DbType.SQL_SERVER2005, "Microsoft SQL Server 2005", "CHARINDEX(',' + #{value} + ',', ',' + #{column} + ',') <> 0"),
+ SQL_SERVER2005(DbType.SQL_SERVER2005, "Microsoft SQL Server 2005", "CHARINDEX(',' + CAST(#{value} AS varchar(255)) + ',', ',' + #{column} + ',') > 0"),
/**
* 杈炬ⅵ
*/
- DM(DbType.DM, "DM DBMS", "FIND_IN_SET('#{value}', #{column}) <> 0"),
+ DM(DbType.DM, "DM DBMS", "FIND_IN_SET(#{value}, #{column}) <> 0"),
/**
* 浜哄ぇ閲戜粨
*/
- KINGBASE_ES(DbType.KINGBASE_ES, "KingbaseES", "POSITION('#{value}' IN #{column}) <> 0"),
+ KINGBASE_ES(DbType.KINGBASE_ES, "KingbaseES", "POSITION(',' || CAST(#{value} AS VARCHAR) || ',' IN ',' || #{column} || ',') > 0"),
/**
* OceanBase
*/
- OCEAN_BASE(DbType.OCEAN_BASE, "OceanBase", "FIND_IN_SET('#{value}', #{column}) <> 0")
+ OCEAN_BASE(DbType.OCEAN_BASE, "OceanBase", "FIND_IN_SET(#{value}, #{column}) <> 0")
;
@@ -95,7 +93,9 @@
}
public static String getFindInSetTemplate(DbType dbType) {
- return Optional.of(MAP_BY_MP.get(dbType).getFindInSetTemplate())
+ return Optional.ofNullable(MAP_BY_MP.get(dbType))
+ .map(DbTypeEnum::getFindInSetTemplate)
+ .filter(StrUtil::isNotBlank)
.orElseThrow(() -> new IllegalArgumentException("FIND_IN_SET not supported"));
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
index 5ccee20..08bdf19 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
@@ -170,6 +170,17 @@
return CollUtil.getFirst(list);
}
+ /**
+ * 鑾峰彇婊¤冻鏉′欢鐨勬渶鏂颁竴鏉¤褰�
+ * <p>
+ * 鐩殑锛氳В鍐冲苟鍙戝満鏅笅锛屾彃鍏ュ鏉¤褰曞悗锛屼娇鐢� selectOne 浼氭姤閿欑殑闂
+ *
+ * @param queryWrapper 鏌ヨ鏉′欢
+ * @return 鏈�鏂颁竴鏉★紱涓嶅瓨鍦ㄨ繑鍥� null
+ */
+ default T selectLastOne(LambdaQueryWrapper<T> queryWrapper) {
+ return CollUtil.getLast(selectList(queryWrapper));
+ }
default Long selectCount() {
return selectCount(new QueryWrapper<>());
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java
index a728365..b766199 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java
@@ -25,6 +25,13 @@
return this;
}
+ public LambdaQueryWrapperX<T> likeRightIfPresent(SFunction<T, ?> column, String val) {
+ if (StringUtils.hasText(val)) {
+ return (LambdaQueryWrapperX<T>) super.likeRight(column, val);
+ }
+ return this;
+ }
+
public LambdaQueryWrapperX<T> inIfPresent(SFunction<T, ?> column, Collection<?> values) {
if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
return (LambdaQueryWrapperX<T>) super.in(column, values);
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java
index aed2f02..6b0de23 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java
@@ -27,6 +27,13 @@
return this;
}
+ public <S> MPJLambdaWrapperX<T> likeRightIfPresent(SFunction<S, ?> column, String val) {
+ if (StringUtils.hasText(val)) {
+ return (MPJLambdaWrapperX<T>) super.likeRight(column, val);
+ }
+ return this;
+ }
+
public <S> MPJLambdaWrapperX<T> inIfPresent(SFunction<S, ?> column, Collection<?> values) {
if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
return (MPJLambdaWrapperX<T>) super.in(column, values);
@@ -101,7 +108,6 @@
}
return this;
}
-
// ========== 閲嶅啓鐖剁被鏂规硶锛屾柟渚块摼寮忚皟鐢� ==========
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java
index 087b1b8..bff0122 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java
@@ -25,6 +25,13 @@
return this;
}
+ public QueryWrapperX<T> likeRightIfPresent(String column, String val) {
+ if (StringUtils.hasText(val)) {
+ return (QueryWrapperX<T>) super.likeRight(column, val);
+ }
+ return this;
+ }
+
public QueryWrapperX<T> inIfPresent(String column, Collection<?> values) {
if (!CollectionUtils.isEmpty(values)) {
return (QueryWrapperX<T>) super.in(column, values);
@@ -95,13 +102,13 @@
}
public QueryWrapperX<T> betweenIfPresent(String column, Object[] values) {
- if (values!= null && values.length != 0 && values[0] != null && values[1] != null) {
+ if (values != null && values.length != 0 && values[0] != null && values[1] != null) {
return (QueryWrapperX<T>) super.between(column, values[0], values[1]);
}
- if (values!= null && values.length != 0 && values[0] != null) {
+ if (values != null && values.length != 0 && values[0] != null) {
return (QueryWrapperX<T>) ge(column, values[0]);
}
- if (values!= null && values.length != 0 && values[1] != null) {
+ if (values != null && values.length != 0 && values[1] != null) {
return (QueryWrapperX<T>) le(column, values[1]);
}
return this;
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
index 2b4d138..ab4612c 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
@@ -23,6 +23,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.regex.Pattern;
/**
* MyBatis 宸ュ叿绫�
@@ -30,6 +31,12 @@
public class MyBatisUtils {
private static final String MYSQL_ESCAPE_CHARACTER = "`";
+
+ private static final Pattern SAFE_COLUMN_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+)*$");
+
+ private static final String FIND_IN_SET_VALUE_PLACEHOLDER = "#{value}";
+
+ private static final String FIND_IN_SET_COLUMN_PLACEHOLDER = "#{column}";
public static <T> Page<T> buildPage(PageParam pageParam) {
return buildPage(pageParam, null);
@@ -42,8 +49,11 @@
// 鎺掑簭瀛楁
if (CollUtil.isNotEmpty(sortingFields)) {
for (SortingField sortingField : sortingFields) {
- page.addOrder(new OrderItem().setAsc(SortingField.ORDER_ASC.equals(sortingField.getOrder()))
- .setColumn(StrUtil.toUnderlineCase(sortingField.getField())));
+ String columnName = buildSafeOrderColumn(sortingField.getField());
+ if (columnName == null) {
+ continue;
+ }
+ page.addOrder(new OrderItem().setAsc(isAscOrder(sortingField.getOrder())).setColumn(columnName));
}
}
return page;
@@ -57,28 +67,50 @@
if (wrapper instanceof QueryWrapper<T>) {
QueryWrapper<T> query = (QueryWrapper<T>) wrapper;
for (SortingField sortingField : sortingFields) {
- query.orderBy(true,
- SortingField.ORDER_ASC.equals(sortingField.getOrder()),
- StrUtil.toUnderlineCase(sortingField.getField()));
+ String columnName = buildSafeOrderColumn(sortingField.getField());
+ if (columnName == null) {
+ continue;
+ }
+ query.orderBy(true, isAscOrder(sortingField.getOrder()), columnName);
}
} else if (wrapper instanceof LambdaQueryWrapper<T>) {
// LambdaQueryWrapper 涓嶇洿鎺ユ敮鎸佸瓧绗︿覆瀛楁鎺掑簭锛屼娇鐢� last 鏂规硶鎷兼帴 ORDER BY
LambdaQueryWrapper<T> lambdaQuery = (LambdaQueryWrapper<T>) wrapper;
StringBuilder orderBy = new StringBuilder();
for (SortingField sortingField : sortingFields) {
+ String columnName = buildSafeOrderColumn(sortingField.getField());
+ if (columnName == null) {
+ continue;
+ }
if (StrUtil.isNotEmpty(orderBy)) {
orderBy.append(", ");
}
- orderBy.append(StrUtil.toUnderlineCase(sortingField.getField()))
- .append(" ")
- .append(SortingField.ORDER_ASC.equals(sortingField.getOrder()) ? "ASC" : "DESC");
+ orderBy.append(columnName).append(" ").append(getOrderDirection(sortingField.getOrder()));
}
- lambdaQuery.last("ORDER BY " + orderBy);
+ if (StrUtil.isNotEmpty(orderBy)) {
+ lambdaQuery.last("ORDER BY " + orderBy);
+ }
// 鍙﹀涓�濊矾锛歨ttps://blog.csdn.net/m0_59084856/article/details/138450913
} else {
throw new IllegalArgumentException("Unsupported wrapper type: " + wrapper.getClass().getName());
}
+ }
+
+ public static boolean isAscOrder(String order) {
+ return SortingField.ORDER_ASC.equals(order);
+ }
+
+ public static String getOrderDirection(String order) {
+ return isAscOrder(order) ? "ASC" : "DESC";
+ }
+
+ private static String buildSafeOrderColumn(String field) {
+ String columnName = StrUtil.toUnderlineCase(field);
+ if (StrUtil.isEmpty(columnName) || !SAFE_COLUMN_NAME_PATTERN.matcher(columnName).matches()) {
+ return null;
+ }
+ return columnName;
}
/**
@@ -129,15 +161,43 @@
/**
* 璺ㄦ暟鎹簱鐨� find_in_set 瀹炵幇
*
- * @param column 瀛楁鍚嶇О
- * @param value 鏌ヨ鍊�(涓嶅甫鍗曞紩鍙�)
+ * @param columnName 瀛楁鍚嶇О
* @return sql
*/
- public static String findInSet(String column, Object value) {
+ public static String findInSet(String columnName) {
+ return findInSet(columnName, 0);
+ }
+
+ /**
+ * 璺ㄦ暟鎹簱鐨� find_in_set 瀹炵幇锛岄�傜敤浜庡悓涓�涓� apply 璇彞涓湁澶氫釜鍙傛暟鐨勫満鏅�
+ *
+ * @param columnName 瀛楁鍚嶇О
+ * @param paramIndex apply 鍙傛暟搴忓彿
+ * @return sql
+ */
+ public static String findInSetWithParamIndex(String columnName, int paramIndex) {
+ return findInSet(columnName, paramIndex);
+ }
+
+ private static String findInSet(String columnName, int paramIndex) {
DbType dbType = JdbcUtils.getDbType();
+ return findInSet(dbType, columnName, paramIndex);
+ }
+
+ static String findInSet(DbType dbType, String columnName, int paramIndex) {
+ if (!isSafeColumnName(columnName)) {
+ throw new IllegalArgumentException("Invalid column name: " + columnName);
+ }
+ if (paramIndex < 0) {
+ throw new IllegalArgumentException("Invalid param index: " + paramIndex);
+ }
return DbTypeEnum.getFindInSetTemplate(dbType)
- .replace("#{column}", column)
- .replace("#{value}", StrUtil.toString(value));
+ .replace(FIND_IN_SET_COLUMN_PLACEHOLDER, columnName)
+ .replace(FIND_IN_SET_VALUE_PLACEHOLDER, "{" + paramIndex + "}");
+ }
+
+ private static boolean isSafeColumnName(String columnName) {
+ return StrUtil.isNotEmpty(columnName) && SAFE_COLUMN_NAME_PATTERN.matcher(columnName).matches();
}
/**
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java
index b3f1384..9555ac9 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/translate/config/YudaoTranslateAutoConfiguration.java
@@ -11,7 +11,7 @@
@Bean
@ConditionalOnBean(TransService.class)
- @SuppressWarnings({"InstantiationOfUtilityClass", "SpringJavaInjectionPointsAutowiringInspection"})
+ @SuppressWarnings("InstantiationOfUtilityClass")
public TranslateUtils translateUtils(TransService transService) {
TranslateUtils.init(transService);
return new TranslateUtils();
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtilsTest.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtilsTest.java
new file mode 100644
index 0000000..abe8891
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtilsTest.java
@@ -0,0 +1,173 @@
+package cn.iocoder.yudao.framework.mybatis.core.util;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.SortingField;
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * {@link MyBatisUtils} 鐨勫崟鍏冩祴璇�
+ */
+public class MyBatisUtilsTest {
+
+ @Test
+ public void testBuildPage_sortingFields() {
+ // 鍑嗗鍙傛暟
+ PageParam pageParam = new PageParam();
+ pageParam.setPageNo(2);
+ pageParam.setPageSize(20);
+ List<SortingField> sortingFields = Arrays.asList(
+ new SortingField("userName", SortingField.ORDER_ASC),
+ new SortingField("u.id", SortingField.ORDER_DESC),
+ new SortingField("name desc", SortingField.ORDER_DESC));
+
+ // 璋冪敤
+ Page<Object> page = MyBatisUtils.buildPage(pageParam, sortingFields);
+
+ // 鏂█
+ assertEquals(2, page.getCurrent());
+ assertEquals(20, page.getSize());
+ assertEquals(2, page.orders().size());
+ assertOrderItem(page.orders().get(0), "user_name", true);
+ assertOrderItem(page.orders().get(1), "u.id", false);
+ }
+
+ @Test
+ public void testAddOrder_queryWrapper() {
+ // 鍑嗗鍙傛暟
+ QueryWrapper<Object> query = new QueryWrapper<>();
+ List<SortingField> sortingFields = Arrays.asList(
+ new SortingField("userName", SortingField.ORDER_ASC),
+ new SortingField("u.id", SortingField.ORDER_DESC),
+ new SortingField("name;drop", SortingField.ORDER_ASC));
+
+ // 璋冪敤
+ MyBatisUtils.addOrder(query, sortingFields);
+
+ // 鏂█
+ assertEquals(" ORDER BY user_name ASC,u.id DESC", query.getSqlSegment());
+ }
+
+ @Test
+ public void testAddOrder_lambdaQueryWrapper() {
+ // 鍑嗗鍙傛暟
+ LambdaQueryWrapper<Object> query = new LambdaQueryWrapper<>();
+ List<SortingField> sortingFields = Arrays.asList(
+ new SortingField("userName", SortingField.ORDER_ASC),
+ new SortingField("u.id", SortingField.ORDER_DESC),
+ new SortingField("name`", SortingField.ORDER_ASC));
+
+ // 璋冪敤
+ MyBatisUtils.addOrder(query, sortingFields);
+
+ // 鏂█
+ assertEquals(" ORDER BY user_name ASC, u.id DESC", query.getSqlSegment());
+ }
+
+ @Test
+ public void testAddOrder_lambdaQueryWrapper_invalidSortingFields() {
+ // 鍑嗗鍙傛暟
+ LambdaQueryWrapper<Object> query = new LambdaQueryWrapper<>();
+ List<SortingField> sortingFields = Arrays.asList(
+ new SortingField("name desc", SortingField.ORDER_ASC),
+ new SortingField("name;drop", SortingField.ORDER_DESC));
+
+ // 璋冪敤
+ MyBatisUtils.addOrder(query, sortingFields);
+
+ // 鏂█
+ assertEquals("", query.getSqlSegment());
+ }
+
+ @Test
+ public void testOrderDirection() {
+ assertTrue(MyBatisUtils.isAscOrder(SortingField.ORDER_ASC));
+ assertFalse(MyBatisUtils.isAscOrder(SortingField.ORDER_DESC));
+ assertEquals("ASC", MyBatisUtils.getOrderDirection(SortingField.ORDER_ASC));
+ assertEquals("DESC", MyBatisUtils.getOrderDirection(SortingField.ORDER_DESC));
+ assertEquals("DESC", MyBatisUtils.getOrderDirection(null));
+ }
+
+ @Test
+ public void testFindInSet() {
+ assertEquals("FIND_IN_SET({0}, websites) <> 0",
+ MyBatisUtils.findInSet(DbType.MYSQL, "websites", 0));
+ assertEquals("POSITION(',' || CAST({0} AS VARCHAR) || ',' IN ',' || websites || ',') > 0",
+ MyBatisUtils.findInSet(DbType.H2, "websites", 0));
+ assertEquals("INSTR(',' || t.websites || ',', ',' || {0} || ',') > 0",
+ MyBatisUtils.findInSet(DbType.ORACLE, "t.websites", 0));
+ assertEquals("POSITION(',' || CAST({1} AS VARCHAR) || ',' IN ',' || websites || ',') > 0",
+ MyBatisUtils.findInSet(DbType.POSTGRE_SQL, "websites", 1));
+ assertEquals("CHARINDEX(',' + CAST({2} AS varchar(255)) + ',', ',' + websites + ',') > 0",
+ MyBatisUtils.findInSet(DbType.SQL_SERVER, "websites", 2));
+ }
+
+ @Test
+ public void testFindInSet_invalidColumnName() {
+ assertThrows(IllegalArgumentException.class,
+ () -> MyBatisUtils.findInSet(DbType.MYSQL, "websites;drop table system_tenant", 0));
+ assertThrows(IllegalArgumentException.class,
+ () -> MyBatisUtils.findInSet(DbType.MYSQL, "FIND_IN_SET(value, websites)", 0));
+ }
+
+ @Test
+ public void testFindInSet_invalidParamIndex() {
+ assertThrows(IllegalArgumentException.class,
+ () -> MyBatisUtils.findInSet(DbType.MYSQL, "websites", -1));
+ }
+
+ @Test
+ public void testFindInSet_applyBindsValue() {
+ // 鍑嗗鍙傛暟
+ QueryWrapper<Object> query = new QueryWrapper<>();
+ String value = "test' OR 1 = 1";
+
+ // 璋冪敤
+ query.apply(MyBatisUtils.findInSet(DbType.MYSQL, "to_mails", 0), value);
+
+ // 鏂█锛歋QL 鐗囨閲屽彧鏈� MyBatis Plus 鍙傛暟鍗犱綅锛岀敤鎴疯緭鍏ヤ笉浼氳鐩存帴鎷兼帴杩涘幓
+ assertEquals("(FIND_IN_SET(#{ew.paramNameValuePairs.MPGENVAL1}, to_mails) <> 0)",
+ query.getSqlSegment());
+ assertFalse(query.getSqlSegment().contains(value));
+ assertEquals(value, query.getParamNameValuePairs().get("MPGENVAL1"));
+ }
+
+ @Test
+ public void testFindInSet_applyBindsMultipleValues() {
+ // 鍑嗗鍙傛暟
+ QueryWrapper<Object> query = new QueryWrapper<>();
+ String value1 = "1' OR 1 = 1";
+ String value2 = "2' OR 1 = 1";
+
+ // 璋冪敤
+ query.apply(MyBatisUtils.findInSet(DbType.MYSQL, "tag_ids", 0)
+ + " OR " + MyBatisUtils.findInSet(DbType.MYSQL, "tag_ids", 1), value1, value2);
+
+ // 鏂█锛氬涓弬鏁伴兘鐢� MyBatis Plus 鐢熸垚鍗犱綅绗︼紝涓嶆嫾鎺ョ敤鎴疯緭鍏�
+ assertEquals("(FIND_IN_SET(#{ew.paramNameValuePairs.MPGENVAL1}, tag_ids) <> 0"
+ + " OR FIND_IN_SET(#{ew.paramNameValuePairs.MPGENVAL2}, tag_ids) <> 0)",
+ query.getSqlSegment());
+ assertFalse(query.getSqlSegment().contains(value1));
+ assertFalse(query.getSqlSegment().contains(value2));
+ assertEquals(value1, query.getParamNameValuePairs().get("MPGENVAL1"));
+ assertEquals(value2, query.getParamNameValuePairs().get("MPGENVAL2"));
+ }
+
+ private void assertOrderItem(OrderItem orderItem, String column, boolean asc) {
+ assertEquals(column, orderItem.getColumn());
+ assertEquals(asc, orderItem.isAsc());
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
index 636f821..cc94094 100644
--- a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoCacheAutoConfiguration.java
@@ -75,8 +75,12 @@
RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory,
BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize()));
- // 鍒涘缓 TenantRedisCacheManager 瀵硅薄
- return new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration);
+ // 鍒涘缓 TimeoutRedisCacheManager 瀵硅薄
+ TimeoutRedisCacheManager cacheManager = new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration);
+ // 寮�鍚簨鍔℃劅鐭ワ細@Transactional 鏂规硶鍐呯殑 @CacheEvict / @CachePut 鑷姩寤惰繜鍒� afterCommit锛�
+ // 閬垮厤浜嬪姟鏈彁浜ゅ氨娓呯紦瀛樿骞跺彂璇荤┛鍐欒剰鍊硷紱鏃犱簨鍔℃椂绔嬪嵆鐢熸晥锛岃涓轰笉鍙�
+ cacheManager.setTransactionAware(true);
+ return cacheManager;
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java
index aa7d1b0..87d0b72 100644
--- a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java
+++ b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java
@@ -1,22 +1,11 @@
package cn.iocoder.yudao.framework.redis.config;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import cn.hutool.core.util.StrUtil;
import org.redisson.spring.starter.RedissonAutoConfigurationV4;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
-
-import java.nio.charset.StandardCharsets;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.TreeSet;
-
-import tools.jackson.core.type.TypeReference;
-import tools.jackson.databind.ObjectMapper;
/**
* Redis 閰嶇疆绫�
@@ -43,103 +32,12 @@
return template;
}
+ @SuppressWarnings("UnnecessaryLocalVariable")
public static RedisSerializer<?> buildRedisSerializer() {
- // 浣跨敤鑷畾涔夊簭鍒楀寲鍣紝瑙e喅 Set/List 绛� Collection 鍙嶅簭鍒楀寲绫诲瀷闂
- return new TypedJsonRedisSerializer();
- }
-
- /**
- * 鑷畾涔� Redis 搴忓垪鍖栧櫒锛岃В鍐� Set/List 绛� Collection 鍙嶅簭鍒楀寲绫诲瀷闂
- */
- private static class TypedJsonRedisSerializer implements RedisSerializer<Object> {
-
- private static final String JAVA_TYPE_PREFIX = "@class:";
- private static final ObjectMapper OBJECT_MAPPER = JsonUtils.getObjectMapper();
- private static final TypeReference<HashSet<Object>> HASH_SET_TYPE = new TypeReference<>() {};
- private static final TypeReference<LinkedHashSet<Object>> LINKED_HASH_SET_TYPE = new TypeReference<>() {};
- private static final TypeReference<TreeSet<Object>> TREE_SET_TYPE = new TypeReference<>() {};
-
- @Override
- public byte[] serialize(Object value) {
- if (value == null) {
- return new byte[0];
- }
- // 灏嗙被鍨嬩俊鎭笌 JSON 涓�璧峰瓨鍌�
- String json = JsonUtils.toJsonString(value);
- String typePrefix = JAVA_TYPE_PREFIX + value.getClass().getName() + ":";
- return (typePrefix + json).getBytes(StandardCharsets.UTF_8);
- }
-
- @Override
- public Object deserialize(byte[] bytes) {
- if (bytes == null || bytes.length == 0) {
- return null;
- }
- String content = new String(bytes, StandardCharsets.UTF_8);
- if (!content.startsWith(JAVA_TYPE_PREFIX)) {
- // 鍏煎鏃ф暟鎹細娌℃湁绫诲瀷淇℃伅鐨勬儏鍐�
- // 妫�娴嬫槸鍚︿负 JSON 鏁扮粍锛岃嫢鏄垯杞崲涓� HashSet
- return deserializeLegacyData(content);
- }
- // 鎻愬彇绫诲瀷淇℃伅鍜� JSON
- int colonIndex = content.indexOf(':', JAVA_TYPE_PREFIX.length());
- if (colonIndex == -1) {
- return deserializeLegacyData(content);
- }
- String className = content.substring(JAVA_TYPE_PREFIX.length(), colonIndex);
- String json = content.substring(colonIndex + 1);
- try {
- Class<?> clazz = Class.forName(className);
- // 鐗规畩澶勭悊 Set 绫诲瀷锛屽洜涓� Jackson 榛樿浼氬皢 JSON 鏁扮粍鍙嶅簭鍒楀寲涓� List
- return deserializeWithTypeHint(json, clazz);
- } catch (ClassNotFoundException e) {
- // 绫诲瀷涓嶅瓨鍦ㄦ椂锛屽皾璇曞吋瀹硅В鏋�
- return deserializeLegacyData(json);
- } catch (Exception e) {
- // 瑙f瀽澶辫触鏃讹紝灏濊瘯鍏煎瑙f瀽
- return deserializeLegacyData(json);
- }
- }
-
- /**
- * 鍏煎鏃ф暟鎹紙娌℃湁绫诲瀷鍓嶇紑锛夌殑瑙f瀽
- * 瀵逛簬 JSON 鏁扮粍锛岄粯璁よ浆鎹负 HashSet
- */
- private Object deserializeLegacyData(String content) {
- if (StrUtil.isEmpty(content)) {
- return null;
- }
- content = content.trim();
- // 鍒ゆ柇鏄惁涓� JSON 鏁扮粍
- if (content.startsWith("[") && content.endsWith("]")) {
- try {
- // 鏁扮粍绫诲瀷榛樿杞负 HashSet
- return OBJECT_MAPPER.readValue(content, HASH_SET_TYPE);
- } catch (Exception e) {
- return JsonUtils.parseObject(content, Object.class);
- }
- }
- // 鍏朵粬绫诲瀷鐩存帴瑙f瀽
- return JsonUtils.parseObject(content, Object.class);
- }
-
- private Object deserializeWithTypeHint(String json, Class<?> clazz) {
- // 澶勭悊 Set 鎺ュ彛鐨勫疄鐜扮被
- if (HashSet.class.isAssignableFrom(clazz) ||
- "java.util.Collections$UnmodifiableSet".equals(clazz.getName()) ||
- "java.util.Collections$SingletonSet".equals(clazz.getName()) ||
- Set.class.isAssignableFrom(clazz)) {
- return OBJECT_MAPPER.readValue(json, HASH_SET_TYPE);
- }
- if (LinkedHashSet.class.isAssignableFrom(clazz)) {
- return OBJECT_MAPPER.readValue(json, LINKED_HASH_SET_TYPE);
- }
- if (TreeSet.class.isAssignableFrom(clazz)) {
- return OBJECT_MAPPER.readValue(json, TREE_SET_TYPE);
- }
- // 浣跨敤 Jackson 鐨� readValue 鎸囧畾绫诲瀷锛岀‘淇� POJO 姝g‘鍙嶅簭鍒楀寲
- return OBJECT_MAPPER.readValue(json, clazz);
- }
+ RedisSerializer<Object> json = RedisSerializer.json();
+ // 鐗规畩锛歴pring boot 4.x 鏃犻渶瑙e喅 LocalDateTime 鐨勫簭鍒楀寲
+ // 鍘熷洜锛歋pring Data Redis 4 浣跨敤 Jackson 3锛孯edisSerializer.json() 宸叉敮鎸� Java Time 绫诲瀷
+ return json;
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
index 26b8624..f20d4f6 100644
--- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
@@ -29,11 +29,14 @@
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import org.springframework.web.util.pattern.PathPattern;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
/**
* 鑷畾涔夌殑 Spring Security 閰嶇疆閫傞厤鍣ㄥ疄鐜�
@@ -153,6 +156,7 @@
return webProperties.getAppApi().getPrefix() + url;
}
+ @SuppressWarnings("removal")
private Multimap<HttpMethod, String> getPermitAllUrlsFromAnnotations() {
Multimap<HttpMethod, String> result = HashMultimap.create();
// 鑾峰緱鎺ュ彛瀵瑰簲鐨� HandlerMethod 闆嗗悎
@@ -167,7 +171,12 @@
continue;
}
Set<String> urls = new HashSet<>();
- urls.addAll(entry.getKey().getPatternValues());
+ if (entry.getKey().getPatternsCondition() != null) {
+ urls.addAll(entry.getKey().getPatternsCondition().getPatterns());
+ }
+ if (entry.getKey().getPathPatternsCondition() != null) {
+ urls.addAll(convertList(entry.getKey().getPathPatternsCondition().getPatterns(), PathPattern::getPatternString));
+ }
if (urls.isEmpty()) {
continue;
}
diff --git a/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java b/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java
index 120f529..88ceee6 100644
--- a/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java
+++ b/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/handler/JsonWebSocketMessageHandler.java
@@ -76,7 +76,7 @@
Long tenantId = WebSocketFrameworkUtils.getTenantId(session);
TenantUtils.execute(tenantId, () -> messageListener.onMessage(session, messageObj));
} catch (Throwable ex) {
- log.error("[handleTextMessage][session({}) message({}) 澶勭悊寮傚父]", session.getId(), message.getPayload());
+ log.error("[handleTextMessage][session({}) message({}) 澶勭悊寮傚父]", session.getId(), message.getPayload(), ex);
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java b/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java
index 3a31825..f3392f6 100644
--- a/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java
+++ b/yudao-framework/yudao-spring-boot-starter-websocket/src/main/java/cn/iocoder/yudao/framework/websocket/core/security/LoginUserHandshakeInterceptor.java
@@ -27,9 +27,10 @@
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
- if (loginUser != null) {
- WebSocketFrameworkUtils.setLoginUser(loginUser, attributes);
+ if (loginUser == null) {
+ return false;
}
+ WebSocketFrameworkUtils.setLoginUser(loginUser, attributes);
return true;
}
diff --git a/yudao-module-ai/pom.xml b/yudao-module-ai/pom.xml
index 04b06d1..2eac23a 100644
--- a/yudao-module-ai/pom.xml
+++ b/yudao-module-ai/pom.xml
@@ -19,10 +19,9 @@
鍥藉锛歄penAI銆丱llama銆丮idjourney銆丼tableDiffusion銆丼uno
</description>
<properties>
- <spring-ai.version>2.0.0-M7</spring-ai.version>
- <spring-ai-legacy-model.version>2.0.0-M4</spring-ai-legacy-model.version>
+ <spring-ai.version>2.0.0</spring-ai.version>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud.ai/spring-ai-alibaba -->
- <alibaba-ai.version>1.1.2.3</alibaba-ai.version>
+ <alibaba-ai.version>2.0.0-M1.1</alibaba-ai.version>
<tinyflow.version>1.2.6</tinyflow.version>
</properties>
@@ -89,17 +88,17 @@
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
- <artifactId>spring-ai-starter-model-azure-openai</artifactId>
- <version>${spring-ai-legacy-model.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-anthropic</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
+ <version>${spring-ai.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.ai</groupId>
+ <artifactId>spring-ai-starter-model-google-genai</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
@@ -113,35 +112,10 @@
<version>${spring-ai.version}</version>
</dependency>
<dependency>
- <!-- 鏅鸿氨 GLM -->
- <groupId>org.springframework.ai</groupId>
- <artifactId>spring-ai-starter-model-zhipuai</artifactId>
- <version>${spring-ai-legacy-model.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.ai</groupId>
- <artifactId>spring-ai-starter-model-minimax</artifactId>
- <version>${spring-ai.version}</version>
- </dependency>
-
- <dependency>
<!-- 閫氫箟鍗冮棶 -->
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>${alibaba-ai.version}</version>
- </dependency>
-
- <dependency>
- <!-- 鏂囧績涓�瑷� -->
- <groupId>org.springaicommunity</groupId>
- <artifactId>qianfan-core</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <!-- 鏈堜箣鏆楅潰 -->
- <groupId>org.springaicommunity</groupId>
- <artifactId>moonshot-core</artifactId>
- <version>1.0.0</version>
</dependency>
<!-- 鍚戦噺瀛樺偍锛歨ttps://db-engines.com/en/ranking/vector+dbms -->
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java
index 8a8a388..4658a08 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/ErrorCodeConstants.java
@@ -12,6 +12,7 @@
// ========== API 瀵嗛挜 1-040-000-000 ==========
ErrorCode API_KEY_NOT_EXISTS = new ErrorCode(1_040_000_000, "API 瀵嗛挜涓嶅瓨鍦�");
ErrorCode API_KEY_DISABLE = new ErrorCode(1_040_000_001, "API 瀵嗛挜宸茬鐢紒");
+ ErrorCode API_CONFIG_PLACEHOLDER_NOT_RESOLVED = new ErrorCode(1_040_000_002, "AI 閰嶇疆({})鏃犳硶瑙f瀽锛岃妫�鏌ョ幆澧冨彉閲忔垨閰嶇疆椤�");
// ========== API 妯″瀷 1-040-001-000 ==========
ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1_040_001_000, "妯″瀷涓嶅瓨鍦�!");
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
index bf15ec1..3c09144 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
@@ -28,6 +28,7 @@
MINI_MAX("MiniMax", "MiniMax"), // 绋�瀹囩鎶�
MOONSHOT("Moonshot", "鏈堜箣鏆楅潰"), // KIMI
BAI_CHUAN("BaiChuan", "鐧惧窛鏅鸿兘"), // 鐧惧窛鏅鸿兘
+ STEP_FUN("StepFun", "闃惰穬鏄熻景"), // 闃惰穬鏄熻景
// ========== 鍥藉骞冲彴 ==========
@@ -40,7 +41,7 @@
STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI
MIDJOURNEY("Midjourney", "Midjourney"), // Midjourney
SUNO("Suno", "Suno"), // Suno AI
- GROK("Grok","Grok"), // Grok
+ GROK("Grok", "Grok"), // Grok
;
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
index 559da13..17c3c42 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
@@ -6,29 +6,42 @@
import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactoryImpl;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.grok.GrokChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.minimax.MiniMaxChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.moonshot.MoonshotChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.stepfun.StepFunChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatModel;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.yiyan.YiYanChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.zhipu.ZhiPuChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.AiWebSearchClient;
import cn.iocoder.yudao.module.ai.framework.ai.core.webserch.bocha.AiBoChaWebSearchClient;
import cn.iocoder.yudao.module.ai.tool.method.PersonService;
+import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
+import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
+import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
+import com.alibaba.cloud.ai.dashscope.embedding.text.DashScopeEmbeddingModel;
+import com.alibaba.cloud.ai.dashscope.embedding.text.DashScopeEmbeddingOptions;
+import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
+import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
import io.micrometer.observation.ObservationRegistry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
import org.springframework.ai.deepseek.api.DeepSeekApi;
+import org.springframework.ai.document.MetadataMode;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
+import org.springframework.ai.retry.RetryUtils;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
import org.springframework.ai.tokenizer.TokenCountEstimator;
@@ -40,11 +53,11 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
-import java.util.Optional;
/**
* 鑺嬮亾 AI 鑷姩閰嶇疆
@@ -75,30 +88,70 @@
// ========== 鍚勭 AI Client 鍒涘缓 ==========
@Bean
- @ConditionalOnProperty(value = "yudao.ai.gemini.enable", havingValue = "true")
- public GeminiChatModel geminiChatModel(YudaoAiProperties yudaoAiProperties) {
- YudaoAiProperties.Gemini properties = yudaoAiProperties.getGemini();
- return buildGeminiChatClient(properties);
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(value = "spring.ai.dashscope.api-key")
+ public DashScopeChatModel dashScopeChatModel(@Value("${spring.ai.dashscope.api-key}") String apiKey,
+ ToolCallingManager toolCallingManager,
+ ObservationRegistry observationRegistry) {
+ return buildTongYiChatModel(apiKey, toolCallingManager, observationRegistry);
}
- public GeminiChatModel buildGeminiChatClient(YudaoAiProperties.Gemini properties) {
- if (StrUtil.isEmpty(properties.getModel())) {
- properties.setModel(GeminiChatModel.MODEL_DEFAULT);
- }
- OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
- .baseUrl(GeminiChatModel.BASE_URL)
- .apiKey(properties.getApiKey())
- .build())
- .options(OpenAiChatOptions.builder()
- .model(properties.getModel())
- .temperature(properties.getTemperature())
- .maxTokens(properties.getMaxTokens())
- .topP(properties.getTopP())
- .build())
- .toolCallingManager(getToolCallingManager())
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(value = "spring.ai.dashscope.api-key")
+ public DashScopeImageModel dashScopeImageModel(@Value("${spring.ai.dashscope.api-key}") String apiKey,
+ ObservationRegistry observationRegistry) {
+ return buildTongYiImagesModel(apiKey, observationRegistry);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(value = "spring.ai.dashscope.api-key")
+ public DashScopeEmbeddingModel dashScopeEmbeddingModel(@Value("${spring.ai.dashscope.api-key}") String apiKey,
+ ObservationRegistry observationRegistry) {
+ return buildTongYiEmbeddingModel(apiKey, null, observationRegistry);
+ }
+
+ public static DashScopeChatModel buildTongYiChatModel(String apiKey) {
+ return buildTongYiChatModel(apiKey, getToolCallingManager(), getObservationRegistry());
+ }
+
+ private static DashScopeChatModel buildTongYiChatModel(String apiKey, ToolCallingManager toolCallingManager,
+ ObservationRegistry observationRegistry) {
+ DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(apiKey).build();
+ DashScopeChatOptions options = DashScopeChatOptions.builder()
+ .model(DashScopeApi.DEFAULT_CHAT_MODEL)
+ .temperature(0.7)
.build();
- return new GeminiChatModel(openAiChatModel);
+ return new DashScopeChatModel(dashScopeApi, options, toolCallingManager, RetryUtils.DEFAULT_RETRY_TEMPLATE,
+ observationRegistry);
+ }
+
+ public static DashScopeImageModel buildTongYiImagesModel(String apiKey) {
+ return buildTongYiImagesModel(apiKey, getObservationRegistry());
+ }
+
+ private static DashScopeImageModel buildTongYiImagesModel(String apiKey, ObservationRegistry observationRegistry) {
+ DashScopeImageApi dashScopeImageApi = DashScopeImageApi.builder().apiKey(apiKey).build();
+ DashScopeImageOptions options = DashScopeImageOptions.builder()
+ .model(DashScopeImageApi.DEFAULT_IMAGE_MODEL)
+ .build();
+ return new DashScopeImageModel(dashScopeImageApi, options, RetryUtils.DEFAULT_RETRY_TEMPLATE,
+ observationRegistry);
+ }
+
+ public static DashScopeEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model) {
+ return buildTongYiEmbeddingModel(apiKey, model, getObservationRegistry());
+ }
+
+ private static DashScopeEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model,
+ ObservationRegistry observationRegistry) {
+ DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(apiKey).build();
+ DashScopeEmbeddingOptions options = DashScopeEmbeddingOptions.builder()
+ .model(StrUtil.blankToDefault(model, DashScopeApi.DEFAULT_EMBEDDING_MODEL))
+ .build();
+ return new DashScopeEmbeddingModel(dashScopeApi, MetadataMode.EMBED, options, RetryUtils.DEFAULT_RETRY_TEMPLATE,
+ observationRegistry);
}
@Bean
@@ -112,18 +165,18 @@
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(DouBaoChatModel.MODEL_DEFAULT);
}
- OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
+ DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
.baseUrl(DouBaoChatModel.BASE_URL)
+ .completionsPath(DouBaoChatModel.COMPLETE_PATH)
.apiKey(properties.getApiKey())
.build())
- .options(OpenAiChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
return new DouBaoChatModel(openAiChatModel);
}
@@ -144,13 +197,12 @@
.baseUrl(SiliconFlowApiConstants.DEFAULT_BASE_URL)
.apiKey(properties.getApiKey())
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
return new SiliconFlowChatModel(openAiChatModel);
}
@@ -166,11 +218,8 @@
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(HunYuanChatModel.MODEL_DEFAULT);
}
- // 鐗规畩锛氱敱浜庢贩鍏冨ぇ妯″瀷涓嶆彁渚� deepseek锛岃�屾槸閫氳繃鐭ヨ瘑寮曟搸锛屾墍浠ラ渶瑕佸尯鍒嗕笅 URL
if (StrUtil.isEmpty(properties.getBaseUrl())) {
- properties.setBaseUrl(
- StrUtil.startWithIgnoreCase(properties.getModel(), "deepseek") ? HunYuanChatModel.DEEP_SEEK_BASE_URL
- : HunYuanChatModel.BASE_URL);
+ properties.setBaseUrl(HunYuanChatModel.BASE_URL);
}
// 鍒涘缓 DeepSeekChatModel銆丠unYuanChatModel 瀵硅薄
DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
@@ -179,13 +228,12 @@
.completionsPath(HunYuanChatModel.COMPLETE_PATH)
.apiKey(properties.getApiKey())
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
return new HunYuanChatModel(openAiChatModel);
}
@@ -201,24 +249,15 @@
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(XingHuoChatModel.MODEL_DEFAULT);
}
- OpenAIOkHttpClient.Builder builder = OpenAIOkHttpClient.builder()
- .baseUrl(XingHuoChatModel.BASE_URL_V1)
- .apiKey(properties.getAppKey() + ":" + properties.getSecretKey());
- if ("x1".equals(properties.getModel())) {
- builder.baseUrl(XingHuoChatModel.BASE_URL_V2);
- }
- OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiClient(builder.build())
- .options(OpenAiChatOptions.builder()
+ return XingHuoChatModel.builder()
+ .apiKey(properties.getApiKey())
+ .options(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- // TODO @鑺嬭壙锛氭槦鐏殑 function call 鏈� bug锛屼細鎶� ToolResponseMessage must have an id 閿欒锛侊紒锛�
- .toolCallingManager(getToolCallingManager())
.build();
- return new XingHuoChatModel(openAiChatModel);
}
@Bean
@@ -232,20 +271,135 @@
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(BaiChuanChatModel.MODEL_DEFAULT);
}
- OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
+ DeepSeekChatModel deepSeekChatModel = DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
.baseUrl(BaiChuanChatModel.BASE_URL)
.apiKey(properties.getApiKey())
+ .completionsPath(BaiChuanChatModel.COMPLETE_PATH)
.build())
- .options(OpenAiChatOptions.builder()
+ .options(DeepSeekChatOptions.builder()
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
- return new BaiChuanChatModel(openAiChatModel);
+ return new BaiChuanChatModel(deepSeekChatModel);
+ }
+
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.yiyan.enable", havingValue = "true")
+ public YiYanChatModel yiYanChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.YiYan properties = yudaoAiProperties.getYiyan();
+ return buildYiYanChatClient(properties);
+ }
+
+ public YiYanChatModel buildYiYanChatClient(YudaoAiProperties.YiYan properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(YiYanChatModel.MODEL_DEFAULT);
+ }
+ return new YiYanChatModel(buildDeepSeekCompatibleChatModel(
+ StrUtil.blankToDefault(properties.getBaseUrl(), YiYanChatModel.BASE_URL),
+ null, properties.getApiKey(), properties.getModel(), properties.getTemperature(),
+ properties.getMaxTokens(), properties.getTopP()));
+ }
+
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.zhipu.enable", havingValue = "true")
+ public ZhiPuChatModel zhiPuChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.ZhiPu properties = yudaoAiProperties.getZhipu();
+ return buildZhiPuChatClient(properties);
+ }
+
+ public ZhiPuChatModel buildZhiPuChatClient(YudaoAiProperties.ZhiPu properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(ZhiPuChatModel.MODEL_DEFAULT);
+ }
+ DeepSeekChatModel deepSeekChatModel = DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(StrUtil.blankToDefault(properties.getBaseUrl(), ZhiPuChatModel.BASE_URL))
+ .apiKey(properties.getApiKey())
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(properties.getModel())
+ .temperature(properties.getTemperature())
+ .maxTokens(properties.getMaxTokens())
+ .topP(properties.getTopP())
+ .build())
+ .build();
+ return new ZhiPuChatModel(deepSeekChatModel);
+ }
+
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.minimax.enable", havingValue = "true")
+ public MiniMaxChatModel miniMaxChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.MiniMax properties = yudaoAiProperties.getMinimax();
+ return buildMiniMaxChatClient(properties);
+ }
+
+ public MiniMaxChatModel buildMiniMaxChatClient(YudaoAiProperties.MiniMax properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(MiniMaxChatModel.MODEL_DEFAULT);
+ }
+ return new MiniMaxChatModel(buildDeepSeekCompatibleChatModel(
+ StrUtil.blankToDefault(properties.getBaseUrl(), MiniMaxChatModel.BASE_URL),
+ null, properties.getApiKey(), properties.getModel(), properties.getTemperature(),
+ properties.getMaxTokens(), properties.getTopP()));
+ }
+
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.moonshot.enable", havingValue = "true")
+ public MoonshotChatModel moonshotChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.Moonshot properties = yudaoAiProperties.getMoonshot();
+ return buildMoonshotChatClient(properties);
+ }
+
+ public MoonshotChatModel buildMoonshotChatClient(YudaoAiProperties.Moonshot properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(MoonshotChatModel.MODEL_DEFAULT);
+ }
+ return new MoonshotChatModel(buildDeepSeekCompatibleChatModel(
+ StrUtil.blankToDefault(properties.getBaseUrl(), MoonshotChatModel.BASE_URL),
+ MoonshotChatModel.COMPLETE_PATH, properties.getApiKey(), properties.getModel(),
+ properties.getTemperature(), properties.getMaxTokens(), properties.getTopP()));
+ }
+
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.stepfun.enable", havingValue = "true")
+ public StepFunChatModel stepFunChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.StepFun properties = yudaoAiProperties.getStepfun();
+ return buildStepFunChatClient(properties);
+ }
+
+ public StepFunChatModel buildStepFunChatClient(YudaoAiProperties.StepFun properties) {
+ if (StrUtil.isEmpty(properties.getModel())) {
+ properties.setModel(StepFunChatModel.MODEL_DEFAULT);
+ }
+ return new StepFunChatModel(buildDeepSeekCompatibleChatModel(
+ StrUtil.blankToDefault(properties.getBaseUrl(), StepFunChatModel.BASE_URL),
+ StepFunChatModel.COMPLETE_PATH, properties.getApiKey(), properties.getModel(),
+ properties.getTemperature(), properties.getMaxTokens(), properties.getTopP()));
+ }
+
+ private static DeepSeekChatModel buildDeepSeekCompatibleChatModel(String baseUrl, String completionsPath,
+ String apiKey, String model,
+ Double temperature, Integer maxTokens,
+ Double topP) {
+ DeepSeekApi.Builder apiBuilder = DeepSeekApi.builder()
+ .baseUrl(baseUrl)
+ .apiKey(apiKey);
+ if (StrUtil.isNotEmpty(completionsPath)) {
+ apiBuilder.completionsPath(completionsPath);
+ }
+ return DeepSeekChatModel.builder()
+ .deepSeekApi(apiBuilder.build())
+ .options(DeepSeekChatOptions.builder()
+ .model(model)
+ .temperature(temperature)
+ .maxTokens(maxTokens)
+ .topP(topP)
+ .build())
+ .build();
}
@Bean
@@ -261,25 +415,28 @@
return new SunoApi(yudaoAiProperties.getSuno().getBaseUrl());
}
- public ChatModel buildGrokChatClient(YudaoAiProperties.Grok properties) {
+ @Bean
+ @ConditionalOnProperty(value = "yudao.ai.grok.enable", havingValue = "true")
+ public GrokChatModel grokChatClient(YudaoAiProperties yudaoAiProperties) {
+ YudaoAiProperties.Grok properties = yudaoAiProperties.getGrok();
+ return buildGrokChatClient(properties);
+ }
+
+ public GrokChatModel buildGrokChatClient(YudaoAiProperties.Grok properties) {
if (StrUtil.isEmpty(properties.getModel())) {
properties.setModel(GrokChatModel.MODEL_DEFAULT);
}
OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
- .baseUrl(Optional.ofNullable(properties.getBaseUrl())
- .orElse(GrokChatModel.BASE_URL))
- .apiKey(properties.getApiKey())
- .build())
.options(OpenAiChatOptions.builder()
+ .baseUrl(StrUtil.blankToDefault(properties.getBaseUrl(), GrokChatModel.BASE_URL))
+ .apiKey(properties.getApiKey())
.model(properties.getModel())
.temperature(properties.getTemperature())
.maxTokens(properties.getMaxTokens())
.topP(properties.getTopP())
.build())
- .toolCallingManager(getToolCallingManager())
.build();
- return new DouBaoChatModel(openAiChatModel);
+ return new GrokChatModel(openAiChatModel);
}
// ========== RAG 鐩稿叧 ==========
@@ -298,6 +455,10 @@
return SpringUtil.getBean(ToolCallingManager.class);
}
+ private static ObservationRegistry getObservationRegistry() {
+ return SpringUtil.getBean(ObservationRegistry.class);
+ }
+
// ========== Web Search 鐩稿叧 ==========
@Bean
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
index 986c24c..234fa2c 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
@@ -14,11 +14,6 @@
public class YudaoAiProperties {
/**
- * 璋锋瓕 Gemini
- */
- private Gemini gemini;
-
- /**
* 瀛楄妭璞嗗寘
*/
private DouBao doubao;
@@ -44,6 +39,36 @@
private BaiChuan baichuan;
/**
+ * 鏂囧績涓�瑷�
+ */
+ private YiYan yiyan;
+
+ /**
+ * 鏅鸿氨
+ */
+ private ZhiPu zhipu;
+
+ /**
+ * MiniMax
+ */
+ private MiniMax minimax;
+
+ /**
+ * 鏈堜箣鏆楅潰
+ */
+ private Moonshot moonshot;
+
+ /**
+ * 闃惰穬鏄熻景
+ */
+ private StepFun stepfun;
+
+ /**
+ * Grok
+ */
+ private Grok grok;
+
+ /**
* Midjourney 缁樺浘
*/
private Midjourney midjourney;
@@ -58,19 +83,6 @@
* 缃戠粶鎼滅储
*/
private WebSearch webSearch;
-
- @Data
- public static class Gemini {
-
- private String enable;
- private String apiKey;
-
- private String model;
- private Double temperature;
- private Integer maxTokens;
- private Double topP;
-
- }
@Data
public static class DouBao {
@@ -116,9 +128,7 @@
public static class XingHuo {
private String enable;
- private String appId;
- private String appKey;
- private String secretKey;
+ private String apiKey;
private String model;
private Double temperature;
@@ -131,6 +141,62 @@
public static class BaiChuan {
private String enable;
+ private String apiKey;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
+ @Data
+ public static class YiYan {
+
+ private String enable;
+ private String baseUrl;
+ private String apiKey;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
+ @Data
+ public static class ZhiPu {
+
+ private String enable;
+ private String baseUrl;
+ private String apiKey;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
+ @Data
+ public static class MiniMax {
+
+ private String enable;
+ private String baseUrl;
+ private String apiKey;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
+ @Data
+ public static class Moonshot {
+
+ private String enable;
+ private String baseUrl;
private String apiKey;
private String model;
@@ -175,6 +241,20 @@
}
@Data
+ public static class StepFun {
+
+ private String enable;
+ private String apiKey;
+ private String baseUrl;
+
+ private String model;
+ private Double temperature;
+ private Integer maxTokens;
+ private Double topP;
+
+ }
+
+ @Data
public static class WebSearch {
private boolean enable;
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
index c2f96ae..ec9d404 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
@@ -8,52 +8,40 @@
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
-import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import cn.iocoder.yudao.module.ai.framework.ai.config.AiAutoConfiguration;
import cn.iocoder.yudao.module.ai.framework.ai.config.YudaoAiProperties;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.minimax.MiniMaxChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.moonshot.MoonshotChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.stepfun.StepFunChatModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.suno.api.SunoApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.yiyan.YiYanChatModel;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.zhipu.ZhiPuChatModel;
+import cn.iocoder.yudao.module.ai.util.AiUtils;
import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatAutoConfiguration;
import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeEmbeddingAutoConfiguration;
import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeImageAutoConfiguration;
-import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
-import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
-import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.dashscope.embedding.text.DashScopeEmbeddingModel;
-import com.alibaba.cloud.ai.dashscope.embedding.text.DashScopeEmbeddingOptions;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
-import com.anthropic.client.okhttp.AnthropicOkHttpClient;
-import com.azure.ai.openai.OpenAIClientBuilder;
-import com.azure.core.credential.KeyCredential;
-import com.openai.client.OpenAIClient;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
+import com.google.genai.Client;
+import com.google.genai.types.HttpOptions;
import io.micrometer.observation.ObservationRegistry;
import io.milvus.client.MilvusServiceClient;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import lombok.SneakyThrows;
-import org.springaicommunity.moonshot.MoonshotChatModel;
-import org.springaicommunity.moonshot.MoonshotChatOptions;
-import org.springaicommunity.moonshot.api.MoonshotApi;
-import org.springaicommunity.qianfan.QianFanChatModel;
-import org.springaicommunity.qianfan.QianFanEmbeddingModel;
-import org.springaicommunity.qianfan.QianFanEmbeddingOptions;
-import org.springaicommunity.qianfan.QianFanImageModel;
-import org.springaicommunity.qianfan.api.QianFanApi;
-import org.springaicommunity.qianfan.api.QianFanImageApi;
-import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
-import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingModel;
+import org.springframework.ai.anthropic.AnthropicChatModel;
+import org.springframework.ai.anthropic.AnthropicChatOptions;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
@@ -62,37 +50,24 @@
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
+import org.springframework.ai.google.genai.GoogleGenAiChatModel;
+import org.springframework.ai.google.genai.GoogleGenAiChatOptions;
import org.springframework.ai.image.ImageModel;
-import org.springframework.ai.minimax.MiniMaxChatModel;
-import org.springframework.ai.minimax.MiniMaxChatOptions;
-import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
-import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
-import org.springframework.ai.minimax.api.MiniMaxApi;
import org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration;
-import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatAutoConfiguration;
-import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingAutoConfiguration;
-import org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiEmbeddingProperties;
import org.springframework.ai.model.deepseek.autoconfigure.DeepSeekChatAutoConfiguration;
-import org.springframework.ai.model.minimax.autoconfigure.MiniMaxChatAutoConfiguration;
-import org.springframework.ai.model.minimax.autoconfigure.MiniMaxEmbeddingAutoConfiguration;
+import org.springframework.ai.model.google.genai.autoconfigure.chat.GoogleGenAiChatAutoConfiguration;
import org.springframework.ai.model.ollama.autoconfigure.OllamaChatAutoConfiguration;
import org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration;
import org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration;
import org.springframework.ai.model.openai.autoconfigure.OpenAiImageAutoConfiguration;
import org.springframework.ai.model.stabilityai.autoconfigure.StabilityAiImageAutoConfiguration;
import org.springframework.ai.model.tool.ToolCallingManager;
-import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiChatAutoConfiguration;
-import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiEmbeddingAutoConfiguration;
-import org.springframework.ai.model.zhipuai.autoconfigure.ZhiPuAiImageAutoConfiguration;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.OllamaEmbeddingModel;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaEmbeddingOptions;
-import org.springframework.ai.openai.OpenAiChatModel;
-import org.springframework.ai.openai.OpenAiEmbeddingModel;
-import org.springframework.ai.openai.OpenAiEmbeddingOptions;
-import org.springframework.ai.openai.OpenAiImageModel;
-import org.springframework.ai.anthropic.AnthropicChatModel;
+import org.springframework.ai.openai.*;
+import org.springframework.ai.retry.RetryUtils;
import org.springframework.ai.stabilityai.StabilityAiImageModel;
import org.springframework.ai.stabilityai.api.StabilityAiApi;
import org.springframework.ai.vectorstore.SimpleVectorStore;
@@ -110,18 +85,17 @@
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreAutoConfiguration;
import org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreProperties;
-import org.springframework.ai.zhipuai.*;
-import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
-import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.data.redis.autoconfigure.DataRedisProperties;
-import org.springframework.web.client.RestClient;
-import redis.clients.jedis.JedisPooled;
+import redis.clients.jedis.DefaultJedisClientConfig;
+import redis.clients.jedis.HostAndPort;
+import redis.clients.jedis.JedisClientConfig;
+import redis.clients.jedis.RedisClient;
import java.io.File;
import java.time.Duration;
-import java.util.List;
+import java.util.Collections;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
@@ -136,7 +110,9 @@
public class AiModelFactoryImpl implements AiModelFactory {
@Override
- public ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url) {
+ public ChatModel getOrCreateChatModel(AiPlatformEnum platform, String rawApiKey, String rawUrl) {
+ final String apiKey = resolveSpringPlaceholders(rawApiKey);
+ final String url = resolveSpringPlaceholders(rawUrl);
String cacheKey = buildClientCacheKey(ChatModel.class, platform, apiKey, url);
return Singleton.get(cacheKey, (Func0<ChatModel>) () -> {
// noinspection EnhancedSwitchMigration
@@ -159,6 +135,8 @@
return buildMiniMaxChatModel(apiKey, url);
case MOONSHOT:
return buildMoonshotChatModel(apiKey, url);
+ case STEP_FUN:
+ return buildStepFunChatModel(apiKey, url);
case XING_HUO:
return buildXingHuoChatModel(apiKey);
case BAI_CHUAN:
@@ -170,11 +148,11 @@
case ANTHROPIC:
return buildAnthropicChatModel(apiKey, url);
case GEMINI:
- return buildGeminiChatModel(apiKey);
+ return buildGeminiChatModel(apiKey, url);
case OLLAMA:
return buildOllamaChatModel(url);
case GROK:
- return buildGrokChatModel(apiKey,url);
+ return buildGrokChatModel(apiKey, url);
default:
throw new IllegalArgumentException(StrUtil.format("鏈煡骞冲彴({})", platform));
}
@@ -188,7 +166,7 @@
case TONG_YI:
return SpringUtil.getBean(DashScopeChatModel.class);
case YI_YAN:
- return SpringUtil.getBean(QianFanChatModel.class);
+ return SpringUtil.getBean(YiYanChatModel.class);
case DEEP_SEEK:
return SpringUtil.getBean(DeepSeekChatModel.class);
case DOU_BAO:
@@ -198,23 +176,23 @@
case SILICON_FLOW:
return SpringUtil.getBean(SiliconFlowChatModel.class);
case ZHI_PU:
- return SpringUtil.getBean(ZhiPuAiChatModel.class);
+ return SpringUtil.getBean(ZhiPuChatModel.class);
case MINI_MAX:
return SpringUtil.getBean(MiniMaxChatModel.class);
case MOONSHOT:
return SpringUtil.getBean(MoonshotChatModel.class);
+ case STEP_FUN:
+ return SpringUtil.getBean(StepFunChatModel.class);
case XING_HUO:
return SpringUtil.getBean(XingHuoChatModel.class);
case BAI_CHUAN:
return SpringUtil.getBean(BaiChuanChatModel.class);
case OPENAI:
return SpringUtil.getBean(OpenAiChatModel.class);
- case AZURE_OPENAI:
- return SpringUtil.getBean(AzureOpenAiChatModel.class);
case ANTHROPIC:
return SpringUtil.getBean(AnthropicChatModel.class);
case GEMINI:
- return SpringUtil.getBean(GeminiChatModel.class);
+ return SpringUtil.getBean(GoogleGenAiChatModel.class);
case OLLAMA:
return SpringUtil.getBean(OllamaChatModel.class);
default:
@@ -228,10 +206,6 @@
switch (platform) {
case TONG_YI:
return SpringUtil.getBean(DashScopeImageModel.class);
- case YI_YAN:
- return SpringUtil.getBean(QianFanImageModel.class);
- case ZHI_PU:
- return SpringUtil.getBean(ZhiPuAiImageModel.class);
case SILICON_FLOW:
return SpringUtil.getBean(SiliconFlowImageModel.class);
case OPENAI:
@@ -244,19 +218,17 @@
}
@Override
- public ImageModel getOrCreateImageModel(AiPlatformEnum platform, String apiKey, String url) {
+ public ImageModel getOrCreateImageModel(AiPlatformEnum platform, String rawApiKey, String rawUrl) {
+ String apiKey = resolveSpringPlaceholders(rawApiKey);
+ String url = resolveSpringPlaceholders(rawUrl);
// noinspection EnhancedSwitchMigration
switch (platform) {
case TONG_YI:
return buildTongYiImagesModel(apiKey);
- case YI_YAN:
- return buildQianFanImageModel(apiKey);
- case ZHI_PU:
- return buildZhiPuAiImageModel(apiKey, url);
case OPENAI:
return buildOpenAiImageModel(apiKey, url);
case SILICON_FLOW:
- return buildSiliconFlowImageModel(apiKey,url);
+ return buildSiliconFlowImageModel(apiKey, url);
case STABLE_DIFFUSION:
return buildStabilityAiImageModel(apiKey, url);
default:
@@ -265,9 +237,11 @@
}
@Override
- public MidjourneyApi getOrCreateMidjourneyApi(String apiKey, String url) {
- String cacheKey = buildClientCacheKey(MidjourneyApi.class, AiPlatformEnum.MIDJOURNEY.getPlatform(), apiKey,
- url);
+ public MidjourneyApi getOrCreateMidjourneyApi(String rawApiKey, String rawUrl) {
+ final String apiKey = resolveSpringPlaceholders(rawApiKey);
+ final String url = resolveSpringPlaceholders(rawUrl);
+ String cacheKey = buildClientCacheKey(MidjourneyApi.class, AiPlatformEnum.MIDJOURNEY.getPlatform(),
+ apiKey, url);
return Singleton.get(cacheKey, (Func0<MidjourneyApi>) () -> {
YudaoAiProperties.Midjourney properties = SpringUtil.getBean(YudaoAiProperties.class)
.getMidjourney();
@@ -276,25 +250,23 @@
}
@Override
- public SunoApi getOrCreateSunoApi(String apiKey, String url) {
+ public SunoApi getOrCreateSunoApi(String rawApiKey, String rawUrl) {
+ final String apiKey = resolveSpringPlaceholders(rawApiKey);
+ final String url = resolveSpringPlaceholders(rawUrl);
String cacheKey = buildClientCacheKey(SunoApi.class, AiPlatformEnum.SUNO.getPlatform(), apiKey, url);
return Singleton.get(cacheKey, (Func0<SunoApi>) () -> new SunoApi(url));
}
@Override
@SuppressWarnings("EnhancedSwitchMigration")
- public EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String apiKey, String url, String model) {
+ public EmbeddingModel getOrCreateEmbeddingModel(AiPlatformEnum platform, String rawApiKey, String rawUrl, String model) {
+ final String apiKey = resolveSpringPlaceholders(rawApiKey);
+ final String url = resolveSpringPlaceholders(rawUrl);
String cacheKey = buildClientCacheKey(EmbeddingModel.class, platform, apiKey, url, model);
return Singleton.get(cacheKey, (Func0<EmbeddingModel>) () -> {
switch (platform) {
case TONG_YI:
return buildTongYiEmbeddingModel(apiKey, model);
- case YI_YAN:
- return buildYiYanEmbeddingModel(apiKey, model);
- case ZHI_PU:
- return buildZhiPuEmbeddingModel(apiKey, url, model);
- case MINI_MAX:
- return buildMiniMaxEmbeddingModel(apiKey, url, model);
case OPENAI:
return buildOpenAiEmbeddingModel(apiKey, url, model);
case AZURE_OPENAI:
@@ -336,60 +308,31 @@
return StrUtil.format("{}#{}", clazz.getName(), ArrayUtil.join(params, "_"));
}
+ private static String resolveSpringPlaceholders(String value) {
+ // yml 閰嶇疆鐨勫崰浣嶇鐢� Spring 鑷姩瑙f瀽锛汥B 閲屼繚瀛樼殑 ${xxx} 闇�瑕佸湪杩欓噷鎵嬪姩瑙f瀽銆�
+ return AiUtils.resolveSpringPlaceholders(value);
+ }
+
// ========== 鍚勭鍒涘缓 spring-ai 瀹㈡埛绔殑鏂规硶 ==========
/**
* 鍙弬鑰� {@link DashScopeChatAutoConfiguration} 鐨� dashscopeChatModel 鏂规硶
*/
private static DashScopeChatModel buildTongYiChatModel(String key) {
- DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(key).build();
- DashScopeChatOptions options = DashScopeChatOptions
- .builder()
- .model(DashScopeApi.DEFAULT_CHAT_MODEL)
- .temperature(0.7)
- .build();
- return DashScopeChatModel
- .builder()
- .dashScopeApi(dashScopeApi)
- .defaultOptions(options)
- .toolCallingManager(getToolCallingManager())
- .build();
+ return AiAutoConfiguration.buildTongYiChatModel(key);
}
/**
* 鍙弬鑰� {@link DashScopeImageAutoConfiguration} 鐨� dashScopeImageModel 鏂规硶
*/
private static DashScopeImageModel buildTongYiImagesModel(String key) {
- DashScopeImageApi dashScopeImageApi = DashScopeImageApi.builder().apiKey(key).build();
- return DashScopeImageModel.builder()
- .dashScopeApi(dashScopeImageApi)
- .build();
+ return AiAutoConfiguration.buildTongYiImagesModel(key);
}
- /**
- * 鍙弬鑰� QianFanChatAutoConfiguration 鐨� qianFanChatModel 鏂规硶
- */
- private static QianFanChatModel buildYiYanChatModel(String key) {
- // TODO spring ai qianfan 鏈� bug锛屾棤娉曚娇鐢� https://github.com/spring-ai-community/qianfan/issues/6
- List<String> keys = StrUtil.split(key, '|');
- Assert.equals(keys.size(), 2, "YiYanChatClient 鐨勫瘑閽ラ渶瑕� (appKey|secretKey) 鏍煎紡");
- String appKey = keys.get(0);
- String secretKey = keys.get(1);
- QianFanApi qianFanApi = new QianFanApi(appKey, secretKey);
- return new QianFanChatModel(qianFanApi);
- }
-
- /**
- * 鍙弬鑰� QianFanEmbeddingAutoConfiguration 鐨� qianFanImageModel 鏂规硶
- */
- private QianFanImageModel buildQianFanImageModel(String key) {
- // TODO spring ai qianfan 鏈� bug锛屾棤娉曚娇鐢� https://github.com/spring-ai-community/qianfan/issues/6
- List<String> keys = StrUtil.split(key, '|');
- Assert.equals(keys.size(), 2, "YiYanChatClient 鐨勫瘑閽ラ渶瑕� (appKey|secretKey) 鏍煎紡");
- String appKey = keys.get(0);
- String secretKey = keys.get(1);
- QianFanImageApi qianFanApi = new QianFanImageApi(appKey, secretKey);
- return new QianFanImageModel(qianFanApi);
+ private ChatModel buildYiYanChatModel(String apiKey) {
+ YudaoAiProperties.YiYan properties = new YudaoAiProperties.YiYan()
+ .setApiKey(apiKey);
+ return new AiAutoConfiguration().buildYiYanChatClient(properties);
}
/**
@@ -401,8 +344,7 @@
.temperature(0.7).build();
return DeepSeekChatModel.builder()
.deepSeekApi(deepSeekApi)
- .defaultOptions(options)
- .toolCallingManager(getToolCallingManager())
+ .options(options)
.build();
}
@@ -434,62 +376,47 @@
}
/**
- * 鍙弬鑰� {@link ZhiPuAiChatAutoConfiguration} 鐨� zhiPuAiChatModel 鏂规硶
+ * 鍙弬鑰� {@link AiAutoConfiguration#zhiPuChatClient(YudaoAiProperties)}
*/
- private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
- ZhiPuAiApi.Builder zhiPuAiApiBuilder = ZhiPuAiApi.builder().apiKey(apiKey);
- if (StrUtil.isNotEmpty(url)) {
- zhiPuAiApiBuilder.baseUrl(url);
- }
- ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().model(ZhiPuAiApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
- return new ZhiPuAiChatModel(zhiPuAiApiBuilder.build(), options, getToolCallingManager(), new org.springframework.core.retry.RetryTemplate(),
- getObservationRegistry().getIfAvailable());
+ private ZhiPuChatModel buildZhiPuChatModel(String apiKey, String url) {
+ YudaoAiProperties.ZhiPu properties = new YudaoAiProperties.ZhiPu()
+ .setBaseUrl(url).setApiKey(apiKey);
+ return new AiAutoConfiguration().buildZhiPuChatClient(properties);
}
/**
- * 鍙弬鑰� {@link ZhiPuAiImageAutoConfiguration} 鐨� zhiPuAiImageModel 鏂规硶
- */
- private ZhiPuAiImageModel buildZhiPuAiImageModel(String apiKey, String url) {
- ZhiPuAiImageApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiImageApi(apiKey)
- : new ZhiPuAiImageApi(url, apiKey, RestClient.builder());
- return new ZhiPuAiImageModel(zhiPuAiApi);
- }
-
- /**
- * 鍙弬鑰� {@link MiniMaxChatAutoConfiguration} 鐨� miniMaxChatModel 鏂规硶
+ * 鍙弬鑰� {@link AiAutoConfiguration#miniMaxChatClient(YudaoAiProperties)}
*/
private MiniMaxChatModel buildMiniMaxChatModel(String apiKey, String url) {
- MiniMaxApi miniMaxApi = StrUtil.isEmpty(url) ? new MiniMaxApi(apiKey)
- : new MiniMaxApi(url, apiKey);
- MiniMaxChatOptions options = MiniMaxChatOptions.builder().model(MiniMaxApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
- return new MiniMaxChatModel(miniMaxApi, options, getToolCallingManager(), new org.springframework.core.retry.RetryTemplate());
+ YudaoAiProperties.MiniMax properties = new YudaoAiProperties.MiniMax()
+ .setBaseUrl(url).setApiKey(apiKey);
+ return new AiAutoConfiguration().buildMiniMaxChatClient(properties);
}
/**
- * 鍙弬鑰� MoonshotChatAutoConfiguration 鐨� moonshotChatModel 鏂规硶
+ * 鍙弬鑰� {@link AiAutoConfiguration#moonshotChatClient(YudaoAiProperties)}
*/
private MoonshotChatModel buildMoonshotChatModel(String apiKey, String url) {
- MoonshotApi.Builder moonshotApiBuilder = MoonshotApi.builder()
- .apiKey(apiKey);
- if (StrUtil.isNotEmpty(url)) {
- moonshotApiBuilder.baseUrl(url);
- }
- MoonshotChatOptions options = MoonshotChatOptions.builder().model(MoonshotApi.DEFAULT_CHAT_MODEL).build();
- return MoonshotChatModel.builder()
- .moonshotApi(moonshotApiBuilder.build())
- .defaultOptions(options)
- .toolCallingManager(getToolCallingManager())
- .build();
+ YudaoAiProperties.Moonshot properties = new YudaoAiProperties.Moonshot()
+ .setBaseUrl(url).setApiKey(apiKey);
+ return new AiAutoConfiguration().buildMoonshotChatClient(properties);
+ }
+
+ /**
+ * 鍙弬鑰� {@link AiAutoConfiguration#stepFunChatClient(YudaoAiProperties)}
+ */
+ private StepFunChatModel buildStepFunChatModel(String apiKey, String url) {
+ YudaoAiProperties.StepFun properties = new YudaoAiProperties.StepFun()
+ .setBaseUrl(url).setApiKey(apiKey);
+ return new AiAutoConfiguration().buildStepFunChatClient(properties);
}
/**
* 鍙弬鑰� {@link AiAutoConfiguration#xingHuoChatClient(YudaoAiProperties)}
*/
- private static XingHuoChatModel buildXingHuoChatModel(String key) {
- List<String> keys = StrUtil.split(key, '|');
- Assert.equals(keys.size(), 2, "XingHuoChatClient 鐨勫瘑閽ラ渶瑕� (appKey|secretKey) 鏍煎紡");
+ private static XingHuoChatModel buildXingHuoChatModel(String apiKey) {
YudaoAiProperties.XingHuo properties = new YudaoAiProperties.XingHuo()
- .setAppKey(keys.get(0)).setSecretKey(keys.get(1));
+ .setApiKey(apiKey).setModel(XingHuoChatModel.MODEL_DEFAULT);
return new AiAutoConfiguration().buildXingHuoChatClient(properties);
}
@@ -507,52 +434,73 @@
*/
private static OpenAiChatModel buildOpenAiChatModel(String openAiToken, String url) {
return OpenAiChatModel.builder()
- .openAiClient(buildOpenAiClient(openAiToken, url))
- .toolCallingManager(getToolCallingManager())
+ .options(buildOpenAiChatOptions(openAiToken, url).build())
.build();
}
- /**
- * 鍙弬鑰� {@link AzureOpenAiChatAutoConfiguration}
- */
- private static AzureOpenAiChatModel buildAzureOpenAiChatModel(String apiKey, String url) {
- // TODO @鑺嬭壙锛氫娇鐢ㄥ墠锛岃娴嬭瘯锛屾殏鏃舵病瀵嗛挜锛侊紒锛�
- OpenAIClientBuilder openAIClientBuilder = new OpenAIClientBuilder()
- .endpoint(url).credential(new KeyCredential(apiKey));
- return AzureOpenAiChatModel.builder()
- .openAIClientBuilder(openAIClientBuilder)
- .toolCallingManager(getToolCallingManager())
+ private static OpenAiChatModel buildAzureOpenAiChatModel(String openAiToken, String url) {
+ return OpenAiChatModel.builder()
+ .options(buildOpenAiChatOptions(openAiToken, url)
+ .azure(true)
+ .build())
.build();
+ }
+
+ private static OpenAiChatOptions.Builder buildOpenAiChatOptions(String apiKey, String url) {
+ OpenAiChatOptions.Builder optionsBuilder = OpenAiChatOptions.builder().apiKey(apiKey);
+ if (StrUtil.isNotEmpty(url)) {
+ optionsBuilder.baseUrl(url);
+ }
+ return optionsBuilder;
}
/**
* 鍙弬鑰� {@link AnthropicChatAutoConfiguration} 鐨� anthropicApi 鏂规硶
*/
private static AnthropicChatModel buildAnthropicChatModel(String apiKey, String url) {
- AnthropicOkHttpClient.Builder builder = AnthropicOkHttpClient.builder().apiKey(apiKey);
+ AnthropicChatOptions.Builder optionsBuilder = AnthropicChatOptions.builder().apiKey(apiKey);
if (StrUtil.isNotEmpty(url)) {
- builder.baseUrl(url);
+ optionsBuilder.baseUrl(url);
}
return AnthropicChatModel.builder()
- .anthropicClient(builder.build())
- .toolCallingManager(getToolCallingManager())
+ .options(optionsBuilder.build())
.build();
}
/**
- * 鍙弬鑰� {@link AiAutoConfiguration#buildGeminiChatClient(YudaoAiProperties.Gemini)}
+ * 鍙弬鑰� {@link GoogleGenAiChatAutoConfiguration} 鐨� googleGenAiChatModel 鏂规硶
*/
- private static GeminiChatModel buildGeminiChatModel(String apiKey) {
- YudaoAiProperties.Gemini properties = SpringUtil.getBean(YudaoAiProperties.class)
- .getGemini().setApiKey(apiKey);
- return new AiAutoConfiguration().buildGeminiChatClient(properties);
+ private static GoogleGenAiChatModel buildGeminiChatModel(String apiKey, String url) {
+ Client.Builder clientBuilder = Client.builder().apiKey(apiKey);
+ if (StrUtil.isNotBlank(url)) {
+ clientBuilder.httpOptions(HttpOptions.builder()
+ .baseUrl(url)
+ // TeamOrouter 鐨� Gemini 鍘熺敓鍗忚浣跨敤 Authorization Bearer 閴存潈
+ .headers(Collections.singletonMap("Authorization", "Bearer " + apiKey))
+ .build());
+ }
+ return GoogleGenAiChatModel.builder()
+ .genAiClient(clientBuilder.build())
+ .options(GoogleGenAiChatOptions.builder()
+ .model("gemini-2.5-flash")
+ .build())
+ .toolCallingManager(SpringUtil.getBean(ToolCallingManager.class))
+ .retryTemplate(RetryUtils.DEFAULT_RETRY_TEMPLATE)
+ .observationRegistry(SpringUtil.getBean(ObservationRegistry.class))
+ .build();
}
/**
* 鍙弬鑰� {@link OpenAiImageAutoConfiguration} 鐨� openAiImageModel 鏂规硶
*/
private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) {
- return new OpenAiImageModel(buildOpenAiClient(openAiToken, url));
+ OpenAiImageOptions.Builder optionsBuilder = OpenAiImageOptions.builder().apiKey(openAiToken);
+ if (StrUtil.isNotEmpty(url)) {
+ optionsBuilder.baseUrl(url);
+ }
+ return OpenAiImageModel.builder()
+ .options(optionsBuilder.build())
+ .build();
}
/**
@@ -571,7 +519,6 @@
OllamaApi ollamaApi = OllamaApi.builder().baseUrl(url).build();
return OllamaChatModel.builder()
.ollamaApi(ollamaApi)
- .toolCallingManager(getToolCallingManager())
.build();
}
@@ -597,44 +544,7 @@
* 鍙弬鑰� {@link DashScopeEmbeddingAutoConfiguration} 鐨� DashScopeEmbeddingModel 鏂规硶
*/
private DashScopeEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model) {
- DashScopeApi dashScopeApi = DashScopeApi.builder().apiKey(apiKey).build();
- DashScopeEmbeddingOptions dashScopeEmbeddingOptions = DashScopeEmbeddingOptions.builder().model(model).build();
- return new DashScopeEmbeddingModel(dashScopeApi, MetadataMode.EMBED, dashScopeEmbeddingOptions);
- }
-
- /**
- * 鍙弬鑰� {@link ZhiPuAiEmbeddingAutoConfiguration} 鐨� ZhiPuAiEmbeddingModel 鏂规硶
- */
- private ZhiPuAiEmbeddingModel buildZhiPuEmbeddingModel(String apiKey, String url, String model) {
- ZhiPuAiApi.Builder zhiPuAiApiBuilder = ZhiPuAiApi.builder().apiKey(apiKey);
- if (StrUtil.isNotEmpty(url)) {
- zhiPuAiApiBuilder.baseUrl(url);
- }
- ZhiPuAiEmbeddingOptions zhiPuAiEmbeddingOptions = ZhiPuAiEmbeddingOptions.builder().model(model).build();
- return new ZhiPuAiEmbeddingModel(zhiPuAiApiBuilder.build(), MetadataMode.EMBED, zhiPuAiEmbeddingOptions);
- }
-
- /**
- * 鍙弬鑰� {@link MiniMaxEmbeddingAutoConfiguration} 鐨� miniMaxEmbeddingModel 鏂规硶
- */
- private EmbeddingModel buildMiniMaxEmbeddingModel(String apiKey, String url, String model) {
- MiniMaxApi miniMaxApi = StrUtil.isEmpty(url)? new MiniMaxApi(apiKey)
- : new MiniMaxApi(url, apiKey);
- MiniMaxEmbeddingOptions miniMaxEmbeddingOptions = MiniMaxEmbeddingOptions.builder().model(model).build();
- return new MiniMaxEmbeddingModel(miniMaxApi, MetadataMode.EMBED, miniMaxEmbeddingOptions);
- }
-
- /**
- * 鍙弬鑰� {@link QianFanEmbeddingModel} 鐨� qianFanEmbeddingModel 鏂规硶
- */
- private QianFanEmbeddingModel buildYiYanEmbeddingModel(String key, String model) {
- List<String> keys = StrUtil.split(key, '|');
- Assert.equals(keys.size(), 2, "YiYanChatClient 鐨勫瘑閽ラ渶瑕� (appKey|secretKey) 鏍煎紡");
- String appKey = keys.get(0);
- String secretKey = keys.get(1);
- QianFanApi qianFanApi = new QianFanApi(appKey, secretKey);
- QianFanEmbeddingOptions qianFanEmbeddingOptions = QianFanEmbeddingOptions.builder().model(model).build();
- return new QianFanEmbeddingModel(qianFanApi, MetadataMode.EMBED, qianFanEmbeddingOptions);
+ return AiAutoConfiguration.buildTongYiEmbeddingModel(apiKey, model);
}
private OllamaEmbeddingModel buildOllamaEmbeddingModel(String url, String model) {
@@ -642,7 +552,7 @@
OllamaEmbeddingOptions ollamaOptions = OllamaEmbeddingOptions.builder().model(model).build();
return OllamaEmbeddingModel.builder()
.ollamaApi(ollamaApi)
- .defaultOptions(ollamaOptions)
+ .options(ollamaOptions)
.build();
}
@@ -650,31 +560,31 @@
* 鍙弬鑰� {@link OpenAiEmbeddingAutoConfiguration} 鐨� openAiEmbeddingModel 鏂规硶
*/
private OpenAiEmbeddingModel buildOpenAiEmbeddingModel(String openAiToken, String url, String model) {
- OpenAiEmbeddingOptions openAiEmbeddingProperties = OpenAiEmbeddingOptions.builder().model(model).build();
- return new OpenAiEmbeddingModel(buildOpenAiClient(openAiToken, url), MetadataMode.EMBED, openAiEmbeddingProperties);
- }
-
- private static OpenAIClient buildOpenAiClient(String apiKey, String url) {
- OpenAIOkHttpClient.Builder builder = OpenAIOkHttpClient.builder().apiKey(apiKey);
+ OpenAiEmbeddingOptions.Builder optionsBuilder = OpenAiEmbeddingOptions.builder()
+ .apiKey(openAiToken)
+ .model(model);
if (StrUtil.isNotEmpty(url)) {
- builder.baseUrl(url);
+ optionsBuilder.baseUrl(url);
}
- return builder.build();
+ return OpenAiEmbeddingModel.builder()
+ .metadataMode(MetadataMode.EMBED)
+ .options(optionsBuilder.build())
+ .build();
}
- /**
- * 鍙弬鑰� {@link AzureOpenAiEmbeddingAutoConfiguration} 鐨� azureOpenAiEmbeddingModel 鏂规硶
- */
- private AzureOpenAiEmbeddingModel buildAzureOpenAiEmbeddingModel(String apiKey, String url, String model) {
- // TODO @鑺嬭壙锛氭墜澶存殏鏃舵病瀵嗛挜锛屼娇鐢ㄥ缓璁啀娴嬭瘯涓�
- AzureOpenAiEmbeddingAutoConfiguration azureOpenAiAutoConfiguration = new AzureOpenAiEmbeddingAutoConfiguration();
- // 鍒涘缓 OpenAIClientBuilder 瀵硅薄
- OpenAIClientBuilder openAIClientBuilder = new OpenAIClientBuilder()
- .endpoint(url).credential(new KeyCredential(apiKey));
- // 鑾峰彇 AzureOpenAiChatProperties 瀵硅薄
- AzureOpenAiEmbeddingProperties embeddingProperties = SpringUtil.getBean(AzureOpenAiEmbeddingProperties.class);
- return azureOpenAiAutoConfiguration.azureOpenAiEmbeddingModel(openAIClientBuilder, embeddingProperties,
- getObservationRegistry(), getEmbeddingModelObservationConvention());
+ private OpenAiEmbeddingModel buildAzureOpenAiEmbeddingModel(String openAiToken, String url, String model) {
+ OpenAiEmbeddingOptions.Builder optionsBuilder = OpenAiEmbeddingOptions.builder()
+ .apiKey(openAiToken)
+ .model(model)
+ .deploymentName(model)
+ .azure(true);
+ if (StrUtil.isNotEmpty(url)) {
+ optionsBuilder.baseUrl(url);
+ }
+ return OpenAiEmbeddingModel.builder()
+ .metadataMode(MetadataMode.EMBED)
+ .options(optionsBuilder.build())
+ .build();
}
// ========== 鍚勭鍒涘缓 VectorStore 鐨勬柟娉� ==========
@@ -737,13 +647,11 @@
*/
private RedisVectorStore buildRedisVectorStore(EmbeddingModel embeddingModel,
Map<String, Class<?>> metadataFields) {
- // 鍒涘缓 JedisPooled 瀵硅薄
- DataRedisProperties redisProperties = SpringUtils.getBean(DataRedisProperties.class);
- JedisPooled jedisPooled = new JedisPooled(redisProperties.getHost(), redisProperties.getPort(),
- redisProperties.getUsername(), redisProperties.getPassword());
+ // 鍒涘缓 RedisClient 瀵硅薄
+ RedisClient redisClient = buildRedisClient();
// 鍒涘缓 RedisVectorStoreProperties 瀵硅薄
RedisVectorStoreProperties properties = SpringUtil.getBean(RedisVectorStoreProperties.class);
- RedisVectorStore redisVectorStore = RedisVectorStore.builder(jedisPooled, embeddingModel)
+ RedisVectorStore redisVectorStore = RedisVectorStore.builder(redisClient, embeddingModel)
.indexName(properties.getIndexName()).prefix(properties.getPrefix())
.initializeSchema(properties.isInitializeSchema())
.metadataFields(convertList(metadataFields.entrySet(), entry -> {
@@ -764,6 +672,43 @@
// 鍒濆鍖栫储寮�
redisVectorStore.afterPropertiesSet();
return redisVectorStore;
+ }
+
+ private RedisClient buildRedisClient() {
+ DataRedisProperties redisProperties = SpringUtil.getBean(DataRedisProperties.class);
+ Assert.isNull(redisProperties.getCluster(), "RedisVectorStore 鏆備笉鏀寔 Redis Cluster 妯″紡");
+ Assert.isNull(redisProperties.getSentinel(), "RedisVectorStore 鏆備笉鏀寔 Redis Sentinel 妯″紡");
+ Assert.isNull(redisProperties.getMasterreplica(), "RedisVectorStore 鏆備笉鏀寔 Redis Master-Replica 妯″紡");
+ if (StrUtil.isNotEmpty(redisProperties.getUrl())) {
+ return RedisClient.create(redisProperties.getUrl());
+ }
+ DefaultJedisClientConfig.Builder clientConfigBuilder = DefaultJedisClientConfig.builder()
+ .ssl(redisProperties.getSsl().isEnabled())
+ .database(redisProperties.getDatabase());
+ if (StrUtil.isNotEmpty(redisProperties.getUsername())) {
+ clientConfigBuilder.user(redisProperties.getUsername());
+ }
+ if (StrUtil.isNotEmpty(redisProperties.getPassword())) {
+ clientConfigBuilder.password(redisProperties.getPassword());
+ }
+ if (StrUtil.isNotEmpty(redisProperties.getClientName())) {
+ clientConfigBuilder.clientName(redisProperties.getClientName());
+ }
+ if (redisProperties.getTimeout() != null) {
+ clientConfigBuilder.socketTimeoutMillis(toMillis(redisProperties.getTimeout()));
+ }
+ if (redisProperties.getConnectTimeout() != null) {
+ clientConfigBuilder.connectionTimeoutMillis(toMillis(redisProperties.getConnectTimeout()));
+ }
+ JedisClientConfig clientConfig = clientConfigBuilder.build();
+ return RedisClient.builder()
+ .hostAndPort(new HostAndPort(redisProperties.getHost(), redisProperties.getPort()))
+ .clientConfig(clientConfig)
+ .build();
+ }
+
+ private static int toMillis(Duration duration) {
+ return Math.toIntExact(duration.toMillis());
}
/**
@@ -825,10 +770,6 @@
private static BatchingStrategy getBatchingStrategy() {
return SpringUtil.getBean(BatchingStrategy.class);
- }
-
- private static ToolCallingManager getToolCallingManager() {
- return SpringUtil.getBean(ToolCallingManager.class);
}
private static ObjectProvider<EmbeddingModelObservationConvention> getEmbeddingModelObservationConvention() {
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java
index 5fb71c9..3ea5ecc 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/baichuan/BaiChuanChatModel.java
@@ -6,7 +6,7 @@
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.openai.OpenAiChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
import reactor.core.publisher.Flux;
/**
@@ -20,26 +20,35 @@
public static final String BASE_URL = "https://api.baichuan-ai.com";
- public static final String MODEL_DEFAULT = "Baichuan4-Turbo";
+ public static final String COMPLETE_PATH = "/v1/chat/completions";
+
+ public static final String MODEL_DEFAULT = "Baichuan-M3";
/**
- * 鍏煎 OpenAI 鎺ュ彛锛岃繘琛屽鐢�
+ * 鍏煎 OpenAI 鎺ュ彛锛屽鐢� DeepSeek 瀹㈡埛绔�
*/
- private final OpenAiChatModel openAiChatModel;
+ private final DeepSeekChatModel deepSeekChatModel;
@Override
public ChatResponse call(Prompt prompt) {
- return openAiChatModel.call(prompt);
+ return deepSeekChatModel.call(prompt);
}
@Override
public Flux<ChatResponse> stream(Prompt prompt) {
- return openAiChatModel.stream(prompt);
+ return deepSeekChatModel.stream(prompt);
}
@Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java
index a542cb3..3caedc9 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java
@@ -20,7 +20,7 @@
public static final String BASE_URL = "https://ark.cn-beijing.volces.com/api";
public static final String COMPLETE_PATH = "/v3/chat/completions";
- public static final String MODEL_DEFAULT = "doubao-1-5-lite-32k-250115";
+ public static final String MODEL_DEFAULT = "doubao-seed-2-1-turbo-260628";
/**
* 鍏煎 OpenAI 鎺ュ彛锛岃繘琛屽鐢�
@@ -38,8 +38,15 @@
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/gemini/GeminiChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/gemini/GeminiChatModel.java
deleted file mode 100644
index 378a0af..0000000
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/gemini/GeminiChatModel.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.ai.chat.model.ChatModel;
-import org.springframework.ai.chat.model.ChatResponse;
-import org.springframework.ai.chat.prompt.ChatOptions;
-import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.openai.OpenAiChatModel;
-import reactor.core.publisher.Flux;
-
-/**
- * 璋锋瓕 Gemini {@link ChatModel} 瀹炵幇绫伙紝鍩轰簬 Google AI Studio 鎻愪緵鐨� <a href="https://ai.google.dev/gemini-api/docs/openai">OpenAI 鍏煎鏂规</a>
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Slf4j
-@RequiredArgsConstructor
-public class GeminiChatModel implements ChatModel {
-
- public static final String BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/";
- public static final String COMPLETE_PATH = "/chat/completions";
-
- public static final String MODEL_DEFAULT = "gemini-2.5-flash";
-
- /**
- * 鍏煎 OpenAI 鎺ュ彛锛岃繘琛屽鐢�
- */
- private final OpenAiChatModel openAiChatModel;
-
- @Override
- public ChatResponse call(Prompt prompt) {
- return openAiChatModel.call(prompt);
- }
-
- @Override
- public Flux<ChatResponse> stream(Prompt prompt) {
- return openAiChatModel.stream(prompt);
- }
-
- @Override
- public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
- }
-
-}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java
index 06eed25..7c9215a 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/grok/GrokChatModel.java
@@ -17,9 +17,9 @@
@RequiredArgsConstructor
public class GrokChatModel implements ChatModel {
- public static final String BASE_URL = "https://api.x.ai";
+ public static final String BASE_URL = "https://api.x.ai/v1";
public static final String COMPLETE_PATH = "/v1/chat/completions";
- public static final String MODEL_DEFAULT = "grok-4-fast-reasoning";
+ public static final String MODEL_DEFAULT = "grok-4.3";
/**
* 鍏煎 OpenAI 鎺ュ彛锛岃繘琛屽鐢�
@@ -37,8 +37,15 @@
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java
index 9513c6c..0f3c3a9 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java
@@ -9,10 +9,9 @@
import reactor.core.publisher.Flux;
/**
- * 鑵句簯娣峰厓 {@link ChatModel} 瀹炵幇绫�
+ * 鑵捐娣峰厓 {@link ChatModel} 瀹炵幇绫�
*
- * 1. 娣峰厓澶фā鍨嬶細鍩轰簬 <a href="https://cloud.tencent.com/document/product/1729/111007">鐭ヨ瘑寮曟搸鍘熷瓙鑳藉姏</a> 瀹炵幇
- * 2. 鐭ヨ瘑寮曟搸鍘熷瓙鑳藉姏锛氬熀浜� <a href="https://cloud.tencent.com/document/product/1772/115969">鐭ヨ瘑寮曟搸鍘熷瓙鑳藉姏</a> 瀹炵幇
+ * 鍩轰簬 <a href="https://cloud.tencent.com/document/product/1823/132252">TokenHub OpenAI 鍏煎鎺ュ彛</a> 瀹炵幇
*
* @author fansili
*/
@@ -20,14 +19,10 @@
@RequiredArgsConstructor
public class HunYuanChatModel implements ChatModel {
- public static final String BASE_URL = "https://api.hunyuan.cloud.tencent.com";
+ public static final String BASE_URL = "https://tokenhub.tencentmaas.com";
public static final String COMPLETE_PATH = "/v1/chat/completions";
- public static final String MODEL_DEFAULT = "hunyuan-turbo";
-
- public static final String DEEP_SEEK_BASE_URL = "https://api.lkeap.cloud.tencent.com";
-
- public static final String DEEP_SEEK_MODEL_DEFAULT = "deepseek-v3";
+ public static final String MODEL_DEFAULT = "hy3-preview";
/**
* 鍏煎 OpenAI 鎺ュ彛锛岃繘琛屽鐢�
@@ -45,8 +40,15 @@
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/minimax/MiniMaxChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/minimax/MiniMaxChatModel.java
new file mode 100644
index 0000000..d464ab8
--- /dev/null
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/minimax/MiniMaxChatModel.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.minimax;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * MiniMax {@link ChatModel} 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class MiniMaxChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://api.minimaxi.com/v1";
+
+ public static final String MODEL_DEFAULT = "MiniMax-M3";
+
+ /**
+ * 鍏煎 OpenAI 鎺ュ彛锛屽鐢� DeepSeek 瀹㈡埛绔�
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux<ChatResponse> stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/moonshot/MoonshotChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/moonshot/MoonshotChatModel.java
new file mode 100644
index 0000000..391cec5
--- /dev/null
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/moonshot/MoonshotChatModel.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.moonshot;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * 鏈堜箣鏆楅潰 {@link ChatModel} 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class MoonshotChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://api.moonshot.cn";
+
+ public static final String COMPLETE_PATH = "/v1/chat/completions";
+
+ public static final String MODEL_DEFAULT = "kimi-k2.6";
+
+ /**
+ * 鍏煎 OpenAI 鎺ュ彛锛屽鐢� DeepSeek 瀹㈡埛绔�
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux<ChatResponse> stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java
index 24a00ac..6016ba3 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowApiConstants.java
@@ -25,7 +25,7 @@
public static final String DEFAULT_BASE_URL = "https://api.siliconflow.cn";
- public static final String MODEL_DEFAULT = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B";
+ public static final String MODEL_DEFAULT = "deepseek-ai/DeepSeek-V4-Pro";
public static final String DEFAULT_IMAGE_MODEL = "Kwai-Kolors/Kolors";
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java
index a910e34..9d66f25 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java
@@ -6,7 +6,6 @@
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.openai.OpenAiChatModel;
import reactor.core.publisher.Flux;
/**
@@ -36,8 +35,15 @@
}
@Override
+ public ChatOptions getOptions() {
+ return openAiChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModel.getDefaultOptions();
+ return getOptions();
}
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
index 2e4ce99..d6d5b7b 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowImageModel.java
@@ -29,9 +29,9 @@
import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.metadata.OpenAiImageGenerationMetadata;
import org.springframework.ai.retry.RetryUtils;
+import org.springframework.core.retry.RetryTemplate;
import org.springframework.http.ResponseEntity;
import org.jspecify.annotations.Nullable;
-import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.Assert;
import java.util.List;
@@ -95,8 +95,8 @@
.observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext,
this.observationRegistry)
.observe(() -> {
- ResponseEntity<SiliconFlowImageApi.SiliconFlowImageResponse> imageResponseEntity = this.retryTemplate
- .execute(ctx -> this.siliconFlowImageApi.createImage(imageRequest));
+ ResponseEntity<SiliconFlowImageApi.SiliconFlowImageResponse> imageResponseEntity = RetryUtils.execute(
+ this.retryTemplate, () -> this.siliconFlowImageApi.createImage(imageRequest));
ImageResponse imageResponse = convertResponse(imageResponseEntity, imageRequest);
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/stepfun/StepFunChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/stepfun/StepFunChatModel.java
new file mode 100644
index 0000000..6b115d8
--- /dev/null
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/stepfun/StepFunChatModel.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.stepfun;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * 闃惰穬鏄熻景 {@link ChatModel} 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class StepFunChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://api.stepfun.com";
+
+ public static final String COMPLETE_PATH = "/v1/chat/completions";
+
+ public static final String MODEL_DEFAULT = "step-3.7-flash";
+
+ /**
+ * 鍏煎 OpenAI 鎺ュ彛锛屽鐢� DeepSeek 瀹㈡埛绔�
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux<ChatResponse> stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java
index cbac3b6..65a1c99 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java
@@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo;
-import lombok.RequiredArgsConstructor;
+import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
/**
@@ -14,37 +17,144 @@
* @author fansili
*/
@Slf4j
-@RequiredArgsConstructor
public class XingHuoChatModel implements ChatModel {
- public static final String BASE_URL_V1 = "https://spark-api-open.xf-yun.com";
-
- public static final String BASE_URL_V2 = "https://spark-api-open.xf-yun.com";
- public static final String BASE_COMPLETIONS_PATH_V2 = "/v2/chat/completions";
+ /**
+ * 鏄熺伀 X2
+ *
+ * @see <a href="https://spark-api-open.xf-yun.com/x2/chat/completions">鎺ュ彛鍦板潃</a>
+ */
+ public static final String MODEL_X2 = "x2";
/**
- * 宸茬煡妯″瀷鍚嶅垪琛細x1銆�4.0Ultra銆乬eneralv3.5銆乵ax-32k銆乬eneralv3銆乸ro-128k銆乴ite
+ * 鏄熺伀 X2 Flash
+ *
+ * @see <a href="https://spark-api-open.xf-yun.com/agent/v1/chat/completions">鎺ュ彛鍦板潃</a>
*/
- public static final String MODEL_DEFAULT = "4.0Ultra";
+ public static final String MODEL_X2_FLASH = "x2-flash";
+
+ private static final String BASE_URL_X2 = "https://spark-api-open.xf-yun.com/x2";
+
+ private static final String BASE_URL_X2_FLASH = "https://spark-api-open.xf-yun.com/agent/v1";
+
+ public static final String MODEL_DEFAULT = MODEL_X2_FLASH;
+
+ private static String getBaseUrl(String model) {
+ if (MODEL_X2_FLASH.equals(model)) {
+ return BASE_URL_X2_FLASH;
+ }
+ return BASE_URL_X2;
+ }
+
+ private final String apiKey;
+
+ private final DeepSeekChatOptions options;
/**
- * v1 鍏煎 OpenAI 鎺ュ彛锛岃繘琛屽鐢�
+ * 鍏煎 OpenAI 鎺ュ彛锛岃繘琛屽鐢�
*/
- private final ChatModel openAiChatModelV1;
+ private final ChatModel chatModelX2;
+
+ private final ChatModel chatModelX2Flash;
+
+ private XingHuoChatModel(String apiKey, DeepSeekChatOptions options) {
+ this.apiKey = apiKey;
+ this.options = options;
+ this.chatModelX2 = buildChatModel(MODEL_X2);
+ this.chatModelX2Flash = buildChatModel(MODEL_X2_FLASH);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
@Override
public ChatResponse call(Prompt prompt) {
- return openAiChatModelV1.call(prompt);
+ return getChatModel(prompt).call(buildApiPrompt(prompt));
}
@Override
public Flux<ChatResponse> stream(Prompt prompt) {
- return openAiChatModelV1.stream(prompt);
+ return getChatModel(prompt).stream(buildApiPrompt(prompt));
}
@Override
+ public ChatOptions getOptions() {
+ return options;
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
public ChatOptions getDefaultOptions() {
- return openAiChatModelV1.getDefaultOptions();
+ return getOptions();
+ }
+
+ private ChatModel getChatModel(Prompt prompt) {
+ String model = options.getModel();
+ ChatOptions options = prompt.getOptions();
+ if (options != null && isBusinessModel(options.getModel())) {
+ model = options.getModel();
+ }
+ return getChatModel(model);
+ }
+
+ private ChatModel getChatModel(String model) {
+ if (MODEL_X2_FLASH.equals(model)) {
+ return chatModelX2Flash;
+ }
+ return chatModelX2;
+ }
+
+ private ChatModel buildChatModel(String model) {
+ return DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(getBaseUrl(model))
+ .apiKey(apiKey)
+ .build())
+ .options(options.mutate().model("spark-x").build())
+ .build();
+ }
+
+ private static Prompt buildApiPrompt(Prompt prompt) {
+ ChatOptions options = prompt.getOptions();
+ if (options == null) {
+ return prompt;
+ }
+ return Prompt.builder()
+ .messages(prompt.getInstructions())
+ .chatOptions(options.mutate().model("spark-x").build())
+ .build();
+ }
+
+ private static boolean isBusinessModel(String model) {
+ return MODEL_X2.equals(model) || MODEL_X2_FLASH.equals(model);
+ }
+
+ public static final class Builder {
+
+ private String apiKey;
+
+ private DeepSeekChatOptions options;
+
+ public Builder apiKey(String apiKey) {
+ this.apiKey = apiKey;
+ return this;
+ }
+
+ public Builder options(DeepSeekChatOptions options) {
+ this.options = options;
+ return this;
+ }
+
+ public XingHuoChatModel build() {
+ DeepSeekChatOptions options = this.options != null ? this.options : DeepSeekChatOptions.builder().build();
+ if (StrUtil.isEmpty(options.getModel())) {
+ options = options.mutate().model(MODEL_DEFAULT).build();
+ }
+ return new XingHuoChatModel(apiKey, options);
+ }
+
}
}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/yiyan/YiYanChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/yiyan/YiYanChatModel.java
new file mode 100644
index 0000000..75631e6
--- /dev/null
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/yiyan/YiYanChatModel.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.yiyan;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * 鏂囧績涓�瑷� {@link ChatModel} 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class YiYanChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://qianfan.baidubce.com/v2";
+
+ public static final String MODEL_DEFAULT = "ernie-5.1";
+
+ /**
+ * 鍏煎 OpenAI 鎺ュ彛锛屽鐢� DeepSeek 瀹㈡埛绔�
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux<ChatResponse> stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/zhipu/ZhiPuChatModel.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/zhipu/ZhiPuChatModel.java
new file mode 100644
index 0000000..f22c77c
--- /dev/null
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/zhipu/ZhiPuChatModel.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.zhipu;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import reactor.core.publisher.Flux;
+
+/**
+ * 鏅鸿氨 {@link ChatModel} 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class ZhiPuChatModel implements ChatModel {
+
+ public static final String BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
+
+ public static final String MODEL_DEFAULT = "glm-5.2";
+
+ /**
+ * 鍏煎 OpenAI 鎺ュ彛锛屽鐢� DeepSeek 瀹㈡埛绔�
+ */
+ private final DeepSeekChatModel deepSeekChatModel;
+
+ @Override
+ public ChatResponse call(Prompt prompt) {
+ return deepSeekChatModel.call(prompt);
+ }
+
+ @Override
+ public Flux<ChatResponse> stream(Prompt prompt) {
+ return deepSeekChatModel.stream(prompt);
+ }
+
+ @Override
+ public ChatOptions getOptions() {
+ return deepSeekChatModel.getOptions();
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ @SuppressWarnings("removal")
+ public ChatOptions getDefaultOptions() {
+ return getOptions();
+ }
+
+}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
index 3def2a9..0163edb 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java
@@ -29,14 +29,12 @@
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
-import org.springaicommunity.qianfan.QianFanImageOptions;
import org.springframework.ai.image.ImageModel;
import org.springframework.ai.image.ImageOptions;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.openai.OpenAiImageOptions;
import org.springframework.ai.stabilityai.api.StabilityAiImageOptions;
-import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -167,15 +165,6 @@
return DashScopeImageOptions.builder()
.model(model.getModel()).n(1)
.height(draw.getHeight()).width(draw.getWidth())
- .build();
- } else if (ObjUtil.equal(model.getPlatform(), AiPlatformEnum.YI_YAN.getPlatform())) {
- return QianFanImageOptions.builder()
- .model(model.getModel()).N(1)
- .height(draw.getHeight()).width(draw.getWidth())
- .build();
- } else if (ObjUtil.equal(model.getPlatform(), AiPlatformEnum.ZHI_PU.getPlatform())) {
- return ZhiPuAiImageOptions.builder()
- .model(model.getModel())
.build();
}
throw new IllegalArgumentException("涓嶆敮鎸佺殑 AI 骞冲彴锛�" + model.getPlatform());
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java
index 235e54a..32dd6f0 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java
@@ -198,4 +198,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
index 1518523..d687c54 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
@@ -8,22 +8,23 @@
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
-import org.springaicommunity.moonshot.MoonshotChatOptions;
-import org.springaicommunity.qianfan.QianFanChatOptions;
+import cn.hutool.extra.spring.SpringUtil;
import org.springframework.ai.anthropic.AnthropicChatOptions;
-import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
import org.springframework.ai.chat.messages.*;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.deepseek.DeepSeekAssistantMessage;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
-import org.springframework.ai.minimax.MiniMaxChatOptions;
+import org.springframework.ai.google.genai.GoogleGenAiChatOptions;
import org.springframework.ai.ollama.api.OllamaChatOptions;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.tool.ToolCallback;
-import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
+import org.springframework.core.env.Environment;
import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.API_CONFIG_PLACEHOLDER_NOT_RESOLVED;
/**
* Spring AI 宸ュ叿绫�
@@ -36,13 +37,42 @@
public static final String TOOL_CONTEXT_TENANT_ID = "TENANT_ID";
/**
+ * 瑙f瀽 DB 绛夊姩鎬侀厤缃噷鐨� Spring 鍗犱綅绗︼紝渚嬪 ${OPENAI_API_KEY}
+ *
+ * @param value 寰呰В鏋愮殑閰嶇疆鍊�
+ * @return 瑙f瀽鍚庣殑閰嶇疆鍊�
+ */
+ public static String resolveSpringPlaceholders(String value) {
+ if (StrUtil.isBlank(value) || !StrUtil.contains(value, "${")) {
+ return value;
+ }
+ try {
+ return SpringUtil.getBean(Environment.class).resolveRequiredPlaceholders(value);
+ } catch (IllegalArgumentException ex) {
+ throw exception(API_CONFIG_PLACEHOLDER_NOT_RESOLVED, value);
+ }
+ }
+
+ /**
+ * 鏍¢獙 API Key锛岄伩鍏嶉泦鎴愭祴璇曚娇鐢ㄩ粯璁ゅ崰浣嶅�煎彂璧疯皟鐢ㄣ��
+ *
+ * @param apiKey API Key
+ */
+ public static void validateApiKey(String apiKey) {
+ if (StrUtil.isBlank(apiKey) || "sk-xxxx".equals(apiKey)) {
+ throw new IllegalStateException("apiKey 涓嶈兘涓虹┖");
+ }
+ }
+
+ /**
* 閫氫箟鍗冮棶鏀寔澶氭ā鎬佺殑妯″瀷
*
* @see <a href="https://bailian.console.aliyun.com/cn-beijing/?tab=model#/model-market/all?providers=qwen&capabilities=VU">妯″瀷骞垮満</a>
* @see <a href="https://help.aliyun.com/zh/model-studio/error-code#error-url">蹇呴』寮�鍚� withMultiModel 鍙傛暟</a>
*/
public static final Set<String> TONG_YI_MULTI_MODELS = SetUtils.asSet(
- // qwen3.5 / 3.6 绯诲垪锛堢粺涓�澶氭ā鎬佷富骞诧級
+ // qwen3.5 / 3.6 / 3.7 绯诲垪锛堢粺涓�澶氭ā鎬佷富骞诧級
+ "qwen3.7-max", "qwen3.7-plus", "qwen3.7-flash",
"qwen3.6-plus", "qwen3.6-flash",
"qwen3.5-plus", "qwen3.5-flash",
// qwen-vl 瑙嗚鐞嗚В
@@ -72,32 +102,29 @@
.enableThinking(true) // TODO 鑺嬭壙锛氶粯璁ら兘寮�鍚� thinking 妯″紡锛屽悗缁彲浠ヨ鐢ㄦ埛閰嶇疆
.multiModel(TONG_YI_MULTI_MODELS.contains(model)) // 鏄惁澶氭ā鎬佹ā鍨�
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
- case YI_YAN:
- return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
case DEEP_SEEK:
case DOU_BAO: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
case HUN_YUAN: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
case SILICON_FLOW: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
+ case YI_YAN: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
+ case ZHI_PU: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
case XING_HUO: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
+ case MINI_MAX: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
+ case MOONSHOT: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
+ case BAI_CHUAN: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
+ case STEP_FUN: // 澶嶇敤 DeepSeek 瀹㈡埛绔�
return DeepSeekChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
- case ZHI_PU:
- return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
- case MINI_MAX:
- return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
- case MOONSHOT:
- return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
- .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case OPENAI:
- case GEMINI: // 澶嶇敤 OpenAI 瀹㈡埛绔�
- case BAI_CHUAN: // 澶嶇敤 OpenAI 瀹㈡埛绔�
case GROK: // 澶嶇敤 OpenAI 瀹㈡埛绔�
return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
+ case GEMINI:
+ return GoogleGenAiChatOptions.builder().model(model).temperature(temperature).maxOutputTokens(maxTokens)
+ .toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case AZURE_OPENAI:
- return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
+ return OpenAiChatOptions.builder().model(model).deploymentName(model).azure(true)
+ .temperature(temperature).maxTokens(maxTokens)
.toolCallbacks(toolCallbacks).toolContext(toolContext).build();
case ANTHROPIC:
return AnthropicChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
@@ -159,4 +186,4 @@
return MapUtil.getStr(output.getMetadata(), "reasoningContent");
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-ai/src/main/java/org/springframework/ai/model/tool/DefaultToolExecutionEligibilityPredicate.java b/yudao-module-ai/src/main/java/org/springframework/ai/model/tool/DefaultToolExecutionEligibilityPredicate.java
new file mode 100644
index 0000000..41f5d06
--- /dev/null
+++ b/yudao-module-ai/src/main/java/org/springframework/ai/model/tool/DefaultToolExecutionEligibilityPredicate.java
@@ -0,0 +1,29 @@
+package org.springframework.ai.model.tool;
+
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+
+import java.lang.reflect.Method;
+
+/**
+ * TODO 鑺嬭壙锛歴pring-ai-alibaba 2.0.0-M1.1 浠嶄緷璧栨棫鐨� Spring AI ToolExecutionEligibilityPredicate锛�
+ * 涓存椂琛ラ綈锛涘崌绾у埌鍏煎 Spring AI 2.0.0 鐨� spring-ai-alibaba 鐗堟湰鍚庯紝鍒犻櫎鏈寘涓嬬殑 shim銆�
+ */
+public class DefaultToolExecutionEligibilityPredicate implements ToolExecutionEligibilityPredicate {
+
+ @Override
+ public boolean test(ChatOptions promptOptions, ChatResponse chatResponse) {
+ return isInternalToolExecutionEnabled(promptOptions) && chatResponse != null && chatResponse.hasToolCalls();
+ }
+
+ private static boolean isInternalToolExecutionEnabled(ChatOptions promptOptions) {
+ try {
+ Method method = promptOptions.getClass().getMethod("getInternalToolExecutionEnabled");
+ Object result = method.invoke(promptOptions);
+ return result == null || Boolean.TRUE.equals(result);
+ } catch (ReflectiveOperationException | SecurityException ignored) {
+ return true;
+ }
+ }
+
+}
diff --git a/yudao-module-ai/src/main/java/org/springframework/ai/model/tool/ToolExecutionEligibilityPredicate.java b/yudao-module-ai/src/main/java/org/springframework/ai/model/tool/ToolExecutionEligibilityPredicate.java
new file mode 100644
index 0000000..c267810
--- /dev/null
+++ b/yudao-module-ai/src/main/java/org/springframework/ai/model/tool/ToolExecutionEligibilityPredicate.java
@@ -0,0 +1,21 @@
+package org.springframework.ai.model.tool;
+
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.util.Assert;
+
+import java.util.function.BiPredicate;
+
+/**
+ * TODO 鑺嬭壙锛歴pring-ai-alibaba 2.0.0-M1.1 浠嶄緷璧栨棫鐨� Spring AI ToolExecutionEligibilityPredicate锛�
+ * 涓存椂琛ラ綈锛涘崌绾у埌鍏煎 Spring AI 2.0.0 鐨� spring-ai-alibaba 鐗堟湰鍚庯紝鍒犻櫎鏈寘涓嬬殑 shim銆�
+ */
+public interface ToolExecutionEligibilityPredicate extends BiPredicate<ChatOptions, ChatResponse> {
+
+ default boolean isToolExecutionRequired(ChatOptions promptOptions, ChatResponse chatResponse) {
+ Assert.notNull(promptOptions, "promptOptions cannot be null");
+ Assert.notNull(chatResponse, "chatResponse cannot be null");
+ return test(promptOptions, chatResponse);
+ }
+
+}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java
index c89a9cc..0bf3a9a 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AnthropicChatModelTest.java
@@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import com.anthropic.client.okhttp.AnthropicOkHttpClient;
+import cn.hutool.system.SystemUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.anthropic.AnthropicChatModel;
@@ -14,6 +14,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link AnthropicChatModel} 闆嗘垚娴嬭瘯绫�
@@ -22,13 +25,18 @@
*/
public class AnthropicChatModelTest {
+ private static final String BASE_URL = SystemUtil.get("ANTHROPIC_BASE_URL",
+ "https://api.teamorouter.com");
+ private static final String API_KEY = SystemUtil.get("ANTHROPIC_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 Anthropic API Key
+ private static final String MODEL = SystemUtil.get("ANTHROPIC_MODEL",
+ "claude-sonnet-4-6");
+
private final AnthropicChatModel chatModel = AnthropicChatModel.builder()
- .anthropicClient(AnthropicOkHttpClient.builder()
- .apiKey("sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942")
- .baseUrl("https://aihubmix.com")
- .build())
.options(AnthropicChatOptions.builder()
- .model("claude-sonnet-4-5")
+ .baseUrl(BASE_URL)
+ .apiKey(API_KEY)
+ .model(MODEL)
.temperature(0.7)
.maxTokens(4096)
.build())
@@ -37,6 +45,7 @@
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -46,11 +55,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -59,19 +70,25 @@
// 璋冪敤
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 鎵撳嵃缁撴灉
- flux.doOnNext(System.out::println).then().block();
+ flux.doOnNext(response -> {
+// System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }).then().block();
}
- // TODO @鑺嬭壙锛氶渶瑕佺瓑 spring ai 鍗囩骇锛歨ttps://github.com/spring-projects/spring-ai/pull/2800
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("thkinking 涓嬶紝1+1 涓轰粈涔堢瓑浜� 2 "));
AnthropicChatOptions options = AnthropicChatOptions.builder()
- .model("claude-sonnet-4-5")
- .temperature(1D)
+ .baseUrl(BASE_URL)
+ .apiKey(API_KEY)
+ .model(MODEL)
+ .thinkingEnabled(1024) // https://platform.claude.com/docs/en/build-with-claude/extended-thinking
+ .maxTokens(4096)
.build();
// 璋冪敤
@@ -79,7 +96,7 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java
index 69776d8..8c5a1b8 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/AzureOpenAIChatModelTests.java
@@ -1,44 +1,52 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import com.azure.ai.openai.OpenAIClientBuilder;
-import com.azure.core.credential.AzureKeyCredential;
+import cn.hutool.system.SystemUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
-import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.openai.OpenAiChatModel;
+import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
-import static org.springframework.ai.model.azure.openai.autoconfigure.AzureOpenAiChatProperties.DEFAULT_DEPLOYMENT_NAME;
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
- * {@link AzureOpenAiChatModel} 闆嗘垚娴嬭瘯
+ * Azure OpenAI 闆嗘垚娴嬭瘯
*
* @author 鑺嬮亾婧愮爜
*/
public class AzureOpenAIChatModelTests {
- // TODO @鑺嬭壙锛氭櫄鐐瑰湪璋冩暣
- private final OpenAIClientBuilder openAiApi = new OpenAIClientBuilder()
- .endpoint("https://eastusprejade.openai.azure.com")
- .credential(new AzureKeyCredential("xxx"));
- private final AzureOpenAiChatModel chatModel = AzureOpenAiChatModel.builder()
- .openAIClientBuilder(openAiApi)
- .defaultOptions(AzureOpenAiChatOptions.builder()
- .deploymentName(DEFAULT_DEPLOYMENT_NAME)
+ private static final String BASE_URL = SystemUtil.get("AZURE_OPENAI_BASE_URL",
+ "https://xxx.openai.azure.com");
+ private static final String API_KEY = SystemUtil.get("AZURE_OPENAI_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 Azure OpenAI API Key
+ private static final String DEPLOYMENT_NAME = SystemUtil.get("AZURE_OPENAI_DEPLOYMENT_NAME",
+ "gpt-5.4"); // Azure 涓婂垱寤虹殑妯″瀷閮ㄧ讲鍚嶇О
+
+ private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
+ .options(OpenAiChatOptions.builder()
+ .baseUrl(BASE_URL)
+ .apiKey(API_KEY)
+ .model(DEPLOYMENT_NAME)
+ .microsoftFoundry(true)
+ .deploymentName(DEPLOYMENT_NAME)
+ .temperature(0.7)
.build())
.build();
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -48,12 +56,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -64,7 +73,7 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
index 96a1257..167532a 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/BaiChuanChatModelTests.java
@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -9,12 +9,16 @@
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.openai.OpenAiChatModel;
-import org.springframework.ai.openai.OpenAiChatOptions;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link BaiChuanChatModel} 闆嗘垚娴嬭瘯
@@ -23,22 +27,27 @@
*/
public class BaiChuanChatModelTests {
- private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
+ private static final String API_KEY = SystemUtil.get("BAICHUAN_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑鐧惧窛 API Key
+ private static final String MODEL = SystemUtil.get("BAICHUAN_MODEL",
+ BaiChuanChatModel.MODEL_DEFAULT);
+
+ private final BaiChuanChatModel chatModel = new BaiChuanChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
.baseUrl(BaiChuanChatModel.BASE_URL)
- .apiKey("sk-61b6766a94c70786ed02673f5e16af3c") // apiKey
+ .completionsPath(BaiChuanChatModel.COMPLETE_PATH)
+ .apiKey(API_KEY)
.build())
- .options(OpenAiChatOptions.builder()
- .model("Baichuan4-Turbo") // 妯″瀷锛坔ttps://platform.baichuan-ai.com/docs/api锛�
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL)
.temperature(0.7)
.build())
- .build();
-
- private final BaiChuanChatModel chatModel = new BaiChuanChatModel(openAiChatModel);
+ .build());
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -48,11 +57,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -61,7 +72,10 @@
// 璋冪敤
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 鎵撳嵃缁撴灉
- flux.doOnNext(System.out::println).then().block();
+ flux.doOnNext(response -> {
+// System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }).then().block();
}
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java
index 62f842a..bc6f4a9 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/CozeChatModelTests.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -9,6 +8,7 @@
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
+import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -23,7 +23,7 @@
public class CozeChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl("http://127.0.0.1:3000")
.apiKey("app-4hy2d7fJauSbrKbzTKX1afuP") // apiKey
.build())
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
index 2fbe0ee..51e385a 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -14,6 +15,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link DeepSeekChatModel} 闆嗘垚娴嬭瘯
@@ -22,12 +26,17 @@
*/
public class DeepSeekChatModelTests {
+ private static final String API_KEY = SystemUtil.get("DEEPSEEK_API_KEY",
+ "sk-xxxx");
+ private static final String MODEL = SystemUtil.get("DEEPSEEK_MODEL",
+ "deepseek-v4-flash");
+
private final DeepSeekChatModel chatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
- .apiKey("sk-eaf4172a057344dd9bc64b1f806b6axx") // apiKey
+ .apiKey(API_KEY) // apiKey
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
- .model("deepseek-chat") // 妯″瀷
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL) // 妯″瀷
.temperature(0.7)
.build())
.build();
@@ -35,6 +44,7 @@
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -43,12 +53,13 @@
// 璋冪敤
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
- System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -63,11 +74,12 @@
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
- .model("deepseek-reasoner")
+ .model(MODEL)
.build();
// 璋冪敤
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java
index 64c708d..cde8d60 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DifyChatModelTests.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -9,6 +8,7 @@
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
+import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -23,7 +23,7 @@
public class DifyChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl("http://127.0.0.1:3000")
.apiKey("app-4hy2d7fJauSbrKbzTKX1afuP") // apiKey
.build())
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java
index 38c4f0b..75ce0ad 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -15,6 +16,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link DouBaoChatModel} 闆嗘垚娴嬭瘯
@@ -23,19 +27,19 @@
*/
public class DouBaoChatModelTests {
- /**
- * 鐩告瘮 OpenAIChatModel 鏉ヨ锛孌eepSeekChatModel 鍙互鍏煎璞嗗寘鐨� thinking 鑳藉姏锛�
- */
+ private static final String API_KEY = SystemUtil.get("DOUBAO_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑璞嗗寘 API Key
+ private static final String MODEL = SystemUtil.get("DOUBAO_MODEL",
+ DouBaoChatModel.MODEL_DEFAULT);
+
private final DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(DouBaoChatModel.BASE_URL)
.completionsPath(DouBaoChatModel.COMPLETE_PATH)
- .apiKey("5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272") // apiKey
+ .apiKey(API_KEY)
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
- .model("doubao-1-5-lite-32k-250115") // 妯″瀷锛坉oubao锛�
-// .model("doubao-seed-1-6-thinking-250715") // 妯″瀷锛坉oubao锛�
-// .model("deepseek-r1-250120") // 妯″瀷锛坉eepseek锛�
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL)
.temperature(0.7)
.build())
.build();
@@ -45,6 +49,7 @@
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -54,11 +59,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -67,25 +74,26 @@
// 璋冪敤
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 鎵撳嵃缁撴灉
- flux.doOnNext(System.out::println).then().block();
+ flux.doOnNext(response -> {
+// System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }).then().block();
}
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
- DeepSeekChatOptions options = DeepSeekChatOptions.builder()
- .model("doubao-seed-1-6-thinking-250715")
- .build();
// 璋冪敤
- Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
+ Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java
index 790d908..09e5153 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/FastGPTChatModelTests.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -9,6 +8,7 @@
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
+import org.springframework.ai.openai.OpenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
@@ -23,7 +23,7 @@
public class FastGPTChatModelTests {
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
+ .options(OpenAiChatOptions.builder()
.baseUrl("https://cloud.fastgpt.cn/api")
.apiKey("fastgpt-aqcc61kFtF8CeaglnGAfQOCIDWwjGdJVJHv6hIlMo28otFlva2aZNK") // apiKey
.build())
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java
index f9bd70a..8337157 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java
@@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.system.SystemUtil;
+import com.google.genai.Client;
+import com.google.genai.types.HttpOptions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -9,36 +11,48 @@
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.openai.OpenAiChatModel;
-import org.springframework.ai.openai.OpenAiChatOptions;
+import org.springframework.ai.google.genai.GoogleGenAiChatModel;
+import org.springframework.ai.google.genai.GoogleGenAiChatOptions;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
- * {@link GeminiChatModel} 闆嗘垚娴嬭瘯
+ * {@link GoogleGenAiChatModel} 闆嗘垚娴嬭瘯
*
* @author 鑺嬮亾婧愮爜
*/
public class GeminiChatModelTests {
- private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
- .baseUrl(GeminiChatModel.BASE_URL)
- .apiKey("AIzaSyAVoBxgoFvvte820vEQMma2LKBnC98bqMQ")
- .build())
- .options(OpenAiChatOptions.builder()
- .model(GeminiChatModel.MODEL_DEFAULT) // 妯″瀷
- .temperature(0.7)
- .build())
- .build();
+ private static final String BASE_URL = SystemUtil.get("GEMINI_BASE_URL");
+ private static final String API_KEY = SystemUtil.get("GEMINI_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 Gemini API Key
+ private static final String MODEL = "gemini-3.5-flash";
- private final GeminiChatModel chatModel = new GeminiChatModel(openAiChatModel);
+ private final GoogleGenAiChatModel chatModel = GoogleGenAiChatModel.builder()
+ .genAiClient(buildClient())
+ .options(GoogleGenAiChatOptions.builder()
+ .model(MODEL) // 妯″瀷
+ .temperature(0.7)
+ .build())
+ .build();
+
+ private static Client buildClient() {
+ Client.Builder builder = Client.builder().apiKey(API_KEY);
+ if (StrUtil.isNotBlank(BASE_URL)) {
+ builder.httpOptions(HttpOptions.builder().baseUrl(BASE_URL).build());
+ }
+ return builder.build();
+ }
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -48,11 +62,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -61,7 +77,32 @@
// 璋冪敤
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 鎵撳嵃缁撴灉
- flux.doOnNext(System.out::println).then().block();
+ flux.doOnNext(response -> {
+ System.out.println(response);
+// System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }).then().block();
+ }
+
+ @Test
+ @Disabled
+ public void testStream_thinking() {
+ validateApiKey(API_KEY);
+ // 鍑嗗鍙傛暟
+ List<Message> messages = new ArrayList<>();
+ messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
+ GoogleGenAiChatOptions options = GoogleGenAiChatOptions.builder()
+ .model(MODEL)
+ .thinkingBudget(1024)
+ .includeThoughts(true)
+ .build();
+
+ // 璋冪敤
+ Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
+ // 鎵撳嵃缁撴灉
+ flux.doOnNext(response -> {
+ System.out.println(response);
+// System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }).then().block();
}
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GrokChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GrokChatModelTests.java
new file mode 100644
index 0000000..7301da9
--- /dev/null
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GrokChatModelTests.java
@@ -0,0 +1,77 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+
+import cn.hutool.system.SystemUtil;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.grok.GrokChatModel;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.chat.messages.Message;
+import org.springframework.ai.chat.messages.SystemMessage;
+import org.springframework.ai.chat.messages.UserMessage;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.openai.OpenAiChatModel;
+import org.springframework.ai.openai.OpenAiChatOptions;
+import reactor.core.publisher.Flux;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
+
+/**
+ * {@link GrokChatModel} 闆嗘垚娴嬭瘯
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class GrokChatModelTests {
+
+ private static final String API_KEY = SystemUtil.get("GROK_API_KEY",
+ "sk-xxxx");
+ private static final String MODEL = SystemUtil.get("GROK_MODEL",
+ GrokChatModel.MODEL_DEFAULT);
+
+ private final GrokChatModel chatModel = new GrokChatModel(OpenAiChatModel.builder()
+ .options(OpenAiChatOptions.builder()
+ .baseUrl(GrokChatModel.BASE_URL)
+ .apiKey(API_KEY)
+ .model(MODEL)
+ .temperature(0.7)
+ .build())
+ .build());
+
+ @Test
+ @Disabled
+ public void testCall() {
+ validateApiKey(API_KEY);
+ // 鍑嗗鍙傛暟
+ List<Message> messages = new ArrayList<>();
+ messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
+ messages.add(new UserMessage("1 + 1 = 锛�"));
+
+ // 璋冪敤
+ ChatResponse response = chatModel.call(new Prompt(messages));
+ // 鎵撳嵃缁撴灉
+ System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }
+
+ @Test
+ @Disabled
+ public void testStream() {
+ validateApiKey(API_KEY);
+ // 鍑嗗鍙傛暟
+ List<Message> messages = new ArrayList<>();
+ messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
+ messages.add(new UserMessage("1 + 1 = 锛�"));
+
+ // 璋冪敤
+ Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
+ // 鎵撳嵃缁撴灉
+ flux.doOnNext(response -> {
+// System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }).then().block();
+ }
+
+}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java
index eeafef2..3f894af 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -15,6 +16,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link HunYuanChatModel} 闆嗘垚娴嬭瘯
@@ -23,14 +27,19 @@
*/
public class HunYuanChatModelTests {
+ private static final String API_KEY = SystemUtil.get("HUNYUAN_API_KEY",
+ "sk-xxxx");
+ private static final String MODEL = SystemUtil.get("HUNYUAN_MODEL",
+ HunYuanChatModel.MODEL_DEFAULT);
+
private final DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(HunYuanChatModel.BASE_URL)
.completionsPath(HunYuanChatModel.COMPLETE_PATH)
- .apiKey("sk-abc") // apiKey
+ .apiKey(API_KEY) // apiKey
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
- .model(HunYuanChatModel.MODEL_DEFAULT) // 妯″瀷
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL) // 妯″瀷
.temperature(0.7)
.build())
.build();
@@ -40,6 +49,7 @@
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -48,12 +58,13 @@
// 璋冪敤
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
- System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -68,78 +79,16 @@
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
- .model("hunyuan-a13b")
-// .model("hunyuan-turbos-latest")
+ .model(MODEL)
.build();
// 璋冪敤
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages, options));
- // 鎵撳嵃缁撴灉
- flux.doOnNext(response -> {
-// System.out.println(response);
- System.out.println(response.getResult().getOutput());
- }).then().block();
- }
-
- private final DeepSeekChatModel deepSeekOpenAiChatModel = DeepSeekChatModel.builder()
- .deepSeekApi(DeepSeekApi.builder()
- .baseUrl(HunYuanChatModel.DEEP_SEEK_BASE_URL)
- .completionsPath(HunYuanChatModel.COMPLETE_PATH)
- .apiKey("sk-abc") // apiKey
- .build())
- .defaultOptions(DeepSeekChatOptions.builder()
-// .model(HunYuanChatModel.DEEP_SEEK_MODEL_DEFAULT) // 妯″瀷锛�"deepseek-v3"锛�
- .model("deepseek-r1") // 妯″瀷锛�"deepseek-r1"锛�
- .temperature(0.7)
- .build())
- .build();
-
- private final HunYuanChatModel deepSeekChatModel = new HunYuanChatModel(deepSeekOpenAiChatModel);
-
- @Test
- @Disabled
- public void testCall_deepseek() {
- // 鍑嗗鍙傛暟
- List<Message> messages = new ArrayList<>();
- messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
- messages.add(new UserMessage("1 + 1 = 锛�"));
-
- // 璋冪敤
- ChatResponse response = deepSeekChatModel.call(new Prompt(messages));
- // 鎵撳嵃缁撴灉
- System.out.println(response);
- }
-
- @Test
- @Disabled
- public void testStream_deepseek() {
- // 鍑嗗鍙傛暟
- List<Message> messages = new ArrayList<>();
- messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
- messages.add(new UserMessage("1 + 1 = 锛�"));
-
- // 璋冪敤
- Flux<ChatResponse> flux = deepSeekChatModel.stream(new Prompt(messages));
- // 鎵撳嵃缁撴灉
- flux.doOnNext(System.out::println).then().block();
- }
-
- @Test
- @Disabled
- public void testStream_deepseek_thinking() {
- // 鍑嗗鍙傛暟
- List<Message> messages = new ArrayList<>();
- messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
- DeepSeekChatOptions options = DeepSeekChatOptions.builder()
- .model("deepseek-r1")
- .build();
-
- // 璋冪敤
- Flux<ChatResponse> flux = deepSeekChatModel.stream(new Prompt(messages, options));
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
index 080146e..cafb360 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java
@@ -27,7 +27,7 @@
.ollamaApi(OllamaApi.builder()
.baseUrl("http://127.0.0.1:11434") // Ollama 鏈嶅姟鍦板潃
.build())
- .defaultOptions(OllamaChatOptions.builder()
+ .options(OllamaChatOptions.builder()
.model(OllamaModel.LLAMA3.getName()) // 妯″瀷
.build())
.build();
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java
index 8fb133d..ceefd22 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java
@@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.minimax.MiniMaxChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -7,13 +9,16 @@
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.minimax.MiniMaxChatModel;
-import org.springframework.ai.minimax.MiniMaxChatOptions;
-import org.springframework.ai.minimax.api.MiniMaxApi;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link MiniMaxChatModel} 鐨勯泦鎴愭祴璇�
@@ -22,14 +27,24 @@
*/
public class MiniMaxChatModelTests {
- private final MiniMaxChatModel chatModel = new MiniMaxChatModel(
- new MiniMaxApi("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLnjovmlofmlowiLCJVc2VyTmFtZSI6IueOi-aWh-aWjCIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxODk3Mjg3MjQ5NDU2ODA4MzQ2IiwiUGhvbmUiOiIxNTYwMTY5MTM5OSIsIkdyb3VwSUQiOiIxODk3Mjg3MjQ5NDQ4NDE5NzM4IiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDMtMTEgMTI6NTI6MDIiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.aAuB7gWW_oA4IYhh-CF7c9MfWWxKN49B_HK-DYjXaDwwffhiG-H1571z1WQhp9QytWG-DqgLejneeSxkiq1wQIe3FsEP2wz4BmGBct31LehbJu8ehLxg_vg75Uod1nFAHbm5mZz6JSVLNIlSo87Xr3UtSzJhAXlapEkcqlA4YOzOpKrZ8l5_OJPTORTCmHWZYgJcRS-faNiH62ZnUEHUozesTFhubJHo5GfJCw_edlnmfSUocERV1BjWvenhZ9My-aYXNktcW9WaSj9l6gayV7A0Ium_PL55T9ln1PcI8gayiVUKJGJDoqNyF1AF9_aF9NOKtTnQzwNqnZdlTYH6hw"), // 瀵嗛挜
- MiniMaxChatOptions.builder()
- .model(MiniMaxApi.ChatModel.ABAB_6_5_G_Chat.getValue()) // 妯″瀷
- .build());
+ private static final String API_KEY = SystemUtil.get("MINIMAX_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 MiniMax API Key
+ private static final String MODEL = SystemUtil.get("MINIMAX_MODEL",
+ MiniMaxChatModel.MODEL_DEFAULT);
+
+ private final MiniMaxChatModel chatModel = new MiniMaxChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(MiniMaxChatModel.BASE_URL)
+ .apiKey(API_KEY)
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL)
+ .build())
+ .build());
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -39,12 +54,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -55,19 +71,19 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
- // TODO @鑺嬭壙锛氭殏鏃舵病瑙f瀽 reasoning_content 缁撴灉锛岄渶瑕佺瓑瀹樻柟淇
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
- MiniMaxChatOptions options = MiniMaxChatOptions.builder()
- .model("MiniMax-M1")
+ DeepSeekChatOptions options = DeepSeekChatOptions.builder()
+ .model(MODEL)
.build();
// 璋冪敤
@@ -75,7 +91,7 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
index b50ab80..22d04bf 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java
@@ -1,19 +1,24 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.moonshot.MoonshotChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import org.springaicommunity.moonshot.MoonshotChatModel;
-import org.springaicommunity.moonshot.MoonshotChatOptions;
-import org.springaicommunity.moonshot.api.MoonshotApi;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link MoonshotChatModel} 鐨勯泦鎴愭祴璇�
@@ -22,18 +27,27 @@
*/
public class MoonshotChatModelTests {
- private final MoonshotChatModel chatModel = MoonshotChatModel.builder()
- .moonshotApi(MoonshotApi.builder()
- .apiKey("sk-aHYYV1SARscItye5QQRRNbXij4fy65Ee7pNZlC9gsSQnUKXA") // 瀵嗛挜
+ private static final String API_KEY = SystemUtil.get("MOONSHOT_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 Moonshot API Key
+ private static final String MODEL = SystemUtil.get("MOONSHOT_MODEL",
+ MoonshotChatModel.MODEL_DEFAULT);
+
+ private final MoonshotChatModel chatModel = new MoonshotChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(MoonshotChatModel.BASE_URL)
+ .completionsPath(MoonshotChatModel.COMPLETE_PATH)
+ .apiKey(API_KEY)
.build())
- .defaultOptions(MoonshotChatOptions.builder()
- .model("kimi-k2-0711-preview") // 妯″瀷
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL)
+ .temperature(1D)
.build())
- .build();
+ .build());
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -43,12 +57,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -59,20 +74,19 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
- // TODO @鑺嬭壙锛氭殏鏃舵病瑙f瀽 reasoning_content 缁撴灉锛岄渶瑕佺瓑瀹樻柟淇
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
- MoonshotChatOptions options = MoonshotChatOptions.builder()
-// .model("kimi-k2-0711-preview")
- .model("kimi-thinking-preview")
+ DeepSeekChatOptions options = DeepSeekChatOptions.builder()
+ .model(MODEL)
.build();
// 璋冪敤
@@ -80,7 +94,7 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
index c03a5de..119d569 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OllamaChatModelTests.java
@@ -26,7 +26,7 @@
.ollamaApi(OllamaApi.builder()
.baseUrl("http://127.0.0.1:11434") // Ollama 鏈嶅姟鍦板潃
.build())
- .defaultOptions(OllamaChatOptions.builder()
+ .options(OllamaChatOptions.builder()
// .model("qwen") // 妯″瀷锛坔ttps://ollama.com/library/qwen锛�
.model("deepseek-r1") // 妯″瀷锛坔ttps://ollama.com/library/deepseek-r1锛�
.build())
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
index 9f1d6eb..9c5fa52 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java
@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
-import com.azure.ai.openai.models.ReasoningEffortValue;
+import cn.hutool.system.SystemUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -17,6 +16,8 @@
import java.util.List;
import java.util.Objects;
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
+
/**
* {@link OpenAiChatModel} 闆嗘垚娴嬭瘯
*
@@ -24,14 +25,18 @@
*/
public class OpenAIChatModelTests {
+ private static final String BASE_URL = SystemUtil.get("OPENAI_BASE_URL",
+ "https://api.teamorouter.com/v1");
+ private static final String API_KEY = SystemUtil.get("OPENAI_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 OpenAI API Key
+ private static final String MODEL = SystemUtil.get("OPENAI_MODEL",
+ "gpt-5.5");
+
private final OpenAiChatModel chatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
- .baseUrl("https://api.holdai.top")
- .apiKey("sk-z5joyRoV1iFEnh2SAi8QPNrIZTXyQSyxTmD5CoNDQbFixK2l") // apiKey
- .build())
.options(OpenAiChatOptions.builder()
- .model("gpt-5-nano-2025-08-07") // 妯″瀷
-// .model("o1") // 妯″瀷
+ .baseUrl(BASE_URL)
+ .apiKey(API_KEY)
+ .model(MODEL)
.temperature(0.7)
.build())
.build();
@@ -39,6 +44,7 @@
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -54,6 +60,7 @@
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -72,14 +79,16 @@
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
OpenAiChatOptions options = OpenAiChatOptions.builder()
- .model("gpt-5")
-// .model("o4-mini")
-// .model("o3-pro")
- .reasoningEffort(ReasoningEffortValue.LOW.getValue())
+ .baseUrl(BASE_URL)
+ .apiKey(API_KEY)
+ .model(MODEL)
+ .reasoningEffort("low") // https://help.openai.com/zh-hant/articles/5072518-controlling-the-length-of-openai-model-responses
+ .maxCompletionTokens(1024)
.build();
// 璋冪敤
@@ -90,7 +99,5 @@
System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
-
-
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java
index 3bb58e6..6064cfd 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowChatModel;
import org.junit.jupiter.api.Disabled;
@@ -16,6 +17,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link SiliconFlowChatModel} 闆嗘垚娴嬭瘯
@@ -24,15 +28,22 @@
*/
public class SiliconFlowChatModelTests {
+ private static final String API_KEY = SystemUtil.get("SILICONFLOW_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 SiliconFlow API Key
+ private static final String MODEL = SystemUtil.get("SILICONFLOW_MODEL",
+ SiliconFlowApiConstants.MODEL_DEFAULT);
+
private final DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
.deepSeekApi(DeepSeekApi.builder()
.baseUrl(SiliconFlowApiConstants.DEFAULT_BASE_URL)
- .apiKey("sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz") // apiKey
+ .apiKey(API_KEY)
.build())
- .defaultOptions(DeepSeekChatOptions.builder()
- .model(SiliconFlowApiConstants.MODEL_DEFAULT) // 妯″瀷
-// .model("deepseek-ai/DeepSeek-R1") // 妯″瀷锛坉eepseek-ai/DeepSeek-R1锛夊彲鐢ㄨ禒璐�
-// .model("Pro/deepseek-ai/DeepSeek-R1") // 妯″瀷锛圥ro/deepseek-ai/DeepSeek-R1锛夐渶瑕佷粯璐�
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL) // 妯″瀷
+// .model("deepseek-ai/DeepSeek-V4-Flash") // 妯″瀷
+// .model("moonshotai/Kimi-K2.7-Code") // 妯″瀷
+// .model("moonshotai/Kimi-K2.6") // 妯″瀷
+// .model("zai-org/GLM-5.2") // 妯″瀷
.temperature(0.7)
.build())
.build();
@@ -42,6 +53,7 @@
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -56,6 +68,7 @@
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -70,11 +83,12 @@
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
- .model("deepseek-ai/DeepSeek-R1")
+ .model(MODEL)
.build();
// 璋冪敤
@@ -82,7 +96,7 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/StepFunChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/StepFunChatModelTests.java
new file mode 100644
index 0000000..e84a94a
--- /dev/null
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/StepFunChatModelTests.java
@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+
+import cn.hutool.system.SystemUtil;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.stepfun.StepFunChatModel;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.ai.chat.messages.Message;
+import org.springframework.ai.chat.messages.SystemMessage;
+import org.springframework.ai.chat.messages.UserMessage;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
+import reactor.core.publisher.Flux;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
+
+/**
+ * {@link StepFunChatModel} 闆嗘垚娴嬭瘯
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class StepFunChatModelTests {
+
+ private static final String API_KEY = SystemUtil.get("STEPFUN_API_KEY",
+ "sk-xxxx");
+ private static final String MODEL = SystemUtil.get("STEPFUN_MODEL",
+ StepFunChatModel.MODEL_DEFAULT);
+
+ private final StepFunChatModel chatModel = new StepFunChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(StepFunChatModel.BASE_URL)
+ .completionsPath(StepFunChatModel.COMPLETE_PATH)
+ .apiKey(API_KEY)
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL)
+ .temperature(0.7)
+ .build())
+ .build());
+
+ @Test
+ @Disabled
+ public void testCall() {
+ validateApiKey(API_KEY);
+ // 鍑嗗鍙傛暟
+ List<Message> messages = new ArrayList<>();
+ messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
+ messages.add(new UserMessage("1 + 1 = 锛�"));
+
+ // 璋冪敤
+ ChatResponse response = chatModel.call(new Prompt(messages));
+ // 鎵撳嵃缁撴灉
+ System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }
+
+ @Test
+ @Disabled
+ public void testStream() {
+ validateApiKey(API_KEY);
+ // 鍑嗗鍙傛暟
+ List<Message> messages = new ArrayList<>();
+ messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
+ messages.add(new UserMessage("1 + 1 = 锛�"));
+
+ // 璋冪敤
+ Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
+ // 鎵撳嵃缁撴灉
+ flux.doOnNext(response -> {
+// System.out.println(response);
+// System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ System.out.println(response.getResult() != null ? response.getResult().getOutput() : null);
+ }).then().block();
+ }
+
+}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java
index 056709d..8c2fb5d 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java
@@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.ai.util.AiUtils;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
@@ -22,7 +24,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
import static java.util.Arrays.asList;
/**
@@ -32,13 +36,18 @@
*/
public class TongYiChatModelTests {
+ private static final String API_KEY = SystemUtil.get("DASHSCOPE_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 DashScope API Key
+ private static final String MODEL = SystemUtil.get("DASHSCOPE_MODEL",
+ "qwen3.7-plus");
+
private final DashScopeChatModel chatModel = DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder()
- .apiKey("sk-cd9f39e99ea54840bd1888282325f55a") // https://bailian.console.aliyun.com/cn-beijing/?tab=model#/api-key 鑾峰彇瀵嗛挜
+ .apiKey(API_KEY)
.build())
.defaultOptions(DashScopeChatOptions.builder()
- .multiModel(true) // 娉ㄦ剰锛氬綋浣跨敤 qwen3.6-plus 绛夊妯℃�佹ā鍨嬶紝闇�瑕佽缃负 true锛屽彲瑙� https://help.aliyun.com/zh/model-studio/error-code#error-url 閾炬帴
- .model("qwen3.6-plus") // 妯″瀷
+ .multiModel(AiUtils.TONG_YI_MULTI_MODELS.contains(MODEL)) // 澶氭ā鎬佹ā鍨嬮渶瑕佽缃负 true锛屽彲瑙� https://help.aliyun.com/zh/model-studio/error-code#error-url
+ .model(MODEL) // 妯″瀷
// .model("deepseek-r1") // 妯″瀷锛坉eepseek-r1锛�
// .model("deepseek-v3") // 妯″瀷锛坉eepseek-v3锛�
// .model("deepseek-r1-distill-qwen-1.5b") // 妯″瀷锛坉eepseek-r1-distill-qwen-1.5b锛�
@@ -49,6 +58,7 @@
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -58,12 +68,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
// messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -74,18 +85,19 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
DashScopeChatOptions options = DashScopeChatOptions.builder()
- .model("qwen3.6-plus").multiModel(true)
+ .model(MODEL).multiModel(AiUtils.TONG_YI_MULTI_MODELS.contains(MODEL))
// .withModel("qwen-max-2025-01-25")
.enableThinking(true) // 蹇呴』璁剧疆锛屽惁鍒欎細鎶ラ敊
.build();
@@ -95,17 +107,18 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
@Test
@Disabled
public void testRerank() {
+ validateApiKey(API_KEY);
// 鍑嗗鐜
RerankModel rerankModel = new DashScopeRerankModel(
DashScopeApi.builder()
- .apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
+ .apiKey(API_KEY)
.build());
// 鍑嗗鍙傛暟
String query = "spring";
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java
index 77dbd2b..2e08cf6 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.xinghuo.XingHuoChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -8,13 +9,14 @@
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.deepseek.DeepSeekChatOptions;
-import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link XingHuoChatModel} 闆嗘垚娴嬭瘯
@@ -23,24 +25,23 @@
*/
public class XingHuoChatModelTests {
- private final DeepSeekChatModel openAiChatModel = DeepSeekChatModel.builder()
- .deepSeekApi(DeepSeekApi.builder()
- .baseUrl(XingHuoChatModel.BASE_URL_V2)
- .completionsPath(XingHuoChatModel.BASE_COMPLETIONS_PATH_V2)
- .apiKey("75b161ed2aef4719b275d6e7f2a4d4cd:YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz") // appKey:secretKey
- .build())
- .defaultOptions(DeepSeekChatOptions.builder()
-// .model("generalv3.5") // 妯″瀷
- .model("x1") // 妯″瀷
- .temperature(0.7)
- .build())
- .build();
+ private static final String API_KEY = SystemUtil.get("XINGHUO_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑璁鏄熺伀 API Key
+ private static final String MODEL = SystemUtil.get("XINGHUO_MODEL",
+ XingHuoChatModel.MODEL_DEFAULT);
- private final XingHuoChatModel chatModel = new XingHuoChatModel(openAiChatModel);
+ private final XingHuoChatModel chatModel = XingHuoChatModel.builder()
+ .apiKey(API_KEY)
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL)
+ .temperature(0.7)
+ .build())
+ .build();
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -55,6 +56,7 @@
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -69,11 +71,12 @@
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
DeepSeekChatOptions options = DeepSeekChatOptions.builder()
- .model("x1")
+ .model(MODEL)
.build();
// 璋冪敤
@@ -81,7 +84,7 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
index cb7be2a..068a062 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/YiYanChatModelTests.java
@@ -1,62 +1,76 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.yiyan.YiYanChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import org.springaicommunity.qianfan.QianFanChatModel;
-import org.springaicommunity.qianfan.QianFanChatOptions;
-import org.springaicommunity.qianfan.api.QianFanApi;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
-// TODO @鑺嬭壙锛氱櫨搴﹀崈甯� API 鎻愪緵浜� V2 鐗堟湰锛岀洰鍓� Spring AI 涓嶅吋瀹癸紝鍙叧閿� <https://github.com/spring-projects/spring-ai/issues/2179> 杩涘睍
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
+
/**
- * {@link QianFanChatModel} 鐨勯泦鎴愭祴璇�
+ * {@link YiYanChatModel} 鐨勯泦鎴愭祴璇�
*
* @author fansili
*/
public class YiYanChatModelTests {
- private final QianFanChatModel chatModel = new QianFanChatModel(
- new QianFanApi("DGnyzREuaY7av7c38bOM9Ji2", "9aR8myflEOPDrEeLhoXv0FdqANOAyIZW"), // 瀵嗛挜
- QianFanChatOptions.builder()
- .model("ERNIE-4.5-8K-Preview")
- .build()
- );
+ private static final String API_KEY = SystemUtil.get("YIYAN_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑鏂囧績涓�瑷� API Key
+ private static final String MODEL = SystemUtil.get("YIYAN_MODEL",
+ YiYanChatModel.MODEL_DEFAULT);
+
+ private final YiYanChatModel chatModel = new YiYanChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(YiYanChatModel.BASE_URL)
+ .apiKey(API_KEY)
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL)
+ .build())
+ .build());
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
- // TODO @鑺嬭壙锛氭枃蹇冧竴瑷�锛屽彧瑕佸甫涓� system message 灏辨姤閿欙紝宸茬粡鍚勭娴嬭瘯锛屽緢鑾悕锛�
-// messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
messages.add(new UserMessage("1 + 1 = 锛�"));
// 璋冪敤
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
- // TODO @鑺嬭壙锛氭枃蹇冧竴瑷�锛屽彧瑕佸甫涓� system message 灏辨姤閿欙紝宸茬粡鍚勭娴嬭瘯锛屽緢鑾悕锛�
-// messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
messages.add(new UserMessage("1 + 1 = 锛�"));
// 璋冪敤
Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
// 鎵撳嵃缁撴灉
- flux.doOnNext(System.out::println).then().block();
+ flux.doOnNext(response -> {
+// System.out.println(response);
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
+ }).then().block();
}
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java
index 18c3179..1abaa43 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java
@@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat;
+import cn.hutool.system.SystemUtil;
+import cn.iocoder.yudao.module.ai.framework.ai.core.model.zhipu.ZhiPuChatModel;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.messages.Message;
@@ -7,31 +9,43 @@
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
-import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
-import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
+import org.springframework.ai.deepseek.DeepSeekChatModel;
+import org.springframework.ai.deepseek.DeepSeekChatOptions;
+import org.springframework.ai.deepseek.api.DeepSeekApi;
import reactor.core.publisher.Flux;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
- * {@link ZhiPuAiChatModel} 鐨勯泦鎴愭祴璇�
+ * {@link ZhiPuChatModel} 鐨勯泦鎴愭祴璇�
*
* @author 鑺嬮亾婧愮爜
*/
public class ZhiPuAiChatModelTests {
- private final ZhiPuAiChatModel chatModel = new ZhiPuAiChatModel(
- ZhiPuAiApi.builder().apiKey("2f35fb6ca4ea41fab898729b7fac086c.6ESSfPcCkxaKEUlR").build(), // 瀵嗛挜
- ZhiPuAiChatOptions.builder()
- .model(ZhiPuAiApi.ChatModel.GLM_4.getName()) // 妯″瀷
+ private static final String API_KEY = SystemUtil.get("ZHIPU_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑鏅鸿氨 API Key
+ private static final String MODEL = SystemUtil.get("ZHIPU_MODEL",
+ ZhiPuChatModel.MODEL_DEFAULT);
+
+ private final ZhiPuChatModel chatModel = new ZhiPuChatModel(DeepSeekChatModel.builder()
+ .deepSeekApi(DeepSeekApi.builder()
+ .baseUrl(ZhiPuChatModel.BASE_URL)
+ .apiKey(API_KEY)
+ .build())
+ .options(DeepSeekChatOptions.builder()
+ .model(MODEL)
.build()
- );
+ ).build());
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -41,12 +55,13 @@
ChatResponse response = chatModel.call(new Prompt(messages));
// 鎵撳嵃缁撴灉
System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}
@Test
@Disabled
public void testStream() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("浣犳槸涓�涓紭璐ㄧ殑鏂囪█鏂囦綔鑰咃紝鐢ㄦ枃瑷�鏂囨弿杩扮潃鍚勫煄甯傜殑浜烘枃椋庢櫙銆�"));
@@ -57,19 +72,19 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
- // TODO @鑺嬭壙锛氭殏鏃舵病瑙f瀽 reasoning_content 缁撴灉锛岄渶瑕佺瓑瀹樻柟淇
@Test
@Disabled
public void testStream_thinking() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage("璇︾粏鍒嗘瀽涓嬶紝濡備綍璁捐涓�涓數鍟嗙郴缁燂紵"));
- ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder()
- .model("GLM-4.5")
+ DeepSeekChatOptions options = DeepSeekChatOptions.builder()
+ .model(MODEL)
.build();
// 璋冪敤
@@ -77,7 +92,7 @@
// 鎵撳嵃缁撴灉
flux.doOnNext(response -> {
// System.out.println(response);
- System.out.println(response.getResult().getOutput());
+ System.out.println(Objects.requireNonNull(response.getResult()).getOutput());
}).then().block();
}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
index a1675b1..a30e7cf 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/OpenAiImageModelTests.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.image;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.image.ImageOptions;
@@ -16,10 +15,12 @@
*/
public class OpenAiImageModelTests {
- private final OpenAiImageModel imageModel = new OpenAiImageModel(OpenAIOkHttpClient.builder()
- .baseUrl("https://api.holdai.top") // apiKey
- .apiKey("sk-PytRecQlmjEteoa2RRN6cGnwslo72UUPLQVNEMS6K9yjbmpD")
- .build());
+ private final OpenAiImageModel imageModel = OpenAiImageModel.builder()
+ .options(OpenAiImageOptions.builder()
+ .baseUrl("https://api.holdai.top") // apiKey
+ .apiKey("sk-xxx")
+ .build())
+ .build();
@Test
@Disabled
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java
deleted file mode 100644
index 156360f..0000000
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/QianFanImageTests.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package cn.iocoder.yudao.module.ai.framework.ai.core.model.image;
-
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-import org.springaicommunity.qianfan.QianFanImageModel;
-import org.springaicommunity.qianfan.QianFanImageOptions;
-import org.springaicommunity.qianfan.api.QianFanImageApi;
-import org.springframework.ai.image.ImagePrompt;
-import org.springframework.ai.image.ImageResponse;
-
-import static cn.iocoder.yudao.module.ai.framework.ai.core.model.image.StabilityAiImageModelTests.viewImage;
-
-// TODO @鑺嬭壙锛氱櫨搴﹀崈甯� API 鎻愪緵浜� V2 鐗堟湰锛岀洰鍓� Spring AI 涓嶅吋瀹癸紝鍙叧閿� <https://github.com/spring-projects/spring-ai/issues/2179> 杩涘睍
-
-/**
- * {@link QianFanImageModel} 闆嗘垚娴嬭瘯绫�
- */
-public class QianFanImageTests {
-
- private final QianFanImageModel imageModel = new QianFanImageModel(
- new QianFanImageApi("qS8k8dYr2nXunagK4SSU8Xjj", "pHGbx51ql2f0hOyabQvSZezahVC3hh3e")); // 瀵嗛挜
-
- @Test
- @Disabled
- public void testCall() {
- // 鍑嗗鍙傛暟
- // 鍙敮鎸� 1024x1024銆�768x768銆�768x1024銆�1024x768銆�576x1024銆�1024x576
- QianFanImageOptions imageOptions = QianFanImageOptions.builder()
- .model(QianFanImageApi.ImageModel.Stable_Diffusion_XL.getValue())
- .width(1024).height(1024)
- .N(1)
- .build();
- ImagePrompt prompt = new ImagePrompt("good", imageOptions);
-
- // 鏂规硶璋冪敤
- ImageResponse response = imageModel.call(prompt);
- // 鎵撳嵃缁撴灉
- String b64Json = response.getResult().getOutput().getB64Json();
- System.out.println(response);
- viewImage(b64Json);
- }
-
-}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/SiliconFlowImageModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/SiliconFlowImageModelTests.java
index 5e58c40..887832d 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/SiliconFlowImageModelTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/SiliconFlowImageModelTests.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.image;
+import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageApi;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageModel;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageOptions;
@@ -8,18 +9,24 @@
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
+
/**
* {@link SiliconFlowImageModel} 闆嗘垚娴嬭瘯
*/
public class SiliconFlowImageModelTests {
+ private static final String API_KEY = SystemUtil.get("SILICONFLOW_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 SiliconFlow API Key
+
private final SiliconFlowImageModel imageModel = new SiliconFlowImageModel(
- new SiliconFlowImageApi("sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz") // 瀵嗛挜
+ new SiliconFlowImageApi(API_KEY)
);
@Test
@Disabled
public void testCall() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
SiliconFlowImageOptions imageOptions = SiliconFlowImageOptions.builder()
.model("Kwai-Kolors/Kolors")
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java
index a556f79..dbc3546 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.image;
+import cn.hutool.system.SystemUtil;
import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
@@ -8,6 +9,8 @@
import org.springframework.ai.image.ImageOptions;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
+
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
/**
* {@link DashScopeImageModel} 闆嗘垚娴嬭瘯绫�
@@ -24,9 +27,12 @@
*/
public class TongYiImagesModelTest {
+ private static final String API_KEY = SystemUtil.get("DASHSCOPE_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑 DashScope API Key
+
private final DashScopeImageModel imageModel = DashScopeImageModel.builder()
.dashScopeApi(DashScopeImageApi.builder()
- .apiKey("sk-cd9f39e99ea54840bd1888282325f55a") // https://bailian.console.aliyun.com/cn-beijing/?tab=model#/api-key 鑾峰彇瀵嗛挜
+ .apiKey(API_KEY)
.build())
.build();
@@ -34,6 +40,7 @@
@Test
@Disabled
public void imageCallTest() {
+ validateApiKey(API_KEY);
// 鍑嗗鍙傛暟
ImageOptions options = DashScopeImageOptions.builder()
.model("wan2.7-image")
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/ZhiPuAiImageModelTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/ZhiPuAiImageModelTests.java
deleted file mode 100644
index bb16aac..0000000
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/ZhiPuAiImageModelTests.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package cn.iocoder.yudao.module.ai.framework.ai.core.model.image;
-
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-import org.springframework.ai.image.ImagePrompt;
-import org.springframework.ai.image.ImageResponse;
-import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
-import org.springframework.ai.zhipuai.ZhiPuAiImageOptions;
-import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
-
-/**
- * {@link ZhiPuAiImageModel} 闆嗘垚娴嬭瘯
- */
-public class ZhiPuAiImageModelTests {
-
- private final ZhiPuAiImageModel imageModel = new ZhiPuAiImageModel(
- new ZhiPuAiImageApi("78d3228c1d9e5e342a3e1ab349e2dd7b.VXLoq5vrwK2ofboy") // 瀵嗛挜
- );
-
- @Test
- @Disabled
- public void testCall() {
- // 鍑嗗鍙傛暟
- ZhiPuAiImageOptions imageOptions = ZhiPuAiImageOptions.builder()
- .model(ZhiPuAiImageApi.ImageModel.CogView_3.getValue())
- .build();
- ImagePrompt prompt = new ImagePrompt("涓囬噷闀垮煄", imageOptions);
-
- // 鏂规硶璋冪敤
- ImageResponse response = imageModel.call(prompt);
- // 鎵撳嵃缁撴灉
- System.out.println(response);
- }
-
-}
diff --git a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
index 6f5cee0..3efc524 100644
--- a/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
+++ b/yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java
@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.ai.framework.ai.core.model.mcp;
+import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel;
-import com.openai.client.okhttp.OpenAIOkHttpClient;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
@@ -10,16 +10,19 @@
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
+import static cn.iocoder.yudao.module.ai.util.AiUtils.validateApiKey;
+
@Disabled
public class DouBaoMcpTests {
+ private static final String API_KEY = SystemUtil.get("DOUBAO_API_KEY",
+ "sk-xxxx"); // 鎸夐渶鏀规垚浣犵殑璞嗗寘 API Key
+
private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
- .openAiClient(OpenAIOkHttpClient.builder()
- .baseUrl(DouBaoChatModel.BASE_URL)
- .apiKey("5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272") // apiKey
- .build())
.options(OpenAiChatOptions.builder()
- .model("doubao-1-5-lite-32k-250115") // 妯″瀷锛坉oubao锛�
+ .baseUrl(DouBaoChatModel.BASE_URL)
+ .apiKey(API_KEY)
+ .model(DouBaoChatModel.MODEL_DEFAULT) // 妯″瀷锛坉oubao锛�
.temperature(0.7)
.build())
.build();
@@ -36,6 +39,7 @@
@Test
public void testMcpGetUserInfo() {
+ validateApiKey(API_KEY);
// 鎵撳嵃缁撴灉
System.out.println(chatClient.prompt()
.user("鐩墠鏈夊摢浜涘伐鍏峰彲浠ヤ娇鐢�")
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
index 09df9b7..add6f20 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
@@ -196,6 +196,7 @@
@GetMapping("/get-bpmn-model-view")
@Operation(summary = "鑾峰彇娴佺▼瀹炰緥鐨� BPMN 妯″瀷瑙嗗浘", description = "鍦ㄣ�愭祦绋嬭缁嗐�戠晫闈腑锛岃繘琛岃皟鐢�")
@Parameter(name = "id", description = "娴佺▼瀹炰緥鐨勭紪鍙�", required = true)
+ @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<BpmProcessInstanceBpmnModelViewRespVO> getProcessInstanceBpmnModelView(
@RequestParam(value = "id") String id) {
return success(processInstanceService.getProcessInstanceBpmnModelView(id));
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java
index 0a785b1..c8a994d 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java
@@ -107,6 +107,9 @@
@Schema(description = "绛惧悕", example = "https://www.iocoder.cn/sign.png")
private String signPicUrl;
+ @Schema(description = "闄勪欢", example = "[https://test.yudao.iocoder.cn/20260609/test.txt]")
+ private List<String> attachments;
+
}
}
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
index 0969fda..9c65114 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
@@ -21,6 +21,9 @@
@Schema(description = "绛惧悕", example = "https://www.iocoder.cn/sign.png")
private String signPicUrl;
+ @Schema(description = "闄勪欢", example = "[https://test.yudao.iocoder.cn/20260609/test.txt]")
+ private List<String> attachments;
+
@Schema(description = "鍙橀噺瀹炰緥锛堝姩鎬佽〃鍗曪級", requiredMode = Schema.RequiredMode.REQUIRED)
private Map<String, Object> variables;
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java
index d4dca29..21408fd 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java
@@ -5,6 +5,8 @@
import jakarta.validation.constraints.NotEmpty;
+import java.util.List;
+
@Schema(description = "绠$悊鍚庡彴 - 涓嶉�氳繃娴佺▼浠诲姟鐨� Request VO")
@Data
public class BpmTaskRejectReqVO {
@@ -16,4 +18,7 @@
@Schema(description = "瀹℃壒鎰忚", requiredMode = Schema.RequiredMode.REQUIRED, example = "涓嶉敊涓嶉敊锛�")
private String reason;
+ @Schema(description = "闄勪欢", example = "[https://test.yudao.iocoder.cn/20260609/test.txt]")
+ private List<String> attachments;
+
}
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
index 90e7753..fbd5ab7 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
@@ -9,6 +9,7 @@
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
@@ -21,7 +22,6 @@
import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
@@ -34,6 +34,7 @@
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.engine.task.Attachment;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.mapstruct.Mapper;
@@ -82,7 +83,7 @@
if (CollUtil.isNotEmpty(respVO.getTasks())) {
respVO.getTasks().forEach(task -> {
AdminUserRespDTO assigneeUser = userMap.get(task.getAssignee());
- if (assigneeUser!= null) {
+ if (assigneeUser != null) {
task.setAssigneeUser(BeanUtils.toBean(assigneeUser, UserSimpleBaseVO.class));
MapUtils.findAndThen(deptMap, assigneeUser.getDeptId(), dept -> task.getAssigneeUser().setDeptName(dept.getName()));
}
@@ -137,10 +138,10 @@
default BpmMessageSendWhenProcessInstanceRejectReqDTO buildProcessInstanceRejectMessage(ProcessInstance instance, String reason) {
return new BpmMessageSendWhenProcessInstanceRejectReqDTO()
- .setProcessInstanceName(instance.getName())
- .setProcessInstanceId(instance.getId())
- .setReason(reason)
- .setStartUserId(NumberUtils.parseLong(instance.getStartUserId()));
+ .setProcessInstanceName(instance.getName())
+ .setProcessInstanceId(instance.getId())
+ .setReason(reason)
+ .setStartUserId(NumberUtils.parseLong(instance.getStartUserId()));
}
default BpmProcessInstanceBpmnModelViewRespVO buildProcessInstanceBpmnModelView(HistoricProcessInstance processInstance,
@@ -183,8 +184,8 @@
}
default UserSimpleBaseVO buildUser(Long userId,
- Map<Long, AdminUserRespDTO> userMap,
- Map<Long, DeptRespDTO> deptMap) {
+ Map<Long, AdminUserRespDTO> userMap,
+ Map<Long, DeptRespDTO> deptMap) {
if (userId == null) {
return null;
}
@@ -200,13 +201,14 @@
return userVO;
}
- default BpmApprovalDetailRespVO.ActivityNodeTask buildApprovalTaskInfo(HistoricTaskInstance task) {
+ default BpmApprovalDetailRespVO.ActivityNodeTask buildApprovalTaskInfo(HistoricTaskInstance task, List<Attachment> attachments) {
if (task == null) {
return null;
}
return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class)
.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task))
- .setSignPicUrl(FlowableUtils.getTaskSignPicUrl(task));
+ .setSignPicUrl(FlowableUtils.getTaskSignPicUrl(task))
+ .setAttachments(convertList(attachments, Attachment::getUrl));
}
default Set<Long> parseUserIds(HistoricProcessInstance processInstance,
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmAttachmentTypeEnum.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmAttachmentTypeEnum.java
new file mode 100644
index 0000000..fa1bf26
--- /dev/null
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmAttachmentTypeEnum.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.bpm.enums.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 闄勪欢绫诲瀷鏋氫妇
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmAttachmentTypeEnum {
+
+ TASK_ATTACHMENT("1", "鐢ㄦ埛浠诲姟闄勪欢");
+
+ /**
+ * 鎿嶄綔绫诲瀷
+ * <p>
+ * 鐢变簬 BPM attachment 绫诲瀷涓� String锛屾墍浠ヨ繖閲屽氨涓嶄娇鐢� Integer
+ */
+ private final String type;
+ /**
+ * 鎿嶄綔鍚嶅瓧
+ */
+ private final String name;
+}
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java
index 2a45e3a..15d3505 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java
@@ -24,7 +24,7 @@
MULTI_DEPT_LEADER_MULTI(23, "杩炵画澶氱骇閮ㄩ棬鐨勮礋璐d汉"),
POST(22, "宀椾綅"),
USER(30, "鐢ㄦ埛"),
- APPROVE_USER_SELECT(34, "瀹℃壒浜鸿嚜韬�"), // 褰撳墠瀹℃壒浜猴紝鍙湪瀹℃壒鏃讹紝閫夋嫨涓嬩竴涓妭鐐圭殑瀹℃壒浜�
+ APPROVE_USER_SELECT(34, "瀹℃壒浜鸿嚜閫�"), // 褰撳墠瀹℃壒浜猴紝鍙湪瀹℃壒鏃讹紝閫夋嫨涓嬩竴涓妭鐐圭殑瀹℃壒浜�
START_USER_SELECT(35, "鍙戣捣浜鸿嚜閫�"), // 鐢宠浜鸿嚜宸憋紝鍙湪鎻愪氦鐢宠鏃讹紝閫夋嫨姝よ妭鐐圭殑瀹℃壒浜�
START_USER(36, "鍙戣捣浜鸿嚜宸�"), // 鐢宠浜鸿嚜宸�, 涓�鑸揣鎸ㄥ紑濮嬭妭鐐癸紝甯哥敤浜庡彂璧蜂汉淇℃伅瀹℃牳鍦烘櫙
START_USER_DEPT_LEADER(37, "鍙戣捣浜洪儴闂ㄨ礋璐d汉"),
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java
index 6ed6c3a..ee1e3f6 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java
@@ -166,7 +166,7 @@
/**
* 娣诲姞 HTTP 璇锋眰鍙傛暟銆傝姹傚ご鎴栬�呰姹備綋
*
- * @param params HTTP 璇锋眰鍙傛暟
+ * @param headers HTTP 璇锋眰澶�
* @param paramSettings HTTP 璇锋眰鍙傛暟璁剧疆
* @param processVariables 娴佺▼鍙橀噺
*/
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
index b624c53..726e0dc 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
@@ -457,6 +457,54 @@
}
/**
+ * 鏍规嵁鑺傜偣锛岄�掑綊鑾峰彇涓婃父 source 涓� UserTask 鐨勫叆鍙h繛绾�
+ *
+ * 1. 濡傛灉褰撳墠鑺傜偣鐨勭洿鎺ュ叆鍙h繛绾� source 灏辨槸 UserTask锛屽垯鐩存帴杩斿洖璇ヨ繛绾�
+ * 2. 濡傛灉褰撳墠鑺傜偣鐨勭洿鎺ュ叆鍙h繛绾� source 涓嶆槸 UserTask锛屽垯缁х画鍚戜笂閫掑綊鏌ユ壘
+ * 3. 濡傛灉閫掑綊杩囩▼涓亣鍒� StartEvent 鎴� SubProcess锛屽垯鍋滄璇ュ垎鏀户缁悜涓婃煡鎵�
+ *
+ * @param source 璧峰鑺傜偣
+ * @return 涓婃父杩炴帴 UserTask 鐨勫叆鍙h繛绾垮垪琛�
+ */
+ public static List<SequenceFlow> getElementIncomingUserTaskFlows(FlowElement source) {
+ List<SequenceFlow> result = new ArrayList<>();
+ collectElementIncomingUserTaskFlows(source, new HashSet<>(), new HashSet<>(), result);
+ return result;
+ }
+
+ private static void collectElementIncomingUserTaskFlows(FlowElement source, Set<String> visitedSequenceFlowIds,
+ Set<String> resultSequenceFlowIds, List<SequenceFlow> result) {
+ // 濡傛灉鏄紑濮嬭妭鐐规垨瀛愭祦绋嬶紝鍒欏仠姝㈣鍒嗘敮鍚戜笂鏌ユ壘
+ if (source == null || source instanceof StartEvent || source instanceof SubProcess) {
+ return;
+ }
+ // 鑾峰彇鍏ュ彛杩炵嚎
+ List<SequenceFlow> incomingFlows = getElementIncomingFlows(source);
+ if (CollUtil.isEmpty(incomingFlows)) {
+ return;
+ }
+
+ // 寰幆鎵惧埌鐩爣鍏冪礌
+ for (SequenceFlow incomingFlow : incomingFlows) {
+ // 濡傛灉鍙戠幇杩炵嚎閲嶅锛岃鏄庤繛绾垮凡缁忚蛋杩囥�傝烦杩�
+ if (incomingFlow == null || !visitedSequenceFlowIds.add(incomingFlow.getId())) {
+ continue;
+ }
+ // 濡傛灉 source 鏄� UserTask锛屽垯娣诲姞鍒扮粨鏋滀腑
+ FlowElement sourceFlowElement = incomingFlow.getSourceFlowElement();
+ if (sourceFlowElement instanceof UserTask) {
+ if (resultSequenceFlowIds.add(incomingFlow.getId())) {
+ result.add(incomingFlow);
+ }
+ continue;
+ }
+ // 閫掑綊鍚戜笂鏌ユ壘 UserTask
+ collectElementIncomingUserTaskFlows(sourceFlowElement, visitedSequenceFlowIds,
+ resultSequenceFlowIds, result);
+ }
+ }
+
+ /**
* 鏍规嵁鑺傜偣锛岃幏鍙栧嚭鍙h繛绾�
*
* @param source 璧峰鑺傜偣
@@ -910,13 +958,88 @@
}
/**
- * 鏌ユ壘璧峰鑺傜偣涓嬩竴涓敤鎴蜂换鍔″垪琛ㄥ垪琛�
+ * 鏌ユ壘璧峰鑺傜偣涓嬩竴涓敤鎴蜂换鍔″垪琛�, 璇ユ柟娉曚細閫掑綊鍚戜笅鏌ユ壘锛氳烦杩囬潪 UserTask 鑺傜偣, 鏀寔缃戝叧鏉′欢鍒ゆ柇
+ *
+ * <ul>
+ * <li>鎺掍粬缃戝叧锛氳蛋婊¤冻鏉′欢鐨勫敮涓�涓�鏉¤矾寰勶紙鍚粯璁よ矾寰勫厹搴曪級</li>
+ * <li>鍖呭缃戝叧锛氳蛋鎵�鏈夋弧瓒虫潯浠剁殑璺緞</li>
+ * <li>骞惰缃戝叧锛氳蛋鎵�鏈夊嚭鍙h矾寰�</li>
+ * </ul>
+ *
+ * @param currentElement 褰撳墠鑺傜偣
+ * @param bpmnModel BPMN 妯″瀷
+ * @param variables 娴佺▼鍙橀噺锛堢敤浜庣綉鍏虫潯浠跺垽鏂級
+ * @return 涓嬩竴涓敤鎴蜂换鍔¤妭鐐瑰垪琛�
+ */
+ public static List<UserTask> getNextUserTasks(FlowElement currentElement, BpmnModel bpmnModel,
+ Map<String, Object> variables) {
+ return getNextUserTasks(currentElement, bpmnModel, variables, new HashSet<>(), new ArrayList<>());
+ }
+
+ private static List<UserTask> getNextUserTasks(FlowElement currentElement, BpmnModel bpmnModel,
+ Map<String, Object> variables,
+ Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
+ // 1. 鏍规嵁鑺傜偣绫诲瀷鍐冲畾瑕侀亶鍘嗙殑鍑哄彛杩炵嚎
+ // 缃戝叧闇�瑕佹牴鎹潯浠惰〃杈惧紡绛涢�夛紱鍏跺畠鑺傜偣鐩存帴鍙栨墍鏈� outgoing flows
+ List<SequenceFlow> outgoingFlows;
+ if (currentElement instanceof Gateway) {
+ outgoingFlows = getGatewayOutgoingFlows((Gateway) currentElement, variables);
+ } else {
+ outgoingFlows = getElementOutgoingFlows(currentElement);
+ }
+ if (CollUtil.isEmpty(outgoingFlows)) {
+ return userTaskList;
+ }
+ // 2. 閬嶅巻鍑哄彛杩炵嚎锛岄�掑綊鏌ユ壘鐢ㄦ埛浠诲姟
+ for (SequenceFlow outgoingFlow : outgoingFlows) {
+ // 闃叉杩炵嚎鎴愮幆瀵艰嚧姝诲惊鐜�
+ if (hasSequenceFlow.contains(outgoingFlow.getId())) {
+ continue;
+ }
+ hasSequenceFlow.add(outgoingFlow.getId());
+ // 鑾峰彇鐩爣鑺傜偣
+ FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef());
+ if (targetElement == null || targetElement instanceof EndEvent) {
+ continue;
+ }
+ if (targetElement instanceof UserTask) {
+ // 鎵惧埌鐢ㄦ埛浠诲姟锛氬姞鍏ョ粨鏋�
+ userTaskList.add((UserTask) targetElement);
+ } else {
+ // 闈炵敤鎴蜂换鍔★紙缃戝叧銆佹湇鍔′换鍔°�佷腑闂翠簨浠剁瓑锛夛細缁х画閫掑綊鍚戜笅鏌ユ壘
+ getNextUserTasks(targetElement, bpmnModel, variables, hasSequenceFlow, userTaskList);
+ }
+ }
+ return userTaskList;
+ }
+
+ /**
+ * 鏍规嵁缃戝叧绫诲瀷涓庢祦绋嬪彉閲忥紝绛涢�夌綉鍏崇殑鍑哄彛杩炵嚎
+ *
+ * @param gateway 缃戝叧鑺傜偣
+ * @param variables 娴佺▼鍙橀噺
+ * @return 鍛戒腑鐨勫嚭鍙h繛绾垮垪琛�
+ */
+ private static List<SequenceFlow> getGatewayOutgoingFlows(Gateway gateway, Map<String, Object> variables) {
+ if (gateway instanceof ExclusiveGateway) {
+ SequenceFlow matchFlow = findMatchSequenceFlowByExclusiveGateway(gateway, variables);
+ return matchFlow == null ? Collections.emptyList() : Collections.singletonList(matchFlow);
+ }
+ if (gateway instanceof InclusiveGateway) {
+ return new ArrayList<>(findMatchSequenceFlowsByInclusiveGateway(gateway, variables));
+ }
+ // 榛樿锛堝苟琛岀綉鍏崇瓑锛夛細璧版墍鏈夊嚭鍙�
+ return gateway.getOutgoingFlows();
+ }
+
+ /**
+ * 鏌ユ壘璧峰鑺傜偣涓嬩竴涓敤鎴蜂换鍔″垪琛ㄥ垪琛�, 涓嶅垽鏂綉鍏虫潯浠�
*
* @param source 璧峰鑺傜偣
* @return 缁撴灉
*/
public static List<UserTask> getNextUserTasks(FlowElement source) {
- return getNextUserTasks(source, null, null);
+ return getNextUserTasks(source, new HashSet<>(), new ArrayList<>());
}
/**
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
index 4c91611..565deb8 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
@@ -25,8 +25,10 @@
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.TaskInfo;
+import tools.jackson.databind.JsonNode;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -245,10 +247,10 @@
}
// 瑙f瀽琛ㄥ崟閰嶇疆
- Map<String, BpmFormFieldVO> formFieldsMap = new HashMap<>();
+ Map<String, BpmFormFieldVO> formFieldsMap = new LinkedHashMap<>();
processDefinitionInfo.getFormFields().forEach(formFieldStr -> {
- BpmFormFieldVO formField = JsonUtils.parseObject(formFieldStr, BpmFormFieldVO.class);
- parseFormField(formField, formFieldsMap);
+ JsonNode formFieldNode = JsonUtils.parseObject(formFieldStr, JsonNode.class);
+ parseFormField(formFieldNode, formFieldsMap);
});
// 鎯呭喌涓�锛氬綋鑷畾涔変簡鎽樿
@@ -275,18 +277,32 @@
/**
* 閫掑綊瑙f瀽琛ㄥ崟瀛楁
*/
- private static void parseFormField(BpmFormFieldVO formField, Map<String, BpmFormFieldVO> formFieldsMap) {
- if (formField == null) {
+ private static void parseFormField(JsonNode formFieldNode, Map<String, BpmFormFieldVO> formFieldsMap) {
+ if (formFieldNode == null || !formFieldNode.isObject()) {
return;
}
- // 濡傛灉瀛樺湪 children -> 璇存槑鏄竷灞�缁勪欢
- if (formField.getChildren() != null && !formField.getChildren().isEmpty()) {
- for (BpmFormFieldVO child : formField.getChildren()) {
+
+ // 濡傛灉 children 閲屽瓨鍦ㄥ璞¤妭鐐癸紝璇存槑鏄竷灞�缁勪欢锛涘瓧绗︿覆鑺傜偣鏄垎鍓茬嚎銆佹爣绛俱�佹枃瀛楃瓑灞曠ず缁勪欢鍐呭锛岀洿鎺ヨ烦杩囥��
+ JsonNode children = formFieldNode.get("children");
+ if (children != null && children.isArray() && children.size() > 0) {
+ boolean hasObjectChild = false;
+ for (JsonNode child : children) {
+ if (!child.isObject()) {
+ continue;
+ }
+ hasObjectChild = true;
parseFormField(child, formFieldsMap);
}
- return;
+ if (hasObjectChild) {
+ return;
+ }
}
+
// 鐪熷疄瀛楁鎵嶅姞鍏� map
+ BpmFormFieldVO formField = new BpmFormFieldVO()
+ .setType(JsonUtils.getText(formFieldNode, "type"))
+ .setField(JsonUtils.getText(formFieldNode, "field"))
+ .setTitle(JsonUtils.getText(formFieldNode, "title"));
if (StrUtil.isNotBlank(formField.getField())) {
formFieldsMap.put(formField.getField(), formField);
}
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
index 5344dd7..a1050ab 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
@@ -7,7 +7,6 @@
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
@@ -25,6 +24,7 @@
import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeTypeEnum;
+import cn.iocoder.yudao.module.bpm.enums.task.BpmAttachmentTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
@@ -57,6 +57,7 @@
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceBuilder;
+import org.flowable.engine.task.Attachment;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.context.annotation.Lazy;
@@ -275,11 +276,10 @@
processVariables.putAll(reqVO.getProcessVariables());
}
- // 3. 鑾峰彇涓嬩竴涓皢瑕佹墽琛岀殑鑺傜偣闆嗗悎
+ // 3.1 鑾峰彇涓嬩竴涓皢瑕佹墽琛岀殑鑺傜偣闆嗗悎
FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
- List<FlowNode> nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables);
- // 浠呬粎鑾峰彇 UserTask 鑺傜偣 TODO add from jason锛氬鏋滅綉鍏宠妭鐐瑰拰缃戝叧鑺傜偣鐩歌繛锛岃幏鍙栦笅涓� UserTask. 璨屼技鏈夌偣涓嶅噯銆�
- List<FlowNode> nextUserTaskList = CollectionUtils.filterList(nextFlowNodes, node -> node instanceof UserTask);
+ // 3.2 鑾峰彇 UserTask 鑺傜偣
+ List<UserTask> nextUserTaskList = BpmnModelUtils.getNextUserTasks(flowElement, bpmnModel, processVariables);
List<ActivityNode> nextActivityNodes = convertList(nextUserTaskList, node -> new ActivityNode().setId(node.getId())
.setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
.setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
@@ -404,8 +404,13 @@
// 閬嶅巻 tasks 鍒楄〃锛屽彧澶勭悊宸茬粨鏉熺殑 UserTask
// 涓轰粈涔堜笉閫氳繃 activities 鍛紵鍥犱负锛屽姞绛惧満鏅笅锛屽畠鍙瓨鍦ㄤ簬 tasks锛屾病鏈� activities锛屽鑷村鏋滈亶鍘� activities 鐨勮瘽锛屽畠鏃犳硶鎴愪负涓�涓妭鐐�
List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null);
+ // 鑾峰彇宸插畬鎴愯妭鐐圭殑闄勪欢
+ Set<String> endTaskIds = convertSet(endTasks, HistoricTaskInstance::getId);
+ List<Attachment> attachments = taskService.getAttachments(historicProcessInstance.getId(), endTaskIds, BpmAttachmentTypeEnum.TASK_ATTACHMENT);
+ Map<String, List<Attachment>> taskAttachmentMap = convertMultiMap(attachments, Attachment::getTaskId);
List<ActivityNode> approvalNodes = convertList(endTasks, task -> {
FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
+ List<Attachment> taskAttachments = taskAttachmentMap.get(task.getId());
ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName())
.setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey())
? BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType()
@@ -414,7 +419,7 @@
.setStatus(getEndActivityNodeStatus(task))
.setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
.setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime()))
- .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task)));
+ .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task, taskAttachments)));
// 濡傛灉鏄彇娑堢姸鎬侊紝鍒欒烦杩�
if (BpmTaskStatusEnum.isCancelStatus(activityNode.getStatus())) {
return null;
@@ -528,14 +533,14 @@
if (task == null) {
continue;
}
- activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task));
+ activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task, null));
// 鍔犵瀛愪换鍔★紝闇�瑕佽繃婊ゆ帀宸茬粡瀹屾垚鐨勫姞绛惧瓙浠诲姟
List<HistoricTaskInstance> childrenTasks = filterList(
taskService.getAllChildrenTaskListByParentTaskId(activity.getTaskId(), tasks),
childTask -> childTask.getEndTime() == null);
if (CollUtil.isNotEmpty(childrenTasks)) {
activityNode.getTasks().addAll(
- convertList(childrenTasks, BpmProcessInstanceConvert.INSTANCE::buildApprovalTaskInfo));
+ convertList(childrenTasks, item->BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(item, null)));
}
}
// 澶勭悊姣忎釜浠诲姟鐨� candidateUsers 灞炴�э細濡傛灉鏄緷娆″鎵癸紝闇�瑕侀娴嬪畠鐨勫悗缁鎵逛汉銆傚洜涓� Task 鏄鎵瑰畬涓�涓紝鍒涘缓涓�涓柊鐨� Task
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
index f7d260e..36a35b3 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
@@ -4,9 +4,11 @@
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutHandlerTypeEnum;
+import cn.iocoder.yudao.module.bpm.enums.task.BpmAttachmentTypeEnum;
import jakarta.validation.Valid;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.history.HistoricActivityInstance;
+import org.flowable.engine.task.Attachment;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.history.HistoricTaskInstance;
@@ -14,6 +16,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* 娴佺▼浠诲姟瀹炰緥 Service 鎺ュ彛
@@ -184,6 +187,17 @@
*/
List<HistoricTaskInstance> getFinishedTaskListByProcessInstanceIdWithoutCancel(String processInstanceId);
+
+ /**
+ * 鏍规嵁鏉′欢鑾峰彇闄勪欢
+ *
+ * @param processInstanceId 娴佺▼ id
+ * @param taskIds 浠诲姟 id 闆嗗悎
+ * @param attachmentType 闄勪欢绫诲瀷
+ * @return 闄勪欢闆嗗悎
+ */
+ List<Attachment> getAttachments(String processInstanceId, Set<String> taskIds, BpmAttachmentTypeEnum attachmentType);
+
// ========== Update 鍐欏叆鐩稿叧鏂规硶 ==========
/**
diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
index 89b7bb2..73f8a01 100644
--- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
+++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -2,7 +2,9 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
+import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.*;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -19,10 +21,7 @@
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
import cn.iocoder.yudao.module.bpm.enums.definition.*;
-import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
-import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
-import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum;
-import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
+import cn.iocoder.yudao.module.bpm.enums.task.*;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmHttpRequestUtils;
@@ -49,6 +48,7 @@
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.engine.task.Attachment;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
@@ -510,6 +510,18 @@
.orderByHistoricTaskInstanceStartTime().asc().list();
}
+ @Override
+ public List<Attachment> getAttachments(String processInstanceId, Set<String> taskIds, BpmAttachmentTypeEnum attachmentType) {
+ List<Attachment> result = taskService.getProcessInstanceAttachments(processInstanceId);
+ if (CollUtil.isNotEmpty(taskIds)) {
+ result = filterList(result, attachment -> taskIds.contains(attachment.getTaskId()));
+ }
+ if (attachmentType != null) {
+ result = filterList(result, attachment -> attachmentType.getType().equals(attachment.getType()));
+ }
+ return result;
+ }
+
/**
* 鍒ゆ柇鎸囧畾鐢ㄦ埛锛屾槸鍚︽槸褰撳墠浠诲姟鐨勫鎵逛汉
*
@@ -592,6 +604,11 @@
// 2.2 娣诲姞璇勮
taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(),
BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason()));
+ // 2.3 娣诲姞闄勪欢
+ if (CollUtil.isNotEmpty(reqVO.getAttachments())) {
+ reqVO.getAttachments().forEach(attachment -> taskService.createAttachment(BpmAttachmentTypeEnum.TASK_ATTACHMENT.getType(),
+ task.getId(), task.getProcessInstanceId(), FileUtil.getName(URLUtil.getPath(attachment)), null, attachment));
+ }
// 3. 璁剧疆娴佺▼鍙橀噺銆傚鏋滄祦绋嬪彉閲忓墠绔紶绌猴紝闇�瑕佷粠鍘嗗彶瀹炰緥涓幏鍙栵紝鍘熷洜锛氬墠绔〃鍗曞鏋滃湪褰撳墠鑺傜偣鏃犲彲缂栬緫鐨勫瓧娈垫椂 variables 涓�瀹氫細涓虹┖
// 鍦烘櫙涓�锛欰 鑺傜偣鍙戣捣锛孊 鑺傜偣琛ㄥ崟鏃犲彲缂栬緫瀛楁锛屽鎵归�氳繃鏃讹紝C 鑺傜偣闇�瑕佹祦绋嬪彉閲忚幏鍙栦笅涓�涓墽琛岃妭鐐癸紝浣嗗洜涓� B 鑺傜偣鏃犲彲缂栬緫鐨勫瓧娈碉紝variables 涓虹┖锛屾祦绋嬪彲鑳藉嚭鐜伴棶棰樸��
@@ -606,9 +623,9 @@
}
// 4. 鏍¢獙骞跺鐞� APPROVE_USER_SELECT 褰撳墠瀹℃壒浜猴紝閫夋嫨涓嬩竴鑺傜偣瀹℃壒浜虹殑閫昏緫
- Map<String, Object> variables = validateAndSetNextAssignees(task.getTaskDefinitionKey(), processVariables,
+ validateAndSetNextAssignees(task.getTaskDefinitionKey(), processVariables,
bpmnModel, reqVO.getNextAssignees(), instance);
- runtimeService.setVariables(task.getProcessInstanceId(), variables);
+ runtimeService.setVariables(task.getProcessInstanceId(), processVariables);
// 5. 濡傛灉褰撳墠鑺傜偣 Id 瀛樺湪浜庨渶瑕侀娴嬬殑娴佺▼鑺傜偣涓紝浠庝腑绉婚櫎銆� 娴佺▼鍙橀噺鍦ㄥ洖閫�鎿嶄綔涓缃�
Object needSimulateTaskIds = runtimeService.getVariable(task.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS);
@@ -618,8 +635,16 @@
runtimeService.setVariable(task.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS, needSimulateTaskIdsByReturn);
}
- // 6. 璋冪敤 BPM complete 鍘诲畬鎴愪换鍔�
- taskService.complete(task.getId(), variables, true);
+ // 6. 娓呯悊閫�鍥炶缃殑涓嶈嚜鍔ㄩ�氳繃鐨勫彉閲忋�備粎鍦ㄨ鏍囪瀛樺湪鏃舵墠鍒犻櫎锛岄伩鍏嶆瘡娆″畬鎴愪换鍔¢兘浜х敓鏃犺皳鐨� DB delete
+ String returnFlagKey = String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey());
+ if (runtimeService.hasVariable(task.getProcessInstanceId(), returnFlagKey)) {
+ log.info("[approveTask][taskId({}) 娓呯悊閫�鍥炴爣璁板彉閲�({})]", task.getId(), returnFlagKey);
+ runtimeService.removeVariable(task.getProcessInstanceId(), returnFlagKey);
+ }
+
+ // 7. 璋冪敤 BPM complete 鍘诲畬鎴愪换鍔�
+ Map<String,Object> taskVariables = MapUtil.emptyIfNull(reqVO.getVariables()); // task local variables. 涓�鑸敤浜庝换鍔″唴宓屾祦绋嬭〃鍗�
+ taskService.complete(task.getId(), taskVariables, true);
// 銆愬姞绛句笓灞炪�戝鐞嗗姞绛句换鍔�
handleParentTaskIfSign(task.getParentTaskId());
@@ -646,10 +671,10 @@
}
// 1. 鑾峰彇涓嬩竴涓皢瑕佹墽琛岀殑鑺傜偣闆嗗悎
FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey);
- List<FlowNode> nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables);
+ List<UserTask> nextFlowNodes = getNextUserTasks(flowElement, bpmnModel, variables);
// 2. 鏍¢獙閫夋嫨鐨勪笅涓�涓妭鐐圭殑瀹℃壒浜猴紝鏄惁鍚堟硶
- for (FlowNode nextFlowNode : nextFlowNodes) {
+ for (UserTask nextFlowNode : nextFlowNodes) {
Integer candidateStrategy = parseCandidateStrategy(nextFlowNode);
// 2.1 鎯呭喌涓�锛氬鏋滆妭鐐逛腑鐨勫鎵逛汉绛栫暐涓� 鍙戣捣浜鸿嚜閫�
if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())) {
@@ -675,8 +700,12 @@
// 2.2 鎯呭喌浜岋細濡傛灉鑺傜偣涓殑瀹℃壒浜虹瓥鐣ヤ负 瀹℃壒浜猴紝鍦ㄥ鎵规椂閫夋嫨涓嬩竴涓妭鐐圭殑瀹℃壒浜猴紝骞朵笖璇ヨ妭鐐圭殑瀹℃壒浜轰负绌�
if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.APPROVE_USER_SELECT.getStrategy())) {
- // 濡傛灉鑺傜偣瀛樺湪锛屼絾鏈厤缃鎵逛汉
+ // 鐗规畩锛氬鏋滃綋鍓嶈妭鐐瑰凡缁忓瓨鍦ㄥ鎵逛汉锛屽垯涓嶅厑璁歌鐩栥�� 渚嬪骞惰鑺傜偣鍚庯紝璁剧疆鐨勫鎵逛汉鑷�夎妭鐐广�� https://t.zsxq.com/daxv1
Map<String, List<Long>> approveUserSelectAssignees = FlowableUtils.getApproveUserSelectAssignees(processInstance.getProcessVariables());
+ if (approveUserSelectAssignees != null && CollUtil.isNotEmpty(approveUserSelectAssignees.get(nextFlowNode.getId()))) {
+ continue;
+ }
+ // 濡傛灉鑺傜偣瀛樺湪锛屼絾鏈厤缃鎵逛汉
List<Long> assignees = nextAssignees != null ? nextAssignees.get(nextFlowNode.getId()) : null;
if (CollUtil.isEmpty(assignees)) {
throw exception(PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName());
@@ -810,7 +839,13 @@
// 2.2 娣诲姞娴佺▼璇勮
taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(),
BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason()));
- // 2.3 濡傛灉褰撳墠浠诲姟鏃惰鍔犵鐨勶紝鍒欏姞瀹冪殑鏍逛换鍔′篃鏍囪鎴愭湭閫氳繃
+ // 2.3 娣诲姞闄勪欢
+ if (CollUtil.isNotEmpty(reqVO.getAttachments())) {
+ reqVO.getAttachments().forEach(attachment -> taskService.createAttachment(BpmAttachmentTypeEnum.TASK_ATTACHMENT.getType(),
+ task.getId(), task.getProcessInstanceId(), FileUtil.getName(URLUtil.getPath(attachment)), null, attachment));
+ }
+
+ // 2.4 濡傛灉褰撳墠浠诲姟鏃惰鍔犵鐨勶紝鍒欏姞瀹冪殑鏍逛换鍔′篃鏍囪鎴愭湭閫氳繃
// 鐤戦棶锛氫负浠�涔堣鏍囪鏈�氳繃鍛紵
// 鍥炵瓟锛氫緥濡傝 A 浠诲姟琚悜鍓嶅姞绛鹃櫎 B 浠诲姟鏃讹紝B 浠诲姟琚鎵逛笉閫氳繃锛屾鏃� A 浼氳鍙栨秷銆傝�� yudao-ui-admin-vue3 涓嶅睍绀衡�滃凡鍙栨秷鈥濈殑浠诲姟锛屽鑷村睍绀轰笉鍑哄鎵逛笉閫氳繃鐨勭粏鑺傘��
if (task.getParentTaskId() != null) {
@@ -922,14 +957,12 @@
// 涓轰粈涔堜笉鐩存帴浣跨敤 runTaskKeyList 鍛紵鍥犱负鍙兘瀛樺湪澶氫釜瀹℃壒鍒嗘敮锛屼緥濡傝锛欰 -> B -> C 鍜� D -> F锛岃�屽彧瑕� C 鎾ゅ洖鍒� A锛岄渶瑕佹帓闄ゆ帀 F
List<UserTask> returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null);
List<String> returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId);
-
// 2. 缁欏綋鍓嶈琚��鍥炵殑 task 鏁扮粍锛岃缃��鍥炴剰瑙�
taskList.forEach(task -> {
// 闇�瑕佹帓闄ゆ帀锛屼笉闇�瑕佽缃��鍥炴剰瑙佺殑浠诲姟
if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) {
return;
}
-
// 鍒ゆ柇鏄惁鍒嗛厤缁欒嚜宸变换鍔★紝鍥犱负浼氱浠诲姟锛屼竴涓妭鐐逛細鏈夊涓换鍔�
if (isAssignUserTask(userId, task)) { // 鎯呭喌涓�锛氳嚜宸辩殑浠诲姟锛岃繘琛� RETURN 鏍囪
// 2.1.1 娣诲姞璇勮
@@ -950,14 +983,20 @@
// 鐩稿叧 issue: https://github.com/flowable/flowable-engine/issues/3944
// 鈶� flowable 7.2.0 鐗堟湰鍚庯紝缁х画浣跨敤 moveActivityIdsToSingleActivityId 鏂规硶銆傚師鍥狅細flowable 7.2.0 鐗堟湰淇浜嗚闂銆�
// 鐩稿叧 issue锛歨ttps://github.com/YunaiV/ruoyi-vue-pro/issues/1018
+ // 鈶� moveActivityIdsToSingleActivityId 浣跨敤閬囧埌闂锛� 鐩稿叧 issue https://gitee.com/zhijiantianya/yudao-cloud/issues/IJM8MS
+ // 鏀规垚 moveExecutionsToSingleActivityId 濂藉儚骞舵病鏈夐亣鍒� 鈶� 鎻愬埌鐨勮秴鏃舵彁閱掑け鏁堢殑闂銆傛殏鏃跺厛鏀瑰洖 moveExecutionsToSingleActivityId
+ // 鈶� moveExecutionsToSingleActivityId 鍥為��澶氬疄渚嬬殑鏃跺�欎笉浼氬幓鍒犻櫎澶氬疄渚嬫牴, 搴旀敼鎴� moveActivityIdsToSingleActivityId
+ // flowable 8.0.0 淇涓婇潰鐩稿叧闂锛� 杩樹慨澶嶄簡骞惰鍒嗘敮鍥為��鐨勯棶棰� https://t.zsxq.com/z4d9i銆�
+ // 鈶� 浣跨敤 moveExecutionsToSingleActivityId 鏂规硶杩涜鍥為��鎿嶄綔鏃讹紝濡傛灉鏄瀹炰緥鐨勭敤鎴蜂换鍔°�愯妺閬撶敤鎴蜂换鍔¢粯璁や负澶氬疄渚嬨�戯紝涓嶄細鍒犻櫎澶氬疄渚嬩换鍔$殑鏍规暟鎹� ACT_RU_EXECUTION
+ // 浼氬鑷存湁涓�浜涢棶棰橈紝鎵�浠ヤ娇鐢� moveActivityIdsToSingleActivityId銆� 浣嗘槸璇ユ柟娉曞湪 flowable 6.8.1 ~ 7.1.0 鐨勭増鏈細鏈� bug 闃诲鍥為��鍔熻兘
+ // 鐩稿叧 issue: https://github.com/flowable/flowable-engine/issues/3944
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(currentTask.getProcessInstanceId())
.moveActivityIdsToSingleActivityId(returnTaskKeyList, reqVO.getTargetTaskDefinitionKey())
// 璁剧疆闇�瑕侀娴嬬殑浠诲姟 ids 鐨勬祦绋嬪彉閲忥紝鐢ㄤ簬杈呭姪棰勬祴
.processVariable(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS, needSimulateTaskDefinitionKeys)
- // 璁剧疆娴佺▼鍙橀噺锛坙ocal锛夎妭鐐归��鍥炴爣璁�, 鐢ㄤ簬閫�鍥炲埌鑺傜偣锛屼笉鎵ц BpmUserTaskAssignStartUserHandlerTypeEnum 绛栫暐锛屽鑷磋嚜鍔ㄩ�氳繃
- .localVariable(reqVO.getTargetTaskDefinitionKey(),
- String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, reqVO.getTargetTaskDefinitionKey()), Boolean.TRUE)
+ // 璁剧疆娴佺▼鍙橀噺鑺傜偣閫�鍥炴爣璁�, 鐢ㄤ簬閫�鍥炲埌鑺傜偣锛屼笉鎵ц BpmUserTaskAssignStartUserHandlerTypeEnum 绛栫暐锛屽鑷磋嚜鍔ㄩ�氳繃
+ .processVariable(String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, reqVO.getTargetTaskDefinitionKey()), Boolean.TRUE)
.changeState();
}
@@ -1464,101 +1503,105 @@
return;
}
- // 鑷姩鍘婚噸锛岄�氳繃鑷姩瀹℃壒鐨勬柟寮�
- BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService.getProcessDefinitionInfo(task.getProcessDefinitionId());
- if (processDefinitionInfo == null) {
- log.error("[processTaskAssigned][taskId({}) 娌℃湁鎵惧埌娴佺▼瀹氫箟({})]", task.getId(), task.getProcessDefinitionId());
- return;
- }
- if (processDefinitionInfo.getAutoApprovalType() != null) {
- HistoricTaskInstanceQuery sameAssigneeQuery = historyService.createHistoricTaskInstanceQuery()
- .processInstanceId(task.getProcessInstanceId())
- .taskAssignee(task.getAssignee()) // 鐩稿悓瀹℃壒浜�
- .taskVariableValueEquals(BpmnVariableConstants.TASK_VARIABLE_STATUS, BpmTaskStatusEnum.APPROVE.getStatus())
- .finished();
- if (BpmAutoApproveTypeEnum.APPROVE_ALL.getType().equals(processDefinitionInfo.getAutoApprovalType())
- && sameAssigneeQuery.count() > 0) {
- getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
- .setReason(BpmAutoApproveTypeEnum.APPROVE_ALL.getName()));
+ // 闇�瑕佸熀浜� instance 璁剧疆绉熸埛缂栧彿锛岄伩鍏� Flowable 鍐呴儴寮傛鎵ц鏃躲�愪緥濡傦細瓒呮椂鑷姩閫氳繃銆� 涓㈠け绉熸埛缂栧彿
+ FlowableUtils.execute(processInstance.getTenantId(), () -> {
+ // 鑷姩鍘婚噸锛岄�氳繃鑷姩瀹℃壒鐨勬柟寮�
+ BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService.getProcessDefinitionInfo(task.getProcessDefinitionId());
+ if (processDefinitionInfo == null) {
+ log.error("[processTaskAssigned][taskId({}) 娌℃湁鎵惧埌娴佺▼瀹氫箟({})]", task.getId(), task.getProcessDefinitionId());
return;
}
- if (BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getType().equals(processDefinitionInfo.getAutoApprovalType())) {
- BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId());
- if (bpmnModel == null) {
- log.error("[processTaskAssigned][taskId({}) 娌℃湁鎵惧埌娴佺▼妯″瀷({})]", task.getId(), task.getProcessDefinitionId());
- return;
- }
- List<String> sourceTaskIds = convertList(BpmnModelUtils.getElementIncomingFlows( // 鑾峰彇鎵�鏈変笂涓�涓妭鐐�
- BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey())),
- SequenceFlow::getSourceRef);
- if (sameAssigneeQuery.taskDefinitionKeys(sourceTaskIds).count() > 0) {
+ if (processDefinitionInfo.getAutoApprovalType() != null) {
+ HistoricTaskInstanceQuery approvedTaskQuery = historyService.createHistoricTaskInstanceQuery()
+ .processInstanceId(task.getProcessInstanceId())
+ .taskVariableValueEquals(BpmnVariableConstants.TASK_VARIABLE_STATUS, BpmTaskStatusEnum.APPROVE.getStatus())
+ .finished();
+ if (BpmAutoApproveTypeEnum.APPROVE_ALL.getType().equals(processDefinitionInfo.getAutoApprovalType())
+ && approvedTaskQuery.taskAssignee(task.getAssignee()).count() > 0) {
getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
- .setReason(BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getName()));
+ .setReason(BpmAutoApproveTypeEnum.APPROVE_ALL.getName()));
return;
}
- }
- }
-
- // 鑾峰彇鍙戣捣浜鸿妭鐐�
- BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId());
- if (bpmnModel == null) {
- log.error("[processTaskAssigned][taskId({}) 娌℃湁鎵惧埌娴佺▼妯″瀷]", task.getId());
- return;
- }
- FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
- // 鍒ゆ柇鏄惁涓洪��鍥炴垨鑰呴┏鍥烇細濡傛灉鏄��鍥炴垨鑰呴┏鍥炰笉璧拌繖涓瓥鐣ワ紙浣跨敤 local variable锛�
- Boolean returnTaskFlag = runtimeService.getVariableLocal(task.getExecutionId(),
- String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey()), Boolean.class);
- Boolean skipStartUserNodeFlag = Convert.toBool(runtimeService.getVariable(processInstance.getProcessInstanceId(),
- BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class));
- if (userTaskElement.getId().equals(START_USER_NODE_ID)
- && (skipStartUserNodeFlag == null // 鐩殑锛氫竴鑸槸鈥滀富娴佺▼鈥濓紝鍙戣捣浜鸿妭鐐癸紝鑷姩閫氳繃瀹℃牳
- || BooleanUtil.isTrue(skipStartUserNodeFlag)) // 鐩殑锛氫竴鑸槸鈥滃瓙娴佺▼鈥濓紝鍙戣捣浜鸿妭鐐癸紝鎸夐厤缃嚜鍔ㄩ�氳繃瀹℃牳
- && ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) {
- getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
- .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason()));
- return;
- }
- // 褰撲笉涓哄彂璧蜂汉鑺傜偣鏃讹紝瀹℃壒浜轰笌鎻愪氦浜轰负鍚屼竴浜烘椂锛屾牴鎹� BpmUserTaskAssignStartUserHandlerTypeEnum 绛栫暐杩涜澶勭悊
- if (ObjectUtil.notEqual(userTaskElement.getId(), START_USER_NODE_ID)
- && StrUtil.equals(task.getAssignee(), processInstance.getStartUserId())) {
- if (ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) {
- Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(userTaskElement);
-
- // 鎯呭喌涓�锛氳嚜鍔ㄨ烦杩�
- if (ObjectUtils.equalsAny(assignStartUserHandlerType,
- BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP.getType())) {
- getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
- .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP.getReason()));
- return;
- }
- // 鎯呭喌浜岋細杞氦缁欓儴闂ㄨ礋璐d汉瀹℃壒
- if (ObjectUtils.equalsAny(assignStartUserHandlerType,
- BpmUserTaskAssignStartUserHandlerTypeEnum.TRANSFER_DEPT_LEADER.getType())) {
- AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
- Assert.notNull(startUser, "鎻愪氦浜�({})淇℃伅涓虹┖", processInstance.getStartUserId());
- DeptRespDTO dept = startUser.getDeptId() != null ? deptApi.getDept(startUser.getDeptId()) : null;
- Assert.notNull(dept, "鎻愪氦浜�({})閮ㄩ棬({})淇℃伅涓虹┖", processInstance.getStartUserId(), startUser.getDeptId());
- // 鎵句笉鍒伴儴闂ㄨ礋璐d汉鐨勬儏鍐典笅锛岃嚜鍔ㄥ鎵归�氳繃
- // noinspection DataFlowIssue
- if (dept.getLeaderUserId() == null) {
+ // 杩炵画瀹℃壒鐨勮妭鐐硅嚜鍔ㄩ�氳繃
+ if (BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getType().equals(processDefinitionInfo.getAutoApprovalType())) {
+ BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId());
+ if (bpmnModel == null) {
+ log.error("[processTaskAssigned][taskId({}) 娌℃湁鎵惧埌娴佺▼妯″瀷({})]", task.getId(), task.getProcessDefinitionId());
+ return;
+ }
+ List<String> sourceTaskIds = convertList(BpmnModelUtils.getElementIncomingUserTaskFlows( // 鑾峰彇鎵�鏈夌殑涓婁竴涓� UserTask 鑺傜偣杩炵嚎
+ BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey())),
+ SequenceFlow::getSourceRef);
+ approvedTaskQuery.taskDefinitionKeys(sourceTaskIds).orderByTaskCreateTime().desc(); // 璁剧疆 taskIds, 骞舵寜鍒涘缓鏃堕棿鍊掑簭鎺掑簭
+ HistoricTaskInstance firstHisTask = CollUtil.getFirst(approvedTaskQuery.list());
+ if (firstHisTask != null && StrUtil.equals(firstHisTask.getAssignee(), task.getAssignee())) {
getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
- .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND.getReason()));
+ .setReason(BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getName()));
return;
}
- // 鎵惧緱鍒伴儴闂ㄨ礋璐d汉鐨勬儏鍐典笅锛屼慨鏀硅礋璐d汉
- if (ObjectUtil.notEqual(dept.getLeaderUserId(), startUser.getId())) {
- getSelf().transferTask(Long.valueOf(task.getAssignee()), new BpmTaskTransferReqVO()
- .setId(task.getId()).setAssigneeUserId(dept.getLeaderUserId())
- .setReason(BpmReasonEnum.ASSIGN_START_USER_TRANSFER_DEPT_LEADER.getReason()));
- return;
- }
- // 濡傛灉閮ㄩ棬璐熻矗浜烘槸鑷繁锛岃繕鏄嚜宸卞鎵瑰惂~
}
}
- }
- // 娉ㄦ剰锛氶渶瑕佸熀浜� instance 璁剧疆绉熸埛缂栧彿锛岄伩鍏� Flowable 鍐呴儴寮傛鏃讹紝涓㈠け绉熸埛缂栧彿
- FlowableUtils.execute(processInstance.getTenantId(), () -> {
+
+ // 鑾峰彇鍙戣捣浜鸿妭鐐�
+ BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId());
+ if (bpmnModel == null) {
+ log.error("[processTaskAssigned][taskId({}) 娌℃湁鎵惧埌娴佺▼妯″瀷]", task.getId());
+ return;
+ }
+ FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
+ // 鍒ゆ柇鏄惁涓洪��鍥炴垨鑰呴┏鍥烇細濡傛灉鏄��鍥炴垨鑰呴┏鍥炰笉璧拌繖涓瓥鐣�
+ Boolean returnTaskFlag = runtimeService.getVariable(processInstance.getProcessInstanceId(),
+ String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey()), Boolean.class);
+ Boolean skipStartUserNodeFlag = Convert.toBool(runtimeService.getVariable(processInstance.getProcessInstanceId(),
+ BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class));
+ if (userTaskElement.getId().equals(START_USER_NODE_ID)
+ && (skipStartUserNodeFlag == null // 鐩殑锛氫竴鑸槸鈥滀富娴佺▼鈥濓紝鍙戣捣浜鸿妭鐐癸紝鑷姩閫氳繃瀹℃牳
+ || BooleanUtil.isTrue(skipStartUserNodeFlag)) // 鐩殑锛氫竴鑸槸鈥滃瓙娴佺▼鈥濓紝鍙戣捣浜鸿妭鐐癸紝鎸夐厤缃嚜鍔ㄩ�氳繃瀹℃牳
+ && ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) {
+ getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
+ .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason()));
+ return;
+ }
+ // 褰撲笉涓哄彂璧蜂汉鑺傜偣鏃讹紝瀹℃壒浜轰笌鎻愪氦浜轰负鍚屼竴浜烘椂锛屾牴鎹� BpmUserTaskAssignStartUserHandlerTypeEnum 绛栫暐杩涜澶勭悊
+ if (ObjectUtil.notEqual(userTaskElement.getId(), START_USER_NODE_ID)
+ && StrUtil.equals(task.getAssignee(), processInstance.getStartUserId())) {
+ if (ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) {
+ Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(userTaskElement);
+
+ // 鎯呭喌涓�锛氳嚜鍔ㄨ烦杩�
+ if (ObjectUtils.equalsAny(assignStartUserHandlerType,
+ BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP.getType())) {
+ getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
+ .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP.getReason()));
+ return;
+ }
+ // 鎯呭喌浜岋細杞氦缁欓儴闂ㄨ礋璐d汉瀹℃壒
+ if (ObjectUtils.equalsAny(assignStartUserHandlerType,
+ BpmUserTaskAssignStartUserHandlerTypeEnum.TRANSFER_DEPT_LEADER.getType())) {
+ AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
+ Assert.notNull(startUser, "鎻愪氦浜�({})淇℃伅涓虹┖", processInstance.getStartUserId());
+ DeptRespDTO dept = startUser.getDeptId() != null ? deptApi.getDept(startUser.getDeptId()) : null;
+ Assert.notNull(dept, "鎻愪氦浜�({})閮ㄩ棬({})淇℃伅涓虹┖", processInstance.getStartUserId(), startUser.getDeptId());
+ // 鎵句笉鍒伴儴闂ㄨ礋璐d汉鐨勬儏鍐典笅锛岃嚜鍔ㄥ鎵归�氳繃
+ // noinspection DataFlowIssue
+ if (dept.getLeaderUserId() == null) {
+ getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId())
+ .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND.getReason()));
+ return;
+ }
+ // 鎵惧緱鍒伴儴闂ㄨ礋璐d汉鐨勬儏鍐典笅锛屼慨鏀硅礋璐d汉
+ if (ObjectUtil.notEqual(dept.getLeaderUserId(), startUser.getId())) {
+ getSelf().transferTask(Long.valueOf(task.getAssignee()), new BpmTaskTransferReqVO()
+ .setId(task.getId()).setAssigneeUserId(dept.getLeaderUserId())
+ .setReason(BpmReasonEnum.ASSIGN_START_USER_TRANSFER_DEPT_LEADER.getReason()));
+ return;
+ }
+ // 濡傛灉閮ㄩ棬璐熻矗浜烘槸鑷繁锛岃繕鏄嚜宸卞鎵瑰惂~
+ }
+ }
+ }
+
+ // 鍙戦�佹秷鎭�
AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
});
diff --git a/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java b/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java
index 308d866..a726377 100644
--- a/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java
+++ b/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate;
+import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@@ -64,7 +65,7 @@
public void setUp() {
userStrategy = new BpmTaskCandidateUserStrategy(); // 鍒涘缓 strategy 瀹炰緥
when(emptyStrategy.getStrategy()).thenReturn(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY);
- strategyList = List.of(userStrategy, emptyStrategy); // 鍒涘缓 strategyList
+ strategyList = ListUtil.of(userStrategy, emptyStrategy); // 鍒涘缓 strategyList
taskCandidateInvoker = new BpmTaskCandidateInvoker(strategyList, adminUserApi);
}
diff --git a/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategyTest.java b/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategyTest.java
index f63ccc3..07ae141 100644
--- a/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategyTest.java
+++ b/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategyTest.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
+import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
@@ -12,7 +13,6 @@
import org.mockito.Mock;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -41,7 +41,7 @@
// mock 鏂规硶锛團lowableUtils锛�
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES,
- MapUtil.of("activity_001", List.of(1L, 2L)));
+ MapUtil.of("activity_001", ListUtil.of(1L, 2L)));
when(processInstance.getProcessVariables()).thenReturn(processVariables);
// 璋冪敤
@@ -56,7 +56,7 @@
String activityId = "activity_001";
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES,
- MapUtil.of("activity_001", List.of(1L, 2L)));
+ MapUtil.of("activity_001", ListUtil.of(1L, 2L)));
// 璋冪敤
Set<Long> userIds = strategy.calculateUsersByActivity(null, activityId, null,
diff --git a/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtilsTest.java b/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtilsTest.java
new file mode 100644
index 0000000..e1bebe1
--- /dev/null
+++ b/yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtilsTest.java
@@ -0,0 +1,167 @@
+package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
+
+import cn.iocoder.yudao.framework.common.core.KeyValue;
+import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
+import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
+import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * {@link FlowableUtils} 鐨勫崟鍏冩祴璇曘��
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+class FlowableUtilsTest {
+
+ @Test
+ public void testGetSummary_customSummary_parseDbFormFields() {
+ // 鍑嗗鍙傛暟锛氭ā鎷� DB 涓� form_fields 瀛楁锛屽垪琛ㄩ噷姣忎釜鍏冪礌閮芥槸涓�涓� form-create 瀛楁 JSON銆�
+ BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionInfo(dbFormFields(),
+ summarySetting(true, "reason", "days", "notExists", "startTime"));
+ Map<String, Object> processVariables = processVariables();
+
+ // 璋冪敤
+ List<KeyValue<String, String>> summary = FlowableUtils.getSummary(processDefinitionInfo, processVariables);
+
+ // 鏂█
+ assertEquals(Arrays.asList(
+ new KeyValue<>("璇峰亣鍘熷洜", "浜嬪亣"),
+ new KeyValue<>("璇峰亣澶╂暟", "3"),
+ new KeyValue<>("寮�濮嬫椂闂�", "2026-05-31 09:00:00")),
+ summary);
+ }
+
+ @Test
+ public void testGetSummary_defaultSummary_parseFirstThreeFieldsByFormOrder() {
+ // 鍑嗗鍙傛暟锛氭湭寮�鍚嚜瀹氫箟鎽樿鏃讹紝榛樿鍙栬〃鍗曢厤缃『搴忛噷鐨勫墠涓変釜鐪熷疄瀛楁銆�
+ BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionInfo(dbFormFields(), null);
+ Map<String, Object> processVariables = processVariables();
+
+ // 璋冪敤
+ List<KeyValue<String, String>> summary = FlowableUtils.getSummary(processDefinitionInfo, processVariables);
+
+ // 鏂█
+ assertEquals(Arrays.asList(
+ new KeyValue<>("璇峰亣鍘熷洜", "浜嬪亣"),
+ new KeyValue<>("寮�濮嬫椂闂�", "2026-05-31 09:00:00"),
+ new KeyValue<>("璇峰亣澶╂暟", "3")),
+ summary);
+ }
+
+ @Test
+ public void testGetSummary_summaryDisabled_useDefaultSummary() {
+ // 鍑嗗鍙傛暟锛氭憳瑕佽缃瓨鍦ㄤ絾鏈惎鐢ㄦ椂锛屼粛璧伴粯璁ゆ憳瑕侀�昏緫銆�
+ BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionInfo(dbFormFields(),
+ summarySetting(false, "remark"));
+ Map<String, Object> processVariables = processVariables();
+
+ // 璋冪敤
+ List<KeyValue<String, String>> summary = FlowableUtils.getSummary(processDefinitionInfo, processVariables);
+
+ // 鏂█
+ assertEquals(Arrays.asList(
+ new KeyValue<>("璇峰亣鍘熷洜", "浜嬪亣"),
+ new KeyValue<>("寮�濮嬫椂闂�", "2026-05-31 09:00:00"),
+ new KeyValue<>("璇峰亣澶╂暟", "3")),
+ summary);
+ }
+
+ @Test
+ public void testGetSummary_displayComponentsOnly_returnEmpty() {
+ // 鍑嗗鍙傛暟锛氬垎鍓茬嚎銆佹爣绛俱�佹枃瀛楃瓑灞曠ず缁勪欢鐨� children 鏄瓧绗︿覆鏁扮粍锛屼笉鏄〃鍗曞瓧娈靛璞°��
+ BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionInfo(Arrays.asList(
+ DIVIDER_FIELD,
+ TEXT_FIELD,
+ TAG_FIELD), null);
+
+ // 璋冪敤
+ List<KeyValue<String, String>> summary = FlowableUtils.getSummary(processDefinitionInfo,
+ Collections.emptyMap());
+
+ // 鏂█
+ assertEquals(Collections.emptyList(), summary);
+ }
+
+ @Test
+ public void testGetSummary_notNormalForm_returnNull() {
+ // 鍑嗗鍙傛暟
+ BpmProcessDefinitionInfoDO processDefinitionInfo = BpmProcessDefinitionInfoDO.builder()
+ .formType(BpmModelFormTypeEnum.CUSTOM.getType())
+ .build();
+
+ // 璋冪敤 & 鏂█
+ assertNull(FlowableUtils.getSummary(null, Collections.emptyMap()));
+ assertNull(FlowableUtils.getSummary(processDefinitionInfo, Collections.emptyMap()));
+ }
+
+ private static BpmProcessDefinitionInfoDO processDefinitionInfo(List<String> formFields,
+ BpmModelMetaInfoVO.SummarySetting summarySetting) {
+ return BpmProcessDefinitionInfoDO.builder()
+ .formType(BpmModelFormTypeEnum.NORMAL.getType())
+ .formFields(formFields)
+ .summarySetting(summarySetting)
+ .build();
+ }
+
+ private static BpmModelMetaInfoVO.SummarySetting summarySetting(Boolean enable, String... fields) {
+ BpmModelMetaInfoVO.SummarySetting summarySetting = new BpmModelMetaInfoVO.SummarySetting();
+ summarySetting.setEnable(enable);
+ summarySetting.setSummary(Arrays.asList(fields));
+ return summarySetting;
+ }
+
+ private static List<String> dbFormFields() {
+ return Arrays.asList(
+ DIVIDER_FIELD,
+ "{\"type\":\"input\",\"field\":\"reason\",\"title\":\"璇峰亣鍘熷洜\",\"value\":\"\","
+ + "\"props\":{\"type\":\"textarea\",\"placeholder\":\"璇疯緭鍏ヨ鍋囧師鍥燶"},"
+ + "\"$required\":\"璇疯緭鍏ヨ鍋囧師鍥燶",\"_fc_id\":\"id_F1\",\"_fc_drag_tag\":\"input\","
+ + "\"hidden\":false,\"display\":true}",
+ TEXT_FIELD,
+ "{\"type\":\"elRow\",\"title\":\"鏍呮牸甯冨眬\",\"children\":["
+ + "{\"type\":\"elCol\",\"props\":{\"span\":12},\"children\":["
+ + "{\"type\":\"DatePicker\",\"field\":\"startTime\",\"title\":\"寮�濮嬫椂闂碶","
+ + "\"props\":{\"type\":\"datetime\",\"placeholder\":\"璇烽�夋嫨寮�濮嬫椂闂碶"},"
+ + "\"_fc_id\":\"id_F2\",\"_fc_drag_tag\":\"datePicker\"}]},"
+ + "\"瀛楁璇存槑\","
+ + "{\"type\":\"elCol\",\"props\":{\"span\":12},\"children\":["
+ + "{\"type\":\"inputNumber\",\"field\":\"days\",\"title\":\"璇峰亣澶╂暟\","
+ + "\"props\":{\"min\":0,\"precision\":1},\"_fc_id\":\"id_F3\","
+ + "\"_fc_drag_tag\":\"inputNumber\"}]}],\"_fc_id\":\"id_LAYOUT\","
+ + "\"_fc_drag_tag\":\"row\"}",
+ TAG_FIELD,
+ "{\"type\":\"input\",\"field\":\"remark\",\"title\":\"澶囨敞\",\"value\":\"\","
+ + "\"props\":{\"placeholder\":\"璇疯緭鍏ュ娉╘"},\"_fc_id\":\"id_F4\","
+ + "\"_fc_drag_tag\":\"input\",\"hidden\":false,\"display\":true}");
+ }
+
+ private static Map<String, Object> processVariables() {
+ Map<String, Object> processVariables = new HashMap<>();
+ processVariables.put("reason", "浜嬪亣");
+ processVariables.put("startTime", "2026-05-31 09:00:00");
+ processVariables.put("days", 3);
+ processVariables.put("remark", "涓嬪崍鍒板");
+ return processVariables;
+ }
+
+ private static final String DIVIDER_FIELD = "{\"type\":\"elDivider\",\"children\":[\"鍩虹淇℃伅\"],"
+ + "\"props\":{\"contentPosition\":\"left\"},\"_fc_id\":\"id_DIVIDER\","
+ + "\"_fc_drag_tag\":\"elDivider\"}";
+
+ private static final String TEXT_FIELD = "{\"type\":\"div\",\"children\":[\"璇锋寜瀹為檯鎯呭喌濉啓\"],"
+ + "\"props\":{\"style\":{\"color\":\"#909399\"}},\"_fc_id\":\"id_TEXT\","
+ + "\"_fc_drag_tag\":\"text\"}";
+
+ private static final String TAG_FIELD = "{\"type\":\"elTag\",\"children\":[\"閲嶈\"],"
+ + "\"props\":{\"type\":\"warning\"},\"_fc_id\":\"id_TAG\",\"_fc_drag_tag\":\"elTag\"}";
+
+}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
index 33e8d84..84d31ab 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
@@ -138,6 +138,26 @@
.setCustomerId(business.getCustomerId())));
}
+ @GetMapping("/list-by-customer")
+ @Operation(summary = "鑾峰緱鍟嗘満鍒楄〃锛屽熀浜庢寚瀹氬鎴�")
+ @Parameter(name = "customerId", description = "瀹㈡埛缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('crm:business:query')")
+ public CommonResult<List<CrmBusinessRespVO>> getBusinessListByCustomer(@RequestParam("customerId") Long customerId) {
+ List<CrmBusinessDO> list = businessService.getBusinessListByCustomerId(customerId);
+ return success(convertList(list, business -> // 鍙繑鍥� id銆乶ame 瀛楁
+ new CrmBusinessRespVO().setId(business.getId()).setName(business.getName())
+ .setCustomerId(business.getCustomerId())));
+ }
+
+ @GetMapping("/list-by-contact")
+ @Operation(summary = "鑾峰緱鍟嗘満鍒楄〃锛屽熀浜庢寚瀹氳仈绯讳汉")
+ @Parameter(name = "contactId", description = "鑱旂郴浜虹紪鍙�", required = true)
+ @PreAuthorize("@ss.hasPermission('crm:business:query')")
+ public CommonResult<List<CrmBusinessRespVO>> getBusinessListByContact(@RequestParam("contactId") Long contactId) {
+ List<CrmBusinessDO> list = businessService.getBusinessListByContact(contactId);
+ return success(buildBusinessDetailList(list));
+ }
+
@GetMapping("/page")
@Operation(summary = "鑾峰緱鍟嗘満鍒嗛〉")
@PreAuthorize("@ss.hasPermission('crm:business:query')")
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java
index 58ea20d..1ff695c 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java
@@ -114,6 +114,17 @@
.setCustomerId(contact.getCustomerId())));
}
+ @GetMapping("/list-by-customer")
+ @Operation(summary = "鑾峰緱鑱旂郴浜哄垪琛紝鍩轰簬鎸囧畾瀹㈡埛")
+ @Parameter(name = "customerId", description = "瀹㈡埛缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('crm:contact:query')")
+ public CommonResult<List<CrmContactRespVO>> getContactListByCustomer(@RequestParam("customerId") Long customerId) {
+ List<CrmContactDO> list = contactService.getContactListByCustomerId(customerId);
+ return success(convertList(list, contact -> // 鍙繑鍥� id銆乶ame 瀛楁
+ new CrmContactRespVO().setId(contact.getId()).setName(contact.getName())
+ .setCustomerId(contact.getCustomerId())));
+ }
+
@GetMapping("/page")
@Operation(summary = "鑾峰緱鑱旂郴浜哄垎椤�")
@PreAuthorize("@ss.hasPermission('crm:contact:query')")
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java
index 7946aea..b59ef80 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/followup/CrmFollowUpRecordController.java
@@ -11,9 +11,12 @@
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.followup.CrmFollowUpRecordDO;
+import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
+import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
import cn.iocoder.yudao.module.crm.service.followup.CrmFollowUpRecordService;
+import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
@@ -27,10 +30,13 @@
import java.util.ArrayList;
import java.util.Map;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CRM_PERMISSION_DENIED;
+import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS;
@Tag(name = "绠$悊鍚庡彴 - 璺熻繘璁板綍")
@@ -45,6 +51,8 @@
private CrmContactService contactService;
@Resource
private CrmBusinessService businessService;
+ @Resource
+ private CrmPermissionService permissionService;
@Resource
private AdminUserApi adminUserApi;
@@ -68,6 +76,13 @@
@Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
public CommonResult<CrmFollowUpRecordRespVO> getFollowUpRecord(@RequestParam("id") Long id) {
CrmFollowUpRecordDO followUpRecord = followUpRecordService.getFollowUpRecord(id);
+ if (followUpRecord == null) {
+ throw exception(FOLLOW_UP_RECORD_NOT_EXISTS);
+ }
+ if (!permissionService.hasPermission(followUpRecord.getBizType(), followUpRecord.getBizId(),
+ getLoginUserId(), CrmPermissionLevelEnum.READ)) {
+ throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(followUpRecord.getBizType()));
+ }
return success(BeanUtils.toBean(followUpRecord, CrmFollowUpRecordRespVO.class));
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java
index 894ab32..cc6d598 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java
@@ -65,6 +65,10 @@
.eq(CrmBusinessDO::getOwnerUserId, ownerUserId));
}
+ default List<CrmBusinessDO> selectListByCustomerId(Long customerId) {
+ return selectList(CrmBusinessDO::getCustomerId, customerId);
+ }
+
default PageResult<CrmBusinessDO> selectPage(CrmStatisticsFunnelReqVO pageVO) {
return selectPage(pageVO, new LambdaQueryWrapperX<CrmBusinessDO>()
.in(CrmBusinessDO::getOwnerUserId, pageVO.getUserIds())
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java
index a62aabb..230ec1f 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java
@@ -3,6 +3,7 @@
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.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO;
import org.apache.ibatis.annotations.Mapper;
@@ -28,9 +29,9 @@
LambdaQueryWrapperX<CrmCustomerLimitConfigDO> query = new LambdaQueryWrapperX<CrmCustomerLimitConfigDO>()
.eq(CrmCustomerLimitConfigDO::getType, type);
query.and(w -> {
- w.apply("FIND_IN_SET({0}, user_ids) > 0", userId);
+ w.apply(MyBatisUtils.findInSet("user_ids"), userId);
if (deptId != null) {
- w.or().apply("FIND_IN_SET({0}, dept_ids) > 0", deptId);
+ w.or().apply(MyBatisUtils.findInSet("dept_ids"), deptId);
}
});
return selectList(query);
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
index 07a6dad..5c1eb8d 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
@@ -26,6 +26,7 @@
ErrorCode BUSINESS_DELETE_FAIL_CONTRACT_EXISTS = new ErrorCode(1_020_002_001, "鍟嗘満宸插叧鑱斿悎鍚岋紝涓嶈兘鍒犻櫎");
ErrorCode BUSINESS_UPDATE_STATUS_FAIL_END_STATUS = new ErrorCode(1_020_002_002, "鏇存柊鍟嗘満鐘舵�佸け璐ワ紝鍘熷洜锛氬凡缁忔槸缁撴潫鐘舵��");
ErrorCode BUSINESS_UPDATE_STATUS_FAIL_STATUS_EQUALS = new ErrorCode(1_020_002_003, "鏇存柊鍟嗘満鐘舵�佸け璐ワ紝鍘熷洜锛氬凡缁忔槸璇ョ姸鎬�");
+ ErrorCode BUSINESS_CONTACT_CUSTOMER_NOT_MATCH = new ErrorCode(1_020_002_004, "鍟嗘満鍏宠仈鐨勮仈绯讳汉涓嶅睘浜庤瀹㈡埛");
// ========== 鑱旂郴浜虹鐞� 1-020-003-000 ==========
ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "鑱旂郴浜轰笉瀛樺湪");
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
index abe5a70..67a6cf3 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
@@ -196,6 +196,22 @@
List<CrmBusinessDO> getBusinessListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId);
/**
+ * 鑾峰緱鍟嗘満鍒楄〃锛屽熀浜庢寚瀹氬鎴�
+ *
+ * @param customerId 瀹㈡埛缂栧彿
+ * @return 鍟嗘満鍒楄〃
+ */
+ List<CrmBusinessDO> getBusinessListByCustomerId(Long customerId);
+
+ /**
+ * 鑾峰緱鍟嗘満鍒楄〃锛屽熀浜庢寚瀹氳仈绯讳汉
+ *
+ * @param contactId 鑱旂郴浜虹紪鍙�
+ * @return 鍟嗘満鍒楄〃
+ */
+ List<CrmBusinessDO> getBusinessListByContact(Long contactId);
+
+ /**
* 鑾峰緱鍟嗘満鍒嗛〉锛岀洰鍓嶇敤浜庛�愭暟鎹粺璁°��
*
* @param pageVO 璇锋眰
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
index 71b1884..1828558 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
@@ -2,6 +2,7 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -15,6 +16,7 @@
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessProductMapper;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
@@ -194,9 +196,15 @@
if (saveReqVO.getCustomerId() != null) {
customerService.validateCustomer(saveReqVO.getCustomerId());
}
- // 鏍¢獙鑱旂郴浜�
+ // 鏍¢獙鑱旂郴浜猴紙涓斿繀椤讳笌鍟嗘満灞炰簬鍚屼竴瀹㈡埛锛岄伩鍏嶈法瀹㈡埛鍏宠仈锛�
if (saveReqVO.getContactId() != null) {
contactService.validateContact(saveReqVO.getContactId());
+ if (saveReqVO.getCustomerId() != null) {
+ CrmContactDO contact = contactService.getContact(saveReqVO.getContactId());
+ if (ObjUtil.notEqual(saveReqVO.getCustomerId(), contact.getCustomerId())) {
+ throw exception(BUSINESS_CONTACT_CUSTOMER_NOT_MATCH);
+ }
+ }
}
// 鏍¢獙璐熻矗浜�
if (saveReqVO.getOwnerUserId() != null) {
@@ -378,6 +386,24 @@
}
@Override
+ @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#customerId", level = CrmPermissionLevelEnum.READ)
+ public List<CrmBusinessDO> getBusinessListByCustomerId(Long customerId) {
+ return businessMapper.selectListByCustomerId(customerId);
+ }
+
+ @Override
+ @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#contactId", level = CrmPermissionLevelEnum.READ)
+ public List<CrmBusinessDO> getBusinessListByContact(Long contactId) {
+ // 1. 鏌ヨ鍏宠仈鐨勫晢鏈虹紪鍙�
+ List<CrmContactBusinessDO> contactBusinessList = contactBusinessService.getContactBusinessListByContactId(contactId);
+ if (CollUtil.isEmpty(contactBusinessList)) {
+ return ListUtil.empty();
+ }
+ // 2. 鏌ヨ鍟嗘満鍒楄〃
+ return businessMapper.selectByIds(convertSet(contactBusinessList, CrmContactBusinessDO::getBusinessId));
+ }
+
+ @Override
public PageResult<CrmBusinessDO> getBusinessPageByDate(CrmStatisticsFunnelReqVO pageVO) {
return businessMapper.selectPage(pageVO);
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java
index 971d413..3095c73 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactService.java
@@ -169,4 +169,12 @@
*/
List<CrmContactDO> getContactListByCustomerIdOwnerUserId(Long customerId, Long ownerUserId);
+ /**
+ * 鑾峰緱鑱旂郴浜哄垪琛紝鍩轰簬鎸囧畾瀹㈡埛
+ *
+ * @param customerId 瀹㈡埛缂栧彿
+ * @return 鑱旂郴浜哄垪琛�
+ */
+ List<CrmContactDO> getContactListByCustomerId(Long customerId);
+
}
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java
index c3855f7..def0fe7 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java
@@ -304,4 +304,10 @@
return contactMapper.selectListByCustomerIdOwnerUserId(customerId, ownerUserId);
}
+ @Override
+ @CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#customerId", level = CrmPermissionLevelEnum.READ)
+ public List<CrmContactDO> getContactListByCustomerId(Long customerId) {
+ return contactMapper.selectListByCustomerId(customerId);
+ }
+
}
diff --git a/yudao-module-erp/pom.xml b/yudao-module-erp/pom.xml
index 30f01bf..ce377ff 100644
--- a/yudao-module-erp/pom.xml
+++ b/yudao-module-erp/pom.xml
@@ -24,27 +24,6 @@
<version>${revision}</version>
</dependency>
- <!-- MDM 涓绘暟鎹鐞嗘ā鍧� API -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-mdm</artifactId>
- <version>${revision}</version>
- </dependency>
-
- <!-- WMS 浠撳簱绠$悊妯″潡 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-wms</artifactId>
- <version>${revision}</version>
- </dependency>
-
- <!-- BPM 娴佺▼妯″潡 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-bpm</artifactId>
- <version>${revision}</version>
- </dependency>
-
<!-- 涓氬姟缁勪欢 -->
<!-- Web 鐩稿叧 -->
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java
index ffe7b2f..de4f814 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ErpProductPageReqVO.java
@@ -20,9 +20,6 @@
@Schema(description = "浜у搧鍒嗙被缂栧彿", example = "11161")
private Long categoryId;
- @Schema(description = "浜у搧鐘舵��", example = "0")
- private Integer status;
-
@Schema(description = "鍒涘缓鏃堕棿")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java
index 8d5168c..3a63540 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseInController.java
@@ -41,7 +41,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "绠$悊鍚庡彴 - ERP 閲囪喘鍏ュ簱")
@RestController
@@ -82,15 +81,6 @@
public CommonResult<Boolean> updatePurchaseInStatus(@RequestParam("id") Long id,
@RequestParam("status") Integer status) {
purchaseInService.updatePurchaseInStatus(id, status);
- return success(true);
- }
-
- @PostMapping("/submit")
- @Operation(summary = "鎻愪氦閲囪喘鍏ュ簱瀹℃壒")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
- @PreAuthorize("@ss.hasPermission('erp:purchase-in:update')")
- public CommonResult<Boolean> submitPurchaseIn(@RequestParam("id") Long id) {
- purchaseInService.submitPurchaseIn(id, getLoginUserId());
return success(true);
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java
index 5ced436..a560906 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java
@@ -40,7 +40,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "绠$悊鍚庡彴 - ERP 閲囪喘璁㈠崟")
@RestController
@@ -81,15 +80,6 @@
public CommonResult<Boolean> updatePurchaseOrderStatus(@RequestParam("id") Long id,
@RequestParam("status") Integer status) {
purchaseOrderService.updatePurchaseOrderStatus(id, status);
- return success(true);
- }
-
- @PostMapping("/submit")
- @Operation(summary = "鎻愪氦閲囪喘璁㈠崟瀹℃壒")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
- @PreAuthorize("@ss.hasPermission('erp:purchase-order:update')")
- public CommonResult<Boolean> submitPurchaseOrder(@RequestParam("id") Long id) {
- purchaseOrderService.submitPurchaseOrder(id, getLoginUserId());
return success(true);
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
index 274fac3..eee8cd9 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
@@ -40,7 +40,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "绠$悊鍚庡彴 - ERP 閿�鍞鍗�")
@RestController
@@ -62,14 +61,14 @@
@PostMapping("/create")
@Operation(summary = "鍒涘缓閿�鍞鍗�")
- @PreAuthorize("@ss.hasPermission('erp:sale-out:create')")
+ @PreAuthorize("@ss.hasPermission('erp:sale-order:create')")
public CommonResult<Long> createSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO createReqVO) {
return success(saleOrderService.createSaleOrder(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "鏇存柊閿�鍞鍗�")
- @PreAuthorize("@ss.hasPermission('erp:sale-out:update')")
+ @PreAuthorize("@ss.hasPermission('erp:sale-order:update')")
public CommonResult<Boolean> updateSaleOrder(@Valid @RequestBody ErpSaleOrderSaveReqVO updateReqVO) {
saleOrderService.updateSaleOrder(updateReqVO);
return success(true);
@@ -77,26 +76,17 @@
@PutMapping("/update-status")
@Operation(summary = "鏇存柊閿�鍞鍗曠殑鐘舵��")
- @PreAuthorize("@ss.hasPermission('erp:sale-out:update-status')")
+ @PreAuthorize("@ss.hasPermission('erp:sale-order:update-status')")
public CommonResult<Boolean> updateSaleOrderStatus(@RequestParam("id") Long id,
@RequestParam("status") Integer status) {
saleOrderService.updateSaleOrderStatus(id, status);
return success(true);
}
- @PostMapping("/submit")
- @Operation(summary = "鎻愪氦閿�鍞鍗曞鎵�")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
- @PreAuthorize("@ss.hasPermission('erp:sale-out:update')")
- public CommonResult<Boolean> submitSaleOrder(@RequestParam("id") Long id) {
- saleOrderService.submitSaleOrder(id, getLoginUserId());
- return success(true);
- }
-
@DeleteMapping("/delete")
@Operation(summary = "鍒犻櫎閿�鍞鍗�")
@Parameter(name = "ids", description = "缂栧彿鏁扮粍", required = true)
- @PreAuthorize("@ss.hasPermission('erp:sale-out:delete')")
+ @PreAuthorize("@ss.hasPermission('erp:sale-order:delete')")
public CommonResult<Boolean> deleteSaleOrder(@RequestParam("ids") List<Long> ids) {
saleOrderService.deleteSaleOrder(ids);
return success(true);
@@ -105,7 +95,7 @@
@GetMapping("/get")
@Operation(summary = "鑾峰緱閿�鍞鍗�")
@Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
- @PreAuthorize("@ss.hasPermission('erp:sale-out:query')")
+ @PreAuthorize("@ss.hasPermission('erp:sale-order:query')")
public CommonResult<ErpSaleOrderRespVO> getSaleOrder(@RequestParam("id") Long id) {
ErpSaleOrderDO saleOrder = saleOrderService.getSaleOrder(id);
if (saleOrder == null) {
@@ -125,7 +115,7 @@
@GetMapping("/page")
@Operation(summary = "鑾峰緱閿�鍞鍗曞垎椤�")
- @PreAuthorize("@ss.hasPermission('erp:sale-out:query')")
+ @PreAuthorize("@ss.hasPermission('erp:sale-order:query')")
public CommonResult<PageResult<ErpSaleOrderRespVO>> getSaleOrderPage(@Valid ErpSaleOrderPageReqVO pageReqVO) {
PageResult<ErpSaleOrderDO> pageResult = saleOrderService.getSaleOrderPage(pageReqVO);
return success(buildSaleOrderVOPageResult(pageResult));
@@ -133,7 +123,7 @@
@GetMapping("/export-excel")
@Operation(summary = "瀵煎嚭閿�鍞鍗� Excel")
- @PreAuthorize("@ss.hasPermission('erp:sale-out:export')")
+ @PreAuthorize("@ss.hasPermission('erp:sale-order:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportSaleOrderExcel(@Valid ErpSaleOrderPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
@@ -171,4 +161,4 @@
});
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java
index cb45f2e..f67398b 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOutController.java
@@ -41,7 +41,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "绠$悊鍚庡彴 - ERP 閿�鍞嚭搴�")
@RestController
@@ -82,15 +81,6 @@
public CommonResult<Boolean> updateSaleOutStatus(@RequestParam("id") Long id,
@RequestParam("status") Integer status) {
saleOutService.updateSaleOutStatus(id, status);
- return success(true);
- }
-
- @PostMapping("/submit")
- @Operation(summary = "鎻愪氦閿�鍞嚭搴撳鎵�")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
- @PreAuthorize("@ss.hasPermission('erp:sale-out:update')")
- public CommonResult<Boolean> submitSaleOut(@RequestParam("id") Long id) {
- saleOutService.submitSaleOut(id, getLoginUserId());
return success(true);
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInDO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInDO.java
index 5849257..b8186f5 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInDO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseInDO.java
@@ -119,10 +119,4 @@
*/
private String remark;
- // ========== BPM 娴佺▼瀹℃壒 ==========
- /**
- * BPM 娴佺▼瀹炰緥缂栧彿
- */
- private String processInstanceId;
-
}
\ No newline at end of file
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java
index 7b28cad..bba1542 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java
@@ -100,12 +100,6 @@
*/
private String remark;
- // ========== BPM 娴佺▼瀹℃壒 ==========
- /**
- * BPM 娴佺▼瀹炰緥缂栧彿
- */
- private String processInstanceId;
-
// ========== 閲囪喘鍏ュ簱 ==========
/**
* 閲囪喘鍏ュ簱鏁伴噺
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java
index 8a9be24..5cdd434 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java
@@ -106,12 +106,6 @@
*/
private String remark;
- // ========== BPM 娴佺▼瀹℃壒 ==========
- /**
- * BPM 娴佺▼瀹炰緥缂栧彿
- */
- private String processInstanceId;
-
// ========== 閿�鍞嚭搴� ==========
/**
* 閿�鍞嚭搴撴暟閲�
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutDO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutDO.java
index 9149f77..65b9d94 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutDO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOutDO.java
@@ -125,10 +125,4 @@
*/
private String remark;
- // ========== BPM 娴佺▼瀹℃壒 ==========
- /**
- * BPM 娴佺▼瀹炰緥缂栧彿
- */
- private String processInstanceId;
-
}
\ No newline at end of file
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java
index f19f26c..42c0174 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java
@@ -17,10 +17,8 @@
@Getter
public enum ErpAuditStatus implements ArrayValuable<Integer> {
- DRAFT(0, "鑽夌"), // 鑽夌鐘舵�侊紝鏈彁浜ゅ鎵�
- PROCESS(10, "瀹℃壒涓�"), // 瀹℃壒涓�
- APPROVE(20, "瀹℃壒閫氳繃"), // 瀹℃壒閫氳繃
- REJECT(30, "瀹℃壒涓嶉�氳繃"); // 瀹℃壒涓嶉�氳繃
+ PROCESS(10, "鏈鏍�"), // 瀹℃牳涓�
+ APPROVE(20, "宸插鏍�"); // 瀹℃牳閫氳繃
public static final Integer[] ARRAYS = Arrays.stream(values()).map(ErpAuditStatus::getStatus).toArray(Integer[]::new);
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
index d8c825a..65f64c2 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
@@ -25,8 +25,6 @@
ErrorCode PURCHASE_ORDER_PROCESS_FAIL_EXISTS_IN = new ErrorCode(1_030_101_008, "鍙嶅鏍稿け璐ワ紝宸插瓨鍦ㄥ搴旂殑閲囪喘鍏ュ簱鍗�");
ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_009, "閲囪喘璁㈠崟椤�({})瓒呰繃鏈�澶у厑璁搁��璐ф暟閲�({})");
ErrorCode PURCHASE_ORDER_PROCESS_FAIL_EXISTS_RETURN = new ErrorCode(1_030_101_010, "鍙嶅鏍稿け璐ワ紝宸插瓨鍦ㄥ搴旂殑閲囪喘閫�璐у崟");
- ErrorCode PURCHASE_ORDER_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_030_101_011, "鎻愪氦瀹℃壒澶辫触锛屽彧鏈夎崏绋跨姸鎬佺殑閲囪喘璁㈠崟鎵嶈兘鎻愪氦瀹℃壒");
- ErrorCode PURCHASE_ORDER_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_030_101_012, "鏇存柊瀹℃壒鐘舵�佸け璐ワ紝鍙湁瀹℃壒涓殑閲囪喘璁㈠崟鎵嶈兘鏇存柊瀹℃壒鐘舵��");
// ========== ERP 閲囪喘鍏ュ簱锛�1-030-102-000锛� ==========
ErrorCode PURCHASE_IN_NOT_EXISTS = new ErrorCode(1_030_102_000, "閲囪喘鍏ュ簱鍗曚笉瀛樺湪");
@@ -38,8 +36,6 @@
ErrorCode PURCHASE_IN_NOT_APPROVE = new ErrorCode(1_030_102_006, "閲囪喘鍏ュ簱鍗曟湭瀹℃牳锛屾棤娉曟搷浣�");
ErrorCode PURCHASE_IN_FAIL_PAYMENT_PRICE_EXCEED = new ErrorCode(1_030_102_007, "浠樻閲戦({})瓒呰繃閲囪喘鍏ュ簱鍗曟�婚噾棰�({})");
ErrorCode PURCHASE_IN_PROCESS_FAIL_EXISTS_PAYMENT = new ErrorCode(1_030_102_008, "鍙嶅鏍稿け璐ワ紝宸插瓨鍦ㄥ搴旂殑浠樻鍗�");
- ErrorCode PURCHASE_IN_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_030_102_009, "鎻愪氦瀹℃壒澶辫触锛屽彧鏈夎崏绋跨姸鎬佺殑閲囪喘鍏ュ簱鍗曟墠鑳芥彁浜ゅ鎵�");
- ErrorCode PURCHASE_IN_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_030_102_010, "鏇存柊瀹℃壒鐘舵�佸け璐ワ紝鍙湁瀹℃壒涓殑閲囪喘鍏ュ簱鍗曟墠鑳芥洿鏂板鎵圭姸鎬�");
// ========== ERP 閲囪喘閫�璐э紙1-030-103-000锛� ==========
ErrorCode PURCHASE_RETURN_NOT_EXISTS = new ErrorCode(1_030_103_000, "閲囪喘閫�璐у崟涓嶅瓨鍦�");
@@ -68,8 +64,6 @@
ErrorCode SALE_ORDER_PROCESS_FAIL_EXISTS_OUT = new ErrorCode(1_020_201_008, "鍙嶅鏍稿け璐ワ紝宸插瓨鍦ㄥ搴旂殑閿�鍞嚭搴撳崟");
ErrorCode SALE_ORDER_ITEM_RETURN_FAIL_OUT_EXCEED = new ErrorCode(1_020_201_009, "閿�鍞鍗曢」({})瓒呰繃鏈�澶у厑璁搁��璐ф暟閲�({})");
ErrorCode SALE_ORDER_PROCESS_FAIL_EXISTS_RETURN = new ErrorCode(1_020_201_010, "鍙嶅鏍稿け璐ワ紝宸插瓨鍦ㄥ搴旂殑閿�鍞��璐у崟");
- ErrorCode SALE_ORDER_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_201_011, "鎻愪氦瀹℃壒澶辫触锛屽彧鏈夎崏绋跨姸鎬佺殑閿�鍞鍗曟墠鑳芥彁浜ゅ鎵�");
- ErrorCode SALE_ORDER_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_201_012, "鏇存柊瀹℃壒鐘舵�佸け璐ワ紝鍙湁瀹℃壒涓殑閿�鍞鍗曟墠鑳芥洿鏂板鎵圭姸鎬�");
// ========== ERP 閿�鍞嚭搴擄紙1-030-202-000锛� ==========
ErrorCode SALE_OUT_NOT_EXISTS = new ErrorCode(1_020_202_000, "閿�鍞嚭搴撳崟涓嶅瓨鍦�");
@@ -81,8 +75,6 @@
ErrorCode SALE_OUT_NOT_APPROVE = new ErrorCode(1_020_202_006, "閿�鍞嚭搴撳崟鏈鏍革紝鏃犳硶鎿嶄綔");
ErrorCode SALE_OUT_FAIL_RECEIPT_PRICE_EXCEED = new ErrorCode(1_020_202_007, "鏀舵閲戦({})瓒呰繃閿�鍞嚭搴撳崟鎬婚噾棰�({})");
ErrorCode SALE_OUT_PROCESS_FAIL_EXISTS_RECEIPT = new ErrorCode(1_020_202_008, "鍙嶅鏍稿け璐ワ紝宸插瓨鍦ㄥ搴旂殑鏀舵鍗�");
- ErrorCode SALE_OUT_SUBMIT_FAIL_NOT_DRAFT = new ErrorCode(1_020_202_009, "鎻愪氦瀹℃壒澶辫触锛屽彧鏈夎崏绋跨姸鎬佺殑閿�鍞嚭搴撳崟鎵嶈兘鎻愪氦瀹℃壒");
- ErrorCode SALE_OUT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1_020_202_010, "鏇存柊瀹℃壒鐘舵�佸け璐ワ紝鍙湁瀹℃壒涓殑閿�鍞嚭搴撳崟鎵嶈兘鏇存柊瀹℃壒鐘舵��");
// ========== ERP 閿�鍞��璐э紙1-030-203-000锛� ==========
ErrorCode SALE_RETURN_NOT_EXISTS = new ErrorCode(1_020_203_000, "閿�鍞��璐у崟涓嶅瓨鍦�");
@@ -138,7 +130,6 @@
// ========== ERP 浜у搧 1-030-500-000 ==========
ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "浜у搧涓嶅瓨鍦�");
ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "浜у搧({})鏈惎鐢�");
- ErrorCode PRODUCT_BAR_CODE_EXISTS = new ErrorCode(1_030_500_002, "浜у搧鏉$爜宸插瓨鍦�");
// ========== ERP 浜у搧鍒嗙被 1-030-501-000 ==========
ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "浜у搧鍒嗙被涓嶅瓨鍦�");
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java
index cf7cb5c..88599a8 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java
@@ -8,15 +8,10 @@
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO;
+import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
-import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemCreateReqDTO;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemUpdateReqDTO;
-import cn.iocoder.yudao.module.mdm.api.category.MdmItemCategoryApi;
-import cn.iocoder.yudao.module.mdm.api.category.dto.MdmItemCategoryRespDTO;
-import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
-import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
+import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
+import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -30,57 +25,46 @@
/**
* ERP 浜у搧 Service 瀹炵幇绫�
*
- * 鏀归�犺鏄庯細ERP 浜у搧鏁版嵁鏉ユ簮浜� MDM 鐗╂枡涓绘暟鎹�
- * - 鎵�鏈変骇鍝佹搷浣滃潎璋冪敤 MDM API
- * - ERP 浜у搧瀵瑰簲 MDM 鐗╂枡绫诲瀷 = 鎴愬搧锛坕temType = 2锛�
- *
* @author 鑺嬮亾婧愮爜
*/
@Service
@Validated
public class ErpProductServiceImpl implements ErpProductService {
- /** ERP 浜у搧瀵瑰簲鐨� MDM 鐗╂枡绫诲瀷锛氭垚鍝� */
- private static final int MDM_ITEM_TYPE_PRODUCT = 2;
+ @Resource
+ private ErpProductMapper productMapper;
@Resource
- private MdmItemApi mdmItemApi;
-
+ private ErpProductCategoryService productCategoryService;
@Resource
- private MdmItemCategoryApi mdmItemCategoryApi;
-
- @Resource
- private MdmUnitMeasureApi mdmUnitMeasureApi;
+ private ErpProductUnitService productUnitService;
@Override
public Long createProduct(ProductSaveReqVO createReqVO) {
- // 1. 鏍¢獙鏉$爜鍞竴
- validateProductBarCodeUnique(null, createReqVO.getBarCode());
-
- // 2. 鏋勫缓鍒涘缓璇锋眰骞惰皟鐢� MDM API
- MdmItemCreateReqDTO createReqDTO = buildCreateReqDTO(createReqVO);
- return mdmItemApi.createItem(createReqDTO).getCheckedData();
+ // TODO 鑺嬭壙锛氭牎楠屽垎绫�
+ // 鎻掑叆
+ ErpProductDO product = BeanUtils.toBean(createReqVO, ErpProductDO.class);
+ productMapper.insert(product);
+ // 杩斿洖
+ return product.getId();
}
@Override
public void updateProduct(ProductSaveReqVO updateReqVO) {
- // 1. 鏍¢獙瀛樺湪
+ // TODO 鑺嬭壙锛氭牎楠屽垎绫�
+ // 鏍¢獙瀛樺湪
validateProductExists(updateReqVO.getId());
-
- // 2. 鏍¢獙鏉$爜鍞竴
- validateProductBarCodeUnique(updateReqVO.getId(), updateReqVO.getBarCode());
-
- // 3. 鏋勫缓鏇存柊璇锋眰骞惰皟鐢� MDM API
- MdmItemUpdateReqDTO updateReqDTO = buildUpdateReqDTO(updateReqVO);
- mdmItemApi.updateItem(updateReqDTO);
+ // 鏇存柊
+ ErpProductDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductDO.class);
+ productMapper.updateById(updateObj);
}
@Override
public void deleteProduct(Long id) {
// 鏍¢獙瀛樺湪
validateProductExists(id);
- // ERP 浜у搧鍒犻櫎瀹為檯涓虹鐢紙MDM 鐗╂枡涓嶈兘鐗╃悊鍒犻櫎锛�
- mdmItemApi.updateItemStatus(id, CommonStatusEnum.DISABLE.getStatus());
+ // 鍒犻櫎
+ productMapper.deleteById(id);
}
@Override
@@ -88,36 +72,35 @@
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
}
-
- // 1. 璋冪敤 MDM API 鑾峰彇鐗╂枡鍒楄〃
- List<MdmItemRespDTO> itemList = mdmItemApi.getItemList(ids).getCheckedData();
- Map<Long, MdmItemRespDTO> itemMap = convertMap(itemList, MdmItemRespDTO::getId);
-
- // 2. 鏍¢獙姣忎釜浜у搧
+ List<ErpProductDO> list = productMapper.selectByIds(ids);
+ Map<Long, ErpProductDO> productMap = convertMap(list, ErpProductDO::getId);
for (Long id : ids) {
- MdmItemRespDTO item = itemMap.get(id);
- if (item == null) {
+ ErpProductDO product = productMap.get(id);
+ if (productMap.get(id) == null) {
throw exception(PRODUCT_NOT_EXISTS);
}
- if (CommonStatusEnum.isDisable(item.getStatus())) {
- throw exception(PRODUCT_NOT_ENABLE, item.getName());
+ if (CommonStatusEnum.isDisable(product.getStatus())) {
+ throw exception(PRODUCT_NOT_ENABLE, product.getName());
}
}
+ return list;
+ }
- // 3. 杞崲涓� ERP Product DO锛堟墜鍔ㄦ槧灏勫瓧娈碉級
- return convertToErpProductDOList(itemList);
+ private void validateProductExists(Long id) {
+ if (productMapper.selectById(id) == null) {
+ throw exception(PRODUCT_NOT_EXISTS);
+ }
}
@Override
public ErpProductDO getProduct(Long id) {
- MdmItemRespDTO item = mdmItemApi.getItem(id).getCheckedData();
- return convertToErpProductDO(item);
+ return productMapper.selectById(id);
}
@Override
public List<ErpProductRespVO> getProductVOListByStatus(Integer status) {
- List<MdmItemRespDTO> itemList = mdmItemApi.getItemListByStatus(status).getCheckedData();
- return buildProductVOList(itemList);
+ List<ErpProductDO> list = productMapper.selectListByStatus(status);
+ return buildProductVOList(list);
}
@Override
@@ -125,188 +108,40 @@
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
}
- List<MdmItemRespDTO> itemList = mdmItemApi.getItemList(ids).getCheckedData();
- return buildProductVOList(itemList);
+ List<ErpProductDO> list = productMapper.selectByIds(ids);
+ return buildProductVOList(list);
}
@Override
public PageResult<ErpProductRespVO> getProductVOPage(ErpProductPageReqVO pageReqVO) {
- // 璋冪敤 MDM API 鍒嗛〉鏌ヨ
- PageResult<MdmItemRespDTO> mdmPageResult = mdmItemApi.getItemPage(
- MDM_ITEM_TYPE_PRODUCT,
- pageReqVO.getStatus(),
- pageReqVO.getPageNo(),
- pageReqVO.getPageSize()
- ).getCheckedData();
+ PageResult<ErpProductDO> pageResult = productMapper.selectPage(pageReqVO);
+ return new PageResult<>(buildProductVOList(pageResult.getList()), pageResult.getTotal());
+ }
- List<ErpProductRespVO> productVOList = buildProductVOList(mdmPageResult.getList());
- return new PageResult<>(productVOList, mdmPageResult.getTotal());
+ private List<ErpProductRespVO> buildProductVOList(List<ErpProductDO> list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ Map<Long, ErpProductCategoryDO> categoryMap = productCategoryService.getProductCategoryMap(
+ convertSet(list, ErpProductDO::getCategoryId));
+ Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(
+ convertSet(list, ErpProductDO::getUnitId));
+ return BeanUtils.toBean(list, ErpProductRespVO.class, product -> {
+ MapUtils.findAndThen(categoryMap, product.getCategoryId(),
+ category -> product.setCategoryName(category.getName()));
+ MapUtils.findAndThen(unitMap, product.getUnitId(),
+ unit -> product.setUnitName(unit.getName()));
+ });
}
@Override
public Long getProductCountByCategoryId(Long categoryId) {
- return mdmItemApi.getItemCountByCategoryId(categoryId).getCheckedData();
+ return productMapper.selectCountByCategoryId(categoryId);
}
@Override
public Long getProductCountByUnitId(Long unitId) {
- return mdmItemApi.getItemCountByUnitMeasureId(unitId).getCheckedData();
+ return productMapper.selectCountByUnitId(unitId);
}
- // ==================== 绉佹湁鏂规硶 ====================
-
- /**
- * 鏍¢獙浜у搧瀛樺湪
- */
- private void validateProductExists(Long id) {
- mdmItemApi.validateItemExists(id).getCheckedData();
- }
-
- /**
- * 鏍¢獙浜у搧鏉$爜鍞竴
- */
- private void validateProductBarCodeUnique(Long id, String barCode) {
- if (barCode == null) {
- return;
- }
- MdmItemRespDTO existItem = mdmItemApi.getItemByBarCode(barCode).getCheckedData();
- if (existItem != null && !existItem.getId().equals(id)) {
- throw exception(PRODUCT_BAR_CODE_EXISTS);
- }
- }
-
- /**
- * 鏋勫缓鍒涘缓璇锋眰 DTO
- * 娉ㄦ剰锛歅roductSaveReqVO 浣跨敤 standard 瀛楁浣滀负瑙勬牸锛孧DM 浣跨敤 specification
- */
- private MdmItemCreateReqDTO buildCreateReqDTO(ProductSaveReqVO saveReqVO) {
- MdmItemCreateReqDTO createReqDTO = new MdmItemCreateReqDTO();
- createReqDTO.setCode(saveReqVO.getBarCode()); // 浣跨敤鏉$爜浣滀负缂栫爜
- createReqDTO.setName(saveReqVO.getName());
- createReqDTO.setBarCode(saveReqVO.getBarCode());
- createReqDTO.setSpecification(saveReqVO.getStandard()); // standard -> specification
- createReqDTO.setCategoryId(saveReqVO.getCategoryId());
- createReqDTO.setUnitMeasureId(saveReqVO.getUnitId()); // unitId -> unitMeasureId
- createReqDTO.setItemType(MDM_ITEM_TYPE_PRODUCT);
- createReqDTO.setStatus(saveReqVO.getStatus() != null ? saveReqVO.getStatus() : CommonStatusEnum.ENABLE.getStatus());
- createReqDTO.setPurchasePrice(saveReqVO.getPurchasePrice());
- createReqDTO.setSalesPrice(saveReqVO.getSalePrice());
- createReqDTO.setCostPrice(saveReqVO.getMinPrice()); // minPrice -> costPrice
- createReqDTO.setExpiryDay(saveReqVO.getExpiryDay());
- createReqDTO.setWeight(saveReqVO.getWeight());
- createReqDTO.setRemark(saveReqVO.getRemark());
- return createReqDTO;
- }
-
- /**
- * 鏋勫缓鏇存柊璇锋眰 DTO
- */
- private MdmItemUpdateReqDTO buildUpdateReqDTO(ProductSaveReqVO saveReqVO) {
- MdmItemUpdateReqDTO updateReqDTO = new MdmItemUpdateReqDTO();
- updateReqDTO.setId(saveReqVO.getId());
- updateReqDTO.setCode(saveReqVO.getBarCode());
- updateReqDTO.setName(saveReqVO.getName());
- updateReqDTO.setBarCode(saveReqVO.getBarCode());
- updateReqDTO.setSpecification(saveReqVO.getStandard()); // standard -> specification
- updateReqDTO.setCategoryId(saveReqVO.getCategoryId());
- updateReqDTO.setUnitMeasureId(saveReqVO.getUnitId()); // unitId -> unitMeasureId
- updateReqDTO.setStatus(saveReqVO.getStatus());
- updateReqDTO.setPurchasePrice(saveReqVO.getPurchasePrice());
- updateReqDTO.setSalesPrice(saveReqVO.getSalePrice());
- updateReqDTO.setCostPrice(saveReqVO.getMinPrice());
- updateReqDTO.setExpiryDay(saveReqVO.getExpiryDay());
- updateReqDTO.setWeight(saveReqVO.getWeight());
- updateReqDTO.setRemark(saveReqVO.getRemark());
- return updateReqDTO;
- }
-
- /**
- * 鏋勫缓浜у搧 VO 鍒楄〃锛堝寘鍚垎绫诲拰鍗曚綅鍚嶇О锛�
- * 娉ㄦ剰锛歁DM 鍜� ERP 瀛楁鍚嶆湁宸紓锛岄渶瑕佹墜鍔ㄦ槧灏�
- */
- private List<ErpProductRespVO> buildProductVOList(List<MdmItemRespDTO> itemList) {
- if (CollUtil.isEmpty(itemList)) {
- return Collections.emptyList();
- }
-
- // 1. 鑾峰彇鍒嗙被鍜屽崟浣嶄俊鎭�
- Set<Long> categoryIds = convertSet(itemList, MdmItemRespDTO::getCategoryId);
- Set<Long> unitIds = convertSet(itemList, MdmItemRespDTO::getUnitMeasureId);
-
- Map<Long, MdmItemCategoryRespDTO> categoryMap = CollUtil.isEmpty(categoryIds)
- ? Collections.emptyMap()
- : convertMap(mdmItemCategoryApi.getItemCategoryList(categoryIds).getCheckedData(), MdmItemCategoryRespDTO::getId);
-
- Map<Long, MdmUnitMeasureRespDTO> unitMap = CollUtil.isEmpty(unitIds)
- ? Collections.emptyMap()
- : convertMap(mdmUnitMeasureApi.getUnitMeasureList(unitIds).getCheckedData(), MdmUnitMeasureRespDTO::getId);
-
- // 2. 鎵嬪姩杞崲骞跺~鍏呭叧鑱斾俊鎭紙澶勭悊瀛楁鍚嶅樊寮傦級
- List<ErpProductRespVO> result = new ArrayList<>();
- for (MdmItemRespDTO mdmItem : itemList) {
- ErpProductRespVO product = new ErpProductRespVO();
- product.setId(mdmItem.getId());
- product.setName(mdmItem.getName());
- product.setBarCode(mdmItem.getBarCode());
- product.setStandard(mdmItem.getSpecification()); // specification -> standard
- product.setCategoryId(mdmItem.getCategoryId());
- product.setUnitId(mdmItem.getUnitMeasureId()); // unitMeasureId -> unitId
- product.setStatus(mdmItem.getStatus());
- product.setPurchasePrice(mdmItem.getPurchasePrice());
- product.setSalePrice(mdmItem.getSalesPrice()); // salesPrice -> salePrice
- product.setMinPrice(mdmItem.getCostPrice()); // costPrice -> minPrice
- product.setExpiryDay(mdmItem.getExpiryDay());
- product.setWeight(mdmItem.getWeight());
- product.setRemark(mdmItem.getRemark());
-
- // 璁剧疆鍒嗙被鍜屽崟浣嶅悕绉�
- MapUtils.findAndThen(categoryMap, mdmItem.getCategoryId(),
- category -> product.setCategoryName(category.getName()));
- MapUtils.findAndThen(unitMap, mdmItem.getUnitMeasureId(),
- unit -> product.setUnitName(unit.getName()));
-
- result.add(product);
- }
- return result;
- }
-
- /**
- * 杞崲 MDM 鐗╂枡涓� ERP 浜у搧 DO
- * 娉ㄦ剰锛氬瓧娈靛悕宸紓闇�瑕佹墜鍔ㄦ槧灏�
- */
- private ErpProductDO convertToErpProductDO(MdmItemRespDTO mdmItem) {
- if (mdmItem == null) {
- return null;
- }
- ErpProductDO product = new ErpProductDO();
- product.setId(mdmItem.getId());
- product.setName(mdmItem.getName());
- product.setBarCode(mdmItem.getBarCode());
- product.setStandard(mdmItem.getSpecification()); // specification -> standard
- product.setCategoryId(mdmItem.getCategoryId());
- product.setUnitId(mdmItem.getUnitMeasureId()); // unitMeasureId -> unitId
- product.setStatus(mdmItem.getStatus());
- product.setPurchasePrice(mdmItem.getPurchasePrice());
- product.setSalePrice(mdmItem.getSalesPrice()); // salesPrice -> salePrice
- product.setMinPrice(mdmItem.getCostPrice()); // costPrice -> minPrice
- product.setExpiryDay(mdmItem.getExpiryDay());
- product.setWeight(mdmItem.getWeight());
- product.setRemark(mdmItem.getRemark());
- return product;
- }
-
- /**
- * 鎵归噺杞崲 MDM 鐗╂枡鍒楄〃涓� ERP 浜у搧鍒楄〃
- */
- private List<ErpProductDO> convertToErpProductDOList(List<MdmItemRespDTO> mdmItemList) {
- if (CollUtil.isEmpty(mdmItemList)) {
- return Collections.emptyList();
- }
- List<ErpProductDO> result = new ArrayList<>();
- for (MdmItemRespDTO mdmItem : mdmItemList) {
- result.add(convertToErpProductDO(mdmItem));
- }
- return result;
- }
-
-}
\ No newline at end of file
+}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java
index 6bc25ff..37aa452 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java
@@ -42,22 +42,6 @@
void updatePurchaseInStatus(Long id, Integer status);
/**
- * 鎻愪氦閲囪喘鍏ュ簱瀹℃壒
- *
- * @param id 缂栧彿
- * @param userId 鐢ㄦ埛缂栧彿
- */
- void submitPurchaseIn(Long id, Long userId);
-
- /**
- * 鏇存柊閲囪喘鍏ュ簱鐨勫鎵圭姸鎬�
- *
- * @param id 缂栧彿
- * @param bpmResult BPM 瀹℃壒缁撴灉
- */
- void updatePurchaseInAuditStatus(Long id, Integer bpmResult);
-
- /**
* 鏇存柊閲囪喘鍏ュ簱鐨勪粯娆鹃噾棰�
*
* @param id 缂栧彿
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java
index 8481a93..adc2f40 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java
@@ -5,8 +5,6 @@
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
-import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.in.ErpPurchaseInSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
@@ -24,7 +22,6 @@
import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -40,6 +37,8 @@
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
+// TODO 鑺嬭壙锛氳褰曟搷浣滄棩蹇�
+
/**
* ERP 閲囪喘鍏ュ簱 Service 瀹炵幇绫�
*
@@ -47,13 +46,7 @@
*/
@Service
@Validated
-@Slf4j
public class ErpPurchaseInServiceImpl implements ErpPurchaseInService {
-
- /**
- * BPM 閲囪喘鍏ュ簱瀹℃壒娴佺▼鏍囪瘑
- */
- public static final String BPM_PROCESS_DEFINITION_KEY = "erp-purchase-in-audit";
@Resource
private ErpPurchaseInMapper purchaseInMapper;
@@ -76,9 +69,6 @@
@Resource
private AdminUserApi adminUserApi;
- @Resource
- private BpmProcessInstanceApi bpmProcessInstanceApi;
-
@Override
@Transactional(rollbackFor = Exception.class)
public Long createPurchaseIn(ErpPurchaseInSaveReqVO createReqVO) {
@@ -96,7 +86,7 @@
// 2.1 鎻掑叆鍏ュ簱
ErpPurchaseInDO purchaseIn = BeanUtils.toBean(createReqVO, ErpPurchaseInDO.class, in -> in
- .setNo(no).setStatus(ErpAuditStatus.DRAFT.getStatus()))
+ .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()))
.setOrderNo(purchaseOrder.getNo()).setSupplierId(purchaseOrder.getSupplierId());
calculateTotalPrice(purchaseIn, purchaseInItems);
purchaseInMapper.insert(purchaseIn);
@@ -191,15 +181,9 @@
: ErpStockRecordBizTypeEnum.PURCHASE_IN_CANCEL.getType();
purchaseInItems.forEach(purchaseInItem -> {
BigDecimal count = approve ? purchaseInItem.getCount() : purchaseInItem.getCount().negate();
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(purchaseInItem.getProductId());
- stockRecordBO.setWarehouseId(purchaseInItem.getWarehouseId());
- stockRecordBO.setCount(count);
- stockRecordBO.setBizType(bizType);
- stockRecordBO.setBizId(purchaseInItem.getInId());
- stockRecordBO.setBizItemId(purchaseInItem.getId());
- stockRecordBO.setBizNo(purchaseIn.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ purchaseInItem.getProductId(), purchaseInItem.getWarehouseId(), count,
+ bizType, purchaseInItem.getInId(), purchaseInItem.getId(), purchaseIn.getNo()));
});
}
@@ -319,85 +303,6 @@
return Collections.emptyList();
}
return purchaseInItemMapper.selectListByInIds(inIds);
- }
-
- // ==================== BPM 娴佺▼瀹℃壒 ====================
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void submitPurchaseIn(Long id, Long userId) {
- // 1. 鏍¢獙閲囪喘鍏ュ簱澶勪簬鑽夌鐘舵��
- ErpPurchaseInDO purchaseIn = validatePurchaseInExists(id);
- if (ObjectUtil.notEqual(purchaseIn.getStatus(), ErpAuditStatus.DRAFT.getStatus())) {
- throw exception(PURCHASE_IN_SUBMIT_FAIL_NOT_DRAFT);
- }
-
- // 2. 鍒涘缓閲囪喘鍏ュ簱瀹℃壒娴佺▼瀹炰緥
- String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
- .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY)
- .setBusinessKey(String.valueOf(id)));
-
- // 3. 鏇存柊閲囪喘鍏ュ簱宸ヤ綔娴佺紪鍙枫�佺姸鎬�
- purchaseInMapper.updateById(new ErpPurchaseInDO()
- .setId(id)
- .setProcessInstanceId(processInstanceId)
- .setStatus(ErpAuditStatus.PROCESS.getStatus()));
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void updatePurchaseInAuditStatus(Long id, Integer bpmResult) {
- // 1. 鏍¢獙閲囪喘鍏ュ簱瀛樺湪
- ErpPurchaseInDO purchaseIn = validatePurchaseInExists(id);
-
- // 2. 鏍¢獙閲囪喘鍏ュ簱澶勪簬瀹℃壒涓�
- if (ObjectUtil.notEqual(purchaseIn.getStatus(), ErpAuditStatus.PROCESS.getStatus())) {
- log.error("[updatePurchaseInAuditStatus][purchaseIn({}) 涓嶅浜庡鎵逛腑锛屾棤娉曟洿鏂板鎵圭粨鏋�({})]",
- purchaseIn.getId(), bpmResult);
- throw exception(PURCHASE_IN_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS);
- }
-
- // 3. 鏇存柊閲囪喘鍏ュ簱瀹℃壒缁撴灉
- Integer auditStatus = convertBpmResultToAuditStatus(bpmResult);
- purchaseInMapper.updateById(new ErpPurchaseInDO()
- .setId(id)
- .setStatus(auditStatus));
-
- // 4. 瀹℃壒閫氳繃鏃跺彉鏇村簱瀛�
- if (ErpAuditStatus.APPROVE.getStatus().equals(auditStatus)) {
- List<ErpPurchaseInItemDO> purchaseInItems = purchaseInItemMapper.selectListByInId(id);
- purchaseInItems.forEach(purchaseInItem -> {
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(purchaseInItem.getProductId());
- stockRecordBO.setWarehouseId(purchaseInItem.getWarehouseId());
- stockRecordBO.setCount(purchaseInItem.getCount());
- stockRecordBO.setBizType(ErpStockRecordBizTypeEnum.PURCHASE_IN.getType());
- stockRecordBO.setBizId(purchaseInItem.getInId());
- stockRecordBO.setBizItemId(purchaseInItem.getId());
- stockRecordBO.setBizNo(purchaseIn.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
- });
- }
- }
-
- /**
- * 灏� BPM 瀹℃壒缁撴灉杞崲涓� ERP 瀹℃壒鐘舵��
- *
- * @param bpmResult BPM 瀹℃壒缁撴灉
- * @return ERP 瀹℃壒鐘舵��
- */
- private Integer convertBpmResultToAuditStatus(Integer bpmResult) {
- // BPM 瀹℃壒缁撴灉锛�2=閫氳繃锛�3=涓嶉�氳繃锛�4=宸插彇娑�
- if (bpmResult == 2) {
- return ErpAuditStatus.APPROVE.getStatus();
- } else if (bpmResult == 3) {
- return ErpAuditStatus.REJECT.getStatus();
- } else if (bpmResult == 4) {
- return ErpAuditStatus.DRAFT.getStatus();
- } else {
- log.warn("[convertBpmResultToAuditStatus][鏈煡鐨� BPM 瀹℃壒缁撴灉({})]", bpmResult);
- return ErpAuditStatus.PROCESS.getStatus();
- }
}
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java
index 15f998b..bfea076 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java
@@ -43,22 +43,6 @@
void updatePurchaseOrderStatus(Long id, Integer status);
/**
- * 鎻愪氦閲囪喘璁㈠崟瀹℃壒
- *
- * @param id 缂栧彿
- * @param userId 鐢ㄦ埛缂栧彿
- */
- void submitPurchaseOrder(Long id, Long userId);
-
- /**
- * 鏇存柊閲囪喘璁㈠崟鐨勫鎵圭姸鎬�
- *
- * @param id 缂栧彿
- * @param bpmResult BPM 瀹℃壒缁撴灉
- */
- void updatePurchaseOrderAuditStatus(Long id, Integer bpmResult);
-
- /**
* 鏇存柊閲囪喘璁㈠崟鐨勫叆搴撴暟閲�
*
* @param id 缂栧彿
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java
index ccd1dd1..b93ca55 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java
@@ -5,8 +5,6 @@
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
-import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
@@ -19,7 +17,6 @@
import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -34,6 +31,8 @@
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
+// TODO 鑺嬭壙锛氳褰曟搷浣滄棩蹇�
+
/**
* ERP 閲囪喘璁㈠崟 Service 瀹炵幇绫�
*
@@ -41,13 +40,7 @@
*/
@Service
@Validated
-@Slf4j
public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
-
- /**
- * BPM 閲囪喘璁㈠崟瀹℃壒娴佺▼鏍囪瘑
- */
- public static final String BPM_PROCESS_DEFINITION_KEY = "erp-purchase-order-audit";
@Resource
private ErpPurchaseOrderMapper purchaseOrderMapper;
@@ -63,9 +56,6 @@
private ErpSupplierService supplierService;
@Resource
private ErpAccountService accountService;
-
- @Resource
- private BpmProcessInstanceApi bpmProcessInstanceApi;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -86,7 +76,7 @@
// 2.1 鎻掑叆璁㈠崟
ErpPurchaseOrderDO purchaseOrder = BeanUtils.toBean(createReqVO, ErpPurchaseOrderDO.class, in -> in
- .setNo(no).setStatus(ErpAuditStatus.DRAFT.getStatus()));
+ .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()));
calculateTotalPrice(purchaseOrder, purchaseOrderItems);
purchaseOrderMapper.insert(purchaseOrder);
// 2.2 鎻掑叆璁㈠崟椤�
@@ -300,69 +290,6 @@
return Collections.emptyList();
}
return purchaseOrderItemMapper.selectListByOrderIds(orderIds);
- }
-
- // ==================== BPM 娴佺▼瀹℃壒 ====================
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void submitPurchaseOrder(Long id, Long userId) {
- // 1. 鏍¢獙閲囪喘璁㈠崟澶勪簬鑽夌鐘舵��
- ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(id);
- if (ObjectUtil.notEqual(purchaseOrder.getStatus(), ErpAuditStatus.DRAFT.getStatus())) {
- throw exception(PURCHASE_ORDER_SUBMIT_FAIL_NOT_DRAFT);
- }
-
- // 2. 鍒涘缓閲囪喘璁㈠崟瀹℃壒娴佺▼瀹炰緥
- String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
- .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY)
- .setBusinessKey(String.valueOf(id)));
-
- // 3. 鏇存柊閲囪喘璁㈠崟宸ヤ綔娴佺紪鍙枫�佺姸鎬�
- purchaseOrderMapper.updateById(new ErpPurchaseOrderDO()
- .setId(id)
- .setProcessInstanceId(processInstanceId)
- .setStatus(ErpAuditStatus.PROCESS.getStatus()));
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void updatePurchaseOrderAuditStatus(Long id, Integer bpmResult) {
- // 1. 鏍¢獙閲囪喘璁㈠崟瀛樺湪
- ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(id);
-
- // 2. 鏍¢獙閲囪喘璁㈠崟澶勪簬瀹℃壒涓�
- if (ObjectUtil.notEqual(purchaseOrder.getStatus(), ErpAuditStatus.PROCESS.getStatus())) {
- log.error("[updatePurchaseOrderAuditStatus][purchaseOrder({}) 涓嶅浜庡鎵逛腑锛屾棤娉曟洿鏂板鎵圭粨鏋�({})]",
- purchaseOrder.getId(), bpmResult);
- throw exception(PURCHASE_ORDER_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS);
- }
-
- // 3. 鏇存柊閲囪喘璁㈠崟瀹℃壒缁撴灉
- Integer auditStatus = convertBpmResultToAuditStatus(bpmResult);
- purchaseOrderMapper.updateById(new ErpPurchaseOrderDO()
- .setId(id)
- .setStatus(auditStatus));
- }
-
- /**
- * 灏� BPM 瀹℃壒缁撴灉杞崲涓� ERP 瀹℃壒鐘舵��
- *
- * @param bpmResult BPM 瀹℃壒缁撴灉
- * @return ERP 瀹℃壒鐘舵��
- */
- private Integer convertBpmResultToAuditStatus(Integer bpmResult) {
- // BPM 瀹℃壒缁撴灉锛�2=閫氳繃锛�3=涓嶉�氳繃锛�4=宸插彇娑�
- if (bpmResult == 2) {
- return ErpAuditStatus.APPROVE.getStatus();
- } else if (bpmResult == 3) {
- return ErpAuditStatus.REJECT.getStatus();
- } else if (bpmResult == 4) {
- return ErpAuditStatus.DRAFT.getStatus();
- } else {
- log.warn("[convertBpmResultToAuditStatus][鏈煡鐨� BPM 瀹℃壒缁撴灉({})]", bpmResult);
- return ErpAuditStatus.PROCESS.getStatus();
- }
}
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java
index f7fa72f..18fe5ce 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java
@@ -177,15 +177,9 @@
: ErpStockRecordBizTypeEnum.PURCHASE_RETURN_CANCEL.getType();
purchaseReturnItems.forEach(purchaseReturnItem -> {
BigDecimal count = approve ? purchaseReturnItem.getCount().negate() : purchaseReturnItem.getCount();
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(purchaseReturnItem.getProductId());
- stockRecordBO.setWarehouseId(purchaseReturnItem.getWarehouseId());
- stockRecordBO.setCount(count);
- stockRecordBO.setBizType(bizType);
- stockRecordBO.setBizId(purchaseReturnItem.getReturnId());
- stockRecordBO.setBizItemId(purchaseReturnItem.getId());
- stockRecordBO.setBizNo(purchaseReturn.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ purchaseReturnItem.getProductId(), purchaseReturnItem.getWarehouseId(), count,
+ bizType, purchaseReturnItem.getReturnId(), purchaseReturnItem.getId(), purchaseReturn.getNo()));
});
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/listener/ErpPurchaseInStatusListener.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/listener/ErpPurchaseInStatusListener.java
deleted file mode 100644
index 3c52a85..0000000
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/listener/ErpPurchaseInStatusListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.erp.service.purchase.listener;
-
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
-import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseInService;
-import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseInServiceImpl;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Component;
-
-/**
- * 閲囪喘鍏ュ簱瀹℃壒鐨勭粨鏋滅殑鐩戝惉鍣ㄥ疄鐜扮被
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Component
-public class ErpPurchaseInStatusListener extends BpmProcessInstanceStatusEventListener {
-
- @Resource
- private ErpPurchaseInService purchaseInService;
-
- @Override
- public String getProcessDefinitionKey() {
- return ErpPurchaseInServiceImpl.BPM_PROCESS_DEFINITION_KEY;
- }
-
- @Override
- protected void onEvent(BpmProcessInstanceStatusEvent event) {
- purchaseInService.updatePurchaseInAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
- }
-
-}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/listener/ErpPurchaseOrderStatusListener.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/listener/ErpPurchaseOrderStatusListener.java
deleted file mode 100644
index 21b8109..0000000
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/listener/ErpPurchaseOrderStatusListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.erp.service.purchase.listener;
-
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
-import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseOrderService;
-import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseOrderServiceImpl;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Component;
-
-/**
- * 閲囪喘璁㈠崟瀹℃壒鐨勭粨鏋滅殑鐩戝惉鍣ㄥ疄鐜扮被
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Component
-public class ErpPurchaseOrderStatusListener extends BpmProcessInstanceStatusEventListener {
-
- @Resource
- private ErpPurchaseOrderService purchaseOrderService;
-
- @Override
- public String getProcessDefinitionKey() {
- return ErpPurchaseOrderServiceImpl.BPM_PROCESS_DEFINITION_KEY;
- }
-
- @Override
- protected void onEvent(BpmProcessInstanceStatusEvent event) {
- purchaseOrderService.updatePurchaseOrderAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
- }
-
-}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java
index 530faa9..c75f201 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java
@@ -43,22 +43,6 @@
void updateSaleOrderStatus(Long id, Integer status);
/**
- * 鎻愪氦閿�鍞鍗曞鎵�
- *
- * @param id 缂栧彿
- * @param userId 鐢ㄦ埛缂栧彿
- */
- void submitSaleOrder(Long id, Long userId);
-
- /**
- * 鏇存柊閿�鍞鍗曠殑瀹℃壒鐘舵��
- *
- * @param id 缂栧彿
- * @param bpmResult BPM 瀹℃壒缁撴灉
- */
- void updateSaleOrderAuditStatus(Long id, Integer bpmResult);
-
- /**
* 鏇存柊閿�鍞鍗曠殑鍑哄簱鏁伴噺
*
* @param id 缂栧彿
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
index 4abe8c6..0edd206 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
@@ -5,8 +5,6 @@
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
-import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
@@ -20,7 +18,6 @@
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -35,6 +32,8 @@
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
+// TODO 鑺嬭壙锛氳褰曟搷浣滄棩蹇�
+
/**
* ERP 閿�鍞鍗� Service 瀹炵幇绫�
*
@@ -42,13 +41,7 @@
*/
@Service
@Validated
-@Slf4j
public class ErpSaleOrderServiceImpl implements ErpSaleOrderService {
-
- /**
- * BPM 閿�鍞鍗曞鎵规祦绋嬫爣璇�
- */
- public static final String BPM_PROCESS_DEFINITION_KEY = "erp-sale-order-audit";
@Resource
private ErpSaleOrderMapper saleOrderMapper;
@@ -67,9 +60,6 @@
@Resource
private AdminUserApi adminUserApi;
-
- @Resource
- private BpmProcessInstanceApi bpmProcessInstanceApi;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -94,7 +84,7 @@
// 2.1 鎻掑叆璁㈠崟
ErpSaleOrderDO saleOrder = BeanUtils.toBean(createReqVO, ErpSaleOrderDO.class, in -> in
- .setNo(no).setStatus(ErpAuditStatus.DRAFT.getStatus()));
+ .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()));
calculateTotalPrice(saleOrder, saleOrderItems);
saleOrderMapper.insert(saleOrder);
// 2.2 鎻掑叆璁㈠崟椤�
@@ -312,69 +302,6 @@
return Collections.emptyList();
}
return saleOrderItemMapper.selectListByOrderIds(orderIds);
- }
-
- // ==================== BPM 娴佺▼瀹℃壒 ====================
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void submitSaleOrder(Long id, Long userId) {
- // 1. 鏍¢獙閿�鍞鍗曞浜庤崏绋跨姸鎬�
- ErpSaleOrderDO saleOrder = validateSaleOrderExists(id);
- if (ObjectUtil.notEqual(saleOrder.getStatus(), ErpAuditStatus.DRAFT.getStatus())) {
- throw exception(SALE_ORDER_SUBMIT_FAIL_NOT_DRAFT);
- }
-
- // 2. 鍒涘缓閿�鍞鍗曞鎵规祦绋嬪疄渚�
- String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
- .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY)
- .setBusinessKey(String.valueOf(id)));
-
- // 3. 鏇存柊閿�鍞鍗曞伐浣滄祦缂栧彿銆佺姸鎬�
- saleOrderMapper.updateById(new ErpSaleOrderDO()
- .setId(id)
- .setProcessInstanceId(processInstanceId)
- .setStatus(ErpAuditStatus.PROCESS.getStatus()));
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void updateSaleOrderAuditStatus(Long id, Integer bpmResult) {
- // 1. 鏍¢獙閿�鍞鍗曞瓨鍦�
- ErpSaleOrderDO saleOrder = validateSaleOrderExists(id);
-
- // 2. 鏍¢獙閿�鍞鍗曞浜庡鎵逛腑
- if (ObjectUtil.notEqual(saleOrder.getStatus(), ErpAuditStatus.PROCESS.getStatus())) {
- log.error("[updateSaleOrderAuditStatus][saleOrder({}) 涓嶅浜庡鎵逛腑锛屾棤娉曟洿鏂板鎵圭粨鏋�({})]",
- saleOrder.getId(), bpmResult);
- throw exception(SALE_ORDER_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS);
- }
-
- // 3. 鏇存柊閿�鍞鍗曞鎵圭粨鏋�
- Integer auditStatus = convertBpmResultToAuditStatus(bpmResult);
- saleOrderMapper.updateById(new ErpSaleOrderDO()
- .setId(id)
- .setStatus(auditStatus));
- }
-
- /**
- * 灏� BPM 瀹℃壒缁撴灉杞崲涓� ERP 瀹℃壒鐘舵��
- *
- * @param bpmResult BPM 瀹℃壒缁撴灉
- * @return ERP 瀹℃壒鐘舵��
- */
- private Integer convertBpmResultToAuditStatus(Integer bpmResult) {
- // BPM 瀹℃壒缁撴灉锛�2=閫氳繃锛�3=涓嶉�氳繃锛�4=宸插彇娑�
- if (bpmResult == 2) {
- return ErpAuditStatus.APPROVE.getStatus();
- } else if (bpmResult == 3) {
- return ErpAuditStatus.REJECT.getStatus();
- } else if (bpmResult == 4) {
- return ErpAuditStatus.DRAFT.getStatus();
- } else {
- log.warn("[convertBpmResultToAuditStatus][鏈煡鐨� BPM 瀹℃壒缁撴灉({})]", bpmResult);
- return ErpAuditStatus.PROCESS.getStatus();
- }
}
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java
index 892f177..616f778 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java
@@ -42,22 +42,6 @@
void updateSaleOutStatus(Long id, Integer status);
/**
- * 鎻愪氦閿�鍞嚭搴撳鎵�
- *
- * @param id 缂栧彿
- * @param userId 鐢ㄦ埛缂栧彿
- */
- void submitSaleOut(Long id, Long userId);
-
- /**
- * 鏇存柊閿�鍞嚭搴撶殑瀹℃壒鐘舵��
- *
- * @param id 缂栧彿
- * @param bpmResult BPM 瀹℃壒缁撴灉
- */
- void updateSaleOutAuditStatus(Long id, Integer bpmResult);
-
- /**
* 鏇存柊閿�鍞嚭搴撶殑鏀舵閲戦
*
* @param id 缂栧彿
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java
index 45aad13..f8af202 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java
@@ -5,8 +5,6 @@
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
-import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
@@ -24,7 +22,6 @@
import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -40,6 +37,8 @@
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
+// TODO 鑺嬭壙锛氳褰曟搷浣滄棩蹇�
+
/**
* ERP 閿�鍞嚭搴� Service 瀹炵幇绫�
*
@@ -47,13 +46,7 @@
*/
@Service
@Validated
-@Slf4j
public class ErpSaleOutServiceImpl implements ErpSaleOutService {
-
- /**
- * BPM 閿�鍞嚭搴撳鎵规祦绋嬫爣璇�
- */
- public static final String BPM_PROCESS_DEFINITION_KEY = "erp-sale-out-audit";
@Resource
private ErpSaleOutMapper saleOutMapper;
@@ -76,9 +69,6 @@
@Resource
private AdminUserApi adminUserApi;
- @Resource
- private BpmProcessInstanceApi bpmProcessInstanceApi;
-
@Override
@Transactional(rollbackFor = Exception.class)
public Long createSaleOut(ErpSaleOutSaveReqVO createReqVO) {
@@ -100,7 +90,7 @@
// 2.1 鎻掑叆鍑哄簱
ErpSaleOutDO saleOut = BeanUtils.toBean(createReqVO, ErpSaleOutDO.class, in -> in
- .setNo(no).setStatus(ErpAuditStatus.DRAFT.getStatus()))
+ .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()))
.setOrderNo(saleOrder.getNo()).setCustomerId(saleOrder.getCustomerId());
calculateTotalPrice(saleOut, saleOutItems);
saleOutMapper.insert(saleOut);
@@ -199,15 +189,9 @@
: ErpStockRecordBizTypeEnum.SALE_OUT_CANCEL.getType();
saleOutItems.forEach(saleOutItem -> {
BigDecimal count = approve ? saleOutItem.getCount().negate() : saleOutItem.getCount();
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(saleOutItem.getProductId());
- stockRecordBO.setWarehouseId(saleOutItem.getWarehouseId());
- stockRecordBO.setCount(count);
- stockRecordBO.setBizType(bizType);
- stockRecordBO.setBizId(saleOutItem.getOutId());
- stockRecordBO.setBizItemId(saleOutItem.getId());
- stockRecordBO.setBizNo(saleOut.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ saleOutItem.getProductId(), saleOutItem.getWarehouseId(), count,
+ bizType, saleOutItem.getOutId(), saleOutItem.getId(), saleOut.getNo()));
});
}
@@ -327,85 +311,6 @@
return Collections.emptyList();
}
return saleOutItemMapper.selectListByOutIds(outIds);
- }
-
- // ==================== BPM 娴佺▼瀹℃壒 ====================
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void submitSaleOut(Long id, Long userId) {
- // 1. 鏍¢獙閿�鍞嚭搴撳浜庤崏绋跨姸鎬�
- ErpSaleOutDO saleOut = validateSaleOutExists(id);
- if (ObjectUtil.notEqual(saleOut.getStatus(), ErpAuditStatus.DRAFT.getStatus())) {
- throw exception(SALE_OUT_SUBMIT_FAIL_NOT_DRAFT);
- }
-
- // 2. 鍒涘缓閿�鍞嚭搴撳鎵规祦绋嬪疄渚�
- String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
- .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY)
- .setBusinessKey(String.valueOf(id)));
-
- // 3. 鏇存柊閿�鍞嚭搴撳伐浣滄祦缂栧彿銆佺姸鎬�
- saleOutMapper.updateById(new ErpSaleOutDO()
- .setId(id)
- .setProcessInstanceId(processInstanceId)
- .setStatus(ErpAuditStatus.PROCESS.getStatus()));
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void updateSaleOutAuditStatus(Long id, Integer bpmResult) {
- // 1. 鏍¢獙閿�鍞嚭搴撳瓨鍦�
- ErpSaleOutDO saleOut = validateSaleOutExists(id);
-
- // 2. 鏍¢獙閿�鍞嚭搴撳浜庡鎵逛腑
- if (ObjectUtil.notEqual(saleOut.getStatus(), ErpAuditStatus.PROCESS.getStatus())) {
- log.error("[updateSaleOutAuditStatus][saleOut({}) 涓嶅浜庡鎵逛腑锛屾棤娉曟洿鏂板鎵圭粨鏋�({})]",
- saleOut.getId(), bpmResult);
- throw exception(SALE_OUT_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS);
- }
-
- // 3. 鏇存柊閿�鍞嚭搴撳鎵圭粨鏋�
- Integer auditStatus = convertBpmResultToAuditStatus(bpmResult);
- saleOutMapper.updateById(new ErpSaleOutDO()
- .setId(id)
- .setStatus(auditStatus));
-
- // 4. 瀹℃壒閫氳繃鏃跺彉鏇村簱瀛橈紙鍑忓皯搴撳瓨锛�
- if (ErpAuditStatus.APPROVE.getStatus().equals(auditStatus)) {
- List<ErpSaleOutItemDO> saleOutItems = saleOutItemMapper.selectListByOutId(id);
- saleOutItems.forEach(saleOutItem -> {
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(saleOutItem.getProductId());
- stockRecordBO.setWarehouseId(saleOutItem.getWarehouseId());
- stockRecordBO.setCount(saleOutItem.getCount().negate());
- stockRecordBO.setBizType(ErpStockRecordBizTypeEnum.SALE_OUT.getType());
- stockRecordBO.setBizId(saleOutItem.getOutId());
- stockRecordBO.setBizItemId(saleOutItem.getId());
- stockRecordBO.setBizNo(saleOut.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
- });
- }
- }
-
- /**
- * 灏� BPM 瀹℃壒缁撴灉杞崲涓� ERP 瀹℃壒鐘舵��
- *
- * @param bpmResult BPM 瀹℃壒缁撴灉
- * @return ERP 瀹℃壒鐘舵��
- */
- private Integer convertBpmResultToAuditStatus(Integer bpmResult) {
- // BPM 瀹℃壒缁撴灉锛�2=閫氳繃锛�3=涓嶉�氳繃锛�4=宸插彇娑�
- if (bpmResult == 2) {
- return ErpAuditStatus.APPROVE.getStatus();
- } else if (bpmResult == 3) {
- return ErpAuditStatus.REJECT.getStatus();
- } else if (bpmResult == 4) {
- return ErpAuditStatus.DRAFT.getStatus();
- } else {
- log.warn("[convertBpmResultToAuditStatus][鏈煡鐨� BPM 瀹℃壒缁撴灉({})]", bpmResult);
- return ErpAuditStatus.PROCESS.getStatus();
- }
}
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java
index ea97f1c..6b3976c 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java
@@ -189,15 +189,9 @@
: ErpStockRecordBizTypeEnum.SALE_RETURN_CANCEL.getType();
saleReturnItems.forEach(saleReturnItem -> {
BigDecimal count = approve ? saleReturnItem.getCount() : saleReturnItem.getCount().negate();
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(saleReturnItem.getProductId());
- stockRecordBO.setWarehouseId(saleReturnItem.getWarehouseId());
- stockRecordBO.setCount(count);
- stockRecordBO.setBizType(bizType);
- stockRecordBO.setBizId(saleReturnItem.getReturnId());
- stockRecordBO.setBizItemId(saleReturnItem.getId());
- stockRecordBO.setBizNo(saleReturn.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ saleReturnItem.getProductId(), saleReturnItem.getWarehouseId(), count,
+ bizType, saleReturnItem.getReturnId(), saleReturnItem.getId(), saleReturn.getNo()));
});
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/listener/ErpSaleOrderStatusListener.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/listener/ErpSaleOrderStatusListener.java
deleted file mode 100644
index 6faaed3..0000000
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/listener/ErpSaleOrderStatusListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.erp.service.sale.listener;
-
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
-import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOrderService;
-import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOrderServiceImpl;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Component;
-
-/**
- * 閿�鍞鍗曞鎵圭殑缁撴灉鐨勭洃鍚櫒瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Component
-public class ErpSaleOrderStatusListener extends BpmProcessInstanceStatusEventListener {
-
- @Resource
- private ErpSaleOrderService saleOrderService;
-
- @Override
- public String getProcessDefinitionKey() {
- return ErpSaleOrderServiceImpl.BPM_PROCESS_DEFINITION_KEY;
- }
-
- @Override
- protected void onEvent(BpmProcessInstanceStatusEvent event) {
- saleOrderService.updateSaleOrderAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
- }
-
-}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/listener/ErpSaleOutStatusListener.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/listener/ErpSaleOutStatusListener.java
deleted file mode 100644
index 8e01981..0000000
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/listener/ErpSaleOutStatusListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.erp.service.sale.listener;
-
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
-import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOutService;
-import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOutServiceImpl;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Component;
-
-/**
- * 閿�鍞嚭搴撳鎵圭殑缁撴灉鐨勭洃鍚櫒瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Component
-public class ErpSaleOutStatusListener extends BpmProcessInstanceStatusEventListener {
-
- @Resource
- private ErpSaleOutService saleOutService;
-
- @Override
- public String getProcessDefinitionKey() {
- return ErpSaleOutServiceImpl.BPM_PROCESS_DEFINITION_KEY;
- }
-
- @Override
- protected void onEvent(BpmProcessInstanceStatusEvent event) {
- saleOutService.updateSaleOutAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java
index 11b9f73..bbe08ae 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java
@@ -135,15 +135,9 @@
bizType = count.compareTo(BigDecimal.ZERO) > 0 ? ErpStockRecordBizTypeEnum.CHECK_MORE_IN_CANCEL.getType()
: ErpStockRecordBizTypeEnum.CHECK_LESS_OUT_CANCEL.getType();
}
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(stockCheckItem.getProductId());
- stockRecordBO.setWarehouseId(stockCheckItem.getWarehouseId());
- stockRecordBO.setCount(count);
- stockRecordBO.setBizType(bizType);
- stockRecordBO.setBizId(stockCheckItem.getCheckId());
- stockRecordBO.setBizItemId(stockCheckItem.getId());
- stockRecordBO.setBizNo(stockCheck.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ stockCheckItem.getProductId(), stockCheckItem.getWarehouseId(), count,
+ bizType, stockCheckItem.getCheckId(), stockCheckItem.getId(), stockCheck.getNo()));
});
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java
index 837240d..38967de 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java
@@ -130,15 +130,9 @@
: ErpStockRecordBizTypeEnum.OTHER_IN_CANCEL.getType();
stockInItems.forEach(stockInItem -> {
BigDecimal count = approve ? stockInItem.getCount() : stockInItem.getCount().negate();
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(stockInItem.getProductId());
- stockRecordBO.setWarehouseId(stockInItem.getWarehouseId());
- stockRecordBO.setCount(count);
- stockRecordBO.setBizType(bizType);
- stockRecordBO.setBizId(stockInItem.getInId());
- stockRecordBO.setBizItemId(stockInItem.getId());
- stockRecordBO.setBizNo(stockIn.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ stockInItem.getProductId(), stockInItem.getWarehouseId(), count,
+ bizType, stockInItem.getInId(), stockInItem.getId(), stockIn.getNo()));
});
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java
index 9f20497..f039227 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java
@@ -128,24 +128,12 @@
stockMoveItems.forEach(stockMoveItem -> {
BigDecimal fromCount = approve ? stockMoveItem.getCount().negate() : stockMoveItem.getCount();
BigDecimal toCount = approve ? stockMoveItem.getCount() : stockMoveItem.getCount().negate();
- ErpStockRecordCreateReqBO fromStockRecordBO = new ErpStockRecordCreateReqBO();
- fromStockRecordBO.setProductId(stockMoveItem.getProductId());
- fromStockRecordBO.setWarehouseId(stockMoveItem.getFromWarehouseId());
- fromStockRecordBO.setCount(fromCount);
- fromStockRecordBO.setBizType(fromBizType);
- fromStockRecordBO.setBizId(stockMoveItem.getMoveId());
- fromStockRecordBO.setBizItemId(stockMoveItem.getId());
- fromStockRecordBO.setBizNo(stockMove.getNo());
- stockRecordService.createStockRecord(fromStockRecordBO);
- ErpStockRecordCreateReqBO toStockRecordBO = new ErpStockRecordCreateReqBO();
- toStockRecordBO.setProductId(stockMoveItem.getProductId());
- toStockRecordBO.setWarehouseId(stockMoveItem.getToWarehouseId());
- toStockRecordBO.setCount(toCount);
- toStockRecordBO.setBizType(toBizType);
- toStockRecordBO.setBizId(stockMoveItem.getMoveId());
- toStockRecordBO.setBizItemId(stockMoveItem.getId());
- toStockRecordBO.setBizNo(stockMove.getNo());
- stockRecordService.createStockRecord(toStockRecordBO);
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ stockMoveItem.getProductId(), stockMoveItem.getFromWarehouseId(), fromCount,
+ fromBizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo()));
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ stockMoveItem.getProductId(), stockMoveItem.getToWarehouseId(), toCount,
+ toBizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo()));
});
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java
index 1058533..5a229fc 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java
@@ -131,15 +131,9 @@
: ErpStockRecordBizTypeEnum.OTHER_OUT_CANCEL.getType();
stockOutItems.forEach(stockOutItem -> {
BigDecimal count = approve ? stockOutItem.getCount().negate() : stockOutItem.getCount();
- ErpStockRecordCreateReqBO stockRecordBO = new ErpStockRecordCreateReqBO();
- stockRecordBO.setProductId(stockOutItem.getProductId());
- stockRecordBO.setWarehouseId(stockOutItem.getWarehouseId());
- stockRecordBO.setCount(count);
- stockRecordBO.setBizType(bizType);
- stockRecordBO.setBizId(stockOutItem.getOutId());
- stockRecordBO.setBizItemId(stockOutItem.getId());
- stockRecordBO.setBizNo(stockOut.getNo());
- stockRecordService.createStockRecord(stockRecordBO);
+ stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO(
+ stockOutItem.getProductId(), stockOutItem.getWarehouseId(), count,
+ bizType, stockOutItem.getOutId(), stockOutItem.getId(), stockOut.getNo()));
});
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java
index 0bfaed8..d84951c 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockRecordServiceImpl.java
@@ -1,33 +1,20 @@
package cn.iocoder.yudao.module.erp.service.stock;
-import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.record.ErpStockRecordPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockRecordDO;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockRecordMapper;
import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO;
-import cn.iocoder.yudao.module.mdm.api.item.MdmItemSkuApi;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemSkuRespDTO;
-import cn.iocoder.yudao.module.wms.api.inventory.WmsInventoryApi;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.WmsReceiptReqDTO;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.WmsShipmentReqDTO;
-import cn.iocoder.yudao.module.wms.enums.inventory.WmsInventoryBizTypeEnum;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
-import java.util.List;
/**
* ERP 浜у搧搴撳瓨鏄庣粏 Service 瀹炵幇绫�
- *
- * 鏀归�犺鏄庯細搴撳瓨鍙樻洿璋冪敤 WMS 搴撳瓨 API
- * - 鍏ュ簱鎿嶄綔璋冪敤 WmsInventoryApi.receipt()
- * - 鍑哄簱鎿嶄綔璋冪敤 WmsInventoryApi.shipment()
- * - productId 瀵瑰簲 MDM itemId锛岄�氳繃 SKU API 鑾峰彇榛樿 SKU
*
* @author 鑺嬮亾婧愮爜
*/
@@ -40,12 +27,6 @@
@Resource
private ErpStockService stockService;
-
- @Resource
- private WmsInventoryApi wmsInventoryApi;
-
- @Resource
- private MdmItemSkuApi mdmItemSkuApi;
@Override
public ErpStockRecordDO getStockRecord(Long id) {
@@ -60,98 +41,13 @@
@Override
@Transactional(rollbackFor = Exception.class)
public void createStockRecord(ErpStockRecordCreateReqBO createReqBO) {
- // 1. 鑾峰彇浜у搧鐨勯粯璁� SKU ID锛圗RP productId = MDM itemId锛�
- Long skuId = getDefaultSkuId(createReqBO.getProductId());
- if (skuId == null) {
- // 濡傛灉娌℃湁 SKU锛屼娇鐢ㄥ師鏈夐�昏緫鏇存柊搴撳瓨
- BigDecimal totalCount = stockService.updateStockCountIncrement(
- createReqBO.getProductId(), createReqBO.getWarehouseId(), createReqBO.getCount());
- ErpStockRecordDO stockRecord = BeanUtils.toBean(createReqBO, ErpStockRecordDO.class)
- .setTotalCount(totalCount);
- stockRecordMapper.insert(stockRecord);
- return;
- }
-
- // 2. 鏍规嵁 count 姝h礋鍒ゆ柇鍏ュ簱杩樻槸鍑哄簱
- BigDecimal count = createReqBO.getCount();
- if (count.compareTo(BigDecimal.ZERO) > 0) {
- // 鍏ュ簱鎿嶄綔
- WmsReceiptReqDTO receiptReq = buildReceiptReqDTO(createReqBO, skuId);
- wmsInventoryApi.receipt(receiptReq);
- } else if (count.compareTo(BigDecimal.ZERO) < 0) {
- // 鍑哄簱鎿嶄綔锛堟暟閲忚浆涓烘鏁帮級
- WmsShipmentReqDTO shipmentReq = buildShipmentReqDTO(createReqBO, skuId);
- wmsInventoryApi.shipment(shipmentReq);
- }
-
- // 3. 鍒涘缓搴撳瓨鏄庣粏锛堣褰曟搷浣滐級
- BigDecimal currentStock = wmsInventoryApi.getAvailableQuantity(skuId, createReqBO.getWarehouseId()).getCheckedData();
+ // 1. 鏇存柊搴撳瓨
+ BigDecimal totalCount = stockService.updateStockCountIncrement(
+ createReqBO.getProductId(), createReqBO.getWarehouseId(), createReqBO.getCount());
+ // 2. 鍒涘缓搴撳瓨鏄庣粏
ErpStockRecordDO stockRecord = BeanUtils.toBean(createReqBO, ErpStockRecordDO.class)
- .setTotalCount(currentStock != null ? currentStock : BigDecimal.ZERO);
+ .setTotalCount(totalCount);
stockRecordMapper.insert(stockRecord);
- }
-
- /**
- * 鑾峰彇浜у搧鐨勯粯璁� SKU ID
- */
- private Long getDefaultSkuId(Long productId) {
- if (productId == null) {
- return null;
- }
- List<MdmItemSkuRespDTO> skuList = mdmItemSkuApi.getItemSkuListByItemId(productId).getCheckedData();
- if (CollUtil.isEmpty(skuList)) {
- return null;
- }
- return skuList.get(0).getId();
- }
-
- /**
- * 鏋勫缓鍏ュ簱璇锋眰
- */
- private WmsReceiptReqDTO buildReceiptReqDTO(ErpStockRecordCreateReqBO createReqBO, Long skuId) {
- WmsReceiptReqDTO receiptReq = new WmsReceiptReqDTO();
- receiptReq.setBizType(convertBizType(createReqBO.getBizType()));
- receiptReq.setBizId(createReqBO.getBizId());
- receiptReq.setBizNo(createReqBO.getBizNo());
- receiptReq.setWarehouseId(createReqBO.getWarehouseId());
- receiptReq.setRemark(createReqBO.getRemark());
-
- WmsReceiptReqDTO.Item item = new WmsReceiptReqDTO.Item();
- item.setSkuId(skuId);
- item.setQuantity(createReqBO.getCount());
- receiptReq.setItems(List.of(item));
- return receiptReq;
- }
-
- /**
- * 鏋勫缓鍑哄簱璇锋眰
- */
- private WmsShipmentReqDTO buildShipmentReqDTO(ErpStockRecordCreateReqBO createReqBO, Long skuId) {
- WmsShipmentReqDTO shipmentReq = new WmsShipmentReqDTO();
- shipmentReq.setBizType(convertBizType(createReqBO.getBizType()));
- shipmentReq.setBizId(createReqBO.getBizId());
- shipmentReq.setBizNo(createReqBO.getBizNo());
- shipmentReq.setWarehouseId(createReqBO.getWarehouseId());
- shipmentReq.setRemark(createReqBO.getRemark());
-
- WmsShipmentReqDTO.Item item = new WmsShipmentReqDTO.Item();
- item.setSkuId(skuId);
- item.setQuantity(createReqBO.getCount().negate()); // 鍑哄簱鏁伴噺涓烘鏁�
- shipmentReq.setItems(List.of(item));
- return shipmentReq;
- }
-
- /**
- * 杞崲涓氬姟绫诲瀷锛圗RP 涓氬姟绫诲瀷鏄犲皠鍒� WMS 涓氬姟绫诲瀷锛�
- */
- private Integer convertBizType(Integer erpBizType) {
- // ERP 涓氬姟绫诲瀷鏄犲皠鍒� WMS 涓氬姟绫诲瀷
- // 鍙互鏍规嵁瀹為檯涓氬姟闇�姹傛墿灞曟槧灏勫叧绯�
- if (erpBizType == null) {
- return WmsInventoryBizTypeEnum.OTHER.getType();
- }
- // 榛樿杩斿洖 OTHER 绫诲瀷锛屽悗缁彲鏍规嵁 ERP 涓氬姟绫诲瀷鏋氫妇鎵╁睍
- return WmsInventoryBizTypeEnum.OTHER.getType();
}
}
\ No newline at end of file
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java
index 31dee0e..6541170 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockServiceImpl.java
@@ -1,34 +1,22 @@
package cn.iocoder.yudao.module.erp.service.stock;
-import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
-import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService;
-import cn.iocoder.yudao.module.mdm.api.item.MdmItemSkuApi;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemSkuRespDTO;
-import cn.iocoder.yudao.module.wms.api.inventory.WmsInventoryApi;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.WmsInventoryQueryReqDTO;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.WmsInventoryRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
-import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE;
+import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_COUNT_NEGATIVE2;
/**
* ERP 浜у搧搴撳瓨 Service 瀹炵幇绫�
- *
- * 鏀归�犺鏄庯細ERP 搴撳瓨璋冪敤 WMS 搴撳瓨 API
- * - productId 瀵瑰簲 MDM itemId
- * - 閫氳繃 MDM SKU API 鑾峰彇鐗╂枡鐨勯粯璁� SKU
- * - 搴撳瓨鎿嶄綔璋冪敤 WMS Inventory API
*
* @author 鑺嬮亾婧愮爜
*/
@@ -38,24 +26,18 @@
/**
* 鍏佽搴撳瓨涓鸿礋鏁�
+ *
* TODO 鑺嬭壙锛氬悗缁仛鎴� db 閰嶇疆
*/
private static final Boolean NEGATIVE_STOCK_COUNT_ENABLE = false;
@Resource
private ErpProductService productService;
-
@Resource
private ErpWarehouseService warehouseService;
@Resource
private ErpStockMapper stockMapper;
-
- @Resource
- private WmsInventoryApi wmsInventoryApi;
-
- @Resource
- private MdmItemSkuApi mdmItemSkuApi;
@Override
public ErpStockDO getStock(Long id) {
@@ -64,117 +46,44 @@
@Override
public ErpStockDO getStock(Long productId, Long warehouseId) {
- // 閫氳繃 MDM 鑾峰彇浜у搧鐨勯粯璁� SKU锛岀劧鍚庢煡璇� WMS 搴撳瓨
- Long skuId = getDefaultSkuId(productId);
- if (skuId == null) {
- return null;
- }
-
- // 鏌ヨ WMS 搴撳瓨
- BigDecimal quantity = wmsInventoryApi.getAvailableQuantity(skuId, warehouseId).getCheckedData();
- if (quantity == null || quantity.compareTo(BigDecimal.ZERO) == 0) {
- return null;
- }
-
- // 杞崲涓� ERP Stock DO
- ErpStockDO stock = new ErpStockDO();
- stock.setProductId(productId);
- stock.setWarehouseId(warehouseId);
- stock.setCount(quantity);
- return stock;
+ return stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId);
}
@Override
public BigDecimal getStockCount(Long productId) {
- // 閫氳繃 MDM 鑾峰彇浜у搧鐨勯粯璁� SKU锛岀劧鍚庢煡璇� WMS 搴撳瓨鎬婚噺
- Long skuId = getDefaultSkuId(productId);
- if (skuId == null) {
- return BigDecimal.ZERO;
- }
-
- // 鏌ヨ璇� SKU 鍦ㄦ墍鏈変粨搴撶殑搴撳瓨
- WmsInventoryQueryReqDTO queryReq = new WmsInventoryQueryReqDTO();
- queryReq.setSkuIds(List.of(skuId));
- queryReq.setOnlyPositive(true);
-
- List<WmsInventoryRespDTO> inventories = wmsInventoryApi.getInventoryList(queryReq).getCheckedData();
- if (CollUtil.isEmpty(inventories)) {
- return BigDecimal.ZERO;
- }
-
- return inventories.stream()
- .map(WmsInventoryRespDTO::getQuantity)
- .filter(q -> q != null)
- .reduce(BigDecimal.ZERO, BigDecimal::add);
+ BigDecimal count = stockMapper.selectSumByProductId(productId);
+ return count != null ? count : BigDecimal.ZERO;
}
@Override
public PageResult<ErpStockDO> getStockPage(ErpStockPageReqVO pageReqVO) {
- // 鏆傛椂淇濈暀鍘熼�昏緫锛屽悗缁彲鏀逛负璋冪敤 WMS 鍒嗛〉 API
return stockMapper.selectPage(pageReqVO);
}
@Override
public BigDecimal updateStockCountIncrement(Long productId, Long warehouseId, BigDecimal count) {
- // 閫氳繃 MDM 鑾峰彇浜у搧鐨勯粯璁� SKU
- Long skuId = getDefaultSkuId(productId);
- if (skuId == null) {
- throw exception(STOCK_COUNT_NEGATIVE2,
- productService.getProduct(productId).getName(),
- warehouseService.getWarehouse(warehouseId).getName());
- }
-
- // 鏌ヨ褰撳墠搴撳瓨
- BigDecimal currentStock = wmsInventoryApi.getAvailableQuantity(skuId, warehouseId).getCheckedData();
- if (currentStock == null) {
- currentStock = BigDecimal.ZERO;
- }
-
- // 鏍¢獙搴撳瓨鏄惁鍏呰冻锛堝嚭搴撴椂锛�
- if (!NEGATIVE_STOCK_COUNT_ENABLE && count.compareTo(BigDecimal.ZERO) < 0) {
- BigDecimal afterStock = currentStock.add(count);
- if (afterStock.compareTo(BigDecimal.ZERO) < 0) {
- throw exception(STOCK_COUNT_NEGATIVE,
- productService.getProduct(productId).getName(),
- warehouseService.getWarehouse(warehouseId).getName(),
- currentStock, count.abs());
- }
- }
-
- // TODO: 璋冪敤 WMS 搴撳瓨鍙樻洿 API锛堥渶瑕� WMS 鎻愪緵 increment/decrement 鏂规硶锛�
- // 鏆傛椂淇濈暀鍘熼�昏緫锛屼娇鐢ㄦ湰鍦板簱瀛樿〃
+ // 1.1 鏌ヨ褰撳墠搴撳瓨
ErpStockDO stock = stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId);
if (stock == null) {
- stock = new ErpStockDO()
- .setProductId(productId)
- .setWarehouseId(warehouseId)
- .setCount(BigDecimal.ZERO);
+ stock = new ErpStockDO().setProductId(productId).setWarehouseId(warehouseId).setCount(BigDecimal.ZERO);
stockMapper.insert(stock);
}
+ // 1.2 鏍¢獙搴撳瓨鏄惁鍏呰冻
+ if (!NEGATIVE_STOCK_COUNT_ENABLE && stock.getCount().add(count).compareTo(BigDecimal.ZERO) < 0) {
+ throw exception(STOCK_COUNT_NEGATIVE, productService.getProduct(productId).getName(),
+ warehouseService.getWarehouse(warehouseId).getName(), stock.getCount(), count);
+ }
+ // 2. 搴撳瓨鍙樻洿
int updateCount = stockMapper.updateCountIncrement(stock.getId(), count, NEGATIVE_STOCK_COUNT_ENABLE);
if (updateCount == 0) {
- throw exception(STOCK_COUNT_NEGATIVE2,
- productService.getProduct(productId).getName(),
+ // 姝ゆ椂涓嶅ソ鍘绘煡璇㈡渶鏂板簱瀛橈紝鎵�浠ョ洿鎺ユ姏鍑鸿鎻愮ず锛屼笉鎻愪緵鍏蜂綋搴撳瓨鏁板瓧
+ throw exception(STOCK_COUNT_NEGATIVE2, productService.getProduct(productId).getName(),
warehouseService.getWarehouse(warehouseId).getName());
}
+ // 3. 杩斿洖鏈�鏂板簱瀛�
return stock.getCount().add(count);
- }
-
- /**
- * 鑾峰彇浜у搧鐨勯粯璁� SKU ID
- * ERP productId 瀵瑰簲 MDM itemId锛岄粯璁や娇鐢ㄧ涓�涓� SKU
- */
- private Long getDefaultSkuId(Long productId) {
- if (productId == null) {
- return null;
- }
- List<MdmItemSkuRespDTO> skuList = mdmItemSkuApi.getItemSkuListByItemId(productId).getCheckedData();
- if (CollUtil.isEmpty(skuList)) {
- return null;
- }
- return skuList.get(0).getId();
}
}
\ No newline at end of file
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java
index acab88a..7006f10 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/stock/bo/ErpStockRecordCreateReqBO.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.erp.service.stock.bo;
import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -13,6 +14,7 @@
*/
@Data
@NoArgsConstructor
+@AllArgsConstructor
public class ErpStockRecordCreateReqBO {
/**
@@ -54,9 +56,4 @@
@NotNull(message = "涓氬姟鍗曞彿涓嶈兘涓虹┖")
private String bizNo;
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
+}
diff --git a/yudao-module-im/pom.xml b/yudao-module-im/pom.xml
new file mode 100644
index 0000000..6fdb223
--- /dev/null
+++ b/yudao-module-im/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao</artifactId>
+ <version>${revision}</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>yudao-module-im</artifactId>
+ <packaging>jar</packaging>
+
+ <name>${project.artifactId}</name>
+ <description>
+ im 妯″潡锛屾垜浠斁鍗虫椂閫氳涓氬姟銆�
+ 渚嬪璇达細鍗曡亰銆佺兢鑱娿�佹秷鎭敹鍙戙�佹秷鎭挙鍥炪�佹秷鎭凡璇荤瓑绛�
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-module-system</artifactId>
+ <version>${revision}</version>
+ </dependency>
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-module-infra</artifactId>
+ <version>${revision}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-common</artifactId>
+ </dependency>
+
+ <!-- Web 鐩稿叧 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-security</artifactId>
+ </dependency>
+
+ <!-- DB 鐩稿叧 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-redis</artifactId>
+ </dependency>
+
+ <!-- 宸ュ叿绫荤浉鍏� -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-excel</artifactId>
+ </dependency>
+
+ <!-- 鏁忔劅璇嶆娴嬶細sensitive-word锛坱rie 鏍戦珮鏁堝尮閰嶏紝鏀寔蹇界暐澶у皬鍐� / 鍏ㄥ崐瑙� / 鏁板瓧椋庢牸锛夛紝鐗堟湰鐢� yudao-dependencies 缁熶竴绠$悊 -->
+ <dependency>
+ <groupId>com.github.houbb</groupId>
+ <artifactId>sensitive-word</artifactId>
+ </dependency>
+
+ <!-- 姹夊瓧杞嫾闊筹細浣滀负 hutool PinyinUtil 鐨勫簳灞傚紩鎿庯紝涓氬姟渚ц皟鐢� StrUtils.toPinyin 鏃舵寜闇�寮曞叆 -->
+ <dependency>
+ <groupId>com.belerweb</groupId>
+ <artifactId>pinyin4j</artifactId>
+ </dependency>
+
+ <!-- Test 娴嬭瘯鐩稿叧 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-test</artifactId>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java
new file mode 100644
index 0000000..4938097
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * @author anhaohao
+ * @since 2024/3/9 涓嬪崍8:59
+ */
+package cn.iocoder.yudao.module.im.api;
\ No newline at end of file
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/channel/ImChannelMaterialController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/channel/ImChannelMaterialController.java
new file mode 100644
index 0000000..e2427a1
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/channel/ImChannelMaterialController.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.controller.admin.channel;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
+import cn.iocoder.yudao.module.im.service.channel.ImChannelMaterialService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+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 static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "鐢ㄦ埛 APP - IM 棰戦亾绱犳潗")
+@RestController
+@RequestMapping("/im/channel/material")
+@Validated
+public class ImChannelMaterialController {
+
+ @Resource
+ private ImChannelMaterialService channelMaterialService;
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰彇绱犳潗璇︽儏锛涚敤浜庡鎴风鐐瑰嚮鍥炬枃鍗$墖娓叉煋璇︽儏椤�")
+ @Parameter(name = "id", description = "绱犳潗缂栧彿", required = true, example = "1024")
+ public CommonResult<ImChannelMaterialRespVO> getMaterial(@RequestParam("id") Long id) {
+ ImChannelMaterialDO material = channelMaterialService.validateMaterialExists(id);
+ return success(BeanUtils.toBean(material, ImChannelMaterialRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationReadController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationReadController.java
new file mode 100644
index 0000000..aea2b9c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationReadController.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.im.controller.admin.conversation;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationReadRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationReadDO;
+import cn.iocoder.yudao.module.im.service.conversation.ImConversationReadService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import org.springframework.validation.annotation.Validated;
+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 java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 浼氳瘽璇讳綅缃�")
+@RestController
+@RequestMapping("/im/conversation-read")
+@Validated
+public class ImConversationReadController {
+
+ @Resource
+ private ImConversationReadService conversationReadService;
+
+ @GetMapping("/pull")
+ @Operation(summary = "澧為噺鎷夊彇褰撳墠鐢ㄦ埛鐨勪細璇濊浣嶇疆锛堥噸杩� / 绂荤嚎琛ュ伩锛�")
+ @Parameters({
+ @Parameter(name = "lastUpdateTime", description = "涓婃鎷夊彇鍒扮殑鏈�鏂版洿鏂版椂闂达紙姣鏃堕棿鎴筹級锛涢娆℃媺鍙栦笉浼�"),
+ @Parameter(name = "lastId", description = "涓婃鎷夊彇鍒扮殑鏈�鍚庝竴鏉¤褰� id锛涢娆℃媺鍙栦笉浼�"),
+ @Parameter(name = "limit", description = "鍗曟鎷夊彇鏉℃暟", required = true)
+ })
+ public CommonResult<List<ImConversationReadRespVO>> pullMyConversationRead(
+ @RequestParam(value = "lastUpdateTime", required = false) Long lastUpdateTime,
+ @RequestParam(value = "lastId", required = false) Long lastId,
+ @RequestParam("limit") @Min(1) @Max(200) Integer limit) {
+ List<ImConversationReadDO> list = conversationReadService.pullConversationReadList(
+ getLoginUserId(), lastUpdateTime, lastId, limit);
+ return success(BeanUtils.toBean(list, ImConversationReadRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationReadRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationReadRespVO.java
new file mode 100644
index 0000000..2cafb46
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationReadRespVO.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.im.controller.admin.conversation.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 浼氳瘽璇讳綅缃� Response VO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Schema(description = "绠$悊鍚庡彴 - IM 浼氳瘽璇讳綅缃� Response VO")
+@Data
+public class ImConversationReadRespVO {
+
+ @Schema(description = "璇讳綅缃紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long id;
+
+ @Schema(description = "浼氳瘽绫诲瀷", example = "1")
+ private Integer conversationType; // 鍙傝 ImConversationTypeEnum 鏋氫妇
+
+ @Schema(description = "鐩爣缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long targetId;
+
+ @Schema(description = "鏈�澶у凡璇绘秷鎭紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
+ private Long messageId;
+
+ @Schema(description = "鏈�杩戞洿鏂版椂闂达紙澧為噺鎷夊彇娓告爣鐢級")
+ private LocalDateTime updateTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFacePackController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFacePackController.java
new file mode 100644
index 0000000..6438c4d
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFacePackController.java
@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.im.controller.admin.face;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.face.vo.pack.ImFacePackUserRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO;
+import cn.iocoder.yudao.module.im.service.face.ImFacePackItemService;
+import cn.iocoder.yudao.module.im.service.face.ImFacePackService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖�")
+@RestController
+@RequestMapping("/im/face-pack")
+@Validated
+public class ImFacePackController {
+
+ @Resource
+ private ImFacePackService facePackService;
+ @Resource
+ private ImFacePackItemService facePackItemService;
+
+ @GetMapping("/list")
+ @Operation(summary = "鑾峰緱鍚敤鐨勮〃鎯呭寘鍒楄〃锛堝惈琛ㄦ儏锛�")
+ public CommonResult<List<ImFacePackUserRespVO>> getFacePackList() {
+ // 1.1 鎷夋墍鏈夊惎鐢ㄨ〃鎯呭寘
+ List<ImFacePackDO> packs = facePackService.getEnabledFacePackList();
+ if (packs.isEmpty()) {
+ return success(ListUtil.of());
+ }
+ // 1.2 鎷夎繖浜涘寘涓嬫墍鏈夊惎鐢ㄨ〃鎯咃紝鎸� packId 鍒嗙粍
+ List<ImFacePackItemDO> items = facePackItemService.getEnabledItemListByPackIds(
+ convertList(packs, ImFacePackDO::getId));
+ Map<Long, List<ImFacePackItemDO>> itemsByPackId = convertMultiMap(items, ImFacePackItemDO::getPackId);
+
+ // 2. 鎷艰锛欱eanUtils 鎶� pack 瀛楁鏄犲皠 + 鑷繁濉� items
+ List<ImFacePackUserRespVO> result = convertList(packs, pack -> {
+ ImFacePackUserRespVO vo = BeanUtils.toBean(pack, ImFacePackUserRespVO.class);
+ vo.setItems(BeanUtils.toBean(itemsByPackId.getOrDefault(pack.getId(), ListUtil.of()), ImFacePackUserRespVO.Item.class));
+ return vo;
+ });
+ return success(result);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java
new file mode 100644
index 0000000..7f27c17
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.im.controller.admin.face;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO;
+import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 涓汉琛ㄦ儏")
+@RestController
+@RequestMapping("/im/face-user-item")
+@Validated
+public class ImFaceUserItemController {
+
+ @Resource
+ private ImFaceUserItemService faceUserItemService;
+
+ @GetMapping("/list")
+ @Operation(summary = "鑾峰緱鎴戠殑涓汉琛ㄦ儏鍒楄〃")
+ public CommonResult<List<ImFaceUserItemRespVO>> getFaceUserItemList() {
+ List<ImFaceUserItemDO> items = faceUserItemService.getFaceUserItemList(getLoginUserId());
+ return success(BeanUtils.toBean(items, ImFaceUserItemRespVO.class));
+ }
+
+ @PostMapping("/create")
+ @Operation(summary = "娣诲姞涓汉琛ㄦ儏")
+ public CommonResult<Long> createFaceUserItem(@Valid @RequestBody ImFaceUserItemSaveReqVO reqVO) {
+ return success(faceUserItemService.createFaceUserItem(getLoginUserId(), reqVO));
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎涓汉琛ㄦ儏")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "4096")
+ public CommonResult<Boolean> deleteFaceUserItem(@RequestParam("id") Long id) {
+ faceUserItemService.deleteFaceUserItem(getLoginUserId(), id);
+ return success(true);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/pack/ImFacePackUserRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/pack/ImFacePackUserRespVO.java
new file mode 100644
index 0000000..5a73d82
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/pack/ImFacePackUserRespVO.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.im.controller.admin.face.vo.pack;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "IM 琛ㄦ儏鍖咃紙鐢ㄦ埛绔級 Response VO")
+@Data
+public class ImFacePackUserRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "琛ㄦ儏鍖呭悕绉�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鐚富瀛�")
+ private String name;
+
+ @Schema(description = "琛ㄦ儏鍖呭浘鏍�", example = "https://cdn.example.com/face/pack/cat.png")
+ private String icon;
+
+ @Schema(description = "琛ㄦ儏鍒楄〃", requiredMode = Schema.RequiredMode.REQUIRED)
+ private List<Item> items;
+
+ @Schema(description = "IM 琛ㄦ儏鍖呴」锛堢敤鎴风锛�")
+ @Data
+ public static class Item {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long id;
+
+ @Schema(description = "琛ㄦ儏鍥� URL", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "https://cdn.example.com/face/pack/cat-001.png")
+ private String url;
+
+ @Schema(description = "琛ㄦ儏鍚�", example = "鐙楀ご")
+ private String name;
+
+ @Schema(description = "娓叉煋瀹藉害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ private Integer width;
+
+ @Schema(description = "娓叉煋楂樺害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ private Integer height;
+
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java
new file mode 100644
index 0000000..61be778
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "IM 涓汉琛ㄦ儏 Response VO")
+@Data
+public class ImFaceUserItemRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
+ private Long id;
+
+ @Schema(description = "琛ㄦ儏鍥� URL", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "https://cdn.example.com/face/user/abc.gif")
+ private String url;
+
+ @Schema(description = "琛ㄦ儏鍚�", example = "鐙楀ご")
+ private String name;
+
+ @Schema(description = "娓叉煋瀹藉害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ private Integer width;
+
+ @Schema(description = "娓叉煋楂樺害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ private Integer height;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java
new file mode 100644
index 0000000..b9a508d
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "IM 涓汉琛ㄦ儏鏂板 Request VO")
+@Data
+public class ImFaceUserItemSaveReqVO {
+
+ @Schema(description = "琛ㄦ儏鍥� URL", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "https://cdn.example.com/face/user/abc.gif")
+ @NotBlank(message = "琛ㄦ儏鍥� URL 涓嶈兘涓虹┖")
+ @Size(max = 512, message = "琛ㄦ儏鍥� URL 闀垮害涓嶈兘瓒呰繃 512")
+ private String url;
+
+ @Schema(description = "琛ㄦ儏鍚�", example = "鐙楀ご")
+ @Size(max = 64, message = "琛ㄦ儏鍚嶉暱搴︿笉鑳借秴杩� 64")
+ private String name;
+
+ @Schema(description = "娓叉煋瀹藉害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ @NotNull(message = "娓叉煋瀹藉害涓嶈兘涓虹┖")
+ @Min(value = 1, message = "娓叉煋瀹藉害涓嶈兘灏忎簬 1 鍍忕礌")
+ @Max(value = 2048, message = "娓叉煋瀹藉害涓嶈兘澶т簬 2048 鍍忕礌")
+ private Integer width;
+
+ @Schema(description = "娓叉煋楂樺害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ @NotNull(message = "娓叉煋楂樺害涓嶈兘涓虹┖")
+ @Min(value = 1, message = "娓叉煋楂樺害涓嶈兘灏忎簬 1 鍍忕礌")
+ @Max(value = 2048, message = "娓叉煋楂樺害涓嶈兘澶т簬 2048 鍍忕礌")
+ private Integer height;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendController.java
new file mode 100644
index 0000000..1cb8913
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendController.java
@@ -0,0 +1,143 @@
+package cn.iocoder.yudao.module.im.controller.admin.friend;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.common.util.string.StrUtils;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.ImFriendRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.ImFriendUpdateReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.singleton;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 濂藉弸")
+@RestController
+@RequestMapping("/im/friend")
+@Validated
+public class ImFriendController {
+
+ @Resource
+ private ImFriendService friendService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/list")
+ @Operation(summary = "鑾峰緱褰撳墠鐧诲綍鐢ㄦ埛鐨勫ソ鍙嬪垪琛�")
+ public CommonResult<List<ImFriendRespVO>> getMyFriendList() {
+ List<ImFriendDO> friends = friendService.getFriendList(getLoginUserId());
+ return success(buildFriendRespVOList(friends));
+ }
+
+ @GetMapping("/pull")
+ @Operation(summary = "澧為噺鎷夊彇褰撳墠鐢ㄦ埛鐨勫ソ鍙嬪叧绯伙紙閲嶈繛 / 绂荤嚎琛ュ伩锛�")
+ @Parameters({
+ @Parameter(name = "lastUpdateTime", description = "涓婃鎷夊彇鍒扮殑鏈�鏂版洿鏂版椂闂达紙姣鏃堕棿鎴筹級锛涢娆℃媺鍙栦笉浼�"),
+ @Parameter(name = "lastId", description = "涓婃鎷夊彇鍒扮殑鏈�鍚庝竴鏉¤褰� id锛涢娆℃媺鍙栦笉浼�"),
+ @Parameter(name = "limit", description = "鍗曟鎷夊彇鏉℃暟", required = true)
+ })
+ public CommonResult<List<ImFriendRespVO>> pullMyFriendList(
+ @RequestParam(value = "lastUpdateTime", required = false) Long lastUpdateTime,
+ @RequestParam(value = "lastId", required = false) Long lastId,
+ @RequestParam("limit") @Min(1) @Max(200) Integer limit) {
+ List<ImFriendDO> list = friendService.pullFriendList(getLoginUserId(), lastUpdateTime, lastId, limit);
+ return success(buildFriendRespVOList(list));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱濂藉弸璇︽儏")
+ @Parameter(name = "friendUserId", description = "濂藉弸鐨勭敤鎴风紪鍙�", required = true, example = "2048")
+ public CommonResult<ImFriendRespVO> getFriend(@RequestParam("friendUserId") Long friendUserId) {
+ ImFriendDO friend = friendService.getFriend(getLoginUserId(), friendUserId);
+ return success(buildFriendRespVO(friend));
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎濂藉弸锛堝崟鍚戣蒋鍒犻櫎锛�")
+ @Parameters({
+ @Parameter(name = "friendUserId", description = "濂藉弸鐨勭敤鎴风紪鍙�", required = true, example = "2048"),
+ @Parameter(name = "clear", description = "鏄惁绾ц仈娓呯悊鏈鐩稿叧鏁版嵁锛堝绉佽亰浼氳瘽锛�")
+ })
+ public CommonResult<Boolean> deleteFriend(
+ @RequestParam("friendUserId") @NotNull(message = "濂藉弸鐢ㄦ埛缂栧彿涓嶈兘涓虹┖") Long friendUserId,
+ @RequestParam(value = "clear", required = false) Boolean clear) {
+ friendService.deleteFriend(getLoginUserId(), friendUserId, clear);
+ return success(true);
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "鏇存柊濂藉弸鍗曡竟灞炴�э紙澶囨敞 / 鍏嶆墦鎵� / 鑱旂郴浜虹疆椤讹級")
+ public CommonResult<Boolean> updateFriend(@Valid @RequestBody ImFriendUpdateReqVO reqVO) {
+ friendService.updateFriend(getLoginUserId(), reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/block")
+ @Operation(summary = "鎷夐粦濂藉弸锛堝繀椤诲厛鏄ソ鍙嬶紱鍗曡竟灞忚斀瀵规柟绉佽亰娑堟伅锛�")
+ @Parameter(name = "friendUserId", description = "濂藉弸鐨勭敤鎴风紪鍙�", required = true, example = "2048")
+ public CommonResult<Boolean> blockFriend(
+ @RequestParam("friendUserId") @NotNull(message = "濂藉弸鐢ㄦ埛缂栧彿涓嶈兘涓虹┖") Long friendUserId) {
+ friendService.blockFriend(getLoginUserId(), friendUserId);
+ return success(true);
+ }
+
+ @PutMapping("/unblock")
+ @Operation(summary = "绉诲嚭榛戝悕鍗�")
+ @Parameter(name = "friendUserId", description = "濂藉弸鐨勭敤鎴风紪鍙�", required = true, example = "2048")
+ public CommonResult<Boolean> unblockFriend(
+ @RequestParam("friendUserId") @NotNull(message = "濂藉弸鐢ㄦ埛缂栧彿涓嶈兘涓虹┖") Long friendUserId) {
+ friendService.unblockFriend(getLoginUserId(), friendUserId);
+ return success(true);
+ }
+
+ // ========== 绉佹湁鏂规硶锛歏O 缁勮 ==========
+
+ private List<ImFriendRespVO> buildFriendRespVOList(Collection<ImFriendDO> friends) {
+ if (CollUtil.isEmpty(friends)) {
+ return Collections.emptyList();
+ }
+ // 鎵归噺鑱氬悎 AdminUser 淇℃伅锛堟樀绉� / 澶村儚锛夛紝閬垮厤 N+1
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ convertList(friends, ImFriendDO::getFriendUserId));
+ return convertList(friends, friend -> {
+ ImFriendRespVO vo = BeanUtils.toBean(friend, ImFriendRespVO.class);
+ MapUtils.findAndThen(userMap, friend.getFriendUserId(), user ->
+ vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
+ // 澶囨敞 / 鏄电О鐨勬嫾闊筹紝缁欏墠绔仛瀛楁瘝鍒嗘《 + 鎷奸煶鎼滅储
+ vo.setDisplayNamePinyin(StrUtils.toPinyin(vo.getDisplayName()))
+ .setNicknamePinyin(StrUtils.toPinyin(vo.getNickname()));
+ return vo;
+ });
+ }
+
+ private ImFriendRespVO buildFriendRespVO(ImFriendDO friend) {
+ if (friend == null) {
+ return null;
+ }
+ return CollUtil.getFirst(buildFriendRespVOList(singleton(friend)));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java
new file mode 100644
index 0000000..c074568
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java
@@ -0,0 +1,143 @@
+package cn.iocoder.yudao.module.im.controller.admin.friend;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.request.ImFriendRequestApplyReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.request.ImFriendRequestRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendRequestService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+
+/**
+ * IM 濂藉弸鐢宠璁板綍 Controller
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Tag(name = "绠$悊鍚庡彴 - IM 濂藉弸鐢宠")
+@RestController
+@RequestMapping("/im/friend-request")
+@Validated
+public class ImFriendRequestController {
+
+ @Resource
+ private ImFriendRequestService friendRequestService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/apply")
+ @Operation(summary = "鍙戣捣濂藉弸鐢宠")
+ public CommonResult<Long> applyFriend(@Valid @RequestBody ImFriendRequestApplyReqVO reqVO) {
+ ImFriendRequestDO request = friendRequestService.applyFriend(getLoginUserId(), reqVO);
+ return success(request != null ? request.getId() : null);
+ }
+
+ @PutMapping("/agree")
+ @Operation(summary = "鍚屾剰濂藉弸鐢宠")
+ @Parameter(name = "id", description = "鐢宠缂栧彿", required = true, example = "1024")
+ public CommonResult<Boolean> agreeFriendRequest(
+ @RequestParam("id") @NotNull(message = "鐢宠缂栧彿涓嶈兘涓虹┖") Long id) {
+ friendRequestService.agreeFriendRequest(getLoginUserId(), id);
+ return success(true);
+ }
+
+ @PutMapping("/refuse")
+ @Operation(summary = "鎷掔粷濂藉弸鐢宠")
+ public CommonResult<Boolean> refuseFriendRequest(
+ @RequestParam("id") @NotNull(message = "鐢宠缂栧彿涓嶈兘涓虹┖") Long id,
+ @RequestParam(value = "handleContent", required = false)
+ @Size(max = 255, message = "澶勭悊鐞嗙敱鏈�澶� 255 涓瓧绗�") String handleContent) {
+ friendRequestService.refuseFriendRequest(getLoginUserId(), id, handleContent);
+ return success(true);
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "鏌ヨ銆屾垜鐩稿叧銆嶇殑濂藉弸鐢宠鍒楄〃锛堟父鏍囧垎椤碉細浼� maxId 鍔犺浇鏇村锛�")
+ @Parameters({
+ @Parameter(name = "maxId", description = "褰撳墠鍒楄〃鏈�鏃ц褰曠殑 id锛涢椤典笉浼�"),
+ @Parameter(name = "limit", description = "鍗曟鎷夊彇鏉℃暟", required = true)
+ })
+ public CommonResult<List<ImFriendRequestRespVO>> getMyFriendRequestList(
+ @RequestParam(value = "maxId", required = false) Long maxId,
+ @RequestParam("limit") @Min(1) @Max(200) Integer limit) {
+ List<ImFriendRequestDO> list = friendRequestService.getMyFriendRequestList(getLoginUserId(), maxId, limit);
+ return success(buildList(list));
+ }
+
+ @GetMapping("/pull")
+ @Operation(summary = "澧為噺鎷夊彇銆屾垜鐩稿叧銆嶇殑濂藉弸鐢宠锛堥噸杩� / 绂荤嚎琛ュ伩锛�")
+ @Parameters({
+ @Parameter(name = "lastUpdateTime", description = "涓婃鎷夊彇鍒扮殑鏈�鏂版洿鏂版椂闂达紙姣鏃堕棿鎴筹級锛涢娆℃媺鍙栦笉浼�"),
+ @Parameter(name = "lastId", description = "涓婃鎷夊彇鍒扮殑鏈�鍚庝竴鏉¤褰� id锛涢娆℃媺鍙栦笉浼�"),
+ @Parameter(name = "limit", description = "鍗曟鎷夊彇鏉℃暟", required = true)
+ })
+ public CommonResult<List<ImFriendRequestRespVO>> pullMyFriendRequestList(
+ @RequestParam(value = "lastUpdateTime", required = false) Long lastUpdateTime,
+ @RequestParam(value = "lastId", required = false) Long lastId,
+ @RequestParam("limit") @Min(1) @Max(200) Integer limit) {
+ List<ImFriendRequestDO> list = friendRequestService.pullFriendRequestList(getLoginUserId(), lastUpdateTime, lastId, limit);
+ return success(buildList(list));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鎸� id 鍗曟煡銆屾垜鐩稿叧銆嶇殑鐢宠璁板綍锛堝甫瓒婃潈杩囨护锛沇ebSocket 閫氱煡鍒拌揪鍚庣敤锛�")
+ @Parameter(name = "id", description = "鐢宠璁板綍缂栧彿", required = true)
+ public CommonResult<ImFriendRequestRespVO> getMyFriendRequest(@RequestParam("id") Long id) {
+ ImFriendRequestDO request = friendRequestService.getFriendRequest(id);
+ // 瓒婃潈杩囨护锛歠romUser / toUser 蹇呮湁涓�鏂规槸褰撳墠鐢ㄦ埛锛屽惁鍒欏綋涓嶅瓨鍦ㄨ繑鍥� null
+ Long currentUserId = getLoginUserId();
+ if (request == null || (ObjUtil.notEqual(request.getFromUserId(), currentUserId)
+ && ObjUtil.notEqual(request.getToUserId(), currentUserId))) {
+ return success(null);
+ }
+ return success(CollUtil.getFirst(buildList(Collections.singletonList(request))));
+ }
+
+ // ========== 绉佹湁鏂规硶锛歏O 缁勮 ==========
+
+ private List<ImFriendRequestRespVO> buildList(List<ImFriendRequestDO> list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 鍙屽悜 OR 鍒楄〃锛寀serIds 鍙� from + to 涓ょ粍骞堕泦
+ Set<Long> userIds = convertSetByFlatMap(list,
+ request -> Stream.of(request.getFromUserId(), request.getToUserId()));
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
+ return convertList(list, request -> {
+ ImFriendRequestRespVO vo = BeanUtils.toBean(request, ImFriendRequestRespVO.class);
+ MapUtils.findAndThen(userMap, request.getFromUserId(), user ->
+ vo.setFromNickname(user.getNickname()).setFromAvatar(user.getAvatar()));
+ MapUtils.findAndThen(userMap, request.getToUserId(), user ->
+ vo.setToNickname(user.getNickname()).setToAvatar(user.getAvatar()));
+ return vo;
+ });
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendRespVO.java
new file mode 100644
index 0000000..6f4b14e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendRespVO.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.im.controller.admin.friend.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 濂藉弸 Response VO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Schema(description = "绠$悊鍚庡彴 - IM 濂藉弸 Response VO")
+@Data
+public class ImFriendRespVO {
+
+ @Schema(description = "鍏崇郴璁板綍缂栧彿", example = "1024")
+ private Long id;
+
+ @Schema(description = "濂藉弸鐨勭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long friendUserId;
+
+ @Schema(description = "鏄惁鍏嶆墦鎵�", example = "false")
+ private Boolean silent;
+
+ @Schema(description = "濂藉弸灞曠ず澶囨敞锛堜粎鑷繁鍙锛�", example = "鑰佸紶")
+ private String displayName;
+
+ @Schema(description = "濂藉弸灞曠ず澶囨敞鐨勬嫾闊筹紙灏忓啓鏃犵┖鏍硷級", example = "laozhang")
+ private String displayNamePinyin;
+
+ @Schema(description = "娣诲姞鏉ユ簮", example = "1")
+ private Integer addSource; // 鍙傝 ImFriendAddSourceEnum 鏋氫妇
+
+ @Schema(description = "鏄惁缃《鑱旂郴浜�", example = "false")
+ private Boolean pinned;
+
+ @Schema(description = "鏄惁鎷夐粦锛堜粎鑷繁鍙锛�", example = "false")
+ private Boolean blocked;
+
+ @Schema(description = "濂藉弸鐘舵��", example = "0")
+ private Integer status;
+
+ @Schema(description = "娣诲姞濂藉弸鏃堕棿")
+ private LocalDateTime addTime;
+
+ @Schema(description = "鍒犻櫎濂藉弸鏃堕棿")
+ private LocalDateTime deleteTime;
+
+ @Schema(description = "鏈�杩戞洿鏂版椂闂达紙澧為噺鎷夊彇娓告爣鐢級")
+ private LocalDateTime updateTime;
+
+ // ========== 涓嬮潰鏄仛鍚堝瓧娈碉紝鏂逛究鍓嶇鏄剧ず ==========
+
+ @Schema(description = "濂藉弸鏄电О锛堝疄鏃惰仛鍚堣嚜 AdminUser锛�", example = "鑺嬮亾")
+ private String nickname;
+
+ @Schema(description = "濂藉弸鏄电О鐨勬嫾闊筹紙灏忓啓鏃犵┖鏍硷級", example = "yudao")
+ private String nicknamePinyin;
+
+ @Schema(description = "濂藉弸澶村儚锛堝疄鏃惰仛鍚堣嚜 AdminUser锛�")
+ private String avatar;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendUpdateReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendUpdateReqVO.java
new file mode 100644
index 0000000..8eee96f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendUpdateReqVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.im.controller.admin.friend.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 濂藉弸鏇存柊 Request VO")
+@Data
+public class ImFriendUpdateReqVO {
+
+ @Schema(description = "濂藉弸鐨勭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "濂藉弸鐢ㄦ埛缂栧彿涓嶈兘涓虹┖")
+ private Long friendUserId;
+
+ @Schema(description = "鏄惁鍏嶆墦鎵帮紱涓嶄紶琛ㄧず涓嶄慨鏀�", example = "true")
+ private Boolean silent;
+
+ @Schema(description = "濂藉弸灞曠ず澶囨敞锛堜粎鑷繁鍙锛夛紱涓嶄紶琛ㄧず涓嶄慨鏀癸紝浼犵┖涓茶〃绀烘竻绌�", example = "鑰佸紶")
+ @Size(max = 16, message = "濂藉弸澶囨敞鏈�澶� 16 涓瓧绗�")
+ private String displayName;
+
+ @Schema(description = "鏄惁缃《鑱旂郴浜猴紱涓嶄紶琛ㄧず涓嶄慨鏀�", example = "true")
+ private Boolean pinned;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/request/ImFriendRequestApplyReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/request/ImFriendRequestApplyReqVO.java
new file mode 100644
index 0000000..fea58c1
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/request/ImFriendRequestApplyReqVO.java
@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.im.controller.admin.friend.vo.request;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendAddSourceEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+/**
+ * IM 濂藉弸鐢宠 - 鍙戣捣 Request VO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Schema(description = "绠$悊鍚庡彴 - IM 濂藉弸鐢宠鍙戣捣 Request VO")
+@Data
+public class ImFriendRequestApplyReqVO {
+
+ @Schema(description = "鎺ユ敹鏂圭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "鎺ユ敹鏂圭敤鎴风紪鍙蜂笉鑳戒负绌�")
+ private Long toUserId;
+
+ @Schema(description = "鐢宠鐞嗙敱", example = "鎴戞槸鑺嬭壙锛堜竴绉嶉鏉愶級")
+ @Size(max = 255, message = "鐢宠鐞嗙敱鏈�澶� 255 涓瓧绗�")
+ private String applyContent;
+
+ @Schema(description = "瀵规帴鏀舵柟鐨勫娉紙浠呰嚜宸卞彲瑙侊級", example = "鑰佸紶")
+ @Size(max = 16, message = "濂藉弸澶囨敞鏈�澶� 16 涓瓧绗�")
+ private String displayName;
+
+ @Schema(description = "娣诲姞鏉ユ簮", example = "1")
+ @InEnum(ImFriendAddSourceEnum.class)
+ private Integer addSource;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/request/ImFriendRequestRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/request/ImFriendRequestRespVO.java
new file mode 100644
index 0000000..d32a098
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/request/ImFriendRequestRespVO.java
@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.im.controller.admin.friend.vo.request;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 濂藉弸鐢宠 Response VO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Schema(description = "绠$悊鍚庡彴 - IM 濂藉弸鐢宠 Response VO")
+@Data
+public class ImFriendRequestRespVO {
+
+ @Schema(description = "鐢宠缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鍙戣捣鏂圭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+ private Long fromUserId;
+
+ @Schema(description = "鎺ユ敹鏂圭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ private Long toUserId;
+
+ @Schema(description = "澶勭悊缁撴灉", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer handleResult; // 鍙傝 ImFriendRequestHandleResultEnum 鏋氫妇
+
+ @Schema(description = "鐢宠鐞嗙敱", example = "鎴戞槸鑺嬭壙锛堜竴绉嶉鏉愶級")
+ private String applyContent;
+
+ @Schema(description = "澶勭悊鐞嗙敱锛堟帴鏀舵柟鎷掔粷鏃跺彲閫夊~锛�", example = "鏆備笉閫氳繃")
+ private String handleContent;
+
+ @Schema(description = "娣诲姞鏉ユ簮", example = "1")
+ private Integer addSource; // 鍙傝 ImFriendAddSourceEnum 鏋氫妇
+
+ @Schema(description = "澶勭悊鏃堕棿")
+ private LocalDateTime handleTime;
+
+ @Schema(description = "鐢宠鍒涘缓鏃堕棿")
+ private LocalDateTime createTime;
+
+ @Schema(description = "鏈�杩戞洿鏂版椂闂达紙澧為噺鎷夊彇娓告爣鐢級")
+ private LocalDateTime updateTime;
+
+ // ========== 涓嬮潰鏄仛鍚堝瓧娈碉紝鏂逛究鍓嶇鏄剧ず ==========
+
+ @Schema(description = "鍙戣捣鏂规樀绉帮紙瀹炴椂鑱氬悎鑷� AdminUser锛�", example = "鑺嬮亾")
+ private String fromNickname;
+
+ @Schema(description = "鍙戣捣鏂瑰ご鍍忥紙瀹炴椂鑱氬悎鑷� AdminUser锛�")
+ private String fromAvatar;
+
+ @Schema(description = "鎺ユ敹鏂规樀绉帮紙瀹炴椂鑱氬悎鑷� AdminUser锛�", example = "鑰佸紶")
+ private String toNickname;
+
+ @Schema(description = "鎺ユ敹鏂瑰ご鍍忥紙瀹炴椂鑱氬悎鑷� AdminUser锛�")
+ private String toAvatar;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java
new file mode 100644
index 0000000..587b216
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java
@@ -0,0 +1,215 @@
+package cn.iocoder.yudao.module.im.controller.admin.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberInviteReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRemoveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupService;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+
+@Tag(name = "绠$悊鍚庡彴 - 缇�")
+@RestController
+@RequestMapping("/im/group")
+@Validated
+public class ImGroupController {
+
+ @Resource
+ private ImGroupService groupService;
+ @Resource
+ private ImGroupMemberService groupMemberService;
+ @Resource
+ private ImGroupMessageService groupMessageService;
+
+ // ==================== 缇ょ殑鍐欐搷浣� ====================
+
+ @PostMapping("/create")
+ @Operation(summary = "鍒涘缓缇�")
+ public CommonResult<ImGroupRespVO> createGroup(@Valid @RequestBody ImGroupCreateReqVO createReqVO) {
+ ImGroupDO group = groupService.createGroup(createReqVO, getLoginUserId());
+ // 鏂板缓缇ゅ繀鏃� pinnedMessages锛岃烦杩囧叧鑱斿洖濉�
+ return success(BeanUtils.toBean(group, ImGroupRespVO.class));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "鏇存柊缇�")
+ public CommonResult<ImGroupRespVO> updateGroup(@Valid @RequestBody ImGroupUpdateReqVO updateReqVO) {
+ ImGroupDO group = groupService.updateGroup(updateReqVO, getLoginUserId());
+ return success(buildGroupRespVO(group, getLoginUserId()));
+ }
+
+ @DeleteMapping("/dissolve")
+ @Operation(summary = "瑙f暎缇�")
+ @Parameter(name = "id", description = "缇ょ紪鍙�", required = true)
+ public CommonResult<Boolean> dissolveGroup(@RequestParam("id") Long id) {
+ groupService.dissolveGroup(id, getLoginUserId());
+ return success(true);
+ }
+
+ // ==================== 缇ょ殑璇绘搷浣� ====================
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱缇�")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ public CommonResult<ImGroupRespVO> getGroup(@RequestParam("id") Long id) {
+ ImGroupDO group = groupService.getGroup(id);
+ return success(buildGroupRespVO(group, getLoginUserId()));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "鑾峰緱褰撳墠鐧诲綍鐢ㄦ埛鐨勭兢鍒楄〃")
+ public CommonResult<List<ImGroupRespVO>> getMyGroupList() {
+ Long loginUserId = getLoginUserId();
+ List<ImGroupDO> groups = groupService.getMyGroupList(loginUserId);
+ return success(buildGroupRespVOList(groups, loginUserId));
+ }
+
+ // ==================== 缇ゆ垚鍛樼殑鍐欐搷浣� ====================
+
+ @PostMapping("/invite")
+ @Operation(summary = "閭�璇风敤鎴峰姞鍏ョ兢")
+ public CommonResult<Boolean> inviteGroupMember(@Valid @RequestBody ImGroupMemberInviteReqVO inviteReqVO) {
+ groupService.inviteGroupMember(getLoginUserId(), inviteReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/quit")
+ @Operation(summary = "閫�鍑虹兢")
+ @Parameter(name = "groupId", description = "缇ょ紪鍙�", required = true)
+ public CommonResult<Boolean> quitGroup(@RequestParam("groupId") Long groupId) {
+ groupService.quitGroup(groupId, getLoginUserId());
+ return success(true);
+ }
+
+ @DeleteMapping("/kicking")
+ @Operation(summary = "绉婚櫎缇ゆ垚鍛�")
+ public CommonResult<Boolean> removeGroupMember(@Valid @RequestBody ImGroupMemberRemoveReqVO removeReqVO) {
+ groupService.removeGroupMember(getLoginUserId(), removeReqVO);
+ return success(true);
+ }
+
+ @PutMapping("/add-admin")
+ @Operation(summary = "娣诲姞缇ょ鐞嗗憳")
+ public CommonResult<Boolean> addGroupAdmin(@Valid @RequestBody ImGroupAdminAddReqVO reqVO) {
+ groupService.addGroupAdmin(getLoginUserId(), reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/remove-admin")
+ @Operation(summary = "鎾ら攢缇ょ鐞嗗憳")
+ public CommonResult<Boolean> removeGroupAdmin(@Valid @RequestBody ImGroupAdminRemoveReqVO reqVO) {
+ groupService.removeGroupAdmin(getLoginUserId(), reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/transfer-owner")
+ @Operation(summary = "杞缇や富")
+ public CommonResult<Boolean> transferGroupOwner(@Valid @RequestBody ImGroupTransferOwnerReqVO transferReqVO) {
+ groupService.transferGroupOwner(getLoginUserId(), transferReqVO);
+ return success(true);
+ }
+
+ // ==================== 缇ゆ秷鎭疆椤� ====================
+
+ @PutMapping("/pin-message")
+ @Operation(summary = "缃《缇ゆ秷鎭紙缇や富 / 绠$悊鍛橈級")
+ public CommonResult<Boolean> pinGroupMessage(@Valid @RequestBody ImGroupMessagePinReqVO reqVO) {
+ groupService.pinGroupMessage(getLoginUserId(), reqVO.getId(), reqVO.getMessageId());
+ return success(true);
+ }
+
+ @PutMapping("/unpin-message")
+ @Operation(summary = "鍙栨秷缃《缇ゆ秷鎭紙缇や富 / 绠$悊鍛橈級")
+ public CommonResult<Boolean> unpinGroupMessage(@Valid @RequestBody ImGroupMessagePinReqVO reqVO) {
+ groupService.unpinGroupMessage(getLoginUserId(), reqVO.getId(), reqVO.getMessageId());
+ return success(true);
+ }
+
+ // ==================== 缇ょ瑷� ====================
+
+ @PutMapping("/mute-all")
+ @Operation(summary = "鍏ㄧ兢绂佽█ / 鍙栨秷锛堢兢涓� / 绠$悊鍛橈級")
+ public CommonResult<Boolean> muteAll(@Valid @RequestBody ImGroupMuteAllReqVO reqVO) {
+ groupService.muteAll(getLoginUserId(), reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/mute-member")
+ @Operation(summary = "绂佽█鎴愬憳")
+ public CommonResult<Boolean> muteMember(@Valid @RequestBody ImGroupMuteMemberReqVO reqVO) {
+ groupService.muteMember(getLoginUserId(), reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/cancel-mute-member")
+ @Operation(summary = "鍙栨秷鎴愬憳绂佽█")
+ public CommonResult<Boolean> cancelMuteMember(@Valid @RequestBody ImGroupCancelMuteMemberReqVO reqVO) {
+ groupService.cancelMuteMember(getLoginUserId(), reqVO);
+ return success(true);
+ }
+
+ /** 鍗曠兢杞� VO + 鍏宠仈鍥炲~ pinnedMessages锛堜粎褰撶櫥褰曠敤鎴锋槸璇ョ兢鏈夋晥鎴愬憳锛� */
+ private ImGroupRespVO buildGroupRespVO(ImGroupDO group, Long loginUserId) {
+ if (group == null) {
+ return null;
+ }
+ return buildGroupRespVOList(Collections.singletonList(group), loginUserId).get(0);
+ }
+
+ /**
+ * 缇ゅ垪琛ㄦ壒閲忚浆 VO + 鍏宠仈鍥炲~ pinnedMessages
+ * <p>
+ * 浠呭綋鐧诲綍鐢ㄦ埛鏄煇缇ょ殑鏈夋晥鎴愬憳鏃舵墠鍥炲~璇ョ兢鐨� pinnedMessages锛岄伩鍏嶉潪鎴愬憳 / 宸查��缇ょ敤鎴疯秺鏉冩嬁鍒扮疆椤舵秷鎭唴瀹�
+ */
+ private List<ImGroupRespVO> buildGroupRespVOList(List<ImGroupDO> groups, Long loginUserId) {
+ if (CollUtil.isEmpty(groups)) {
+ return Collections.emptyList();
+ }
+ // 浠呭綋鍓嶇敤鎴锋槸鏈夋晥鎴愬憳鐨勭兢鎵嶅厑璁稿洖濉疆椤舵秷鎭�
+ Map<Long, ImGroupMemberDO> memberMap = convertMap(
+ groupMemberService.getGroupMemberListByUserId(loginUserId), ImGroupMemberDO::getGroupId);
+ Set<Long> activeGroupIds = convertSet(memberMap.values(), ImGroupMemberDO::getGroupId,
+ member -> CommonStatusEnum.ENABLE.getStatus().equals(member.getStatus()));
+ Set<Long> allMessageIds = convertSetByFlatMap(groups, group -> activeGroupIds.contains(group.getId())
+ ? CollUtil.emptyIfNull(group.getPinnedMessageIds()).stream() : Stream.empty());
+ Map<Long, ImGroupMessageDO> messageMap = groupMessageService.getGroupMessageMap(allMessageIds);
+ // 杞崲杈撳嚭
+ return convertList(groups, group -> {
+ ImGroupRespVO groupVO = BeanUtils.toBean(group, ImGroupRespVO.class);
+ // 鏍囪鐧诲綍鐢ㄦ埛鍦ㄨ缇ょ殑鎴愬憳鐘舵�侊紝渚涘墠绔尯鍒嗗綋鍓嶇兢涓庡巻鍙查��缇�
+ boolean joined = activeGroupIds.contains(group.getId());
+ groupVO.setJoinStatus(joined ? CommonStatusEnum.ENABLE.getStatus() : CommonStatusEnum.DISABLE.getStatus());
+ MapUtils.findAndThen(memberMap, group.getId(), member ->
+ groupVO.setGroupRemark(member.getGroupRemark()).setSilent(Boolean.TRUE.equals(member.getSilent())));
+ if (!joined || CollUtil.isEmpty(group.getPinnedMessageIds())) {
+ return groupVO;
+ }
+ // 鎸� pin 椤哄簭杈撳嚭锛屽凡琚垹闄ょ殑娑堟伅锛坢essageMap 娌″懡涓級璺宠繃
+ List<ImGroupMessageDO> pinnedMesages = convertList(group.getPinnedMessageIds(), messageMap::get);
+ return groupVO.setPinnedMessages(BeanUtils.toBean(pinnedMesages, ImGroupMessageRespVO.class));
+ });
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupMemberController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupMemberController.java
new file mode 100644
index 0000000..c752eeb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupMemberController.java
@@ -0,0 +1,140 @@
+package cn.iocoder.yudao.module.im.controller.admin.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberUpdateReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.GROUP_MEMBER_NOT_IN_GROUP;
+
+@Tag(name = "绠$悊鍚庡彴 - 缇ゆ垚鍛�")
+@RestController
+@RequestMapping("/im/group-member")
+@Validated
+public class ImGroupMemberController {
+
+ @Resource
+ private ImGroupMemberService groupMemberService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PutMapping("/update")
+ @Operation(summary = "鏇存柊缇ゆ垚鍛�")
+ public CommonResult<Boolean> updateGroupMember(@Valid @RequestBody ImGroupMemberUpdateReqVO updateReqVO) {
+ groupMemberService.updateGroupMember(getLoginUserId(), updateReqVO);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱缇ゆ垚鍛�")
+ @Parameters({
+ @Parameter(name = "id", description = "缂栧彿锛堜笌 groupId + userId 浜岄�変竴锛�", example = "1024"),
+ @Parameter(name = "groupId", description = "缇ょ紪鍙凤紙涓� userId 閰嶅悎鏌ワ級", example = "1"),
+ @Parameter(name = "userId", description = "鐢ㄦ埛缂栧彿锛堜笌 groupId 閰嶅悎鏌ワ級", example = "100")
+ })
+ public CommonResult<ImGroupMemberRespVO> getGroupMember(@RequestParam(value = "id", required = false) Long id,
+ @RequestParam(value = "groupId", required = false) Long groupId,
+ @RequestParam(value = "userId", required = false) Long userId) {
+ // 1. 鏌ヨ缇ゆ垚鍛�
+ ImGroupMemberDO member;
+ if (id != null) {
+ member = groupMemberService.getGroupMember(id);
+ } else if (groupId != null && userId != null) {
+ member = groupMemberService.getGroupMember(groupId, userId);
+ } else {
+ // 閬垮厤 selectByGroupIdAndUserId 鏀跺埌 null 鍙傛暟璧板叏琛ㄦ壂 / 鎶� SQL 寮傚父
+ throw new IllegalArgumentException("鍙傛暟缂哄け锛氶渶浼� id 鎴� (groupId, userId)");
+ }
+ if (member == null) {
+ return success(null);
+ }
+
+ // 2. 鏍¢獙褰撳墠鐧诲綍鐢ㄦ埛鏄鎴愬憳鎵�鍦ㄧ兢鐨勬湁鏁堟垚鍛�
+ Long loginUserId = getLoginUserId();
+ groupMemberService.validateMemberInGroup(member.getGroupId(), loginUserId);
+
+ // 3. 杞寲 VO
+ ImGroupMemberRespVO memberVO = BeanUtils.toBean(member, ImGroupMemberRespVO.class);
+ AdminUserRespDTO user = adminUserApi.getUser(member.getUserId());
+ if (user != null) {
+ memberVO.setNickname(user.getNickname()).setAvatar(user.getAvatar());
+ }
+ hidePrivateFieldsIfNotSelf(memberVO, member.getUserId(), loginUserId);
+ return success(memberVO);
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "鑾峰緱鎸囧畾缇ょ殑鎴愬憳鍒楄〃锛堟寜缇ゅ叏閲忔媺鍙栵紝浣滀负鍓嶇鏈湴鎴愬憳 cache 鐨勫畬鏁村熀绾匡級")
+ @Parameter(name = "groupId", description = "缇ょ紪鍙�", required = true, example = "1024")
+ public CommonResult<List<ImGroupMemberRespVO>> getGroupMemberList(@RequestParam("groupId") Long groupId) {
+ // 1.1 鏌ヨ缇ゆ垚鍛樺垪琛紙鍖呭惈 DISABLE 宸查��缇ょ殑鎴愬憳锛屼笉鎸夋椂闂磋繃婊わ級
+ // 璇存槑锛氫繚鐣欏凡閫�缇ゆ垚鍛橈紝鏄负浜嗗墠绔睍绀哄巻鍙叉秷鎭椂锛屼粛鑳介�氳繃璇ユ帴鍙f嬁鍒板凡閫�缇ゆ垚鍛樼殑鏄电О / 澶村儚淇℃伅锛岄伩鍏嶆樉绀轰负绌�
+ List<ImGroupMemberDO> members = groupMemberService.getGroupMemberListByGroupId(groupId);
+ // 1.2 鏍¢獙褰撳墠鐧诲綍鐢ㄦ埛鏄惁涓虹兢鐨勬湁鏁堟垚鍛橈紝闈炴垚鍛樹笉鍙煡鐪�
+ Long loginUserId = getLoginUserId();
+ if (CollUtil.findOne(members, member -> loginUserId.equals(member.getUserId())
+ && CommonStatusEnum.ENABLE.getStatus().equals(member.getStatus())) == null) {
+ throw exception(GROUP_MEMBER_NOT_IN_GROUP);
+ }
+
+ // 2. 鎵归噺鑱氬悎鏄电О / 澶村儚锛屽苟瀵归潪鏈汉缃┖绉佷汉瀛楁
+ return success(buildGroupMemberRespVOList(members));
+ }
+
+ // ========== 绉佹湁鏂规硶锛歏O 缁勮 ==========
+
+ /**
+ * 缇ゆ垚鍛樺垪琛ㄦ壒閲忚浆 VO 锛� 鍏宠仈鍥炲~鏄电О 锛� 澶村儚锛屽苟瀵归潪鏈汉缃┖绉佷汉瀛楁
+ */
+ private List<ImGroupMemberRespVO> buildGroupMemberRespVOList(List<ImGroupMemberDO> members) {
+ if (CollUtil.isEmpty(members)) {
+ return Collections.emptyList();
+ }
+ Long loginUserId = getLoginUserId();
+ // 鎵归噺鑱氬悎 AdminUser 淇℃伅锛堟樀绉� 锛� 澶村儚锛夛紝閬垮厤 N+1
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ convertList(members, ImGroupMemberDO::getUserId));
+ return convertList(members, member -> {
+ ImGroupMemberRespVO vo = BeanUtils.toBean(member, ImGroupMemberRespVO.class);
+ MapUtils.findAndThen(userMap, member.getUserId(), user ->
+ vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
+ hidePrivateFieldsIfNotSelf(vo, member.getUserId(), loginUserId);
+ return vo;
+ });
+ }
+
+ /**
+ * 闈炴湰浜烘煡鐪嬫椂锛岀疆绌烘垚鍛樼殑绉佷汉璁剧疆瀛楁锛坓roupRemark / silent锛�
+ */
+ private void hidePrivateFieldsIfNotSelf(ImGroupMemberRespVO vo, Long memberUserId, Long loginUserId) {
+ if (ObjUtil.notEqual(loginUserId, memberUserId)) {
+ vo.setGroupRemark(null).setSilent(null);
+ }
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupRequestController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupRequestController.java
new file mode 100644
index 0000000..6ffebe5
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupRequestController.java
@@ -0,0 +1,174 @@
+package cn.iocoder.yudao.module.im.controller.admin.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.request.ImGroupRequestApplyReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.request.ImGroupRequestRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupRequestDO;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupRequestService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+
+/**
+ * IM 鍔犵兢鐢宠 Controller
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Tag(name = "绠$悊鍚庡彴 - IM 鍔犵兢鐢宠")
+@RestController
+@RequestMapping("/im/group-request")
+@Validated
+public class ImGroupRequestController {
+
+ @Resource
+ private ImGroupRequestService groupRequestService;
+ @Resource
+ private ImGroupService groupService;
+ @Resource
+ private ImGroupMemberService groupMemberService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/apply")
+ @Operation(summary = "鐢宠鍔犵兢")
+ public CommonResult<Long> applyJoinGroup(@Valid @RequestBody ImGroupRequestApplyReqVO reqVO) {
+ ImGroupRequestDO request = groupRequestService.applyJoinGroup(getLoginUserId(), reqVO);
+ return success(request != null ? request.getId() : null);
+ }
+
+ @PutMapping("/agree")
+ @Operation(summary = "鍚屾剰鍔犵兢鐢宠锛堢兢涓绘垨绠$悊鍛橈級")
+ @Parameter(name = "id", description = "鐢宠缂栧彿", required = true, example = "1024")
+ public CommonResult<Boolean> agreeGroupRequest(
+ @RequestParam("id") @NotNull(message = "鐢宠缂栧彿涓嶈兘涓虹┖") Long id) {
+ groupRequestService.agreeGroupRequest(getLoginUserId(), id);
+ return success(true);
+ }
+
+ @PutMapping("/refuse")
+ @Operation(summary = "鎷掔粷鍔犵兢鐢宠锛堢兢涓绘垨绠$悊鍛橈級")
+ public CommonResult<Boolean> refuseGroupRequest(
+ @RequestParam("id") @NotNull(message = "鐢宠缂栧彿涓嶈兘涓虹┖") Long id,
+ @RequestParam(value = "handleContent", required = false)
+ @Size(max = 255, message = "澶勭悊鐞嗙敱鏈�澶� 255 涓瓧绗�") String handleContent) {
+ groupRequestService.refuseGroupRequest(getLoginUserId(), id, handleContent);
+ return success(true);
+ }
+
+ @GetMapping("/unhandled-list")
+ @Operation(summary = "鏌ヨ銆屾垜绠$悊鐨勬墍鏈夌兢銆嶄笅鐨勬湭澶勭悊鍔犵兢鐢宠鍒楄〃锛堜笉鍒嗛〉锛夛紱鍓嶇 store 鎹娲剧敓妯箙绾㈢偣 + Drawer 鍒楄〃")
+ public CommonResult<List<ImGroupRequestRespVO>> getUnhandledRequestList() {
+ List<ImGroupRequestDO> list = groupRequestService.getUnhandledRequestListByOwnerOrAdmin(getLoginUserId());
+ return success(buildVOList(list));
+ }
+
+ @GetMapping("/pull")
+ @Operation(summary = "澧為噺鎷夊彇銆屾垜绠$悊鐨勭兢銆嶄笅鐨勫姞缇ょ敵璇凤紙閲嶈繛 / 绂荤嚎琛ュ伩锛�")
+ @Parameters({
+ @Parameter(name = "lastUpdateTime", description = "涓婃鎷夊彇鍒扮殑鏈�鏂版洿鏂版椂闂达紙姣鏃堕棿鎴筹級锛涢娆℃媺鍙栦笉浼�"),
+ @Parameter(name = "lastId", description = "涓婃鎷夊彇鍒扮殑鏈�鍚庝竴鏉¤褰� id锛涢娆℃媺鍙栦笉浼�"),
+ @Parameter(name = "limit", description = "鍗曟鎷夊彇鏉℃暟", required = true)
+ })
+ public CommonResult<List<ImGroupRequestRespVO>> pullMyGroupRequestList(
+ @RequestParam(value = "lastUpdateTime", required = false) Long lastUpdateTime,
+ @RequestParam(value = "lastId", required = false) Long lastId,
+ @RequestParam("limit") @Min(1) @Max(200) Integer limit) {
+ List<ImGroupRequestDO> list = groupRequestService.pullGroupRequestList(
+ getLoginUserId(), lastUpdateTime, lastId, limit);
+ return success(buildVOList(list));
+ }
+
+ @GetMapping("/list-by-group")
+ @Operation(summary = "鏌ヨ鎸囧畾缇や笅鐨勫叏閮ㄥ姞缇ょ敵璇凤紙鍚凡澶勭悊锛夛紱浠呯兢涓� / 绠$悊鍛樺彲鏌�")
+ @Parameter(name = "groupId", description = "缇ょ紪鍙�", required = true, example = "1024")
+ public CommonResult<List<ImGroupRequestRespVO>> getGroupRequestListByGroupId(
+ @RequestParam("groupId") @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�") Long groupId) {
+ List<ImGroupRequestDO> list = groupRequestService.getGroupRequestListByGroupId(getLoginUserId(), groupId);
+ return success(buildVOList(list));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鎸� id 鍗曟煡鐢宠璁板綍锛堝甫瓒婃潈杩囨护锛沇ebSocket 閫氱煡鍒拌揪鍚庣敤锛�")
+ @Parameter(name = "id", description = "鐢宠璁板綍缂栧彿", required = true)
+ public CommonResult<ImGroupRequestRespVO> getGroupRequest(@RequestParam("id") Long id) {
+ ImGroupRequestDO request = groupRequestService.getGroupRequest(id);
+ if (request == null) {
+ return success(null);
+ }
+ // 瓒婃潈杩囨护锛氱敵璇蜂汉 / 閭�璇蜂汉 / 缇や富 / 绠$悊鍛樹箣澶栵紝褰撲笉瀛樺湪杩斿洖 null
+ Long currentUserId = getLoginUserId();
+ boolean canSee = ObjUtil.equal(request.getUserId(), currentUserId)
+ || ObjUtil.equal(request.getInviterUserId(), currentUserId)
+ || isGroupOwnerOrAdmin(request.getGroupId(), currentUserId);
+ if (!canSee) {
+ return success(null);
+ }
+
+ // 杞崲骞惰繑鍥�
+ return success(CollUtil.getFirst(buildVOList(Collections.singletonList(request))));
+ }
+
+ /**
+ * 褰撳墠鐢ㄦ埛鏄惁璇ョ兢鐨勬湁鏁堢兢涓� / 绠$悊鍛�
+ */
+ private boolean isGroupOwnerOrAdmin(Long groupId, Long userId) {
+ ImGroupMemberDO member = groupMemberService.getGroupMember(groupId, userId);
+ return member != null
+ && !CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())
+ && ImGroupMemberRoleEnum.isOwnerOrAdmin(member.getRole());
+ }
+
+ /** 鐢宠璁板綍鍒楄〃鎵归噺杞� VO + 鍏宠仈鍥炲~鐢ㄦ埛 / 缇や俊鎭� */
+ private List<ImGroupRequestRespVO> buildVOList(List<ImGroupRequestDO> list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 1. 鑱氬悎 user / inviter 鐢ㄦ埛淇℃伅锛沜onvertSetByFlatMap 鍐呴儴宸茶繃婊� null
+ Set<Long> userIds = convertSetByFlatMap(list,
+ request -> Stream.of(request.getUserId(), request.getInviterUserId()));
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
+ // 2. 鑱氬悎缇や俊鎭紙灏佺 / 瑙f暎缇や篃瑕佸洖濉紝渚夸簬鍓嶇灞曠ず鍘嗗彶锛�
+ Set<Long> groupIds = convertSet(list, ImGroupRequestDO::getGroupId);
+ Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(groupIds);
+ return convertList(list, request -> {
+ ImGroupRequestRespVO vo = BeanUtils.toBean(request, ImGroupRequestRespVO.class);
+ MapUtils.findAndThen(userMap, request.getUserId(), user ->
+ vo.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar()));
+ MapUtils.findAndThen(userMap, request.getInviterUserId(), user ->
+ vo.setInviterNickname(user.getNickname()).setInviterAvatar(user.getAvatar()));
+ MapUtils.findAndThen(groupMap, request.getGroupId(), group ->
+ vo.setGroupName(group.getName()).setGroupAvatar(group.getAvatar()));
+ return vo;
+ });
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupAdminAddReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupAdminAddReqVO.java
new file mode 100644
index 0000000..e4183f0
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupAdminAddReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - 娣诲姞缇ょ鐞嗗憳 Request VO")
+@Data
+public class ImGroupAdminAddReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "鐩爣鐢ㄦ埛缂栧彿鍒楄〃", requiredMode = Schema.RequiredMode.REQUIRED, example = "[101, 102]")
+ @NotEmpty(message = "鐩爣鐢ㄦ埛缂栧彿鍒楄〃涓嶈兘涓虹┖")
+ private List<Long> userIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupAdminRemoveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupAdminRemoveReqVO.java
new file mode 100644
index 0000000..7c35dfb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupAdminRemoveReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - 鎾ら攢缇ょ鐞嗗憳 Request VO")
+@Data
+public class ImGroupAdminRemoveReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "鐩爣鐢ㄦ埛缂栧彿鍒楄〃", requiredMode = Schema.RequiredMode.REQUIRED, example = "[101, 102]")
+ @NotEmpty(message = "鐩爣鐢ㄦ埛缂栧彿鍒楄〃涓嶈兘涓虹┖")
+ private List<Long> userIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupCancelMuteMemberReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupCancelMuteMemberReqVO.java
new file mode 100644
index 0000000..2e2243a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupCancelMuteMemberReqVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 鍙栨秷鎴愬憳绂佽█ Request VO")
+@Data
+public class ImGroupCancelMuteMemberReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "琚彇娑堢瑷�鐨勭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "鐢ㄦ埛缂栧彿涓嶈兘涓虹┖")
+ private Long userId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupCreateReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupCreateReqVO.java
new file mode 100644
index 0000000..ec88708
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupCreateReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゅ垱寤� Request VO")
+@Data
+public class ImGroupCreateReqVO {
+
+ @Schema(description = "缇ゅ悕绉�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鑺嬮亾鎶�鏈氦娴佺兢")
+ @NotBlank(message = "缇ゅ悕绉颁笉鑳戒负绌�")
+ @Size(max = 64, message = "缇ゅ悕绉伴暱搴︿笉鑳借秴杩� 64")
+ private String name;
+
+ @Schema(description = "鍒濆鎴愬憳鐢ㄦ埛缂栧彿鍒楄〃锛堝缓缇ゅ悓鏃堕個璇风殑濂藉弸锛屼笉鍚垱寤鸿�呰嚜宸憋級", example = "[1024, 2048]")
+ private List<Long> memberUserIds;
+
+ @Schema(description = "杩涚兢鏄惁闇�缇や富 / 绠$悊鍛樺鎵癸紱涓嶄紶榛樿 false 鑷敱杩涚兢", example = "false")
+ private Boolean joinApproval;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMessagePinReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMessagePinReqVO.java
new file mode 100644
index 0000000..49c14ff
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMessagePinReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * 绠$悊鍚庡彴 - 缇ゆ秷鎭疆椤� / 鍙栨秷缃《 Request VO
+ */
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ秷鎭疆椤� / 鍙栨秷缃《 Request VO")
+@Data
+public class ImGroupMessagePinReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "娑堟伅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "9527")
+ @NotNull(message = "娑堟伅缂栧彿涓嶈兘涓虹┖")
+ private Long messageId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMuteAllReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMuteAllReqVO.java
new file mode 100644
index 0000000..0a23cb0
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMuteAllReqVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 鍏ㄧ兢绂佽█ / 鍙栨秷 Request VO")
+@Data
+public class ImGroupMuteAllReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "鏄惁鍏ㄧ兢绂佽█", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+ @NotNull(message = "鏄惁鍏ㄧ兢绂佽█涓嶈兘涓虹┖")
+ private Boolean mutedAll;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMuteMemberReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMuteMemberReqVO.java
new file mode 100644
index 0000000..1847648
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupMuteMemberReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 鎴愬憳绂佽█ Request VO")
+@Data
+public class ImGroupMuteMemberReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "琚瑷�鐨勭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "鐢ㄦ埛缂栧彿涓嶈兘涓虹┖")
+ private Long userId;
+
+ @Schema(description = "绂佽█鏃堕暱锛堢锛夛紝0 琛ㄧず姘镐箙绂佽█", requiredMode = Schema.RequiredMode.REQUIRED, example = "600")
+ @NotNull(message = "绂佽█鏃堕暱涓嶈兘涓虹┖")
+ @Min(value = 0, message = "绂佽█鏃堕暱涓嶈兘灏忎簬 0 绉�")
+ private Integer mutedSeconds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupPageReqVO.java
new file mode 100644
index 0000000..fdb6016
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupPageReqVO.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import lombok.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゅ垎椤� Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ImGroupPageReqVO extends PageParam {
+
+ @Schema(description = "缇ゅ悕绉�", example = "鑺嬭壙")
+ private String name;
+
+ @Schema(description = "缇や富鐢ㄦ埛缂栧彿", example = "31460")
+ private Long ownerUserId;
+
+ @Schema(description = "缇ゅ叕鍛�")
+ private String notice;
+
+ @Schema(description = "鍒涘缓鏃堕棿")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupRespVO.java
new file mode 100644
index 0000000..f15d766
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupRespVO.java
@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇� Response VO")
+@Data
+public class ImGroupRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1003")
+ private Long id;
+
+ @Schema(description = "缇ゅ悕绉�", example = "鑺嬭壙")
+ private String name;
+
+ @Schema(description = "缇や富鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "31460")
+ private Long ownerUserId;
+
+ @Schema(description = "缇ゅご鍍�")
+ private String avatar;
+
+ @Schema(description = "缇ゅ叕鍛�")
+ private String notice;
+
+ @Schema(description = "鏄惁灏佺")
+ private Boolean banned;
+
+ @Schema(description = "鏄惁鍏ㄧ兢绂佽█")
+ private Boolean mutedAll;
+
+ @Schema(description = "杩涚兢鏄惁闇�缇や富 / 绠$悊鍛樺鎵�", example = "false")
+ private Boolean joinApproval;
+
+ @Schema(description = "灏佺鏃堕棿")
+ private LocalDateTime bannedTime;
+
+ @Schema(description = "缇ょ姸鎬�", requiredMode = Schema.RequiredMode.REQUIRED)
+ private Integer status;
+
+ @Schema(description = "瑙f暎鏃堕棿")
+ private LocalDateTime dissolvedTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "褰撳墠鐧诲綍鐢ㄦ埛鍦ㄨ缇ょ殑鎴愬憳鐘舵�侊細鍦ㄧ兢 / 宸查��缇わ紙鍘嗗彶閫�缇ょ兢浠嶈繑鍥烇紝渚涘墠绔睍绀虹绾挎秷鎭殑缇ゅ悕 / 澶村儚锛�")
+ private Integer joinStatus; // 鍙傝 CommonStatusEnum 鏋氫妇
+
+ @Schema(description = "褰撳墠鐧诲綍鐢ㄦ埛瀵硅缇ょ殑澶囨敞")
+ private String groupRemark;
+
+ @Schema(description = "褰撳墠鐧诲綍鐢ㄦ埛鏄惁鍏嶆墦鎵�")
+ private Boolean silent;
+
+ @Schema(description = "缇ょ疆椤舵秷鎭垪琛紝鎸� pin 椤哄簭锛堟渶鍏堢疆椤剁殑鍦ㄥ墠锛夛紱闈炶缇ゆ湁鏁堟垚鍛樻椂涓虹┖")
+ private List<ImGroupMessageRespVO> pinnedMessages;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupSaveReqVO.java
new file mode 100644
index 0000000..0275fd8
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupSaveReqVO.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import jakarta.validation.constraints.*;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ柊澧�/淇敼 Request VO")
+@Data
+public class ImGroupSaveReqVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1003")
+ private Long id;
+
+ @Schema(description = "缇ゅ悕绉�", example = "鑺嬭壙")
+ private String name;
+
+ @Schema(description = "缇や富鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "31460")
+ @NotNull(message = "缇や富鐢ㄦ埛缂栧彿涓嶈兘涓虹┖")
+ private Long ownerUserId;
+
+ @Schema(description = "缇ゅご鍍�")
+ private String avatar;
+
+ @Schema(description = "缇ゅ叕鍛�")
+ private String notice;
+
+}
\ No newline at end of file
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupTransferOwnerReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupTransferOwnerReqVO.java
new file mode 100644
index 0000000..226d07e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupTransferOwnerReqVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇や富杞 Request VO")
+@Data
+public class ImGroupTransferOwnerReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "鏂扮兢涓荤敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "202")
+ @NotNull(message = "鏂扮兢涓荤敤鎴风紪鍙蜂笉鑳戒负绌�")
+ private Long newOwnerUserId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupUpdateReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupUpdateReqVO.java
new file mode 100644
index 0000000..99bdfb3
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/ImGroupUpdateReqVO.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo;
+
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.AssertTrue;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ洿鏂� Request VO")
+@Data
+public class ImGroupUpdateReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1003")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "缇ゅ悕绉�", example = "鑺嬮亾鎶�鏈氦娴佺兢")
+ @Size(max = 64, message = "缇ゅ悕绉伴暱搴︿笉鑳借秴杩� 64")
+ private String name;
+
+ @Schema(description = "缇ゅご鍍�")
+ @Size(max = 512, message = "缇ゅご鍍忛暱搴︿笉鑳借秴杩� 512")
+ private String avatar;
+
+ @Schema(description = "缇ゅ叕鍛�")
+ @Size(max = 2048, message = "缇ゅ叕鍛婇暱搴︿笉鑳借秴杩� 2048")
+ private String notice;
+
+ @Schema(description = "杩涚兢鏄惁闇�缇や富 / 绠$悊鍛樺鎵�", example = "true")
+ private Boolean joinApproval;
+
+ @AssertTrue(message = "缇ゅ悕绉颁笉鑳戒负绌�")
+ @JsonIgnore
+ public boolean isNameValid() {
+ return name == null || StrUtil.isNotBlank(name);
+ }
+
+ @AssertTrue(message = "缇ゅご鍍忎笉鑳戒负绌�")
+ @JsonIgnore
+ public boolean isAvatarValid() {
+ return avatar == null || StrUtil.isNotBlank(avatar);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberCreateReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberCreateReqVO.java
new file mode 100644
index 0000000..a486190
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberCreateReqVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ垚鍛橀個璇� Request VO")
+@Data
+public class ImGroupMemberCreateReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long groupId;
+
+ @Schema(description = "鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "21730")
+ @NotNull(message = "鐢ㄦ埛缂栧彿涓嶈兘涓虹┖")
+ private Long userId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberInviteReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberInviteReqVO.java
new file mode 100644
index 0000000..12cd09d
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberInviteReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ垚鍛橀個璇� Request VO")
+@Data
+public class ImGroupMemberInviteReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "13279")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long groupId;
+
+ @Schema(description = "琚個璇风殑鐢ㄦ埛缂栧彿鍒楄〃", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]")
+ @NotEmpty(message = "琚個璇风殑鐢ㄦ埛缂栧彿鍒楄〃涓嶈兘涓虹┖")
+ private List<Long> memberUserIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRemoveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRemoveReqVO.java
new file mode 100644
index 0000000..9862b12
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRemoveReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ垚鍛樼Щ闄� Request VO")
+@Data
+public class ImGroupMemberRemoveReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long groupId;
+
+ @Schema(description = "琚Щ闄ょ殑鐢ㄦ埛缂栧彿鍒楄〃", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]")
+ @NotEmpty(message = "琚Щ闄ょ殑鐢ㄦ埛缂栧彿鍒楄〃涓嶈兘涓虹┖")
+ private List<Long> memberUserIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRespVO.java
new file mode 100644
index 0000000..ce095e1
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberRespVO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ垚鍛� Response VO")
+@Data
+public class ImGroupMemberRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "17071")
+ private Long id;
+
+ @Schema(description = "缇ょ紪鍙�", example = "13279")
+ private Long groupId;
+
+ @Schema(description = "鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "21730")
+ private Long userId;
+
+ @Schema(description = "缁勫唴鏄剧ず鍚�", example = "鑺嬭壙")
+ private String displayUserName;
+
+ @Schema(description = "缇ゅ娉�", example = "鏍稿績缇�")
+ private String groupRemark;
+
+ @Schema(description = "鏄惁鍏嶆墦鎵�")
+ private Boolean silent;
+
+ @Schema(description = "鎴愬憳鐘舵��", example = "0")
+ private Integer status;
+
+ @Schema(description = "鎴愬憳瑙掕壊", example = "3")
+ private Integer role; // 鍙傝 ImGroupMemberRoleEnum 鏋氫妇绫�
+
+ @Schema(description = "鍏ョ兢鏃堕棿")
+ private LocalDateTime joinTime;
+
+ @Schema(description = "閫�缇ゆ椂闂�")
+ private LocalDateTime quitTime;
+
+ @Schema(description = "绂佽█鍒版湡鏃堕棿")
+ private LocalDateTime muteEndTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ // ========== 鍏宠仈 AdminUser 鐨勫瓧娈� ==========
+
+ @Schema(description = "鐢ㄦ埛鏄电О", example = "鑺嬮亾")
+ private String nickname;
+
+ @Schema(description = "鐢ㄦ埛澶村儚")
+ private String avatar;
+
+}
\ No newline at end of file
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberUpdateReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberUpdateReqVO.java
new file mode 100644
index 0000000..8c2c6fd
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/member/ImGroupMemberUpdateReqVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo.member;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ垚鍛樻洿鏂� Request VO")
+@Data
+@Accessors(chain = true)
+public class ImGroupMemberUpdateReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long groupId;
+
+ @Schema(description = "缇ゅ唴鏄电О", example = "鑺嬪ご")
+ private String displayUserName;
+
+ @Schema(description = "缇ゅ娉�", example = "鍏徃缇�")
+ private String groupRemark;
+
+ @Schema(description = "鏄惁鍏嶆墦鎵�")
+ private Boolean silent;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/request/ImGroupRequestApplyReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/request/ImGroupRequestApplyReqVO.java
new file mode 100644
index 0000000..6f34a05
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/request/ImGroupRequestApplyReqVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo.request;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鍔犵兢鐢宠鍙戣捣 Request VO")
+@Data
+public class ImGroupRequestApplyReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long groupId;
+
+ @Schema(description = "鐢宠鐞嗙敱", example = "鎴戞槸鑺嬭壙锛堜竴绉嶉鏉愶級")
+ @Size(max = 255, message = "鐢宠鐞嗙敱鏈�澶� 255 涓瓧绗�")
+ private String applyContent;
+
+ @Schema(description = "鍔犲叆鏉ユ簮", example = "1")
+ @InEnum(ImGroupAddSourceEnum.class)
+ private Integer addSource;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/request/ImGroupRequestRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/request/ImGroupRequestRespVO.java
new file mode 100644
index 0000000..9e21cae
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/vo/request/ImGroupRequestRespVO.java
@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.module.im.controller.admin.group.vo.request;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鍔犵兢鐢宠 Response VO")
+@Data
+public class ImGroupRequestRespVO {
+
+ @Schema(description = "鐢宠缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long groupId;
+
+ @Schema(description = "鐢宠浜� / 琚個璇蜂汉鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+ private Long userId;
+
+ @Schema(description = "閭�璇蜂汉鐢ㄦ埛缂栧彿锛汵ULL 琛ㄧず鐢ㄦ埛涓诲姩鐢宠", example = "200")
+ private Long inviterUserId;
+
+ @Schema(description = "澶勭悊缁撴灉", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer handleResult; // 鍙傝 ImGroupRequestHandleResultEnum 鏋氫妇
+
+ @Schema(description = "鐢宠鐞嗙敱", example = "鎴戞兂鍔犲叆杩欎釜缇�")
+ private String applyContent;
+
+ @Schema(description = "澶勭悊鐞嗙敱锛堟嫆缁濇椂鍙�夊~锛�", example = "鏆備笉閫氳繃")
+ private String handleContent;
+
+ @Schema(description = "澶勭悊浜虹敤鎴风紪鍙�", example = "31460")
+ private Long handleUserId;
+
+ @Schema(description = "鍔犲叆鏉ユ簮", example = "1")
+ private Integer addSource; // 鍙傝 ImGroupAddSourceEnum 鏋氫妇
+
+ @Schema(description = "澶勭悊鏃堕棿")
+ private LocalDateTime handleTime;
+
+ @Schema(description = "鐢宠鍒涘缓鏃堕棿")
+ private LocalDateTime createTime;
+
+ @Schema(description = "鐢宠鏇存柊鏃堕棿锛涘閲忔媺鍙栨父鏍�")
+ private LocalDateTime updateTime;
+
+ // ========== 涓嬮潰鏄仛鍚堝瓧娈碉紝鏂逛究鍓嶇鏄剧ず ==========
+
+ @Schema(description = "鐢宠浜� / 琚個璇蜂汉鏄电О锛堝疄鏃惰仛鍚堣嚜 AdminUser锛�", example = "鑺嬮亾")
+ private String userNickname;
+
+ @Schema(description = "鐢宠浜� / 琚個璇蜂汉澶村儚锛堝疄鏃惰仛鍚堣嚜 AdminUser锛�")
+ private String userAvatar;
+
+ @Schema(description = "閭�璇蜂汉鏄电О锛堝疄鏃惰仛鍚堣嚜 AdminUser锛�", example = "鑰佸紶")
+ private String inviterNickname;
+
+ @Schema(description = "閭�璇蜂汉澶村儚锛堝疄鏃惰仛鍚堣嚜 AdminUser锛�")
+ private String inviterAvatar;
+
+ @Schema(description = "缇ゅ悕绉帮紙瀹炴椂鑱氬悎鑷� ImGroup锛�", example = "鑺嬮亾鎶�鏈氦娴佺兢")
+ private String groupName;
+
+ @Schema(description = "缇ゅご鍍忥紙瀹炴椂鑱氬悎鑷� ImGroup锛�")
+ private String groupAvatar;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/ImChannelManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/ImChannelManagerController.java
new file mode 100644
index 0000000..65e06f7
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/ImChannelManagerController.java
@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.channel;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
+import cn.iocoder.yudao.module.im.service.channel.ImChannelService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 棰戦亾")
+@RestController
+@RequestMapping("/im/manager/channel")
+@Validated
+public class ImChannelManagerController {
+
+ @Resource
+ private ImChannelService channelService;
+
+ @PostMapping("/create")
+ @Operation(summary = "鏂板棰戦亾")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel:create')")
+ public CommonResult<Long> createChannel(@Valid @RequestBody ImChannelSaveReqVO reqVO) {
+ return success(channelService.createChannel(reqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "淇敼棰戦亾")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel:update')")
+ public CommonResult<Boolean> updateChannel(@Valid @RequestBody ImChannelSaveReqVO reqVO) {
+ channelService.updateChannel(reqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎棰戦亾")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel:delete')")
+ public CommonResult<Boolean> deleteChannel(@RequestParam("id") Long id) {
+ channelService.deleteChannel(id);
+ return success(true);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱棰戦亾鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel:query')")
+ public CommonResult<PageResult<ImChannelRespVO>> getChannelPage(@Valid ImChannelPageReqVO pageReqVO) {
+ PageResult<ImChannelDO> pageResult = channelService.getChannelPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, ImChannelRespVO.class));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱棰戦亾璇︽儏")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel:query')")
+ public CommonResult<ImChannelRespVO> getChannel(@RequestParam("id") Long id) {
+ ImChannelDO channel = channelService.getChannel(id);
+ return success(BeanUtils.toBean(channel, ImChannelRespVO.class));
+ }
+
+ @GetMapping("/simple-list")
+ @Operation(summary = "鑾峰緱鍚敤鐨勯閬撶簿绠�鍒楄〃锛涘墠绔〃鍗曢�夋嫨棰戦亾鏃惰皟鐢�")
+ public CommonResult<List<ImChannelRespVO>> getSimpleChannelList() {
+ List<ImChannelDO> list = channelService.getChannelListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ return success(BeanUtils.toBean(list, ImChannelRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/ImChannelMaterialManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/ImChannelMaterialManagerController.java
new file mode 100644
index 0000000..e6e0271
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/ImChannelMaterialManagerController.java
@@ -0,0 +1,99 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.channel;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
+import cn.iocoder.yudao.module.im.service.channel.ImChannelMaterialService;
+import cn.iocoder.yudao.module.im.service.channel.ImChannelService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 棰戦亾绱犳潗")
+@RestController
+@RequestMapping("/im/manager/channel-material")
+@Validated
+public class ImChannelMaterialManagerController {
+
+ @Resource
+ private ImChannelMaterialService channelMaterialService;
+ @Resource
+ private ImChannelService channelService;
+
+ @PostMapping("/create")
+ @Operation(summary = "鏂板绱犳潗")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel-material:create')")
+ public CommonResult<Long> createMaterial(@Valid @RequestBody ImChannelMaterialSaveReqVO reqVO) {
+ return success(channelMaterialService.createMaterial(reqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "淇敼绱犳潗")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel-material:update')")
+ public CommonResult<Boolean> updateMaterial(@Valid @RequestBody ImChannelMaterialSaveReqVO reqVO) {
+ channelMaterialService.updateMaterial(reqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎绱犳潗")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel-material:delete')")
+ public CommonResult<Boolean> deleteMaterial(@RequestParam("id") Long id) {
+ channelMaterialService.deleteMaterial(id);
+ return success(true);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱绱犳潗鍒嗛〉锛涘惈棰戦亾鍚嶅洖濉�")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel-material:query')")
+ public CommonResult<PageResult<ImChannelMaterialRespVO>> getMaterialPage(@Valid ImChannelMaterialPageReqVO pageReqVO) {
+ PageResult<ImChannelMaterialDO> pageResult = channelMaterialService.getMaterialPage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+ // 鍥炲~棰戦亾鍚�
+ List<ImChannelDO> channels = channelService.getChannelList(
+ convertSet(pageResult.getList(), ImChannelMaterialDO::getChannelId));
+ Map<Long, ImChannelDO> channelMap = convertMap(channels, ImChannelDO::getId);
+ return success(BeanUtils.toBean(pageResult, ImChannelMaterialRespVO.class, vo ->
+ MapUtils.findAndThen(channelMap, vo.getChannelId(), c -> vo.setChannelName(c.getName()))));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱绱犳潗璇︽儏锛堝惈瀵屾枃鏈鏂囷級")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel-material:query')")
+ public CommonResult<ImChannelMaterialRespVO> getMaterial(@RequestParam("id") Long id) {
+ ImChannelMaterialDO material = channelMaterialService.getMaterial(id);
+ return success(BeanUtils.toBean(material, ImChannelMaterialRespVO.class));
+ }
+
+ @GetMapping("/simple-list")
+ @Operation(summary = "鑾峰緱鎸囧畾棰戦亾涓嬬殑绱犳潗绮剧畝鍒楄〃锛涚敤浜庢帹閫佸脊绐楃殑绱犳潗涓嬫媺")
+ @Parameter(name = "channelId", description = "棰戦亾缂栧彿", required = true, example = "1")
+ public CommonResult<List<ImChannelMaterialRespVO>> getSimpleMaterialList(@RequestParam("channelId") Long channelId) {
+ List<ImChannelMaterialDO> list = channelMaterialService.getMaterialListByChannelId(channelId);
+ return success(BeanUtils.toBean(list, ImChannelMaterialRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelPageReqVO.java
new file mode 100644
index 0000000..51ac09a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelPageReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImChannelPageReqVO extends PageParam {
+
+ @Schema(description = "棰戦亾涓氬姟鐮�", example = "system_notice")
+ private String code;
+
+ @Schema(description = "棰戦亾鍚嶇О", example = "绯荤粺")
+ private String name;
+
+ @Schema(description = "鐘舵��", example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelRespVO.java
new file mode 100644
index 0000000..59fed78
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelRespVO.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾 Response VO")
+@Data
+public class ImChannelRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "棰戦亾涓氬姟鐮�", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_notice")
+ private String code;
+
+ @Schema(description = "棰戦亾鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "绯荤粺鍏憡")
+ private String name;
+
+ @Schema(description = "棰戦亾澶村儚")
+ private String avatar;
+
+ @Schema(description = "鎺掑簭", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer sort;
+
+ @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelSaveReqVO.java
new file mode 100644
index 0000000..6e1b042
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/channel/ImChannelSaveReqVO.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾鏂板 / 淇敼 Request VO")
+@Data
+public class ImChannelSaveReqVO {
+
+ @Schema(description = "缂栧彿锛堜慨鏀规椂蹇呭~锛�", example = "1024")
+ private Long id;
+
+ @Schema(description = "棰戦亾涓氬姟鐮侊紱鍞竴", requiredMode = Schema.RequiredMode.REQUIRED, example = "system_notice")
+ @NotBlank(message = "棰戦亾缂栫爜涓嶈兘涓虹┖")
+ @Size(max = 64, message = "棰戦亾缂栫爜闀垮害涓嶈兘瓒呰繃 64")
+ @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "棰戦亾缂栫爜鍙兘鐢卞皬鍐欏瓧姣� / 鏁板瓧 / 涓嬪垝绾跨粍鎴愶紝涓斿繀椤讳互瀛楁瘝寮�澶�")
+ private String code;
+
+ @Schema(description = "棰戦亾鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "绯荤粺鍏憡")
+ @NotBlank(message = "棰戦亾鍚嶇О涓嶈兘涓虹┖")
+ @Size(max = 64, message = "棰戦亾鍚嶇О闀垮害涓嶈兘瓒呰繃 64")
+ private String name;
+
+ @Schema(description = "棰戦亾澶村儚", example = "https://cdn.example.com/channel/system_notice.png")
+ @Size(max = 512, message = "澶村儚闀垮害涓嶈兘瓒呰繃 512")
+ private String avatar;
+
+ @Schema(description = "鎺掑簭", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "鎺掑簭涓嶈兘涓虹┖")
+ private Integer sort;
+
+ @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫伙紙0 鍚敤 / 1 绂佺敤锛�
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialPageReqVO.java
new file mode 100644
index 0000000..1bb834b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialPageReqVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾绱犳潗鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImChannelMaterialPageReqVO extends PageParam {
+
+ @Schema(description = "棰戦亾缂栧彿", example = "1")
+ private Long channelId;
+
+ @Schema(description = "鍐呭绫诲瀷", example = "1")
+ private Integer type; // 鍙傝 ImChannelMaterialTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "鏍囬", example = "娲诲姩")
+ private String title;
+
+ @Schema(description = "鍒涘缓鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialRespVO.java
new file mode 100644
index 0000000..55aebed
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialRespVO.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾绱犳潗 Response VO")
+@Data
+public class ImChannelMaterialRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "棰戦亾缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long channelId;
+
+ @Schema(description = "棰戦亾鍚嶇О锛堝叧鑱旀煡璇㈠~鍏咃級")
+ private String channelName;
+
+ @Schema(description = "鍐呭绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer type; // 鍙傝 ImChannelMaterialTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "鏍囬", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String title;
+
+ @Schema(description = "灏侀潰鍥�")
+ private String coverUrl;
+
+ @Schema(description = "鎽樿")
+ private String summary;
+
+ @Schema(description = "姝f枃锛涘瘜鏂囨湰 HTML")
+ private String content;
+
+ @Schema(description = "璺宠浆閾炬帴")
+ private String url;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialSaveReqVO.java
new file mode 100644
index 0000000..e30f35b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/channel/vo/material/ImChannelMaterialSaveReqVO.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾绱犳潗鏂板 / 淇敼 Request VO")
+@Data
+public class ImChannelMaterialSaveReqVO {
+
+ @Schema(description = "缂栧彿锛堜慨鏀规椂蹇呭~锛�", example = "1024")
+ private Long id;
+
+ @Schema(description = "棰戦亾缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "棰戦亾缂栧彿涓嶈兘涓虹┖")
+ private Long channelId;
+
+ @Schema(description = "鍐呭绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "鍐呭绫诲瀷涓嶈兘涓虹┖")
+ private Integer type; // 鍙傝 ImChannelMaterialTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "鏍囬", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍙屽崄涓�娲诲姩鏉ュ暒")
+ @NotBlank(message = "鏍囬涓嶈兘涓虹┖")
+ @Size(max = 128, message = "鏍囬闀垮害涓嶈兘瓒呰繃 128")
+ private String title;
+
+ @Schema(description = "灏侀潰鍥�", example = "https://cdn.example.com/cover.png")
+ @Size(max = 512, message = "灏侀潰鍥鹃暱搴︿笉鑳借秴杩� 512")
+ private String coverUrl;
+
+ @Schema(description = "鎽樿", example = "鍏ㄥ満浜旀姌锛屾埑璇︽儏鐪嬬帺娉�")
+ @Size(max = 255, message = "鎽樿闀垮害涓嶈兘瓒呰繃 255")
+ private String summary;
+
+ @Schema(description = "姝f枃锛涘瘜鏂囨湰 HTML")
+ private String content;
+
+ @Schema(description = "璺宠浆閾炬帴锛涗负绌鸿〃绀鸿蛋瀹㈡埛绔唴缃鎯呴〉", example = "https://example.com/activity/123")
+ @Size(max = 512, message = "璺宠浆閾炬帴闀垮害涓嶈兘瓒呰繃 512")
+ private String url;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackItemManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackItemManagerController.java
new file mode 100644
index 0000000..4a25431
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackItemManagerController.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO;
+import cn.iocoder.yudao.module.im.service.face.ImFacePackItemService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Size;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖呴」")
+@RestController
+@RequestMapping("/im/manager/face-pack-item")
+@Validated
+public class ImFacePackItemManagerController {
+
+ @Resource
+ private ImFacePackItemService facePackItemService;
+
+ @PostMapping("/create")
+ @Operation(summary = "鏂板琛ㄦ儏")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:create')")
+ public CommonResult<Long> createFacePackItem(@Valid @RequestBody ImFacePackItemSaveReqVO reqVO) {
+ return success(facePackItemService.createFacePackItem(reqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "淇敼琛ㄦ儏")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:update')")
+ public CommonResult<Boolean> updateFacePackItem(@Valid @RequestBody ImFacePackItemSaveReqVO reqVO) {
+ facePackItemService.updateFacePackItem(reqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎琛ㄦ儏")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "2048")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:delete')")
+ public CommonResult<Boolean> deleteFacePackItem(@RequestParam("id") Long id) {
+ facePackItemService.deleteFacePackItem(id);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete-list")
+ @Operation(summary = "鎵归噺鍒犻櫎琛ㄦ儏")
+ @Parameter(name = "ids", description = "缂栧彿鍒楄〃", required = true)
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:delete')")
+ public CommonResult<Boolean> deleteFacePackItemList(
+ @RequestParam("ids") @Size(max = 100, message = "鎵归噺鍒犻櫎鏈�澶� 100 鏉�") List<Long> ids) {
+ facePackItemService.deleteFacePackItemList(ids);
+ return success(true);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱琛ㄦ儏鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:query')")
+ public CommonResult<PageResult<ImFacePackItemRespVO>> getFacePackItemPage(@Valid ImFacePackItemPageReqVO pageReqVO) {
+ PageResult<ImFacePackItemDO> pageResult = facePackItemService.getFacePackItemPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, ImFacePackItemRespVO.class));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱琛ㄦ儏璇︽儏")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "2048")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:query')")
+ public CommonResult<ImFacePackItemRespVO> getFacePackItem(@RequestParam("id") Long id) {
+ ImFacePackItemDO item = facePackItemService.getFacePackItem(id);
+ return success(BeanUtils.toBean(item, ImFacePackItemRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackManagerController.java
new file mode 100644
index 0000000..ad2f8ff
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackManagerController.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
+import cn.iocoder.yudao.module.im.service.face.ImFacePackService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Size;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖�")
+@RestController
+@RequestMapping("/im/manager/face-pack")
+@Validated
+public class ImFacePackManagerController {
+
+ @Resource
+ private ImFacePackService facePackService;
+
+ @PostMapping("/create")
+ @Operation(summary = "鏂板琛ㄦ儏鍖�")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack:create')")
+ public CommonResult<Long> createFacePack(@Valid @RequestBody ImFacePackSaveReqVO reqVO) {
+ return success(facePackService.createFacePack(reqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "淇敼琛ㄦ儏鍖�")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack:update')")
+ public CommonResult<Boolean> updateFacePack(@Valid @RequestBody ImFacePackSaveReqVO reqVO) {
+ facePackService.updateFacePack(reqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎琛ㄦ儏鍖�")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack:delete')")
+ public CommonResult<Boolean> deleteFacePack(@RequestParam("id") Long id) {
+ facePackService.deleteFacePack(id);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete-list")
+ @Operation(summary = "鎵归噺鍒犻櫎琛ㄦ儏鍖�")
+ @Parameter(name = "ids", description = "缂栧彿鍒楄〃", required = true)
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack:delete')")
+ public CommonResult<Boolean> deleteFacePackList(@RequestParam("ids")
+ @Size(max = 100, message = "鎵归噺鍒犻櫎鏈�澶� 100 鏉�") List<Long> ids) {
+ facePackService.deleteFacePackList(ids);
+ return success(true);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱琛ㄦ儏鍖呭垎椤�")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack:query')")
+ public CommonResult<PageResult<ImFacePackRespVO>> getFacePackPage(@Valid ImFacePackPageReqVO pageReqVO) {
+ PageResult<ImFacePackDO> pageResult = facePackService.getFacePackPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, ImFacePackRespVO.class));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱琛ㄦ儏鍖呰鎯�")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-pack:query')")
+ public CommonResult<ImFacePackRespVO> getFacePack(@RequestParam("id") Long id) {
+ ImFacePackDO pack = facePackService.getFacePack(id);
+ return success(BeanUtils.toBean(pack, ImFacePackRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFaceUserItemManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFaceUserItemManagerController.java
new file mode 100644
index 0000000..df4a06d
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFaceUserItemManagerController.java
@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO;
+import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 鐢ㄦ埛琛ㄦ儏")
+@RestController
+@RequestMapping("/im/manager/face-user-item")
+@Validated
+public class ImFaceUserItemManagerController {
+
+ @Resource
+ private ImFaceUserItemService faceUserItemService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱鐢ㄦ埛琛ㄦ儏鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-user-item:query')")
+ public CommonResult<PageResult<ImFaceUserItemManagerRespVO>> getFaceUserItemPage(
+ @Valid ImFaceUserItemManagerPageReqVO pageReqVO) {
+ PageResult<ImFaceUserItemDO> pageResult = faceUserItemService.getFaceUserItemPage(pageReqVO);
+ // 鍏宠仈鍥炲~鐢ㄦ埛鏄电О
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ CollectionUtils.convertSet(pageResult.getList(), ImFaceUserItemDO::getUserId));
+ List<ImFaceUserItemManagerRespVO> voList = CollectionUtils.convertList(pageResult.getList(), item -> {
+ ImFaceUserItemManagerRespVO vo = BeanUtils.toBean(item, ImFaceUserItemManagerRespVO.class);
+ AdminUserRespDTO user = userMap.get(item.getUserId());
+ if (user != null) {
+ vo.setUserNickname(user.getNickname());
+ }
+ return vo;
+ });
+ return success(new PageResult<>(voList, pageResult.getTotal()));
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎鐢ㄦ埛琛ㄦ儏")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "4096")
+ @PreAuthorize("@ss.hasPermission('im:manager:face-user-item:delete')")
+ public CommonResult<Boolean> deleteFaceUserItem(@RequestParam("id") Long id) {
+ faceUserItemService.deleteFaceUserItem(id);
+ return success(true);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java
new file mode 100644
index 0000000..eefbbed
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖呴」鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImFacePackItemPageReqVO extends PageParam {
+
+ @Schema(description = "鎵�灞炶〃鎯呭寘缂栧彿", example = "1024")
+ private Long packId;
+
+ @Schema(description = "琛ㄦ儏鍚嶏紝妯$硦鍖归厤", example = "鐙�")
+ private String name;
+
+ @Schema(description = "鐘舵��", example = "0")
+ @InEnum(value = CommonStatusEnum.class, message = "鐘舵�佸繀椤绘槸 {value}")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemRespVO.java
new file mode 100644
index 0000000..817348f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemRespVO.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖呴」 Response VO")
+@Data
+public class ImFacePackItemRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long id;
+
+ @Schema(description = "鎵�灞炶〃鎯呭寘缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long packId;
+
+ @Schema(description = "琛ㄦ儏鍥� URL", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "https://cdn.example.com/face/pack/cat-001.png")
+ private String url;
+
+ @Schema(description = "琛ㄦ儏鍚�", example = "鐙楀ご")
+ private String name;
+
+ @Schema(description = "娓叉煋瀹藉害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ private Integer width;
+
+ @Schema(description = "娓叉煋楂樺害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ private Integer height;
+
+ @Schema(description = "鎺掑簭", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer sort;
+
+ @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemSaveReqVO.java
new file mode 100644
index 0000000..de6842b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemSaveReqVO.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖呴」鏂板 / 淇敼 Request VO")
+@Data
+public class ImFacePackItemSaveReqVO {
+
+ @Schema(description = "缂栧彿锛堜慨鏀规椂蹇呭~锛�", example = "2048")
+ private Long id;
+
+ @Schema(description = "鎵�灞炶〃鎯呭寘缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "琛ㄦ儏鍖呯紪鍙蜂笉鑳戒负绌�")
+ private Long packId;
+
+ @Schema(description = "琛ㄦ儏鍥� URL", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "https://cdn.example.com/face/pack/cat-001.png")
+ @NotBlank(message = "琛ㄦ儏鍥� URL 涓嶈兘涓虹┖")
+ @Size(max = 512, message = "琛ㄦ儏鍥� URL 闀垮害涓嶈兘瓒呰繃 512")
+ private String url;
+
+ @Schema(description = "琛ㄦ儏鍚�", example = "鐙楀ご")
+ @Size(max = 64, message = "琛ㄦ儏鍚嶉暱搴︿笉鑳借秴杩� 64")
+ private String name;
+
+ @Schema(description = "娓叉煋瀹藉害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ @NotNull(message = "娓叉煋瀹藉害涓嶈兘涓虹┖")
+ @Min(value = 1, message = "娓叉煋瀹藉害涓嶈兘灏忎簬 1 鍍忕礌")
+ @Max(value = 2048, message = "娓叉煋瀹藉害涓嶈兘澶т簬 2048 鍍忕礌")
+ private Integer width;
+
+ @Schema(description = "娓叉煋楂樺害锛堝儚绱狅級", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
+ @NotNull(message = "娓叉煋楂樺害涓嶈兘涓虹┖")
+ @Min(value = 1, message = "娓叉煋楂樺害涓嶈兘灏忎簬 1 鍍忕礌")
+ @Max(value = 2048, message = "娓叉煋楂樺害涓嶈兘澶т簬 2048 鍍忕礌")
+ private Integer height;
+
+ @Schema(description = "鎺掑簭", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "鎺掑簭涓嶈兘涓虹┖")
+ private Integer sort;
+
+ @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
+ @InEnum(value = CommonStatusEnum.class, message = "鐘舵�佸繀椤绘槸 {value}")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫伙紙0 鍚敤 / 1 绂佺敤锛�
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackPageReqVO.java
new file mode 100644
index 0000000..e0220af
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackPageReqVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖呭垎椤� Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImFacePackPageReqVO extends PageParam {
+
+ @Schema(description = "琛ㄦ儏鍖呭悕绉帮紝妯$硦鍖归厤", example = "鐚�")
+ private String name;
+
+ @Schema(description = "鐘舵��", example = "0")
+ @InEnum(value = CommonStatusEnum.class, message = "鐘舵�佸繀椤绘槸 {value}")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍒涘缓鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackRespVO.java
new file mode 100644
index 0000000..bdc53d2
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackRespVO.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖� Response VO")
+@Data
+public class ImFacePackRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "琛ㄦ儏鍖呭悕绉�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鐚富瀛�")
+ private String name;
+
+ @Schema(description = "琛ㄦ儏鍖呭浘鏍�", example = "https://cdn.example.com/face/pack/cat.png")
+ private String icon;
+
+ @Schema(description = "鎺掑簭", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer sort;
+
+ @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java
new file mode 100644
index 0000000..86be43d
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 琛ㄦ儏鍖呮柊澧� / 淇敼 Request VO")
+@Data
+public class ImFacePackSaveReqVO {
+
+ @Schema(description = "缂栧彿锛堜慨鏀规椂蹇呭~锛�", example = "1024")
+ private Long id;
+
+ @Schema(description = "琛ㄦ儏鍖呭悕绉�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鐚富瀛�")
+ @NotBlank(message = "琛ㄦ儏鍖呭悕绉颁笉鑳戒负绌�")
+ @Size(max = 64, message = "琛ㄦ儏鍖呭悕绉伴暱搴︿笉鑳借秴杩� 64")
+ private String name;
+
+ @Schema(description = "琛ㄦ儏鍖呭浘鏍�", example = "https://cdn.example.com/face/pack/cat.png")
+ @Size(max = 512, message = "鍥炬爣闀垮害涓嶈兘瓒呰繃 512")
+ private String icon;
+
+ @Schema(description = "鎺掑簭", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "鎺掑簭涓嶈兘涓虹┖")
+ private Integer sort;
+
+ @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
+ @InEnum(value = CommonStatusEnum.class, message = "鐘舵�佸繀椤绘槸 {value}")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫伙紙0 鍚敤 / 1 绂佺敤锛�
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerPageReqVO.java
new file mode 100644
index 0000000..dec8f1f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerPageReqVO.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鐢ㄦ埛琛ㄦ儏鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImFaceUserItemManagerPageReqVO extends PageParam {
+
+ @Schema(description = "鎵�灞炵敤鎴风紪鍙�", example = "1024")
+ private Long userId;
+
+ @Schema(description = "琛ㄦ儏鍚嶏紝妯$硦鍖归厤", example = "鐙�")
+ private String name;
+
+ @Schema(description = "娣诲姞鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerRespVO.java
new file mode 100644
index 0000000..723fc48
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerRespVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鐢ㄦ埛琛ㄦ儏 Response VO")
+@Data
+public class ImFaceUserItemManagerRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
+ private Long id;
+
+ @Schema(description = "鎵�灞炵敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long userId;
+
+ @Schema(description = "鎵�灞炵敤鎴锋樀绉�", example = "寮犱笁")
+ private String userNickname;
+
+ @Schema(description = "琛ㄦ儏鍥� URL", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "https://cdn.example.com/face/user/abc.gif")
+ private String url;
+
+ @Schema(description = "琛ㄦ儏鍚�", example = "鐙楀ご")
+ private String name;
+
+ @Schema(description = "娓叉煋瀹藉害锛堝儚绱狅級", example = "200")
+ private Integer width;
+
+ @Schema(description = "娓叉煋楂樺害锛堝儚绱狅級", example = "200")
+ private Integer height;
+
+ @Schema(description = "娣诲姞鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/ImFriendManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/ImFriendManagerController.java
new file mode 100644
index 0000000..b2f6ae7
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/ImFriendManagerController.java
@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.friend;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 濂藉弸绠$悊")
+@RestController
+@RequestMapping("/im/manager/friend")
+@Validated
+public class ImFriendManagerController {
+
+ @Resource
+ private ImFriendService friendService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱濂藉弸鍏崇郴鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:friend:query')")
+ public CommonResult<PageResult<ImFriendManagerRespVO>> getFriendPage(
+ @Valid ImFriendManagerPageReqVO pageReqVO) {
+ // 1. 鍒嗛〉鏌ヨ
+ PageResult<ImFriendDO> pageResult = friendService.getFriendPage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+ // 2.1 涓�娆℃�ф壒閲忔煡璇㈢敤鎴� + 濂藉弸鐨勬樀绉�
+ Set<Long> userIds = convertSetByFlatMap(pageResult.getList(),
+ f -> Stream.of(f.getUserId(), f.getFriendUserId()));
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
+ // 2.2 杞崲涓� VO锛屽~鍏呮樀绉�
+ return success(BeanUtils.toBean(pageResult, ImFriendManagerRespVO.class, vo -> {
+ MapUtils.findAndThen(userMap, vo.getUserId(),
+ user -> vo.setUserNickname(user.getNickname()));
+ MapUtils.findAndThen(userMap, vo.getFriendUserId(),
+ user -> vo.setFriendNickname(user.getNickname()));
+ }));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/ImFriendRequestManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/ImFriendRequestManagerController.java
new file mode 100644
index 0000000..eac0c9a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/ImFriendRequestManagerController.java
@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.friend;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendRequestManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendRequestManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendRequestService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 濂藉弸鐢宠绠$悊")
+@RestController
+@RequestMapping("/im/manager/friend-request")
+@Validated
+public class ImFriendRequestManagerController {
+
+ @Resource
+ private ImFriendRequestService friendRequestService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱濂藉弸鐢宠鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:friend-request:query')")
+ public CommonResult<PageResult<ImFriendRequestManagerRespVO>> getFriendRequestPage(
+ @Valid ImFriendRequestManagerPageReqVO pageReqVO) {
+ // 1. 鍒嗛〉鏌ヨ
+ PageResult<ImFriendRequestDO> pageResult = friendRequestService.getFriendRequestPage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+
+ // 2.1 涓�娆℃�ф壒閲忔煡璇㈠彂璧锋柟 + 鎺ユ敹鏂圭殑鏄电О
+ Set<Long> userIds = convertSetByFlatMap(pageResult.getList(),
+ request -> Stream.of(request.getFromUserId(), request.getToUserId()));
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
+ // 2.2 杞崲涓� VO锛屽~鍏呮樀绉�
+ return success(BeanUtils.toBean(pageResult, ImFriendRequestManagerRespVO.class, vo -> {
+ MapUtils.findAndThen(userMap, vo.getFromUserId(),
+ user -> vo.setFromNickname(user.getNickname()));
+ MapUtils.findAndThen(userMap, vo.getToUserId(),
+ user -> vo.setToNickname(user.getNickname()));
+ }));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendManagerPageReqVO.java
new file mode 100644
index 0000000..54b5dcc
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendManagerPageReqVO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 濂藉弸鍏崇郴鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImFriendManagerPageReqVO extends PageParam {
+
+ @Schema(description = "鐢ㄦ埛缂栧彿", example = "1024")
+ private Long userId;
+
+ @Schema(description = "濂藉弸鐢ㄦ埛缂栧彿", example = "2048")
+ private Long friendUserId;
+
+ @Schema(description = "濂藉弸鐘舵��", example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鏄惁鍏嶆墦鎵�", example = "false")
+ private Boolean silent;
+
+ @Schema(description = "娣诲姞濂藉弸鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] addTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendManagerRespVO.java
new file mode 100644
index 0000000..6664f24
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendManagerRespVO.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 濂藉弸鍏崇郴 Response VO")
+@Data
+public class ImFriendManagerRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long userId;
+
+ @Schema(description = "鐢ㄦ埛鏄电О", example = "寮犱笁")
+ private String userNickname;
+
+ @Schema(description = "濂藉弸鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long friendUserId;
+
+ @Schema(description = "濂藉弸鏄电О", example = "鏉庡洓")
+ private String friendNickname;
+
+ @Schema(description = "濂藉弸灞曠ず澶囨敞")
+ private String displayName;
+
+ @Schema(description = "娣诲姞鏉ユ簮", example = "1")
+ private Integer addSource; // 鍙傝 ImFriendAddSourceEnum 鏋氫妇绫�
+
+ @Schema(description = "鏄惁鍏嶆墦鎵�", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
+ private Boolean silent;
+
+ @Schema(description = "鏄惁缃《鑱旂郴浜�", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
+ private Boolean pinned;
+
+ @Schema(description = "鏄惁鎷夐粦", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
+ private Boolean blocked;
+
+ @Schema(description = "濂藉弸鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "娣诲姞濂藉弸鏃堕棿")
+ private LocalDateTime addTime;
+
+ @Schema(description = "鍒犻櫎濂藉弸鏃堕棿")
+ private LocalDateTime deleteTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendRequestManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendRequestManagerPageReqVO.java
new file mode 100644
index 0000000..a078909
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendRequestManagerPageReqVO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 濂藉弸鐢宠鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImFriendRequestManagerPageReqVO extends PageParam {
+
+ @Schema(description = "鍙戣捣鏂圭敤鎴风紪鍙�", example = "1024")
+ private Long fromUserId;
+
+ @Schema(description = "鎺ユ敹鏂圭敤鎴风紪鍙�", example = "2048")
+ private Long toUserId;
+
+ @Schema(description = "澶勭悊缁撴灉", example = "0")
+ private Integer handleResult; // 鍙傝 ImFriendRequestHandleResultEnum 鏋氫妇绫�
+
+ @Schema(description = "娣诲姞鏉ユ簮", example = "1")
+ private Integer addSource; // 鍙傝 ImFriendAddSourceEnum 鏋氫妇绫�
+
+ @Schema(description = "鍒涘缓鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendRequestManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendRequestManagerRespVO.java
new file mode 100644
index 0000000..9fa9d4d
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/friend/vo/ImFriendRequestManagerRespVO.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 濂藉弸鐢宠 Response VO")
+@Data
+public class ImFriendRequestManagerRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鍙戣捣鏂圭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long fromUserId;
+
+ @Schema(description = "鍙戣捣鏂规樀绉�", example = "寮犱笁")
+ private String fromNickname;
+
+ @Schema(description = "鎺ユ敹鏂圭敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long toUserId;
+
+ @Schema(description = "鎺ユ敹鏂规樀绉�", example = "鏉庡洓")
+ private String toNickname;
+
+ @Schema(description = "鐢宠鐞嗙敱", example = "鎴戞槸鑺嬭壙")
+ private String applyContent;
+
+ @Schema(description = "鍙戣捣鏂瑰鎺ユ敹鏂圭殑澶囨敞")
+ private String displayName;
+
+ @Schema(description = "娣诲姞鏉ユ簮", example = "1")
+ private Integer addSource; // 鍙傝 ImFriendAddSourceEnum 鏋氫妇绫�
+
+ @Schema(description = "澶勭悊缁撴灉", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer handleResult; // 鍙傝 ImFriendRequestHandleResultEnum 鏋氫妇绫�
+
+ @Schema(description = "澶勭悊鐞嗙敱", example = "鏆備笉閫氳繃")
+ private String handleContent;
+
+ @Schema(description = "澶勭悊鏃堕棿")
+ private LocalDateTime handleTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupManagerController.java
new file mode 100644
index 0000000..46fd4eb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupManagerController.java
@@ -0,0 +1,102 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerBanReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 缇よ亰绠$悊")
+@RestController
+@RequestMapping("/im/manager/group")
+@Validated
+public class ImGroupManagerController {
+
+ @Resource
+ private ImGroupService groupService;
+ @Resource
+ private ImGroupMemberService groupMemberService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱缇ゅ垎椤�")
+ @PreAuthorize("@ss.hasPermission('im:manager:group:query')")
+ public CommonResult<PageResult<ImGroupManagerRespVO>> getGroupPage(@Valid ImGroupManagerPageReqVO pageReqVO) {
+ // 1. 鍒嗛〉鏌ヨ缇�
+ PageResult<ImGroupDO> pageResult = groupService.getGroupPage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+ // 2.1 鎵归噺鏌ヨ鐩稿叧鏁版嵁
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ convertSet(pageResult.getList(), ImGroupDO::getOwnerUserId));
+ Map<Long, Long> memberCountMap = groupMemberService.getActiveMemberCountMap(
+ convertSet(pageResult.getList(), ImGroupDO::getId));
+ // 2.2 杞崲涓� VO锛屽~鍏呯兢涓绘樀绉般�佺兢鎴愬憳鏁伴噺
+ return success(BeanUtils.toBean(pageResult, ImGroupManagerRespVO.class, vo -> {
+ MapUtils.findAndThen(userMap, vo.getOwnerUserId(),
+ user -> vo.setOwnerNickname(user.getNickname()));
+ vo.setMemberCount(memberCountMap.getOrDefault(vo.getId(), 0L).intValue());
+ }));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱缇よ鎯�")
+ @Parameter(name = "id", description = "缇ょ紪鍙�", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:group:query')")
+ public CommonResult<ImGroupManagerRespVO> getGroup(@RequestParam("id") Long id) {
+ ImGroupDO group = groupService.getGroup(id);
+ return success(BeanUtils.toBean(group, ImGroupManagerRespVO.class));
+ }
+
+ @PutMapping("/ban")
+ @Operation(summary = "灏佺缇�")
+ @PreAuthorize("@ss.hasPermission('im:manager:group:ban')")
+ public CommonResult<Boolean> banGroup(@Valid @RequestBody ImGroupManagerBanReqVO reqVO) {
+ groupService.banGroup(getLoginUserId(), reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/unban")
+ @Operation(summary = "瑙e皝缇�")
+ @Parameter(name = "id", description = "缇ょ紪鍙�", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:group:ban')")
+ public CommonResult<Boolean> unbanGroup(@RequestParam("id") Long id) {
+ groupService.unbanGroup(getLoginUserId(), id);
+ return success(true);
+ }
+
+ @DeleteMapping("/dissolve")
+ @Operation(summary = "瑙f暎缇�")
+ @Parameter(name = "id", description = "缇ょ紪鍙�", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:group:dissolve')")
+ public CommonResult<Boolean> dissolveGroup(@RequestParam("id") Long id) {
+ groupService.dissolveGroupByManager(getLoginUserId(), id);
+ return success(true);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupMemberManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupMemberManagerController.java
new file mode 100644
index 0000000..e1fa1f3
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupMemberManagerController.java
@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.member.ImGroupMemberManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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 java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 缇ゆ垚鍛樼鐞�")
+@RestController
+@RequestMapping("/im/manager/group/member")
+@Validated
+public class ImGroupMemberManagerController {
+
+ @Resource
+ private ImGroupMemberService groupMemberService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/list")
+ @Operation(summary = "鑾峰緱缇ゆ垚鍛樺垪琛紙鍚凡閫�缇ゆ垚鍛橈紝鐢卞墠绔寜闇�杩囨护锛�")
+ @Parameter(name = "groupId", description = "缇ょ紪鍙�", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:group:query')")
+ public CommonResult<List<ImGroupMemberManagerRespVO>> getGroupMemberList(@RequestParam("groupId") Long groupId) {
+ // 1. 鏌ヨ缇ゅ叏閮ㄦ垚鍛橈紙鍚凡閫�缇わ級
+ List<ImGroupMemberDO> members = groupMemberService.getGroupMemberListByGroupId(groupId);
+ if (CollUtil.isEmpty(members)) {
+ return success(Collections.emptyList());
+ }
+ // 2.1 鎵归噺鏌ヨ鐢ㄦ埛淇℃伅
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ convertSet(members, ImGroupMemberDO::getUserId));
+ // 2.2 杞崲涓� VO锛屽~鍏呮樀绉般�佸ご鍍�
+ return success(BeanUtils.toBean(members, ImGroupMemberManagerRespVO.class, vo ->
+ MapUtils.findAndThen(userMap, vo.getUserId(), user ->
+ vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()))));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupRequestManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupRequestManagerController.java
new file mode 100644
index 0000000..8010312
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/ImGroupRequestManagerController.java
@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupRequestManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupRequestManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupRequestDO;
+import cn.iocoder.yudao.module.im.service.group.ImGroupRequestService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 鍔犵兢鐢宠绠$悊")
+@RestController
+@RequestMapping("/im/manager/group-request")
+@Validated
+public class ImGroupRequestManagerController {
+
+ @Resource
+ private ImGroupRequestService groupRequestService;
+ @Resource
+ private ImGroupService groupService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱鍔犵兢鐢宠鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:group-request:query')")
+ public CommonResult<PageResult<ImGroupRequestManagerRespVO>> getGroupRequestPage(
+ @Valid ImGroupRequestManagerPageReqVO pageReqVO) {
+ // 1. 鍒嗛〉鏌ヨ
+ PageResult<ImGroupRequestDO> pageResult = groupRequestService.getGroupRequestPage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+
+ // 2.1 鎵归噺鑱氬悎 user / inviter / handler 鐢ㄦ埛鏄电О
+ Set<Long> userIds = convertSetByFlatMap(pageResult.getList(),
+ request -> Stream.of(request.getUserId(), request.getInviterUserId(), request.getHandleUserId())
+ .filter(Objects::nonNull));
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
+ // 2.2 鎵归噺鑱氬悎缇や俊鎭紙鍙栫兢鍚嶏級
+ Set<Long> groupIds = convertSet(pageResult.getList(), ImGroupRequestDO::getGroupId);
+ Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(groupIds);
+ return success(BeanUtils.toBean(pageResult, ImGroupRequestManagerRespVO.class, vo -> {
+ MapUtils.findAndThen(userMap, vo.getUserId(), user -> vo.setUserNickname(user.getNickname()));
+ MapUtils.findAndThen(userMap, vo.getInviterUserId(), user -> vo.setInviterNickname(user.getNickname()));
+ MapUtils.findAndThen(userMap, vo.getHandleUserId(), user -> vo.setHandleNickname(user.getNickname()));
+ MapUtils.findAndThen(groupMap, vo.getGroupId(), group -> vo.setGroupName(group.getName()));
+ }));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerBanReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerBanReqVO.java
new file mode 100644
index 0000000..a4fb819
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerBanReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 缇よ亰灏佺 Request VO")
+@Data
+public class ImGroupManagerBanReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long id;
+
+ @Schema(description = "灏佺鍘熷洜", requiredMode = Schema.RequiredMode.REQUIRED, example = "杩濊鍐呭")
+ @NotBlank(message = "灏佺鍘熷洜涓嶈兘涓虹┖")
+ @Size(max = 200, message = "灏佺鍘熷洜闀垮害涓嶈兘瓒呰繃 200")
+ private String reason;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerPageReqVO.java
new file mode 100644
index 0000000..e7da76b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerPageReqVO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 缇よ亰鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImGroupManagerPageReqVO extends PageParam {
+
+ @Schema(description = "缇ゅ悕绉帮紝妯$硦鍖归厤", example = "鎶�鏈氦娴佺兢")
+ private String name;
+
+ @Schema(description = "缇や富鐢ㄦ埛缂栧彿", example = "1024")
+ private Long ownerUserId;
+
+ @Schema(description = "缇ょ姸鎬�", example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫伙紙0 姝e父 / 1 宸茶В鏁o級
+
+ @Schema(description = "鏄惁灏佺", example = "false")
+ private Boolean banned;
+
+ @Schema(description = "鍒涘缓鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerRespVO.java
new file mode 100644
index 0000000..c1de792
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupManagerRespVO.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 缇よ亰 Response VO")
+@Data
+public class ImGroupManagerRespVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "缇ゅ悕绉�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎶�鏈氦娴佺兢")
+ private String name;
+
+ @Schema(description = "缇ゅご鍍�")
+ private String avatar;
+
+ @Schema(description = "缇ゅ叕鍛�")
+ private String notice;
+
+ @Schema(description = "缇や富鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long ownerUserId;
+
+ @Schema(description = "缇や富鏄电О", example = "寮犱笁")
+ private String ownerNickname;
+
+ @Schema(description = "缇ゆ垚鍛樻暟閲�", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
+ private Integer memberCount;
+
+ @Schema(description = "缇ょ姸鎬�", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "瑙f暎鏃堕棿")
+ private LocalDateTime dissolvedTime;
+
+ @Schema(description = "鏄惁灏佺", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
+ private Boolean banned;
+
+ @Schema(description = "鏄惁鍏ㄧ兢绂佽█")
+ private Boolean mutedAll;
+
+ @Schema(description = "灏佺鍘熷洜")
+ private String bannedReason;
+
+ @Schema(description = "灏佺鏃堕棿")
+ private LocalDateTime bannedTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupRequestManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupRequestManagerPageReqVO.java
new file mode 100644
index 0000000..e51d066
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupRequestManagerPageReqVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鍔犵兢鐢宠鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImGroupRequestManagerPageReqVO extends PageParam {
+
+ @Schema(description = "缇ょ紪鍙�", example = "1024")
+ private Long groupId;
+
+ @Schema(description = "鐢宠浜� / 琚個璇蜂汉鐢ㄦ埛缂栧彿", example = "2048")
+ private Long userId;
+
+ @Schema(description = "閭�璇蜂汉鐢ㄦ埛缂栧彿", example = "31460")
+ private Long inviterUserId;
+
+ @Schema(description = "澶勭悊缁撴灉", example = "0")
+ private Integer handleResult; // 鍙傝 ImGroupRequestHandleResultEnum 鏋氫妇绫�
+
+ @Schema(description = "鍔犲叆鏉ユ簮", example = "1")
+ private Integer addSource; // 鍙傝 ImGroupAddSourceEnum 鏋氫妇绫�
+
+ @Schema(description = "鍒涘缓鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupRequestManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupRequestManagerRespVO.java
new file mode 100644
index 0000000..6f8684e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/ImGroupRequestManagerRespVO.java
@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鍔犵兢鐢宠 Response VO")
+@Data
+public class ImGroupRequestManagerRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long groupId;
+
+ @Schema(description = "缇ゅ悕绉�", example = "鑺嬮亾鎶�鏈氦娴佺兢")
+ private String groupName;
+
+ @Schema(description = "鐢宠浜� / 琚個璇蜂汉鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+ private Long userId;
+
+ @Schema(description = "鐢宠浜� / 琚個璇蜂汉鏄电О", example = "寮犱笁")
+ private String userNickname;
+
+ @Schema(description = "閭�璇蜂汉鐢ㄦ埛缂栧彿锛汵ULL 琛ㄧず鐢ㄦ埛涓诲姩鐢宠", example = "200")
+ private Long inviterUserId;
+
+ @Schema(description = "閭�璇蜂汉鏄电О", example = "鑰佸紶")
+ private String inviterNickname;
+
+ @Schema(description = "鐢宠鐞嗙敱", example = "鎴戞兂鍔犲叆杩欎釜缇�")
+ private String applyContent;
+
+ @Schema(description = "鍔犲叆鏉ユ簮", example = "1")
+ private Integer addSource; // 鍙傝 ImGroupAddSourceEnum 鏋氫妇绫�
+
+ @Schema(description = "澶勭悊缁撴灉", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer handleResult; // 鍙傝 ImGroupRequestHandleResultEnum 鏋氫妇绫�
+
+ @Schema(description = "澶勭悊浜虹敤鎴风紪鍙�", example = "31460")
+ private Long handleUserId;
+
+ @Schema(description = "澶勭悊浜烘樀绉�", example = "绠$悊鍛�")
+ private String handleNickname;
+
+ @Schema(description = "澶勭悊鐞嗙敱", example = "鏆備笉閫氳繃")
+ private String handleContent;
+
+ @Schema(description = "澶勭悊鏃堕棿")
+ private LocalDateTime handleTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/member/ImGroupMemberManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/member/ImGroupMemberManagerRespVO.java
new file mode 100644
index 0000000..b5d1346
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/group/vo/member/ImGroupMemberManagerRespVO.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.member;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 缇ゆ垚鍛� Response VO")
+@Data
+public class ImGroupMemberManagerRespVO {
+
+ @Schema(description = "鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long userId;
+
+ @Schema(description = "鐢ㄦ埛鏄电О", example = "寮犱笁")
+ private String nickname;
+
+ @Schema(description = "鐢ㄦ埛澶村儚")
+ private String avatar;
+
+ @Schema(description = "缁勫唴鏄剧ず鍚�", example = "涓夊摜")
+ private String displayUserName;
+
+ @Schema(description = "缇ゅ娉�", example = "鎶�鏈氦娴佺兢")
+ private String groupRemark;
+
+ @Schema(description = "鏄惁鍏嶆墦鎵�", example = "false")
+ private Boolean silent;
+
+ @Schema(description = "鎴愬憳鐘舵��", example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鎴愬憳瑙掕壊锛�1=缇や富 2=绠$悊鍛� 3=鏅�氭垚鍛�", example = "3")
+ private Integer role; // 鍙傝 ImGroupMemberRoleEnum 鏋氫妇绫�
+
+ @Schema(description = "鍏ョ兢鏃堕棿")
+ private LocalDateTime joinTime;
+
+ @Schema(description = "閫�缇ゆ椂闂�")
+ private LocalDateTime quitTime;
+
+ @Schema(description = "绂佽█鍒版湡鏃堕棿")
+ private LocalDateTime muteEndTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImChannelMessageManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImChannelMessageManagerController.java
new file mode 100644
index 0000000..36a3b60
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImChannelMessageManagerController.java
@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessagePageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessageRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import cn.iocoder.yudao.module.im.service.channel.ImChannelMaterialService;
+import cn.iocoder.yudao.module.im.service.message.ImChannelMessageService;
+import cn.iocoder.yudao.module.im.service.channel.ImChannelService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 棰戦亾娑堟伅")
+@RestController
+@RequestMapping("/im/manager/channel-message")
+@Validated
+public class ImChannelMessageManagerController {
+
+ @Resource
+ private ImChannelMessageService channelMessageService;
+ @Resource
+ private ImChannelService channelService;
+ @Resource
+ private ImChannelMaterialService channelMaterialService;
+
+ @PostMapping("/send")
+ @Operation(summary = "绔嬪嵆鎺ㄩ�侀閬撴秷鎭�")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel-message:send')")
+ public CommonResult<Long> sendMessage(@Valid @RequestBody ImChannelMessageSendReqVO reqVO) {
+ return success(channelMessageService.sendMessage(reqVO));
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎棰戦亾娑堟伅")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel-message:delete')")
+ public CommonResult<Boolean> deleteMessage(@RequestParam("id") Long id) {
+ channelMessageService.deleteMessage(id);
+ return success(true);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱棰戦亾娑堟伅鍒嗛〉锛涘洖濉閬撳悕 / 绱犳潗鏍囬")
+ @PreAuthorize("@ss.hasPermission('im:manager:channel-message:query')")
+ public CommonResult<PageResult<ImChannelMessageRespVO>> getMessagePage(@Valid ImChannelMessagePageReqVO pageReqVO) {
+ PageResult<ImChannelMessageDO> pageResult = channelMessageService.getMessagePage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+ // 鎵归噺鏌ヨ棰戦亾鍜岀礌鏉愶紝骞跺洖濉閬撳悕 / 绱犳潗鏍囬
+ Map<Long, ImChannelDO> channelMap = channelService.getChannelMap(
+ convertSet(pageResult.getList(), ImChannelMessageDO::getChannelId));
+ Map<Long, ImChannelMaterialDO> materialMap = channelMaterialService.getMaterialMap(
+ convertSet(pageResult.getList(), ImChannelMessageDO::getMaterialId));
+ return success(BeanUtils.toBean(pageResult, ImChannelMessageRespVO.class, vo -> {
+ MapUtils.findAndThen(channelMap, vo.getChannelId(), c -> vo.setChannelName(c.getName()));
+ MapUtils.findAndThen(materialMap, vo.getMaterialId(),
+ material -> vo.setMaterialTitle(material.getTitle()).setMaterialCoverUrl(material.getCoverUrl()));
+ }));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImGroupMessageManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImGroupMessageManagerController.java
new file mode 100644
index 0000000..da49a9c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImGroupMessageManagerController.java
@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group.ImGroupMessageManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group.ImGroupMessageManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.service.group.ImGroupService;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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 java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+import static cn.iocoder.yudao.module.im.enums.ImCommonConstants.AT_USER_ID_ALL;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 缇よ亰娑堟伅")
+@RestController
+@RequestMapping("/im/manager/message/group")
+@Validated
+public class ImGroupMessageManagerController {
+
+ @Resource
+ private ImGroupMessageService groupMessageService;
+ @Resource
+ private ImGroupService groupService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱缇よ亰娑堟伅鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:message:query')")
+ public CommonResult<PageResult<ImGroupMessageManagerRespVO>> getGroupMessagePage(
+ @Valid ImGroupMessageManagerPageReqVO pageReqVO) {
+ // 1. 鍒嗛〉鏌ヨ
+ PageResult<ImGroupMessageDO> pageResult = groupMessageService.getGroupMessagePage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+ // 2.1 鎵归噺鏌ヨ缇ゅ悕绉般�佸彂閫佷汉鏄电О銆丂 鐢ㄦ埛鏄电О锛�-1 琛ㄧず @鎵�鏈変汉锛岃烦杩囨煡璇紝鐢卞墠绔垽鏂覆鏌擄級
+ Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(
+ convertSet(pageResult.getList(), ImGroupMessageDO::getGroupId));
+ Set<Long> userIds = convertSetByFlatMap(pageResult.getList(), m -> Stream.concat(
+ Stream.of(m.getSenderId()),
+ CollUtil.emptyIfNull(m.getAtUserIds()).stream()
+ .filter(id -> !Objects.equals(id, AT_USER_ID_ALL))));
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
+ // 2.2 杞崲涓� VO锛屽~鍏呯兢鍚� / 鍙戦�佷汉鏄电О / @ 鐢ㄦ埛鏄电О锛�-1 浣嶇疆鐣� null锛岀敱鍓嶇灞曠ず銆孈鎵�鏈変汉銆嶏級
+ return success(BeanUtils.toBean(pageResult, ImGroupMessageManagerRespVO.class, vo -> {
+ MapUtils.findAndThen(groupMap, vo.getGroupId(), group -> vo.setGroupName(group.getName()));
+ MapUtils.findAndThen(userMap, vo.getSenderId(), user -> vo.setSenderNickname(user.getNickname()));
+ if (CollUtil.isNotEmpty(vo.getAtUserIds())) {
+ vo.setAtUserNicknames(convertList(vo.getAtUserIds(), id -> {
+ AdminUserRespDTO user = userMap.get(id);
+ return user != null ? user.getNickname() : null;
+ }));
+ }
+ }));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱缇よ亰娑堟伅璇︽儏")
+ @Parameter(name = "id", description = "娑堟伅缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:message:query')")
+ public CommonResult<ImGroupMessageManagerRespVO> getGroupMessage(@RequestParam("id") Long id) {
+ ImGroupMessageDO message = groupMessageService.getGroupMessage(id);
+ return success(BeanUtils.toBean(message, ImGroupMessageManagerRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImPrivateMessageManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImPrivateMessageManagerController.java
new file mode 100644
index 0000000..8db5b69
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/ImPrivateMessageManagerController.java
@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates.ImPrivateMessageManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates.ImPrivateMessageManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import cn.iocoder.yudao.module.im.service.message.ImPrivateMessageService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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 java.util.Map;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 绉佽亰娑堟伅")
+@RestController
+@RequestMapping("/im/manager/message/private")
+@Validated
+public class ImPrivateMessageManagerController {
+
+ @Resource
+ private ImPrivateMessageService privateMessageService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱绉佽亰娑堟伅鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:message:query')")
+ public CommonResult<PageResult<ImPrivateMessageManagerRespVO>> getPrivateMessagePage(
+ @Valid ImPrivateMessageManagerPageReqVO pageReqVO) {
+ // 1. 鍒嗛〉鏌ヨ
+ PageResult<ImPrivateMessageDO> pageResult = privateMessageService.getPrivateMessagePage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+ // 2.1 涓�娆℃�ф壒閲忔煡璇㈠彂閫佷汉 + 鎺ユ敹浜烘樀绉�
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSetByFlatMap(pageResult.getList(),
+ m -> Stream.of(m.getSenderId(), m.getReceiverId())));
+ // 2.2 杞崲涓� VO锛屽~鍏呮樀绉�
+ return success(BeanUtils.toBean(pageResult, ImPrivateMessageManagerRespVO.class, vo -> {
+ MapUtils.findAndThen(userMap, vo.getSenderId(), user -> vo.setSenderNickname(user.getNickname()));
+ MapUtils.findAndThen(userMap, vo.getReceiverId(), user -> vo.setReceiverNickname(user.getNickname()));
+ }));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱绉佽亰娑堟伅璇︽儏")
+ @Parameter(name = "id", description = "娑堟伅缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:message:query')")
+ public CommonResult<ImPrivateMessageManagerRespVO> getPrivateMessage(@RequestParam("id") Long id) {
+ ImPrivateMessageDO message = privateMessageService.getPrivateMessage(id);
+ return success(BeanUtils.toBean(message, ImPrivateMessageManagerRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessagePageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessagePageReqVO.java
new file mode 100644
index 0000000..48e1a44
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessagePageReqVO.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾娑堟伅鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImChannelMessagePageReqVO extends PageParam {
+
+ @Schema(description = "棰戦亾缂栧彿", example = "1")
+ private Long channelId;
+
+ @Schema(description = "绱犳潗缂栧彿", example = "1024")
+ private Long materialId;
+
+ @Schema(description = "鍙戦�佹椂闂�", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] sendTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessageRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessageRespVO.java
new file mode 100644
index 0000000..cf1bd64
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessageRespVO.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾娑堟伅 Response VO")
+@Data
+public class ImChannelMessageRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "棰戦亾缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long channelId;
+
+ @Schema(description = "棰戦亾鍚嶇О锛堝叧鑱旀煡璇㈠~鍏咃級")
+ private String channelName;
+
+ @Schema(description = "绱犳潗缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long materialId;
+
+ @Schema(description = "绱犳潗鏍囬锛堝叧鑱旀煡璇㈠~鍏咃級")
+ private String materialTitle;
+
+ @Schema(description = "绱犳潗灏侀潰 URL锛堝叧鑱旀煡璇㈠~鍏咃級")
+ private String materialCoverUrl;
+
+ @Schema(description = "娑堟伅绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "125")
+ private Integer type; // 鍙傝 ImContentTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "娑堟伅鍐呭锛沺ayload JSON 蹇収")
+ private String content;
+
+ @Schema(description = "鎺ユ敹浜虹紪鍙峰垪琛紱涓虹┖琛ㄧず鍏ㄥ憳")
+ private List<Long> receiverUserIds;
+
+ @Schema(description = "鍙戦�佹椂闂�", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime sendTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessageSendReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessageSendReqVO.java
new file mode 100644
index 0000000..a69ff16
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/channel/ImChannelMessageSendReqVO.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 棰戦亾娑堟伅鎺ㄩ�� Request VO")
+@Data
+public class ImChannelMessageSendReqVO {
+
+ @Schema(description = "绱犳潗缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "绱犳潗缂栧彿涓嶈兘涓虹┖")
+ private Long materialId;
+
+ @Schema(description = "鎺ユ敹浜虹紪鍙峰垪琛紱涓虹┖琛ㄧず鍏ㄥ憳", example = "[1024, 2048]")
+ private List<Long> receiverUserIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/group/ImGroupMessageManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/group/ImGroupMessageManagerPageReqVO.java
new file mode 100644
index 0000000..121ac90
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/group/ImGroupMessageManagerPageReqVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 缇よ亰娑堟伅鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImGroupMessageManagerPageReqVO extends PageParam {
+
+ @Schema(description = "缇ょ紪鍙�", example = "1024")
+ private Long groupId;
+
+ @Schema(description = "鍙戦�佷汉缂栧彿", example = "1024")
+ private Long senderId;
+
+ @Schema(description = "娑堟伅绫诲瀷", example = "1")
+ private Integer type; // 鍙傝 ImContentTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "娑堟伅鍐呭", example = "浣犲ソ")
+ private String content;
+
+ @Schema(description = "娑堟伅鐘舵��", example = "0")
+ private Integer status; // 鍙傝 ImMessageStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戦�佹椂闂�", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] sendTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/group/ImGroupMessageManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/group/ImGroupMessageManagerRespVO.java
new file mode 100644
index 0000000..fcc964a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/group/ImGroupMessageManagerRespVO.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 缇よ亰娑堟伅 Response VO")
+@Data
+public class ImGroupMessageManagerRespVO {
+
+ @Schema(description = "娑堟伅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "瀹㈡埛绔秷鎭紪鍙�", example = "c-uuid-xxx")
+ private String clientMessageId;
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long groupId;
+
+ @Schema(description = "缇ゅ悕绉�", example = "鎶�鏈氦娴佺兢")
+ private String groupName;
+
+ @Schema(description = "鍙戦�佷汉缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long senderId;
+
+ @Schema(description = "鍙戦�佷汉鏄电О", example = "寮犱笁")
+ private String senderNickname;
+
+ @Schema(description = "娑堟伅绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer type; // 鍙傝 ImContentTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "娑堟伅鍐呭锛圝SON 鏍煎紡锛�", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String content;
+
+ @Schema(description = "娑堟伅鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status; // 鍙傝 ImMessageStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "@ 鐩爣鐢ㄦ埛缂栧彿鍒楄〃锛�-1 琛ㄧず @鎵�鏈変汉锛�")
+ private List<Long> atUserIds;
+ @Schema(description = "@ 鐩爣鐢ㄦ埛鏄电О鍒楄〃锛�-1 浣嶇疆涓� null锛屽墠绔牴鎹� atUserIds 鑷灞曠ず銆孈鎵�鏈変汉銆嶏級")
+ private List<String> atUserNicknames;
+
+ @Schema(description = "鍥炴墽鐘舵��", example = "0")
+ private Integer receiptStatus; // 鍙傝 ImMessageReceiptStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戦�佹椂闂�", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime sendTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/privates/ImPrivateMessageManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/privates/ImPrivateMessageManagerPageReqVO.java
new file mode 100644
index 0000000..6fa711b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/privates/ImPrivateMessageManagerPageReqVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 绉佽亰娑堟伅鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImPrivateMessageManagerPageReqVO extends PageParam {
+
+ @Schema(description = "鍙戦�佷汉缂栧彿", example = "1024")
+ private Long senderId;
+
+ @Schema(description = "鎺ユ敹浜虹紪鍙�", example = "2048")
+ private Long receiverId;
+
+ @Schema(description = "娑堟伅绫诲瀷", example = "1")
+ private Integer type; // 鍙傝 ImContentTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "娑堟伅鍐呭", example = "浣犲ソ")
+ private String content;
+
+ @Schema(description = "娑堟伅鐘舵��", example = "0")
+ private Integer status; // 鍙傝 ImMessageStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戦�佹椂闂�", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] sendTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/privates/ImPrivateMessageManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/privates/ImPrivateMessageManagerRespVO.java
new file mode 100644
index 0000000..941ef8c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/message/vo/privates/ImPrivateMessageManagerRespVO.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 绉佽亰娑堟伅 Response VO")
+@Data
+public class ImPrivateMessageManagerRespVO {
+
+ @Schema(description = "娑堟伅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "瀹㈡埛绔秷鎭紪鍙�", example = "c-uuid-xxx")
+ private String clientMessageId;
+
+ @Schema(description = "鍙戦�佷汉缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long senderId;
+
+ @Schema(description = "鍙戦�佷汉鏄电О", example = "寮犱笁")
+ private String senderNickname;
+
+ @Schema(description = "鎺ユ敹浜虹紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long receiverId;
+
+ @Schema(description = "鎺ユ敹浜烘樀绉�", example = "鏉庡洓")
+ private String receiverNickname;
+
+ @Schema(description = "娑堟伅绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer type; // 鍙傝 ImContentTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "娑堟伅鍐呭锛圝SON 鏍煎紡锛�", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String content;
+
+ @Schema(description = "娑堟伅鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status; // 鍙傝 ImMessageStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍥炴墽鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer receiptStatus; // 鍙傝 ImMessageReceiptStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戦�佹椂闂�", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime sendTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/ImRtcCallManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/ImRtcCallManagerController.java
new file mode 100644
index 0000000..417e58f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/ImRtcCallManagerController.java
@@ -0,0 +1,113 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.rtc;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcParticipantManagerRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcParticipantDO;
+import cn.iocoder.yudao.module.im.service.group.ImGroupService;
+import cn.iocoder.yudao.module.im.service.rtc.ImRtcCallService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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 java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 閫氳瘽璁板綍")
+@RestController
+@RequestMapping("/im/manager/rtc")
+@Validated
+public class ImRtcCallManagerController {
+
+ @Resource
+ private ImRtcCallService rtcCallService;
+ @Resource
+ private ImGroupService groupService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱閫氳瘽璁板綍鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
+ public CommonResult<PageResult<ImRtcCallManagerRespVO>> getCallPage(@Valid ImRtcCallManagerPageReqVO pageReqVO) {
+ PageResult<ImRtcCallDO> pageResult = rtcCallService.getCallPage(pageReqVO);
+ return success(buildCallRespVOPage(pageResult));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱閫氳瘽璁板綍璇︽儏")
+ @Parameter(name = "id", description = "閫氳瘽缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
+ public CommonResult<ImRtcCallManagerRespVO> getCall(@RequestParam("id") Long id) {
+ ImRtcCallDO call = rtcCallService.getCall(id);
+ if (call == null) {
+ return success(null);
+ }
+ return success(CollUtil.getFirst(buildCallRespVOList(Collections.singletonList(call))));
+ }
+
+ @GetMapping("/participant-list")
+ @Operation(summary = "鑾峰緱閫氳瘽鍙備笌鑰呭垪琛�")
+ @Parameter(name = "id", description = "閫氳瘽缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
+ public CommonResult<List<ImRtcParticipantManagerRespVO>> getCallParticipantList(@RequestParam("id") Long id) {
+ List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipantListByCallId(id);
+ if (CollUtil.isEmpty(participants)) {
+ return success(Collections.emptyList());
+ }
+ // 鏌ヨ鐢ㄦ埛淇℃伅
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ convertSet(participants, ImRtcParticipantDO::getUserId));
+ // 缁勮杩斿洖
+ return success(BeanUtils.toBean(participants, ImRtcParticipantManagerRespVO.class, vo ->
+ MapUtils.findAndThen(userMap, vo.getUserId(),
+ user -> vo.setUserNickname(user.getNickname()))));
+ }
+
+ // ========== 绉佹湁鏂规硶锛歏O 缁勮 ==========
+
+ private PageResult<ImRtcCallManagerRespVO> buildCallRespVOPage(PageResult<ImRtcCallDO> pageResult) {
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return PageResult.empty(pageResult.getTotal());
+ }
+ return new PageResult<>(buildCallRespVOList(pageResult.getList()), pageResult.getTotal());
+ }
+
+ private List<ImRtcCallManagerRespVO> buildCallRespVOList(List<ImRtcCallDO> calls) {
+ // 鏌ヨ鐢ㄦ埛淇℃伅
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ convertSet(calls, ImRtcCallDO::getInviterUserId));
+ Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(
+ convertSet(calls, ImRtcCallDO::getGroupId));
+ // 缁勮杩斿洖
+ return BeanUtils.toBean(calls, ImRtcCallManagerRespVO.class, vo -> {
+ MapUtils.findAndThen(userMap, vo.getInviterUserId(),
+ user -> vo.setInviterNickname(user.getNickname()));
+ MapUtils.findAndThen(groupMap, vo.getGroupId(),
+ group -> vo.setGroupName(group.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerPageReqVO.java
new file mode 100644
index 0000000..f7878fa
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerPageReqVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 閫氳瘽璁板綍鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImRtcCallManagerPageReqVO extends PageParam {
+
+ @Schema(description = "鍙戣捣浜虹敤鎴风紪鍙�", example = "1024")
+ private Long inviterUserId;
+
+ @Schema(description = "浼氳瘽绫诲瀷", example = "1")
+ private Integer conversationType; // 鍙傝 ImConversationTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "濯掍綋绫诲瀷", example = "1")
+ private Integer mediaType; // 鍙傝 ImRtcCallMediaTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "閫氳瘽鐘舵��", example = "10")
+ private Integer status; // 鍙傝 ImRtcCallStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "缁撴潫鍘熷洜", example = "1")
+ private Integer endReason; // 鍙傝 ImRtcCallEndReasonEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戣捣鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] startTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerRespVO.java
new file mode 100644
index 0000000..0151581
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerRespVO.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 閫氳瘽璁板綍 Response VO")
+@Data
+public class ImRtcCallManagerRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "涓氬姟閫氳瘽缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "uuid-xxx")
+ private String room;
+
+ @Schema(description = "浼氳瘽绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer conversationType; // 鍙傝 ImConversationTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "濯掍綋绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer mediaType; // 鍙傝 ImRtcCallMediaTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戣捣浜虹敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long inviterUserId;
+
+ @Schema(description = "鍙戣捣浜烘樀绉�", example = "寮犱笁")
+ private String inviterNickname;
+
+ @Schema(description = "缇ょ紪鍙凤紱绉佽亰涓虹┖", example = "999")
+ private Long groupId;
+
+ @Schema(description = "缇ゅ悕绉帮紱绉佽亰涓虹┖", example = "娴嬭瘯缇�")
+ private String groupName;
+
+ @Schema(description = "閫氳瘽鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ private Integer status; // 鍙傝 ImRtcCallStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "缁撴潫鍘熷洜", example = "1")
+ private Integer endReason; // 鍙傝 ImRtcCallEndReasonEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戣捣鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime startTime;
+
+ @Schema(description = "鎺ラ�氭椂闂达紱鏈帴閫氫负绌�")
+ private LocalDateTime acceptTime;
+
+ @Schema(description = "缁撴潫鏃堕棿锛涙湭缁撴潫涓虹┖")
+ private LocalDateTime endTime;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcParticipantManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcParticipantManagerRespVO.java
new file mode 100644
index 0000000..a990577
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcParticipantManagerRespVO.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 閫氳瘽鍙備笌鑰� Response VO")
+@Data
+public class ImRtcParticipantManagerRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "閫氳瘽缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long callId;
+
+ @Schema(description = "鍙備笌鑰呯敤鎴风紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long userId;
+
+ @Schema(description = "鍙備笌鑰呮樀绉�", example = "寮犱笁")
+ private String userNickname;
+
+ @Schema(description = "鍙備笌瑙掕壊", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer role; // 鍙傝 ImRtcParticipantRoleEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙備笌鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ private Integer status; // 鍙傝 ImRtcParticipantStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "琚個璇锋椂闂�", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime inviteTime;
+
+ @Schema(description = "鎺ュ惉鏃堕棿锛涙湭鎺ュ惉涓虹┖")
+ private LocalDateTime acceptTime;
+
+ @Schema(description = "绂诲紑鏃堕棿锛涙湭鍔犲叆涓虹┖")
+ private LocalDateTime leaveTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/ImSensitiveWordManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/ImSensitiveWordManagerController.java
new file mode 100644
index 0000000..d69248d
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/ImSensitiveWordManagerController.java
@@ -0,0 +1,106 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.sensitiveword.ImSensitiveWordDO;
+import cn.iocoder.yudao.module.im.service.sensitiveword.ImSensitiveWordService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Size;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 鏁忔劅璇�")
+@RestController
+@RequestMapping("/im/manager/sensitive-word")
+@Validated
+public class ImSensitiveWordManagerController {
+
+ @Resource
+ private ImSensitiveWordService sensitiveWordService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "鏂板鏁忔劅璇�")
+ @PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:create')")
+ public CommonResult<Long> createSensitiveWord(@Valid @RequestBody ImSensitiveWordSaveReqVO reqVO) {
+ return success(sensitiveWordService.createSensitiveWord(reqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "淇敼鏁忔劅璇�")
+ @PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:update')")
+ public CommonResult<Boolean> updateSensitiveWord(@Valid @RequestBody ImSensitiveWordSaveReqVO reqVO) {
+ sensitiveWordService.updateSensitiveWord(reqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎鏁忔劅璇�")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:delete')")
+ public CommonResult<Boolean> deleteSensitiveWord(@RequestParam("id") Long id) {
+ sensitiveWordService.deleteSensitiveWord(id);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete-list")
+ @Operation(summary = "鎵归噺鍒犻櫎鏁忔劅璇�")
+ @Parameter(name = "ids", description = "缂栧彿鍒楄〃", required = true)
+ @PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:delete')")
+ public CommonResult<Boolean> deleteSensitiveWordList(
+ @RequestParam("ids")
+ @Size(max = 100, message = "鎵归噺鍒犻櫎鏈�澶� 100 鏉�") List<Long> ids) {
+ sensitiveWordService.deleteSensitiveWordList(ids);
+ return success(true);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱鏁忔劅璇嶅垎椤�")
+ @PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:query')")
+ public CommonResult<PageResult<ImSensitiveWordRespVO>> getSensitiveWordPage(
+ @Valid ImSensitiveWordPageReqVO pageReqVO) {
+ // 1. 鍒嗛〉鏌ヨ
+ PageResult<ImSensitiveWordDO> pageResult = sensitiveWordService.getSensitiveWordPage(pageReqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty(pageResult.getTotal()));
+ }
+ // 2.1 鎵归噺鏌ヨ鍒涘缓浜烘樀绉�
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(pageResult.getList(),
+ word -> NumberUtils.parseLong(word.getCreator())));
+ // 2.2 杞崲涓� VO锛屽~鍏呭垱寤轰汉鏄电О
+ return success(BeanUtils.toBean(pageResult, ImSensitiveWordRespVO.class, vo ->
+ MapUtils.findAndThen(userMap, NumberUtils.parseLong(vo.getCreator()),
+ user -> vo.setCreatorName(user.getNickname()))));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱鏁忔劅璇嶈鎯�")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('im:manager:sensitive-word:query')")
+ public CommonResult<ImSensitiveWordRespVO> getSensitiveWord(@RequestParam("id") Long id) {
+ ImSensitiveWordDO word = sensitiveWordService.getSensitiveWord(id);
+ return success(BeanUtils.toBean(word, ImSensitiveWordRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordPageReqVO.java
new file mode 100644
index 0000000..4fc21f2
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordPageReqVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鏁忔劅璇嶅垎椤� Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ImSensitiveWordPageReqVO extends PageParam {
+
+ @Schema(description = "鏁忔劅璇嶏紝妯$硦鍖归厤", example = "鏁忔劅")
+ private String word;
+
+ @Schema(description = "鐘舵��", example = "0")
+ @InEnum(value = CommonStatusEnum.class, message = "鐘舵�佸繀椤绘槸 {value}")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫伙紙0 鍚敤 / 1 绂佺敤锛�
+
+ @Schema(description = "鍒涘缓鏃堕棿", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordRespVO.java
new file mode 100644
index 0000000..578703f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordRespVO.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鏁忔劅璇� Response VO")
+@Data
+public class ImSensitiveWordRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鏁忔劅璇�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鏁忔劅璇嶅唴瀹�")
+ private String word;
+
+ @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍒涘缓浜�")
+ private String creator;
+ @Schema(description = "鍒涘缓浜烘樀绉�", example = "寮犱笁")
+ private String creatorName;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordSaveReqVO.java
new file mode 100644
index 0000000..5d42140
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/sensitiveword/vo/ImSensitiveWordSaveReqVO.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鏁忔劅璇嶆柊澧� / 淇敼 Request VO")
+@Data
+public class ImSensitiveWordSaveReqVO {
+
+ @Schema(description = "缂栧彿锛堜慨鏀规椂蹇呭~锛�", example = "1024")
+ private Long id;
+
+ @Schema(description = "鏁忔劅璇�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鏁忔劅璇嶅唴瀹�")
+ @NotBlank(message = "鏁忔劅璇嶄笉鑳戒负绌�")
+ @Size(max = 64, message = "鏁忔劅璇嶉暱搴︿笉鑳借秴杩� 64")
+ private String word;
+
+ @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "鐘舵�佷笉鑳戒负绌�")
+ @InEnum(value = CommonStatusEnum.class, message = "鐘舵�佸繀椤绘槸 {value}")
+ private Integer status; // 鍙傝 CommonStatusEnum 鏋氫妇绫伙紙0 鍚敤 / 1 绂佺敤锛�
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/ImStatisticsManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/ImStatisticsManagerController.java
new file mode 100644
index 0000000..0a5f1d5
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/ImStatisticsManagerController.java
@@ -0,0 +1,160 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.statistics;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.statistics.vo.*;
+import cn.iocoder.yudao.module.im.service.statistics.ImStatisticsManagerService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+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 java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 鏁版嵁鐪嬫澘")
+@RestController
+@RequestMapping("/im/manager/statistics")
+@Validated
+public class ImStatisticsManagerController {
+
+ /**
+ * 缇よ妯″垎妗跺悕绉扮殑灞曠ず椤哄簭
+ */
+ private static final List<String> GROUP_SIZE_BUCKETS = Arrays.asList("1-9 浜�", "10-49 浜�", "50-199 浜�", "200+ 浜�");
+ /**
+ * 鐪嬫澘鍒嗗竷榛樿鏃堕棿绐楀彛锛堝ぉ锛�
+ */
+ private static final int DISTRIBUTION_WINDOW_DAYS = 30;
+ /**
+ * TOP 鍙戦�佽�呮暟閲�
+ */
+ private static final int TOP_SENDER_LIMIT = 10;
+
+ @Resource
+ private ImStatisticsManagerService statisticsService;
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @GetMapping("/overview")
+ @Operation(summary = "鑾峰緱鏁版嵁姒傝")
+ @PreAuthorize("@ss.hasPermission('im:manager:statistics:query')")
+ public CommonResult<ImStatisticsManagerOverviewRespVO> getOverview() {
+ LocalDateTime todayBegin = LocalDate.now().atStartOfDay();
+ LocalDateTime tomorrowBegin = todayBegin.plusDays(1);
+ LocalDateTime yesterdayBegin = todayBegin.minusDays(1);
+ // 鍛ㄦ椿/鏈堟椿瀹氫箟涓� N 澶╂粴鍔ㄧ獥鍙o紙鍚粖澶╋級
+ LocalDateTime weekBegin = todayBegin.minusDays(6);
+ LocalDateTime monthBegin = todayBegin.minusDays(29);
+ return success(new ImStatisticsManagerOverviewRespVO()
+ .setTotalUser(statisticsService.getTotalUserCount())
+ .setNewUserToday(statisticsService.getNewUserCount(todayBegin, tomorrowBegin))
+ .setTotalGroup(statisticsService.getTotalGroupCount())
+ .setNewGroupToday(statisticsService.getNewGroupCount(todayBegin, tomorrowBegin))
+ .setActiveUserDaily(statisticsService.getActiveUserCount(todayBegin, tomorrowBegin))
+ .setActiveUserWeekly(statisticsService.getActiveUserCount(weekBegin, tomorrowBegin))
+ .setActiveUserMonthly(statisticsService.getActiveUserCount(monthBegin, tomorrowBegin))
+ .setPrivateMessageToday(statisticsService.getPrivateMessageCount(todayBegin, tomorrowBegin))
+ .setGroupMessageToday(statisticsService.getGroupMessageCount(todayBegin, tomorrowBegin))
+ .setPrivateMessageYesterday(statisticsService.getPrivateMessageCount(yesterdayBegin, todayBegin))
+ .setGroupMessageYesterday(statisticsService.getGroupMessageCount(yesterdayBegin, todayBegin)));
+ }
+
+ @GetMapping("/message-trend")
+ @Operation(summary = "鑾峰緱娑堟伅瓒嬪娍锛堢鑱� / 缇よ亰鍙岀嚎锛�")
+ @Parameter(name = "days", description = "鍥炵湅澶╂暟锛堝惈浠婃棩锛�", example = "7")
+ @PreAuthorize("@ss.hasPermission('im:manager:statistics:query')")
+ public CommonResult<ImStatisticsManagerTrendRespVO> getMessageTrend(
+ @RequestParam(value = "days", defaultValue = "7") @Min(1) @Max(90) int days) {
+ List<LocalDateTime> dates = LocalDateTimeUtils.getLatestDays(days);
+ LocalDateTime beginTime = dates.get(0);
+ LocalDateTime endTime = dates.get(days - 1).plusDays(1);
+ Map<LocalDateTime, Long> privateMap = statisticsService.getPrivateMessageDailyCountMap(beginTime, endTime);
+ Map<LocalDateTime, Long> groupMap = statisticsService.getGroupMessageDailyCountMap(beginTime, endTime);
+ // 杞崲鏍煎紡
+ Map<String, List<Long>> series = new LinkedHashMap<>();
+ series.put("private", alignSeries(dates, privateMap));
+ series.put("group", alignSeries(dates, groupMap));
+ return success(new ImStatisticsManagerTrendRespVO().setDates(dates).setSeries(series));
+ }
+
+ @GetMapping("/user-trend")
+ @Operation(summary = "鑾峰緱鐢ㄦ埛瓒嬪娍锛堟柊澧炴敞鍐� / 鏃ユ椿鍙岀嚎锛�")
+ @Parameter(name = "days", description = "鍥炵湅澶╂暟锛堝惈浠婃棩锛�", example = "7")
+ @PreAuthorize("@ss.hasPermission('im:manager:statistics:query')")
+ public CommonResult<ImStatisticsManagerTrendRespVO> getUserTrend(
+ @RequestParam(value = "days", defaultValue = "7") @Min(1) @Max(90) int days) {
+ List<LocalDateTime> dates = LocalDateTimeUtils.getLatestDays(days);
+ LocalDateTime beginTime = dates.get(0);
+ LocalDateTime endTime = dates.get(days - 1).plusDays(1);
+ Map<LocalDateTime, Long> registerMap = statisticsService.getNewUserDailyCountMap(beginTime, endTime);
+ Map<LocalDateTime, Long> activeMap = statisticsService.getActiveUserDailyCountMap(beginTime, endTime);
+ // 杞崲鏍煎紡
+ Map<String, List<Long>> series = new LinkedHashMap<>();
+ series.put("register", alignSeries(dates, registerMap));
+ series.put("active", alignSeries(dates, activeMap));
+ return success(new ImStatisticsManagerTrendRespVO().setDates(dates).setSeries(series));
+ }
+
+ @GetMapping("/message-type-distribution")
+ @Operation(summary = "鑾峰緱鍐呭绫诲瀷鍒嗗竷锛堟渶杩� 30 澶╋級")
+ @PreAuthorize("@ss.hasPermission('im:manager:statistics:query')")
+ public CommonResult<List<ImStatisticsManagerMessageTypeRespVO>> getMessageTypeDistribution() {
+ LocalDateTime endTime = LocalDate.now().plusDays(1).atStartOfDay();
+ LocalDateTime beginTime = endTime.minusDays(DISTRIBUTION_WINDOW_DAYS);
+ Map<Integer, Long> typeCountMap = statisticsService.getMessageTypeCountMap(beginTime, endTime);
+ // 杞崲鏍煎紡
+ return success(convertList(typeCountMap.entrySet(), entry -> new ImStatisticsManagerMessageTypeRespVO()
+ .setType(entry.getKey()).setValue(entry.getValue())));
+ }
+
+ @GetMapping("/group-size-distribution")
+ @Operation(summary = "鑾峰緱缇よ妯″垎甯�")
+ @PreAuthorize("@ss.hasPermission('im:manager:statistics:query')")
+ public CommonResult<List<ImStatisticsManagerGroupSizeRespVO>> getGroupSizeDistribution() {
+ Map<String, Long> groupSizeMap = statisticsService.getGroupSizeCountMap();
+ // 杞崲鏍煎紡
+ return success(convertList(GROUP_SIZE_BUCKETS, bucket -> new ImStatisticsManagerGroupSizeRespVO()
+ .setRange(bucket).setCount(groupSizeMap.getOrDefault(bucket, 0L))));
+ }
+
+ @GetMapping("/top-senders")
+ @Operation(summary = "鑾峰緱娑堟伅 TOP 鍙戦�佽�咃紙鏈�杩� 30 澶╋級")
+ @PreAuthorize("@ss.hasPermission('im:manager:statistics:query')")
+ public CommonResult<List<ImStatisticsManagerTopSenderRespVO>> getTopSenders() {
+ LocalDateTime endTime = LocalDate.now().plusDays(1).atStartOfDay();
+ LocalDateTime beginTime = endTime.minusDays(DISTRIBUTION_WINDOW_DAYS);
+ Map<Long, Long> topSenderMap = statisticsService.getTopSenderCountMap(beginTime, endTime, TOP_SENDER_LIMIT);
+ // TOP 鍙戦�佽�咃細鎵归噺鍥炲~鏄电О
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(topSenderMap.keySet());
+ return success(convertList(topSenderMap.entrySet(), entry -> {
+ ImStatisticsManagerTopSenderRespVO item = new ImStatisticsManagerTopSenderRespVO()
+ .setUserId(entry.getKey()).setMessageCount(entry.getValue());
+ MapUtils.findAndThen(userMap, entry.getKey(), user -> item.setNickname(user.getNickname()));
+ return item;
+ }));
+ }
+
+ /**
+ * 鎶婃瘡鏃ヨ仛鍚� Map 瀵归綈鍒� dates 搴忓垪锛涚己澶卞ぉ琛� 0
+ */
+ private static List<Long> alignSeries(List<LocalDateTime> dates, Map<LocalDateTime, Long> dailyMap) {
+ return convertList(dates, date -> dailyMap.getOrDefault(date, 0L));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerGroupSizeRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerGroupSizeRespVO.java
new file mode 100644
index 0000000..064f0de
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerGroupSizeRespVO.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鏁版嵁鐪嬫澘缇よ妯″垎甯冮」 Response VO")
+@Data
+public class ImStatisticsManagerGroupSizeRespVO {
+
+ @Schema(description = "鍖洪棿鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "1-9 浜�")
+ private String range;
+
+ @Schema(description = "缇ゆ暟閲�", requiredMode = Schema.RequiredMode.REQUIRED, example = "320")
+ private Long count;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerMessageTypeRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerMessageTypeRespVO.java
new file mode 100644
index 0000000..fce2275
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerMessageTypeRespVO.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鏁版嵁鐪嬫澘鍐呭绫诲瀷鍒嗗竷椤� Response VO")
+@Data
+public class ImStatisticsManagerMessageTypeRespVO {
+
+ @Schema(description = "娑堟伅绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer type; // 鍙傝 ImContentTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "娑堟伅鏁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "8000")
+ private Long value;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerOverviewRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerOverviewRespVO.java
new file mode 100644
index 0000000..dc9e713
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerOverviewRespVO.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鏁版嵁鐪嬫澘姒傝 Response VO")
+@Data
+public class ImStatisticsManagerOverviewRespVO {
+
+ @Schema(description = "鐢ㄦ埛鎬绘暟", requiredMode = Schema.RequiredMode.REQUIRED, example = "12345")
+ private Long totalUser;
+
+ @Schema(description = "浠婃棩鏂板鐢ㄦ埛鏁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
+ private Long newUserToday;
+
+ @Schema(description = "缇ゆ�绘暟", requiredMode = Schema.RequiredMode.REQUIRED, example = "678")
+ private Long totalGroup;
+
+ @Schema(description = "浠婃棩鏂板缓缇ゆ暟", requiredMode = Schema.RequiredMode.REQUIRED, example = "4")
+ private Long newGroupToday;
+
+ @Schema(description = "鏃ユ椿鐢ㄦ埛锛堜粖鏃ュ彂杩囨秷鎭殑鍘婚噸鐢ㄦ埛鏁帮級", requiredMode = Schema.RequiredMode.REQUIRED, example = "1023")
+ private Long activeUserDaily;
+
+ @Schema(description = "鍛ㄦ椿鐢ㄦ埛锛堟渶杩� 7 澶╁彂杩囨秷鎭殑鍘婚噸鐢ㄦ埛鏁帮級", requiredMode = Schema.RequiredMode.REQUIRED, example = "4567")
+ private Long activeUserWeekly;
+
+ @Schema(description = "鏈堟椿鐢ㄦ埛锛堟渶杩� 30 澶╁彂杩囨秷鎭殑鍘婚噸鐢ㄦ埛鏁帮級", requiredMode = Schema.RequiredMode.REQUIRED, example = "8901")
+ private Long activeUserMonthly;
+
+ @Schema(description = "浠婃棩绉佽亰娑堟伅鏁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "8765")
+ private Long privateMessageToday;
+
+ @Schema(description = "浠婃棩缇よ亰娑堟伅鏁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "3210")
+ private Long groupMessageToday;
+
+ @Schema(description = "鏄ㄦ棩绉佽亰娑堟伅鏁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "7890")
+ private Long privateMessageYesterday;
+
+ @Schema(description = "鏄ㄦ棩缇よ亰娑堟伅鏁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "3000")
+ private Long groupMessageYesterday;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerTopSenderRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerTopSenderRespVO.java
new file mode 100644
index 0000000..2f06158
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerTopSenderRespVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鏁版嵁鐪嬫澘 TOP 鍙戦�佽�呴」 Response VO")
+@Data
+public class ImStatisticsManagerTopSenderRespVO {
+
+ @Schema(description = "鐢ㄦ埛缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long userId;
+
+ @Schema(description = "鐢ㄦ埛鏄电О", example = "寮犱笁")
+ private String nickname;
+
+ @Schema(description = "娑堟伅鏁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1500")
+ private Long messageCount;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerTrendRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerTrendRespVO.java
new file mode 100644
index 0000000..e08d980
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/statistics/vo/ImStatisticsManagerTrendRespVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.im.controller.admin.manager.statistics.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+@Schema(description = "绠$悊鍚庡彴 - IM 鏁版嵁鐪嬫澘瓒嬪娍 Response VO")
+@Data
+public class ImStatisticsManagerTrendRespVO {
+
+ @Schema(description = "妯酱鏃ユ湡搴忓垪锛堟瘡澶� 00:00:00锛岀敱鍓嶇鎸夐渶鍙栨棩鏈熼儴鍒嗭級", requiredMode = Schema.RequiredMode.REQUIRED)
+ private List<LocalDateTime> dates;
+
+ @Schema(description = "鏁版嵁绯诲垪锛歬ey 涓虹郴鍒楀悕锛堝 private/group 鎴� register/active锛夛紝value 涓轰笌 dates 绛夐暱鐨勮鏁版暟缁�",
+ requiredMode = Schema.RequiredMode.REQUIRED)
+ private Map<String, List<Long>> series;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImChannelMessageController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImChannelMessageController.java
new file mode 100644
index 0000000..41a8c01
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImChannelMessageController.java
@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.im.controller.admin.message;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.channel.ImChannelMessagePullRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.service.message.ImChannelMessageService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.PositiveOrZero;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+
+@Tag(name = "鐢ㄦ埛 APP - IM 棰戦亾娑堟伅")
+@RestController
+@RequestMapping("/im/channel/message")
+@Validated
+public class ImChannelMessageController {
+
+ @Resource
+ private ImChannelMessageService channelMessageService;
+
+ @GetMapping("/pull")
+ @Operation(summary = "鎷夊彇棰戦亾娑堟伅锛堢绾垮閲忥級锛涙寜 minId 娓告爣鍒嗛〉")
+ public CommonResult<List<ImChannelMessagePullRespVO>> pullChannelMessageList(
+ @RequestParam(value = "minId", defaultValue = "0") @PositiveOrZero(message = "minId 涓嶈兘灏忎簬 0") Long minId,
+ @RequestParam(value = "size", defaultValue = "100")
+ @Min(value = 1, message = "size 蹇呴』澶т簬 0")
+ @Max(value = 200, message = "size 涓�娆℃渶澶� 200 鏉�") Integer size) {
+ // 1. 鎷夊彇娑堟伅鍒楄〃
+ Long userId = getLoginUserId();
+ List<ImChannelMessageDO> list = channelMessageService.pullChannelMessageList(userId, minId, size);
+ if (CollUtil.isEmpty(list)) {
+ return success(Collections.emptyList());
+ }
+ // 2. 鎸夊凡璇绘父鏍囪ˉ receiptStatus锛堝凡璇� DONE / 鏈 PENDING锛�
+ Map<Long, Long> readMaxByChannel = channelMessageService.getChannelReadMaxMessageIdMap(
+ userId, convertSet(list, ImChannelMessageDO::getChannelId));
+ return success(BeanUtils.toBean(list, ImChannelMessagePullRespVO.class, vo -> {
+ Long readMax = readMaxByChannel.get(vo.getChannelId());
+ vo.setReceiptStatus(readMax != null && readMax >= vo.getId()
+ ? ImMessageReceiptStatusEnum.DONE.getStatus()
+ : ImMessageReceiptStatusEnum.PENDING.getStatus());
+ }));
+ }
+
+ @PutMapping("/read")
+ @Operation(summary = "鏍囪棰戦亾娑堟伅宸茶")
+ @Parameter(name = "channelId", description = "棰戦亾缂栧彿", required = true, example = "1")
+ @Parameter(name = "messageId", description = "宸茶鍒扮殑娑堟伅缂栧彿", required = true, example = "100")
+ public CommonResult<Boolean> readChannelMessages(@RequestParam("channelId") Long channelId,
+ @RequestParam("messageId") Long messageId) {
+ channelMessageService.readChannelMessages(getLoginUserId(), channelId, messageId);
+ return success(true);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImGroupMessageController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImGroupMessageController.java
new file mode 100644
index 0000000..4bc719e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImGroupMessageController.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.im.controller.admin.message;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageListReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Min;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 缇よ亰娑堟伅")
+@RestController
+@RequestMapping("/im/message/group")
+@Validated
+public class ImGroupMessageController {
+
+ @Resource
+ private ImGroupMessageService groupMessageService;
+
+ @PostMapping("/send")
+ @Operation(summary = "鍙戦�佺兢鑱婃秷鎭�")
+ public CommonResult<ImGroupMessageRespVO> sendGroupMessage(@Valid @RequestBody ImGroupMessageSendReqVO reqVO) {
+ ImGroupMessageDO message = groupMessageService.sendGroupMessage(getLoginUserId(), reqVO);
+ return success(BeanUtils.toBean(message, ImGroupMessageRespVO.class));
+ }
+
+ @GetMapping("/pull")
+ @Operation(summary = "鎷夊彇缇よ亰娑堟伅锛堝閲忥級")
+ @Parameter(name = "minId", description = "鏈�灏忔秷鎭� id", required = true, example = "0")
+ @Parameter(name = "size", description = "鎷夊彇鏁伴噺", required = true, example = "100")
+ public CommonResult<List<ImGroupMessageRespVO>> pullGroupMessageList(
+ @RequestParam("minId") Long minId,
+ @RequestParam("size") @Min(value = 1, message = "鎷夊彇鏁伴噺鏈�灏忓�间负 1") Integer size) {
+ List<ImGroupMessageDO> messages = groupMessageService.pullGroupMessageList(getLoginUserId(), minId, size);
+ return success(BeanUtils.toBean(messages, ImGroupMessageRespVO.class));
+ }
+
+ @PutMapping("/read")
+ @Operation(summary = "鏍囪缇よ亰娑堟伅宸茶")
+ @Parameter(name = "groupId", description = "缇ょ紪鍙�", required = true, example = "1")
+ @Parameter(name = "messageId", description = "宸茶鍒扮殑娑堟伅缂栧彿", required = true, example = "100")
+ public CommonResult<Boolean> readGroupMessages(@RequestParam("groupId") Long groupId,
+ @RequestParam("messageId") Long messageId) {
+ groupMessageService.readGroupMessages(getLoginUserId(), groupId, messageId);
+ return success(true);
+ }
+
+ @DeleteMapping("/recall")
+ @Operation(summary = "鎾ゅ洖缇よ亰娑堟伅")
+ @Parameter(name = "id", description = "娑堟伅缂栧彿", required = true, example = "1")
+ public CommonResult<ImGroupMessageRespVO> recallGroupMessage(@RequestParam("id") Long id) {
+ ImGroupMessageDO message = groupMessageService.recallGroupMessage(getLoginUserId(), id);
+ return success(BeanUtils.toBean(message, ImGroupMessageRespVO.class));
+ }
+
+ @GetMapping("/get-read-user-ids")
+ @Operation(summary = "鑾峰彇缇ゆ秷鎭凡璇荤敤鎴峰垪琛�")
+ @Parameter(name = "groupId", description = "缇ょ紪鍙�", required = true, example = "1")
+ @Parameter(name = "messageId", description = "娑堟伅缂栧彿", required = true, example = "1")
+ public CommonResult<List<Long>> getGroupReadUserIds(@RequestParam("groupId") Long groupId,
+ @RequestParam("messageId") Long messageId) {
+ return success(groupMessageService.getGroupReadUserIds(getLoginUserId(), groupId, messageId));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "鏌ヨ缇よ亰鍘嗗彶娑堟伅")
+ public CommonResult<List<ImGroupMessageRespVO>> getGroupMessageList(@Valid ImGroupMessageListReqVO reqVO) {
+ List<ImGroupMessageDO> messages = groupMessageService.getGroupMessageList(getLoginUserId(), reqVO);
+ return success(BeanUtils.toBean(messages, ImGroupMessageRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImMessageController.http b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImMessageController.http
new file mode 100644
index 0000000..83d1773
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImMessageController.http
@@ -0,0 +1,18 @@
+### 璇锋眰 /send 鎺ュ彛 => 鎴愬姛
+POST {{baseUrl}}/im/message/send
+Authorization: Bearer {{token}}
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+
+{
+ "clientMessageId": "123",
+ "receiverId": 1,
+ "conversationType": 1,
+ "contentType": 101,
+ "content": "浣犲ソ1"
+}
+
+### 璇锋眰 /pull 鎺ュ彛 => 鎴愬姛
+GET {{baseUrl}}/im/message/pull?sequence=0&size=2
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
\ No newline at end of file
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImPrivateMessageController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImPrivateMessageController.java
new file mode 100644
index 0000000..277dc97
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImPrivateMessageController.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.im.controller.admin.message;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageListReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import cn.iocoder.yudao.module.im.service.message.ImPrivateMessageService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Min;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 绉佽亰娑堟伅")
+@RestController
+@RequestMapping("/im/message/private")
+@Validated
+public class ImPrivateMessageController {
+
+ @Resource
+ private ImPrivateMessageService privateMessageService;
+
+ @PostMapping("/send")
+ @Operation(summary = "鍙戦�佺鑱婃秷鎭�")
+ public CommonResult<ImPrivateMessageRespVO> sendPrivateMessage(
+ @Valid @RequestBody ImPrivateMessageSendReqVO reqVO) {
+ ImPrivateMessageDO message = privateMessageService.sendPrivateMessage(getLoginUserId(), reqVO);
+ return success(BeanUtils.toBean(message, ImPrivateMessageRespVO.class));
+ }
+
+ @GetMapping("/pull")
+ @Operation(summary = "鎷夊彇绉佽亰娑堟伅锛堝閲忥級")
+ @Parameter(name = "minId", description = "鏈�灏忔秷鎭� id", required = true, example = "0")
+ @Parameter(name = "size", description = "鎷夊彇鏁伴噺", required = true, example = "100")
+ public CommonResult<List<ImPrivateMessageRespVO>> pullPrivateMessageList(
+ @RequestParam("minId") Long minId,
+ @RequestParam("size") @Min(value = 1, message = "鎷夊彇鏁伴噺鏈�灏忓�间负 1") Integer size) {
+ List<ImPrivateMessageDO> messages = privateMessageService.pullPrivateMessageList(getLoginUserId(), minId, size);
+ return success(BeanUtils.toBean(messages, ImPrivateMessageRespVO.class));
+ }
+
+ @PutMapping("/read")
+ @Operation(summary = "鏍囪绉佽亰娑堟伅宸茶")
+ @Parameter(name = "receiverId", description = "鎺ユ敹鏂圭敤鎴风紪鍙凤紙瀵规柟锛�", required = true, example = "2")
+ @Parameter(name = "messageId", description = "宸茶浣嶇疆锛堝惈锛夛紝閫氬父鏄細璇濆唴鏈�澶ф秷鎭紪鍙�", required = true, example = "100")
+ public CommonResult<Boolean> readPrivateMessages(@RequestParam("receiverId") Long receiverId,
+ @RequestParam("messageId") Long messageId) {
+ privateMessageService.readPrivateMessages(getLoginUserId(), receiverId, messageId);
+ return success(true);
+ }
+
+ @GetMapping("/max-read-message-id")
+ @Operation(summary = "鏌ヨ瀵规柟宸茶鍒版垜鍙戠殑鏈�澶ф秷鎭� id",
+ description = "鐢ㄤ簬澶氱 / 绂荤嚎鍦烘櫙涓嬬殑宸茶浣嶇疆琛ラ綈锛氳繘鍏ヤ細璇濇垨鏂嚎閲嶈繛鍚庤皟鐢紝鎹鎶婃湰鍦拌嚜鍙戞秷鎭洿鏂颁负宸茶")
+ @Parameter(name = "peerId", description = "瀵规柟鐢ㄦ埛缂栧彿", required = true, example = "2")
+ public CommonResult<Long> getMaxReadMessageId(@RequestParam("peerId") Long peerId) {
+ return success(privateMessageService.getMaxReadMessageId(getLoginUserId(), peerId));
+ }
+
+ @DeleteMapping("/recall")
+ @Operation(summary = "鎾ゅ洖绉佽亰娑堟伅")
+ @Parameter(name = "id", description = "娑堟伅缂栧彿", required = true, example = "1")
+ public CommonResult<ImPrivateMessageRespVO> recallPrivateMessage(@RequestParam("id") Long id) {
+ ImPrivateMessageDO message = privateMessageService.recallPrivateMessage(getLoginUserId(), id);
+ return success(BeanUtils.toBean(message, ImPrivateMessageRespVO.class));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "鏌ヨ绉佽亰鍘嗗彶娑堟伅")
+ public CommonResult<List<ImPrivateMessageRespVO>> getPrivateMessageList(@Valid ImPrivateMessageListReqVO reqVO) {
+ List<ImPrivateMessageDO> messages = privateMessageService.getPrivateMessageList(getLoginUserId(), reqVO);
+ return success(BeanUtils.toBean(messages, ImPrivateMessageRespVO.class));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/channel/ImChannelMessagePullRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/channel/ImChannelMessagePullRespVO.java
new file mode 100644
index 0000000..8a30fcb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/channel/ImChannelMessagePullRespVO.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.im.controller.admin.message.vo.channel;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "鐢ㄦ埛 APP - IM 棰戦亾娑堟伅鎷夊彇 Response VO")
+@Data
+public class ImChannelMessagePullRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "9001")
+ private Long id;
+
+ @Schema(description = "棰戦亾缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long channelId;
+
+ @Schema(description = "绱犳潗缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long materialId;
+
+ @Schema(description = "娑堟伅绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "125")
+ private Integer type;
+
+ @Schema(description = "娑堟伅鍐呭锛沺ayload JSON 蹇収", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String content;
+
+ @Schema(description = "褰撳墠鐢ㄦ埛鍥炴墽 / 宸茶鎬侊紱鎸� Redis 璇讳綅缃绠楋紙宸茶 DONE锛屾湭璇� PENDING锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ private Integer receiptStatus; // 鍙傝 ImMessageReceiptStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戦�佹椂闂�", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime sendTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageListReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageListReqVO.java
new file mode 100644
index 0000000..76aa958
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageListReqVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.im.controller.admin.message.vo.group;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇よ亰鍘嗗彶娑堟伅鍒楄〃 Request VO")
+@Data
+public class ImGroupMessageListReqVO {
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long groupId;
+
+ @Schema(description = "璧峰娑堟伅缂栧彿锛屼粠璇� id 寰�鍓嶆媺鍙栵紙涓嶅惈锛夈�備负绌哄垯浠庢渶鏂版秷鎭紑濮�", example = "1024")
+ private Long maxId;
+
+ @Schema(description = "鎷夊彇鏁伴噺", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ @NotNull(message = "鎷夊彇鏁伴噺涓嶈兘涓虹┖")
+ @Min(value = 1, message = "鎷夊彇鏁伴噺鏈�灏忓�间负 1")
+ @Max(value = 200, message = "鎷夊彇鏁伴噺鏈�澶у�间负 200")
+ private Integer limit;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageRespVO.java
new file mode 100644
index 0000000..ee8a164
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageRespVO.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.im.controller.admin.message.vo.group;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 缇よ亰娑堟伅 Response VO
+ */
+@Schema(description = "绠$悊鍚庡彴 - 缇よ亰娑堟伅 Response VO")
+@Data
+public class ImGroupMessageRespVO {
+
+ @Schema(description = "娑堟伅缂栧彿", example = "1")
+ private Long id;
+
+ @Schema(description = "瀹㈡埛绔秷鎭紪鍙�", example = "uuid-xxx")
+ private String clientMessageId;
+
+ @Schema(description = "鍙戦�佷汉缂栧彿", example = "1")
+ private Long senderId;
+
+ @Schema(description = "缇ょ紪鍙�", example = "1")
+ private Long groupId;
+
+ @Schema(description = "娑堟伅绫诲瀷", example = "0")
+ private Integer type;
+
+ @Schema(description = "娑堟伅鍐呭", example = "{\"content\":\"浣犲ソ\"}")
+ private String content;
+
+ @Schema(description = "娑堟伅鐘舵��", example = "0")
+ private Integer status;
+
+ @Schema(description = "鍙戦�佹椂闂�")
+ private LocalDateTime sendTime;
+
+ @Schema(description = "@鐩爣鐢ㄦ埛缂栧彿鍒楄〃", example = "[1,2,3]")
+ private List<Long> atUserIds;
+
+ @Schema(description = "瀹氬悜鎺ユ敹鐢ㄦ埛缂栧彿鍒楄〃", example = "[1,2]")
+ private List<Long> receiverUserIds;
+
+ @Schema(description = "鍥炴墽鐘舵��", example = "0")
+ private Integer receiptStatus;
+
+ @Schema(description = "宸茶浜烘暟锛堝洖鎵ф秷鎭�佷笖鍙戦�佷汉涓哄綋鍓嶇敤鎴锋椂鏈夊�硷級", example = "3")
+ private Integer readCount;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageSendReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageSendReqVO.java
new file mode 100644
index 0000000..813e35a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/group/ImGroupMessageSendReqVO.java
@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.im.controller.admin.message.vo.group;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.AssertTrue;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 缇よ亰娑堟伅鍙戦�� Request VO
+ */
+@Schema(description = "绠$悊鍚庡彴 - 缇よ亰娑堟伅鍙戦�� Request VO")
+@Data
+public class ImGroupMessageSendReqVO {
+
+ @Schema(description = "瀹㈡埛绔秷鎭紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "uuid-xxx")
+ @NotEmpty(message = "瀹㈡埛绔秷鎭紪鍙蜂笉鑳戒负绌�")
+ private String clientMessageId;
+
+ @Schema(description = "缇ょ紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long groupId;
+
+ @Schema(description = "娑堟伅绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "娑堟伅绫诲瀷涓嶈兘涓虹┖")
+ @InEnum(ImContentTypeEnum.class)
+ private Integer type;
+
+ @Schema(description = "娑堟伅鍐呭锛孞SON 鏍煎紡", requiredMode = Schema.RequiredMode.REQUIRED, example = "{\"content\":\"浣犲ソ\"}")
+ @NotEmpty(message = "娑堟伅鍐呭涓嶈兘涓虹┖")
+ private String content;
+
+ @Schema(description = "@鐩爣鐢ㄦ埛缂栧彿鍒楄〃", example = "[1,2,3]")
+ private List<Long> atUserIds;
+
+ @Schema(description = "鏄惁闇�瑕佸洖鎵�", example = "false")
+ private Boolean receipt;
+
+ /**
+ * 浠呭厑璁哥敤鎴锋秷鎭紙normal锛夌被鍨�
+ */
+ @AssertTrue(message = "娑堟伅绫诲瀷涓嶅厑璁�")
+ @JsonIgnore
+ public boolean isTypeNormal() {
+ return type == null || ImContentTypeEnum.validate(type).isNormal();
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageListReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageListReqVO.java
new file mode 100644
index 0000000..c9259d9
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageListReqVO.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.im.controller.admin.message.vo.privates;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+
+@Schema(description = "绠$悊鍚庡彴 - 绉佽亰鍘嗗彶娑堟伅鍒楄〃 Request VO")
+@Data
+public class ImPrivateMessageListReqVO {
+
+ @Schema(description = "鎺ユ敹浜虹紪鍙凤紙瀵规柟锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @NotNull(message = "鎺ユ敹浜虹紪鍙蜂笉鑳戒负绌�")
+ private Long receiverId;
+
+ @Schema(description = "璧峰娑堟伅缂栧彿锛屼粠璇� id 寰�鍓嶆媺鍙栵紙涓嶅惈锛夈�備负绌哄垯浠庢渶鏂版秷鎭紑濮�", example = "1024")
+ private Long maxId;
+
+ @Schema(description = "鎷夊彇鏁伴噺", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ @NotNull(message = "鎷夊彇鏁伴噺涓嶈兘涓虹┖")
+ @Min(value = 1, message = "鎷夊彇鏁伴噺鏈�灏忓�间负 1")
+ @Max(value = 200, message = "鎷夊彇鏁伴噺鏈�澶у�间负 200")
+ private Integer limit;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessagePageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessagePageReqVO.java
new file mode 100644
index 0000000..b353e77
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessagePageReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.im.controller.admin.message.vo.privates;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import jakarta.validation.constraints.NotNull;
+
+@Schema(description = "绠$悊鍚庡彴 - 绉佽亰娑堟伅鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ImPrivateMessagePageReqVO extends PageParam {
+
+ @Schema(description = "鎺ユ敹浜虹紪鍙凤紙瀵规柟锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @NotNull(message = "鎺ユ敹浜虹紪鍙蜂笉鑳戒负绌�")
+ private Long receiverId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageRespVO.java
new file mode 100644
index 0000000..9b62689
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageRespVO.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.im.controller.admin.message.vo.privates;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 绉佽亰娑堟伅 Response VO
+ */
+@Schema(description = "绠$悊鍚庡彴 - 绉佽亰娑堟伅 Response VO")
+@Data
+public class ImPrivateMessageRespVO {
+
+ @Schema(description = "娑堟伅缂栧彿", example = "1")
+ private Long id;
+
+ @Schema(description = "瀹㈡埛绔秷鎭紪鍙�", example = "uuid-xxx")
+ private String clientMessageId;
+
+ @Schema(description = "鍙戦�佷汉缂栧彿", example = "1")
+ private Long senderId;
+
+ @Schema(description = "鎺ユ敹浜虹紪鍙�", example = "2")
+ private Long receiverId;
+
+ @Schema(description = "娑堟伅绫诲瀷", example = "0")
+ private Integer type;
+
+ @Schema(description = "娑堟伅鍐呭", example = "{\"content\":\"浣犲ソ\"}")
+ private String content;
+
+ @Schema(description = "娑堟伅鐘舵��", example = "0")
+ private Integer status; // 鍙傝 ImMessageStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍥炴墽鐘舵��", example = "0")
+ private Integer receiptStatus; // 鍙傝 ImMessageReceiptStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戦�佹椂闂�")
+ private LocalDateTime sendTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageSendReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageSendReqVO.java
new file mode 100644
index 0000000..6552234
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/privates/ImPrivateMessageSendReqVO.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.im.controller.admin.message.vo.privates;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.AssertTrue;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * 绉佽亰娑堟伅鍙戦�� Request VO
+ */
+@Schema(description = "绠$悊鍚庡彴 - 绉佽亰娑堟伅鍙戦�� Request VO")
+@Data
+public class ImPrivateMessageSendReqVO {
+
+ @Schema(description = "瀹㈡埛绔秷鎭紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "uuid-xxx")
+ @NotEmpty(message = "瀹㈡埛绔秷鎭紪鍙蜂笉鑳戒负绌�")
+ private String clientMessageId;
+
+ @Schema(description = "鎺ユ敹浜虹紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @NotNull(message = "鎺ユ敹浜虹紪鍙蜂笉鑳戒负绌�")
+ private Long receiverId;
+
+ @Schema(description = "娑堟伅绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "娑堟伅绫诲瀷涓嶈兘涓虹┖")
+ @InEnum(ImContentTypeEnum.class)
+ private Integer type;
+
+ @Schema(description = "娑堟伅鍐呭锛孞SON 鏍煎紡", requiredMode = Schema.RequiredMode.REQUIRED, example = "{\"content\":\"浣犲ソ\"}")
+ @NotEmpty(message = "娑堟伅鍐呭涓嶈兘涓虹┖")
+ private String content;
+
+ @Schema(description = "鏄惁闇�瑕佸洖鎵�", example = "false")
+ private Boolean receipt;
+
+ /**
+ * 浠呭厑璁哥敤鎴锋秷鎭紙normal锛夌被鍨�
+ */
+ @AssertTrue(message = "娑堟伅绫诲瀷涓嶅厑璁�")
+ @JsonIgnore
+ public boolean isTypeNormal() {
+ return type == null || ImContentTypeEnum.validate(type).isNormal();
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcCallController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcCallController.java
new file mode 100644
index 0000000..bebabf6
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcCallController.java
@@ -0,0 +1,169 @@
+package cn.iocoder.yudao.module.im.controller.admin.rtc;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallCreateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallInviteReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallRespVO;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcGroupCallRespVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcParticipantDO;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallStatusEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantStatusEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.rtc.ImRtcCallService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "绠$悊鍚庡彴 - IM 瀹炴椂閫氳瘽")
+@RestController
+@RequestMapping("/im/rtc")
+@Validated
+public class ImRtcCallController {
+
+ @Resource
+ private ImRtcCallService rtcCallService;
+ @Resource
+ private ImProperties imProperties;
+
+ @PostMapping("/create")
+ @Operation(summary = "鍒涘缓鏂伴�氳瘽锛涙寜 conversationType 鍖哄垎绉佽亰 / 缇よ亰")
+ public CommonResult<ImRtcCallRespVO> createCall(@Valid @RequestBody ImRtcCallCreateReqVO reqVO) {
+ Long userId = getLoginUserId();
+ ImRtcCallDO call = rtcCallService.createCall(userId, reqVO);
+ return success(buildCallRespVO(call, userId));
+ }
+
+ @PostMapping("/invite")
+ @Operation(summary = "閫氳瘽涓拷鍔犻個璇凤紱浠呯兢閫氳瘽鍙敤")
+ public CommonResult<Boolean> inviteCall(@Valid @RequestBody ImRtcCallInviteReqVO reqVO) {
+ rtcCallService.inviteCall(getLoginUserId(), reqVO);
+ return success(true);
+ }
+
+ @PostMapping("/join")
+ @Operation(summary = "鍔犲叆宸叉湁缇ら�氳瘽锛涚敤浜庤兌鍥婃潯銆屽姞鍏ャ�嶆寜閽�")
+ @Parameter(name = "room", description = "涓氬姟閫氳瘽缂栧彿", required = true, example = "f47ac10b58cc4372a567")
+ public CommonResult<ImRtcCallRespVO> joinCall(@RequestParam("room") String room) {
+ Long userId = getLoginUserId();
+ return success(buildCallRespVO(rtcCallService.joinCall(userId, room), userId));
+ }
+
+ @PostMapping("/accept")
+ @Operation(summary = "鎺ュ惉閫氳瘽")
+ @Parameter(name = "room", description = "涓氬姟閫氳瘽缂栧彿", required = true, example = "f47ac10b58cc4372a567")
+ public CommonResult<ImRtcCallRespVO> accept(@RequestParam("room") String room) {
+ Long userId = getLoginUserId();
+ return success(buildCallRespVO(rtcCallService.acceptCall(userId, room), userId));
+ }
+
+ @PostMapping("/reject")
+ @Operation(summary = "鎷掔粷閫氳瘽")
+ @Parameter(name = "room", description = "涓氬姟閫氳瘽缂栧彿", required = true, example = "f47ac10b58cc4372a567")
+ public CommonResult<Boolean> reject(@RequestParam("room") String room) {
+ rtcCallService.rejectCall(getLoginUserId(), room);
+ return success(true);
+ }
+
+ @PostMapping("/cancel")
+ @Operation(summary = "鍙栨秷閭�璇凤紱涓诲彨鎺ラ�氬墠璋冪敤")
+ @Parameter(name = "room", description = "涓氬姟閫氳瘽缂栧彿", required = true, example = "f47ac10b58cc4372a567")
+ public CommonResult<Boolean> cancel(@RequestParam("room") String room) {
+ rtcCallService.cancelCall(getLoginUserId(), room);
+ return success(true);
+ }
+
+ @PostMapping("/leave")
+ @Operation(summary = "绂诲紑閫氳瘽锛涙帴閫氬悗璋冪敤")
+ @Parameter(name = "room", description = "涓氬姟閫氳瘽缂栧彿", required = true, example = "f47ac10b58cc4372a567")
+ public CommonResult<Boolean> leave(@RequestParam("room") String room) {
+ rtcCallService.leaveCall(getLoginUserId(), room);
+ return success(true);
+ }
+
+ @PostMapping("/no-answer-call-check")
+ @Operation(summary = "鍓嶇 RUNNING 绔� timer 鍏滃簳锛涜Е鍙戝悗绔珛鍗虫壂鎻忚 room 鐨勬尟閾冭秴鏃讹紙鎺ュ彛闈欓粯锛�")
+ @Parameter(name = "room", description = "涓氬姟閫氳瘽缂栧彿", required = true, example = "f47ac10b58cc4372a567")
+ public CommonResult<Boolean> noAnswerCallCheck(@RequestParam("room") String room) {
+ rtcCallService.noAnswerCallCheck(getLoginUserId(), room);
+ return success(true);
+ }
+
+ @GetMapping("/get-active-call")
+ @Operation(summary = "鏌ヨ褰撳墠杩涜涓殑閫氳瘽锛涚敤浜庣兢鑱婇《閮ㄣ�孨 浜烘鍦ㄩ�氳瘽銆嶈兌鍥婃潯")
+ @Parameter(name = "groupId", description = "缇ょ紪鍙�", required = true, example = "2048")
+ public CommonResult<ImRtcGroupCallRespVO> getActiveCall(@RequestParam("groupId") Long groupId) {
+ ImRtcCallDO call = rtcCallService.getActiveCall(getLoginUserId(), groupId);
+ return success(buildGroupActiveRespVO(call));
+ }
+
+ // ========== VO 鎷艰 ==========
+
+ /**
+ * 鎷艰 invite / join / accept / refresh-token 鐨勫搷搴� VO锛涘惈 token + 鍙備笌鑰呭垎妗�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿锛泃oken 鎸夎鐢ㄦ埛绛惧彂
+ * @return 鍝嶅簲 VO锛沜all 涓虹┖杩斿洖 null
+ */
+ private ImRtcCallRespVO buildCallRespVO(ImRtcCallDO call, Long userId) {
+ if (call == null) {
+ return null;
+ }
+ List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipantList(call.getRoom());
+ boolean ended = ImRtcCallStatusEnum.isEnded(call.getStatus());
+ return new ImRtcCallRespVO()
+ .setRoom(call.getRoom())
+ .setLivekitUrl(imProperties.getRtc().getLivekitUrl())
+ // 浠呴潪 ENDED 鍦烘櫙鎵嶇 token锛孍NDED 鍦烘櫙涓嶇锛屽墠绔牴鎹� token 鏄惁瀛樺湪锛屾潵鍒ゆ柇鏄惁灞曠ず銆岄�氳瘽宸茬粨鏉熴�嶇殑鎻愮ず
+ .setToken(ended ? null : rtcCallService.signCallToken(userId, call.getRoom()))
+ .setConversationType(call.getConversationType()).setMediaType(call.getMediaType())
+ .setStatus(call.getStatus()).setEndReason(call.getEndReason())
+ .setInviterId(call.getInviterUserId()).setGroupId(call.getGroupId())
+ .setInviteeIds(filterUserIds(participants, ImRtcParticipantStatusEnum.INVITING))
+ .setJoinedUserIds(filterUserIds(participants, ImRtcParticipantStatusEnum.JOINED));
+ }
+
+ /**
+ * 鎷艰 get-active-call 鐨勫搷搴� VO
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @return 鍝嶅簲 VO锛氬彧鐢ㄤ簬缇よ亰鑳跺泭鏉★紝涓嶅惈 token
+ */
+ private ImRtcGroupCallRespVO buildGroupActiveRespVO(ImRtcCallDO call) {
+ if (call == null) {
+ return null;
+ }
+ List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipantList(call.getRoom());
+ return new ImRtcGroupCallRespVO().setRoom(call.getRoom()).setMediaType(call.getMediaType())
+ .setGroupId(call.getGroupId()).setInviterId(call.getInviterUserId())
+ .setJoinedUserIds(filterUserIds(participants, ImRtcParticipantStatusEnum.JOINED))
+ .setInviteeIds(filterUserIds(participants, ImRtcParticipantStatusEnum.INVITING));
+ }
+
+ /**
+ * 鎸夌姸鎬佽繃婊ゅ弬涓庤�� userId锛涚敤 LinkedHashSet 淇濈暀鍓嶇灞曠ず椤哄簭
+ *
+ * @param participants 鍙備笌鑰呭垪琛�
+ * @param status 鐩爣鐘舵��
+ * @return userId 闆嗗悎
+ */
+ private static Set<Long> filterUserIds(List<ImRtcParticipantDO> participants,
+ ImRtcParticipantStatusEnum status) {
+ return CollectionUtils.convertLinkedSet(participants, ImRtcParticipantDO::getUserId,
+ participant -> Objects.equals(participant.getStatus(), status.getStatus()));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcLiveKitController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcLiveKitController.java
new file mode 100644
index 0000000..b68c2ae
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcLiveKitController.java
@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.module.im.controller.admin.rtc;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
+import cn.iocoder.yudao.module.im.framework.rtc.core.LiveKitClient;
+import cn.iocoder.yudao.module.im.framework.rtc.core.LiveKitWebhookEventDTO;
+import cn.iocoder.yudao.module.im.service.rtc.ImRtcCallService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.annotation.security.PermitAll;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * LiveKit 鍘傚晢瀵规帴鍏ュ彛锛圵ebhook 鍥炶皟锛�
+ * <p>
+ * 瀹夊叏鐢辫姹傜鍚嶏紙JWT + body sha256锛変繚璇侊紝涓嶈蛋鐧诲綍閴存潈锛涗吉閫犺姹備細琚鍚嶆牎楠岀洿鎺ユ嫆缁�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Tag(name = "LiveKit Webhook 鍥炶皟")
+@RestController
+@RequestMapping("/im/livekit")
+@Slf4j
+public class ImRtcLiveKitController {
+
+ @Resource
+ private LiveKitClient liveKitClient;
+ @Resource
+ private ImRtcCallService rtcCallService;
+
+ /**
+ * LiveKit Webhook 鍥炶皟鍏ュ彛
+ *
+ * @param request HTTP 璇锋眰锛涚敤浜庡彇 Authorization 澶村仛绛惧悕鏍¢獙
+ * @param rawBody 鍘熷 JSON body锛涚鍚嶆牎楠岄渶瑕佸師濮嬪瓧鑺�
+ * @return 鏄惁澶勭悊鎴愬姛锛涗吉閫� / 闈炴硶浜嬩欢杩斿洖 false
+ */
+ @PostMapping("/webhook")
+ @Operation(summary = "LiveKit Webhook 鍥炶皟锛涙帴鏀舵垚鍛樼寮� / 鎴块棿缁撴潫绛変簨浠跺仛涓氬姟鎬佸厹搴曟竻鐞�")
+ @PermitAll
+ @TenantIgnore
+ public CommonResult<Boolean> webhook(HttpServletRequest request, @RequestBody String rawBody) {
+ // 1.1 鏍¢獙绛惧悕锛涗吉閫犺姹傜洿鎺� 200 浣嗗拷鐣ワ紝閬垮厤缁欐敾鍑昏�呭弽棣�
+ if (!liveKitClient.verifyWebhookSignature(request.getHeader("Authorization"), rawBody)) {
+ log.warn("[webhook][绛惧悕鏍¢獙澶辫触 ip={} bodyLength={}]",
+ request.getRemoteAddr(), rawBody == null ? 0 : rawBody.length());
+ return success(false);
+ }
+ // 1.2 瑙f瀽浜嬩欢杞借嵎锛涢潪娉� / 绌� event 鐩存帴蹇界暐
+ LiveKitWebhookEventDTO event = JsonUtils.parseObject(rawBody, LiveKitWebhookEventDTO.class);
+ if (event == null || StrUtil.isBlank(event.getEvent())) {
+ return success(false);
+ }
+
+ // 2. 浜ょ粰 service 澶勭悊锛涘箓绛夌敱 service 鑷繁淇濊瘉
+ log.info("[webhook][浜嬩欢澶勭悊 event={} room={}]", event.getEvent(),
+ event.getRoom() == null ? null : event.getRoom().getName());
+ try {
+ rtcCallService.handleLiveKitEvent(event);
+ } catch (Exception e) {
+ log.error("[webhook][浜嬩欢澶勭悊澶辫触 event={} body={}]", event.getEvent(), rawBody, e);
+ }
+ return success(true);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallCreateReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallCreateReqVO.java
new file mode 100644
index 0000000..9dc6a75
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallCreateReqVO.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.im.controller.admin.rtc.vo;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallMediaTypeEnum;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.AssertTrue;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.Set;
+
+@Schema(description = "绠$悊鍚庡彴 - 鍒涘缓閫氳瘽 Request VO")
+@Data
+public class ImRtcCallCreateReqVO {
+
+ @Schema(description = "浼氳瘽绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "浼氳瘽绫诲瀷涓嶈兘涓虹┖")
+ @InEnum(ImConversationTypeEnum.class)
+ private Integer conversationType;
+
+ @Schema(description = "濯掍綋绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @NotNull(message = "濯掍綋绫诲瀷涓嶈兘涓虹┖")
+ @InEnum(ImRtcCallMediaTypeEnum.class)
+ private Integer mediaType;
+
+ @Schema(description = "缇ょ紪鍙凤紱缇よ亰鍦烘櫙蹇呭~", example = "2048")
+ private Long groupId;
+
+ @Schema(description = "琚個璇风殑鐢ㄦ埛缂栧彿闆嗗悎锛涚鑱婂繀浼� 1 涓绔紝缇よ亰蹇呬紶鑷冲皯 1 浜�")
+ private Set<@NotNull(message = "琚個璇风敤鎴风紪鍙蜂笉鑳戒负绌�") Long> inviteeIds;
+
+ /**
+ * 閫氳瘽浠呮敮鎸佺鑱婂拰缇よ亰
+ */
+ @AssertTrue(message = "浼氳瘽绫诲瀷涓嶆敮鎸�")
+ @JsonIgnore
+ public boolean isConversationTypeSupported() {
+ return conversationType == null || ImConversationTypeEnum.isPrivate(conversationType)
+ || ImConversationTypeEnum.isGroup(conversationType);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallInviteReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallInviteReqVO.java
new file mode 100644
index 0000000..7fcde58
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallInviteReqVO.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.im.controller.admin.rtc.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.Set;
+
+@Schema(description = "绠$悊鍚庡彴 - 閫氳瘽涓拷鍔犻個璇� Request VO锛涗粎缇ら�氳瘽鍙敤")
+@Data
+public class ImRtcCallInviteReqVO {
+
+ @Schema(description = "涓氬姟閫氳瘽缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "f47ac10b58cc4372a567")
+ @NotBlank(message = "閫氳瘽缂栧彿涓嶈兘涓虹┖")
+ private String room;
+
+ @Schema(description = "鏂伴個璇风殑鐢ㄦ埛缂栧彿闆嗗悎", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "璇疯嚦灏戦�夋嫨涓�浣嶆垚鍛�")
+ private Set<@NotNull(message = "琚個璇风敤鎴风紪鍙蜂笉鑳戒负绌�") Long> inviteeIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallRespVO.java
new file mode 100644
index 0000000..9f3113c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallRespVO.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.im.controller.admin.rtc.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Set;
+
+@Schema(description = "绠$悊鍚庡彴 - 閫氳瘽浼氳瘽 Response VO锛沬nvite / accept / refreshToken 鍏辩敤")
+@Data
+public class ImRtcCallRespVO {
+
+ @Schema(description = "涓氬姟閫氳瘽缂栧彿")
+ private String room;
+
+ @Schema(description = "LiveKit Server WebSocket 鍦板潃锛涘墠绔� connect 鐢�")
+ private String livekitUrl;
+
+ @Schema(description = "LiveKit 鎺ュ叆 Token锛涢渶瑕佹椂璋� refreshToken 閲嶆柊绛惧彂")
+ private String token;
+
+ @Schema(description = "浼氳瘽绫诲瀷")
+ private Integer conversationType; // 鍙傝 ImConversationTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "濯掍綋绫诲瀷")
+ private Integer mediaType; // 鍙傝 ImCallMediaTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "鐘舵��")
+ private Integer status; // 鍙傝 ImCallStatusEnum 鏋氫妇绫�
+
+ @Schema(description = "缁撴潫鍘熷洜锛涗粎 status=ENDED 鏃舵湁鍊�")
+ private Integer endReason; // 鍙傝 ImRtcCallEndReasonEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戣捣浜虹紪鍙�")
+ private Long inviterId;
+
+ @Schema(description = "缇ょ紪鍙凤紱缇ら�氳瘽鎵嶆湁")
+ private Long groupId;
+
+ @Schema(description = "琚個璇蜂汉缂栧彿闆嗗悎")
+ private Set<Long> inviteeIds;
+
+ @Schema(description = "宸插姞鍏ユ埧闂寸殑鎴愬憳缂栧彿闆嗗悎")
+ private Set<Long> joinedUserIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcGroupCallRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcGroupCallRespVO.java
new file mode 100644
index 0000000..5d1d3ce
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcGroupCallRespVO.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.im.controller.admin.rtc.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.Set;
+
+@Schema(description = "绠$悊鍚庡彴 - 缇ゆ椿璺冮�氳瘽 Response VO锛涗笉鍚� token锛岃兌鍥婃潯浠呭睍绀虹敤")
+@Data
+public class ImRtcGroupCallRespVO {
+
+ @Schema(description = "涓氬姟閫氳瘽缂栧彿")
+ private String room;
+
+ @Schema(description = "缇ょ紪鍙�")
+ private Long groupId;
+
+ @Schema(description = "濯掍綋绫诲瀷")
+ private Integer mediaType; // 鍙傝 ImCallMediaTypeEnum 鏋氫妇绫�
+
+ @Schema(description = "鍙戣捣浜虹紪鍙�")
+ private Long inviterId;
+
+ @Schema(description = "宸插姞鍏ユ埧闂寸殑鐢ㄦ埛缂栧彿闆嗗悎")
+ private Set<Long> joinedUserIds;
+
+ @Schema(description = "琚個璇锋睜锛涚敤浜庤兌鍥婃潯灞曞紑鏃舵樉绀哄緟鍔犲叆澶村儚")
+ private Set<Long> inviteeIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/app/package-info.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/app/package-info.java
new file mode 100644
index 0000000..31a8695
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/app/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * 鍗犱綅
+ */
+package cn.iocoder.yudao.module.im.controller.app;
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/package-info.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/package-info.java
new file mode 100644
index 0000000..f2e831e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * 鎻愪緵 RESTful API 缁欏墠绔細
+ * 1. admin 鍖咃細鎻愪緵缁欑鐞嗗悗鍙� yudao-ui-admin 鍓嶇椤圭洰
+ * 2. app 鍖咃細鎻愪緵缁欑敤鎴� APP yudao-ui-app 鍓嶇椤圭洰锛屽畠鐨� Controller 鍜� VO 閮借娣诲姞 App 鍓嶇紑锛岀敤浜庡拰绠$悊鍚庡彴杩涜鍖哄垎
+ */
+package cn.iocoder.yudao.module.im.controller;
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/channel/ImChannelDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/channel/ImChannelDO.java
new file mode 100644
index 0000000..f385cfa
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/channel/ImChannelDO.java
@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.channel;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * IM 棰戦亾 DO
+ * <p>
+ * 涓氬姟璇箟锛�
+ * - 棰戦亾鏄繍钀ュ崟鍚戞帹閫佺殑涓讳綋锛汣 绔敤鎴蜂笉鑳藉悜棰戦亾鍙戞秷鎭�
+ * - {@link #code} 鏄笟鍔$爜锛圓PI / 瀛楀吀澶栭湶锛夛紝id 鏄暟瀛椾富閿粰鍓嶇浼氳瘽 targetId 鐢�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_channel")
+@KeySequence("im_channel_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImChannelDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 棰戦亾涓氬姟鐮�
+ */
+ private String code;
+ /**
+ * 棰戦亾鍚嶇О
+ */
+ private String name;
+ /**
+ * 棰戦亾澶村儚
+ */
+ private String avatar;
+ /**
+ * 鎺掑簭
+ */
+ private Integer sort;
+ /**
+ * 鐘舵��
+ * <p>
+ * 鏋氫妇 {@link CommonStatusEnum}
+ */
+ private Integer status;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/channel/ImChannelMaterialDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/channel/ImChannelMaterialDO.java
new file mode 100644
index 0000000..0d49721
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/channel/ImChannelMaterialDO.java
@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.channel;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import cn.iocoder.yudao.module.im.enums.channel.ImChannelMaterialTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * IM 棰戦亾绱犳潗 DO
+ * <p>
+ * 涓氬姟璇箟锛�
+ * - 杩愯惀绱犳潗搴擄紝鍙鍙嶅鎺ㄩ��
+ * - 涓�鏉$礌鏉� 1:N 鍏宠仈澶氭潯 {@link ImChannelMessageDO}
+ * - {@link #content} 瀵屾枃鏈粎鍦ㄧ礌鏉愯鎯呮帴鍙f寜闇�杩斿洖锛屾帹閫� payload 涓嶅甫锛岄伩鍏嶅帇鐖� WebSocket 閫氶亾
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_channel_material")
+@KeySequence("im_channel_material_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImChannelMaterialDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 棰戦亾缂栧彿
+ * <p>
+ * 鍏宠仈 {@link ImChannelDO#getId()}
+ */
+ private Long channelId;
+ /**
+ * 绱犳潗鍐呭绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImChannelMaterialTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 鏍囬
+ */
+ private String title;
+ /**
+ * 灏侀潰鍥�
+ */
+ private String coverUrl;
+ /**
+ * 鎽樿
+ */
+ private String summary;
+ /**
+ * 瀵屾枃鏈� HTML锛涘湪 {@link ImChannelMaterialTypeEnum#CONTENT} 浣跨敤
+ */
+ private String content;
+ /**
+ * 璺宠浆閾炬帴锛涘湪 {@link ImChannelMaterialTypeEnum#LINK} 浣跨敤
+ */
+ private String url;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationReadDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationReadDO.java
new file mode 100644
index 0000000..bdd9fa0
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationReadDO.java
@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.conversation;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 浼氳瘽璇讳綅缃� DO
+ * <p>
+ * 鍙〃杈俱�岀敤鎴峰湪鏌愪釜浼氳瘽鐨勬渶澶у凡璇讳綅缃�嶏紝绉佽亰 / 缇よ亰 / 棰戦亾缁熶竴钀借繖寮犺〃锛屾槸璇讳綅缃殑鍞竴鏉冨▉銆�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_conversation_read")
+@KeySequence("im_conversation_read_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImConversationReadDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 鐢ㄦ埛缂栧彿
+ *
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long userId;
+ /**
+ * 浼氳瘽绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImConversationTypeEnum}
+ */
+ private Integer conversationType;
+ /**
+ * 鐩爣缂栧彿
+ * <p>
+ * 绉佽亰鍏宠仈 AdminUserDO 鐨� id锛涚兢鑱婂叧鑱� {@link ImGroupDO#getId()}锛涢閬撳叧鑱� {@link ImChannelDO#getId()}
+ */
+ private Long targetId;
+ /**
+ * 鏈�澶у凡璇绘秷鎭紪鍙�
+ * <p>
+ * 鍏宠仈 {@link ImPrivateMessageDO#getId()}銆亄@link ImGroupMessageDO#getId()}銆亄@link ImChannelMessageDO#getId()}
+ */
+ private Long messageId;
+ /**
+ * 鏈�杩戝凡璇绘椂闂�
+ */
+ private LocalDateTime readTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java
new file mode 100644
index 0000000..0236218
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.face;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * IM 琛ㄦ儏鍖� DO锛堣繍钀ラ厤缃殑绯荤粺琛ㄦ儏鍖呭厓鏁版嵁锛�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_face_pack")
+@KeySequence("im_face_pack_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImFacePackDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 琛ㄦ儏鍖呭悕绉�
+ */
+ private String name;
+ /**
+ * 琛ㄦ儏鍖呭浘鏍�
+ * <p>
+ * 闈㈡澘搴曢儴 tab 鏍忔樉绀�
+ */
+ private String icon;
+ /**
+ * 鎺掑簭
+ */
+ private Integer sort;
+ /**
+ * 鐘舵��
+ * <p>
+ * 鏋氫妇 {@link CommonStatusEnum}
+ */
+ private Integer status;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackItemDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackItemDO.java
new file mode 100644
index 0000000..d3c5676
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackItemDO.java
@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.face;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * IM 琛ㄦ儏鍖呴」 DO锛堢郴缁熻〃鎯呭寘鍐呯殑鍗曞紶琛ㄦ儏鍥撅級
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_face_pack_item")
+@KeySequence("im_face_pack_item_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImFacePackItemDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 鎵�灞炶〃鎯呭寘缂栧彿
+ */
+ private Long packId;
+ /**
+ * 琛ㄦ儏鍥� URL
+ */
+ private String url;
+ /**
+ * 琛ㄦ儏鍚嶏紙鍙�夛紱濡傘�岀嫍澶淬�嶃�屾崅鑴搞�嶏級
+ */
+ private String name;
+ /**
+ * 娓叉煋瀹藉害锛堝儚绱狅級
+ */
+ private Integer width;
+ /**
+ * 娓叉煋楂樺害锛堝儚绱狅級
+ */
+ private Integer height;
+ /**
+ * 鎺掑簭
+ */
+ private Integer sort;
+ /**
+ * 鐘舵��
+ * <p>
+ * 鏋氫妇 {@link CommonStatusEnum}
+ */
+ private Integer status;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java
new file mode 100644
index 0000000..0aee3bb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.face;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * IM 鐢ㄦ埛绉佹湁琛ㄦ儏 DO锛堜釜浜鸿〃鎯呭寘锛屽鐓у井淇°�屾垜鐨勮〃鎯呫�嶏級
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_face_user_item")
+@KeySequence("im_face_user_item_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImFaceUserItemDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 鎵�灞炵敤鎴风紪鍙�
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 缂栧彿
+ */
+ private Long userId;
+ /**
+ * 琛ㄦ儏鍥� URL
+ */
+ private String url;
+ /**
+ * 琛ㄦ儏鍚嶏紙鍙�夛級
+ * <p>
+ * 鐢ㄦ埛绉佹湁琛ㄦ儏閫氬父涓嶅甫鍚嶅瓧锛岀暀瀛楁浠ュ灏嗘潵銆岄噸鍛藉悕銆嶄氦浜�
+ */
+ private String name;
+ /**
+ * 娓叉煋瀹藉害锛堝儚绱狅級
+ */
+ private Integer width;
+ /**
+ * 娓叉煋楂樺害锛堝儚绱狅級
+ */
+ private Integer height;
+ /**
+ * 鎺掑簭
+ */
+ private Integer sort;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendDO.java
new file mode 100644
index 0000000..db9543a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendDO.java
@@ -0,0 +1,90 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.friend;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 濂藉弸鍏崇郴 DO
+ * <p>
+ * 涓氬姟璇箟锛�
+ * - 鍙屽悜鍏崇郴锛欰-B 浜掍负濂藉弸浼氬瓨 2 鏉¤褰曪紙userId=A, friendUserId=B 鍜� userId=B, friendUserId=A锛�
+ * - 鐘舵�佺鐞嗭細{@link #status} 浣跨敤 {@link CommonStatusEnum}锛孍NABLE=姝e父锛孌ISABLE=宸插垹闄�
+ * - 鍏嶆墦鎵帮細{@link #silent} 鎺у埗鏄惁灞忚斀鏉ヨ嚜璇ュソ鍙嬬殑閫氱煡
+ * - 鑱旂郴浜虹疆椤讹細{@link #pinned} 鍗曡竟锛屽奖鍝嶈仈绯讳汉 / 浼氳瘽鎺掑簭
+ * - 榛戝悕鍗曪細{@link #blocked} 寮卞叧鑱� friend锛屽崟杈瑰睆钄藉鏂规秷鎭紙蹇呴』鍏堟槸濂藉弸锛�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_friend")
+@KeySequence("im_friend_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImFriendDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 鐢ㄦ埛缂栧彿
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long userId;
+ /**
+ * 濂藉弸鐢ㄦ埛缂栧彿
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long friendUserId;
+ /**
+ * 鏄惁鍏嶆墦鎵�
+ */
+ private Boolean silent;
+ /**
+ * 濂藉弸灞曠ず澶囨敞
+ */
+ private String displayName;
+ /**
+ * 娣诲姞鏉ユ簮
+ * <p>
+ * 鏋氫妇 {@link cn.iocoder.yudao.module.im.enums.friend.ImFriendAddSourceEnum}
+ */
+ private Integer addSource;
+ /**
+ * 鏄惁缃《鑱旂郴浜�
+ */
+ private Boolean pinned;
+ /**
+ * 鏄惁鎷夐粦锛堝急鍏宠仈 friend锛屽崟杈瑰睆钄藉鏂圭鑱婃秷鎭級
+ */
+ private Boolean blocked;
+ /**
+ * 濂藉弸鐘舵��
+ * <p>
+ * 鏋氫妇 {@link CommonStatusEnum}
+ */
+ private Integer status;
+ /**
+ * 娣诲姞濂藉弸鏃堕棿
+ */
+ private LocalDateTime addTime;
+ /**
+ * 鍒犻櫎濂藉弸鏃堕棿
+ * <p>
+ * 涓嶄负 null 鏃惰〃绀哄凡鍒犻櫎
+ */
+ private LocalDateTime deleteTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendRequestDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendRequestDO.java
new file mode 100644
index 0000000..ec30987
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendRequestDO.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.friend;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendAddSourceEnum;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendRequestHandleResultEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 濂藉弸鐢宠璁板綍 DO
+ * <p>
+ * 閰嶅悎銆岀敵璇� - 瀹℃壒銆嶆祦绋嬶細
+ * - 鍙戣捣鏂硅皟 apply 鎺ュ彛钀藉簱锛坔andleResult=UNHANDLED锛�
+ * - 鎺ユ敹鏂硅皟 agree / refuse 澶勭悊锛堟洿鏂� handleResult / handleTime / handleContent锛�
+ * - 鐢宠閫氳繃鍚庯紝displayName / addSource 鍚屾鍐欏叆 {@link ImFriendDO}
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_friend_request")
+@KeySequence("im_friend_request_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImFriendRequestDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 鍙戣捣鏂圭敤鎴风紪鍙�
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long fromUserId;
+ /**
+ * 鎺ユ敹鏂圭敤鎴风紪鍙�
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long toUserId;
+
+ // ========== 鐢宠鍙戣捣闃舵锛堝彂璧锋柟濉啓锛� ==========
+ /**
+ * 鐢宠鐞嗙敱
+ */
+ private String applyContent;
+ /**
+ * 鍙戣捣鏂瑰鎺ユ敹鏂圭殑澶囨敞
+ * <p>
+ * 鍚屾剰鍚庡啓鍏� A 渚� {@link ImFriendDO#getDisplayName()}锛汢 渚т笉鍔�
+ */
+ private String displayName;
+ /**
+ * 娣诲姞鏉ユ簮
+ * <p>
+ * 鏋氫妇 {@link ImFriendAddSourceEnum}
+ */
+ private Integer addSource;
+
+ // ========== 鐢宠澶勭悊闃舵锛堟帴鏀舵柟濉啓锛� ==========
+ /**
+ * 澶勭悊缁撴灉
+ * <p>
+ * 鏋氫妇 {@link ImFriendRequestHandleResultEnum}
+ */
+ private Integer handleResult;
+ /**
+ * 澶勭悊鐞嗙敱锛堟帴鏀舵柟鎷掔粷鏃跺彲閫夊~锛�
+ */
+ private String handleContent;
+ /**
+ * 澶勭悊鏃堕棿
+ */
+ private LocalDateTime handleTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupDO.java
new file mode 100644
index 0000000..f47f80d
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupDO.java
@@ -0,0 +1,94 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.group;
+
+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.LongListTypeHandler;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * IM 缇や俊鎭� DO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName(value = "im_group",autoResultMap = true)
+@KeySequence("im_group_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷銆傚鏋滄槸 MySQL 绛夋暟鎹簱锛屽彲涓嶅啓銆�
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImGroupDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 缇ゅ悕绉�
+ */
+ private String name;
+ /**
+ * 缇や富鐢ㄦ埛缂栧彿
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long ownerUserId;
+ /**
+ * 缇ゅご鍍�
+ */
+ private String avatar;
+ /**
+ * 缇ゅ叕鍛�
+ */
+ private String notice;
+ /**
+ * 杩涚兢鏄惁闇�缇や富 / 绠$悊鍛樺鎵�
+ * <p>
+ * false 鑷敱杩涚兢锛堥粯璁わ級锛泃rue 闇�瀹℃壒锛屾墍鏈夈�岀敵璇枫�嶃�岄個璇枫�嶈矾寰勯兘闇�缇や富 / 绠$悊鍛樺悓鎰�
+ */
+ private Boolean joinApproval;
+ /**
+ * 鏄惁灏佺
+ */
+ private Boolean banned;
+ /**
+ * 灏佺鍘熷洜
+ */
+ private String bannedReason;
+ /**
+ * 灏佺鏃堕棿
+ */
+ private LocalDateTime bannedTime;
+ /**
+ * 缇ょ姸鎬�
+ * <p>
+ * 鏋氫妇 {@link CommonStatusEnum}
+ * ENABLE = 姝e父锛孌ISABLE = 宸茶В鏁�
+ */
+ private Integer status;
+ /**
+ * 瑙f暎鏃堕棿
+ */
+ private LocalDateTime dissolvedTime;
+ /**
+ * 鏄惁鍏ㄧ兢绂佽█
+ */
+ private Boolean mutedAll;
+ /**
+ * 缇ょ疆椤舵秷鎭紪鍙峰垪琛�
+ * <p>
+ * 浠呭瓨 messageId锛屾搷浣滀汉 / 缃《鏃堕棿浠庡搴� PIN 浜嬩欢鐨勬秷鎭褰曢噷鍙嶆煡
+ */
+ @TableField(typeHandler = LongListTypeHandler.class)
+ private List<Long> pinnedMessageIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupMemberDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupMemberDO.java
new file mode 100644
index 0000000..430264c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupMemberDO.java
@@ -0,0 +1,102 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.group;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 缇ゆ垚鍛� DO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_group_member")
+@KeySequence("im_group_member_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷銆傚鏋滄槸 MySQL 绛夋暟鎹簱锛屽彲涓嶅啓銆�
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImGroupMemberDO extends BaseDO {
+
+ /**
+ * 姘镐箙绂佽█鍒版湡鏃堕棿
+ */
+ public static final LocalDateTime PERMANENT_MUTE_END_TIME = LocalDateTime.of(9999, 12, 31, 23, 59, 59);
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 缇ょ紪鍙�
+ * <p>
+ * 鍏宠仈 {@link ImGroupDO#getId()}
+ */
+ private Long groupId;
+ /**
+ * 鐢ㄦ埛缂栧彿
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long userId;
+ /**
+ * 缁勫唴鏄剧ず鍚�
+ */
+ private String displayUserName;
+ /**
+ * 缇ゅ娉�
+ */
+ private String groupRemark;
+ /**
+ * 鏄惁鍏嶆墦鎵�
+ */
+ private Boolean silent;
+ /**
+ * 鎴愬憳鐘舵��
+ * <p>
+ * 鏋氫妇 {@link CommonStatusEnum}
+ */
+ private Integer status;
+ /**
+ * 鎴愬憳瑙掕壊
+ * <p>
+ * 鏋氫妇 {@link ImGroupMemberRoleEnum}
+ */
+ private Integer role;
+ /**
+ * 鍏ョ兢鏃堕棿
+ */
+ private LocalDateTime joinTime;
+ /**
+ * 鍔犲叆鏉ユ簮
+ * <p>
+ * 鏋氫妇 {@link ImGroupAddSourceEnum}
+ */
+ private Integer addSource;
+ /**
+ * 閭�璇蜂汉鐢ㄦ埛缂栧彿
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁锛涚敤鎴蜂富鍔ㄧ敵璇疯繘缇ゆ椂涓� NULL
+ */
+ private Long inviterUserId;
+ /**
+ * 閫�缇ゆ椂闂�
+ */
+ private LocalDateTime quitTime;
+ /**
+ * 绂佽█鍒版湡鏃堕棿
+ * <p>
+ * null 琛ㄧず鏈瑷�锛涢潪 null 涓斿湪鏈潵琛ㄧず绂佽█涓紱
+ */
+ private LocalDateTime muteEndTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupRequestDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupRequestDO.java
new file mode 100644
index 0000000..6ccb2cf
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupRequestDO.java
@@ -0,0 +1,91 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.group;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupRequestHandleResultEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 鍔犵兢鐢宠璁板綍 DO
+ * <p>
+ * 閰嶅悎銆岀敵璇� - 瀹℃壒銆嶆祦绋嬶細
+ * <ul>
+ * <li>鐢ㄦ埛涓诲姩鐢宠锛氳皟 apply 鎺ュ彛钀藉簱锛坕nviterUserId=null锛宧andleResult=UNHANDLED锛夛紝缇や富 / 绠$悊鍛樺鎵�</li>
+ * <li>鏅�氭垚鍛橀個璇凤細缇� joinType=APPLY_AND_NORMAL_INVITE 鏃惰惤搴擄紙inviterUserId=鎿嶄綔浜猴級锛岀兢涓� / 绠$悊鍛樺鎵�</li>
+ * <li>澶勭悊锛氱兢涓� / 绠$悊鍛樿皟 agree / refuse 鎺ㄨ繘鐘舵�佹満锛涘悓鎰忔椂鎶� addSource / inviterUserId 鍚屾鍐欏叆 {@link ImGroupMemberDO}</li>
+ * </ul>
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_group_request")
+@KeySequence("im_group_request_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷锛汳ySQL 绛夊彲涓嶅啓
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImGroupRequestDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 缇ょ紪鍙�
+ * <p>
+ * 鍏宠仈 {@link ImGroupDO#getId()}
+ */
+ private Long groupId;
+ /**
+ * 鐢宠浜� / 琚個璇蜂汉鐢ㄦ埛缂栧彿
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long userId;
+ /**
+ * 閭�璇蜂汉鐢ㄦ埛缂栧彿
+ * <p>
+ * NULL 琛ㄧず鐢ㄦ埛涓诲姩鐢宠杩涚兢锛涢潪 NULL 琛ㄧず鐢辩兢鎴愬憳閭�璇枫�佸緟缇や富 / 绠$悊鍛樺鎵�
+ */
+ private Long inviterUserId;
+
+ // ========== 鐢宠鍙戣捣闃舵 ==========
+ /**
+ * 鐢宠鐞嗙敱
+ */
+ private String applyContent;
+ /**
+ * 鍔犲叆鏉ユ簮
+ * <p>
+ * 鏋氫妇 {@link ImGroupAddSourceEnum}锛涘悓鎰忔椂鍚屾鍐欏叆 {@link ImGroupMemberDO#getAddSource()}
+ */
+ private Integer addSource;
+
+ // ========== 鐢宠澶勭悊闃舵 ==========
+ /**
+ * 澶勭悊缁撴灉
+ * <p>
+ * 鏋氫妇 {@link ImGroupRequestHandleResultEnum}
+ */
+ private Integer handleResult;
+ /**
+ * 澶勭悊浜虹敤鎴风紪鍙凤紙缇や富鎴栫鐞嗗憳锛�
+ */
+ private Long handleUserId;
+ /**
+ * 澶勭悊鐞嗙敱锛堟嫆缁濇椂鍙�夊~锛�
+ */
+ private String handleContent;
+ /**
+ * 澶勭悊鏃堕棿
+ */
+ private LocalDateTime handleTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImChannelMessageDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImChannelMessageDO.java
new file mode 100644
index 0000000..d71ee7c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImChannelMessageDO.java
@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * IM 棰戦亾娑堟伅 DO
+ * <p>
+ * 涓氬姟璇箟锛�
+ * - 涓�娆℃帹閫� 1 琛岋紱{@link #receiverUserIds} 涓虹┖琛ㄧず鍏ㄥ憳
+ * - {@link #channelId} 鍐椾綑 {@link ImChannelMaterialDO#getChannelId()} 渚夸簬鎸夐閬撴绱�
+ * - {@link #content} 瀛樻帹閫佹椂 payload 鐨� JSON 蹇収锛坱itle / coverUrl / summary / url锛夛紱涓嶅惈瀵屾枃鏈鏂�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName(value = "im_channel_message", autoResultMap = true)
+@KeySequence("im_channel_message_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImChannelMessageDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 棰戦亾缂栧彿
+ * <p>
+ * 鍏宠仈 {@link ImChannelDO#getId()}锛涘啑浣欎究浜庢寜棰戦亾妫�绱�
+ */
+ private Long channelId;
+ /**
+ * 鍏宠仈绱犳潗缂栧彿
+ * <p>
+ * 鍏宠仈 {@link ImChannelMaterialDO#getId()}
+ */
+ private Long materialId;
+ /**
+ * 娑堟伅绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImContentTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭锛涙帹閫佹椂 payload 鐨� JSON 蹇収
+ */
+ private String content;
+ /**
+ * 鎺ユ敹浜虹紪鍙峰垪琛紱涓虹┖琛ㄧず鍏ㄥ憳
+ */
+ @TableField(typeHandler = LongListTypeHandler.class)
+ private List<Long> receiverUserIds;
+ /**
+ * 鍙戦�佹椂闂�
+ */
+ private LocalDateTime sendTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImGroupMessageDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImGroupMessageDO.java
new file mode 100644
index 0000000..bdab8a8
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImGroupMessageDO.java
@@ -0,0 +1,107 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * IM 缇よ亰娑堟伅 DO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName(value = "im_group_message", autoResultMap = true)
+@KeySequence("im_group_message_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImGroupMessageDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 瀹㈡埛绔秷鎭紪鍙凤紝鐢ㄤ簬鍙戦�佸箓绛�
+ */
+ private String clientMessageId;
+ /**
+ * 鍙戦�佷汉缂栧彿
+ *
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long senderId;
+ /**
+ * 缇ょ紪鍙�
+ *
+ * 鍏宠仈 {@link ImGroupDO#getId()}
+ */
+ private Long groupId;
+ /**
+ * 娑堟伅绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImContentTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭锛孞SON 鏍煎紡
+ *
+ * 鍙傝�� content 鍖呬笅鐨� TextMessage銆両mageMessage 绛夌粨鏋勫寲妯″瀷
+ */
+ private String content;
+ /**
+ * 娑堟伅鐘舵��
+ * <p>
+ * 鏋氫妇 {@link ImMessageStatusEnum}
+ */
+ private Integer status;
+ /**
+ * 鍙戦�佹椂闂�
+ */
+ private LocalDateTime sendTime;
+ /**
+ * 瀹氬悜鎺ユ敹鐢ㄦ埛缂栧彿鍒楄〃锛屼互閫楀彿鍒嗛殧
+ * <p>
+ * 涓虹┖琛ㄧず鍏ㄥ憳鍙
+ *
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ @TableField(typeHandler = LongListTypeHandler.class)
+ private List<Long> receiverUserIds;
+ /**
+ * @ 鐩爣鐢ㄦ埛缂栧彿鍒楄〃锛屼互閫楀彿鍒嗛殧
+ *
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ @TableField(typeHandler = LongListTypeHandler.class)
+ private List<Long> atUserIds;
+ /**
+ * 鍥炴墽鐘舵��
+ * <p>
+ * 鏋氫妇 {@link ImMessageReceiptStatusEnum}
+ */
+ private Integer receiptStatus;
+
+ // ========== 闈炶〃瀛楁 ==========
+
+ /**
+ * 绂荤嚎鎷夊彇绛夊満鏅笅鍥炵畻鐨勫凡璇讳汉鏁�
+ */
+ @TableField(exist = false)
+ private Integer readCount;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImPrivateMessageDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImPrivateMessageDO.java
new file mode 100644
index 0000000..808c1ee
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImPrivateMessageDO.java
@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 绉佽亰娑堟伅 DO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_private_message")
+@KeySequence("im_private_message_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImPrivateMessageDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 瀹㈡埛绔秷鎭紪鍙凤紝鐢ㄤ簬鍙戦�佸箓绛�
+ */
+ private String clientMessageId;
+ /**
+ * 鍙戦�佷汉缂栧彿
+ *
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long senderId;
+ /**
+ * 鎺ユ敹浜虹紪鍙�
+ *
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long receiverId;
+ /**
+ * 娑堟伅绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImContentTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭锛孞SON 鏍煎紡
+ *
+ * 鍙傝�� content 鍖呬笅鐨� TextMessage銆両mageMessage 绛夌粨鏋勫寲妯″瀷
+ */
+ private String content;
+ /**
+ * 娑堟伅鐘舵��
+ * <p>
+ * 鏋氫妇 {@link ImMessageStatusEnum}
+ */
+ private Integer status;
+ /**
+ * 鍥炴墽鐘舵��
+ * <p>
+ * 鏋氫妇 {@link ImMessageReceiptStatusEnum}
+ */
+ private Integer receiptStatus;
+ /**
+ * 鍙戦�佹椂闂�
+ */
+ private LocalDateTime sendTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java
new file mode 100644
index 0000000..2422467
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+
+/**
+ * 璇煶娑堟伅鍐呭
+ */
+@Data
+public class AudioMessage {
+
+ /**
+ * 璇煶鏂囦欢 URL
+ */
+ private String url;
+ /**
+ * 璇煶鏃堕暱锛堢锛�
+ */
+ private Integer duration;
+ /**
+ * 鏂囦欢澶у皬锛堝瓧鑺傦級
+ */
+ private Long size;
+
+ /**
+ * 寮曠敤娑堟伅锛堝彲閫夛級
+ */
+ private QuoteMessage quote;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/CardMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/CardMessage.java
new file mode 100644
index 0000000..d99ed12
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/CardMessage.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import lombok.Data;
+
+/**
+ * 鍚嶇墖娑堟伅鍐呭
+ * <p>
+ * 鏀寔涓ょ被鍚嶇墖锛屾寜 targetType 鍖哄垎锛�
+ * 1. 鐢ㄦ埛鍚嶇墖锛坱argetType = PRIVATE锛夛細targetId = 鐢ㄦ埛缂栧彿锛宯ame = 鐢ㄦ埛鏄电О
+ * 2. 缇ゅ悕鐗囷紙targetType = GROUP锛夛細targetId = 缇ょ紪鍙凤紝name = 缇ゅ悕锛屽彲甯� memberCount
+ */
+@Data
+public class CardMessage {
+
+ /**
+ * 鍚嶇墖瀵硅薄绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImConversationTypeEnum}
+ */
+ private Integer targetType;
+ /**
+ * 鐩爣瀵硅薄缂栧彿锛歅RIVATE 鏃� = 鐢ㄦ埛缂栧彿锛汫ROUP 鏃� = 缇ょ紪鍙�
+ */
+ private Long targetId;
+ /**
+ * 鏄剧ず鍚嶅揩鐓э細PRIVATE 鏃� = 鐢ㄦ埛鏄电О锛汫ROUP 鏃� = 缇ゅ悕
+ */
+ private String name;
+ /**
+ * 澶村儚锛堝揩鐓э級
+ */
+ private String avatar;
+ /**
+ * 缇ゆ垚鍛樻暟锛堜粎 targetType = GROUP锛涙帴鏀剁灞曠ず銆孨 浜虹兢鑱娿�嶏級
+ */
+ private Integer memberCount;
+
+ /**
+ * 寮曠敤娑堟伅锛堝彲閫夛級
+ */
+ private QuoteMessage quote;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FaceMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FaceMessage.java
new file mode 100644
index 0000000..6d6a642
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FaceMessage.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+
+/**
+ * 琛ㄦ儏娑堟伅鍐呭
+ * <p>
+ * 鎵胯浇銆岃创鍥� / 鑷畾涔夎〃鎯呭寘銆嶇被娑堟伅锛沀nicode emoji锛堭煒�馃槀锛変粛璧� TEXT
+ */
+@Data
+public class FaceMessage {
+
+ /**
+ * 琛ㄦ儏鍥� URL
+ */
+ private String url;
+ /**
+ * 娓叉煋瀹藉害锛堝儚绱狅紝鍙�夛級
+ * <p>
+ * 瀹㈡埛绔覆鏌撴椂鎸夋灏哄鍗犱綅锛岄伩鍏嶅浘鐗囧姞杞藉畬鎴愬悗鐨勫竷灞�鎶栧姩锛涚己澶辨椂鐢卞鎴风 CSS max-width 鍏滃簳
+ */
+ private Integer width;
+ /**
+ * 娓叉煋楂樺害锛堝儚绱狅紝鍙�夛級
+ */
+ private Integer height;
+ /**
+ * 琛ㄦ儏鍚嶏紙鍙�夛級
+ * <p>
+ * 绯荤粺琛ㄦ儏鍖呴�氬父甯﹀悕瀛楋紙濡傘�岀嫍澶淬�嶃�屾崅鑴搞�嶏級锛岀敤鎴风鏈夎〃鎯呭寘閫氬父涓虹┖
+ */
+ private String name;
+
+ /**
+ * 寮曠敤娑堟伅锛堝彲閫夛級
+ */
+ private QuoteMessage quote;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FileMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FileMessage.java
new file mode 100644
index 0000000..bd4fcc3
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FileMessage.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+
+/**
+ * 鏂囦欢娑堟伅鍐呭
+ */
+@Data
+public class FileMessage {
+
+ /**
+ * 鏂囦欢 URL
+ */
+ private String url;
+ /**
+ * 鏂囦欢鍚�
+ */
+ private String name;
+ /**
+ * 鏂囦欢澶у皬锛堝瓧鑺傦級
+ */
+ private Long size;
+ /**
+ * 鏂囦欢绫诲瀷锛堟墿灞曞悕锛�
+ */
+ private String type;
+
+ /**
+ * 寮曠敤娑堟伅锛堝彲閫夛級
+ */
+ private QuoteMessage quote;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/ImageMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/ImageMessage.java
new file mode 100644
index 0000000..052342a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/ImageMessage.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+
+/**
+ * 鍥剧墖娑堟伅鍐呭
+ */
+@Data
+public class ImageMessage {
+
+ /**
+ * 鍥剧墖 URL
+ */
+ private String url;
+ /**
+ * 缂╃暐鍥� URL
+ */
+ private String thumbnailUrl;
+ /**
+ * 鍥剧墖瀹藉害
+ */
+ private Integer width;
+ /**
+ * 鍥剧墖楂樺害
+ */
+ private Integer height;
+ /**
+ * 鍥剧墖澶у皬锛堝瓧鑺傦級
+ */
+ private Long size;
+
+ /**
+ * 寮曠敤娑堟伅锛堝彲閫夛級
+ */
+ private QuoteMessage quote;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/LocationMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/LocationMessage.java
new file mode 100644
index 0000000..fdbb7c7
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/LocationMessage.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+
+/**
+ * 浣嶇疆娑堟伅鍐呭
+ */
+@Data
+public class LocationMessage {
+
+ /**
+ * 浣嶇疆鎻忚堪
+ */
+ private String description;
+ /**
+ * 缁忓害
+ */
+ private Double longitude;
+ /**
+ * 绾害
+ */
+ private Double latitude;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/MaterialMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/MaterialMessage.java
new file mode 100644
index 0000000..41fbdce
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/MaterialMessage.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 棰戦亾绱犳潗娑堟伅 payload
+ * <p>
+ * 瀵瑰簲 {@link cn.iocoder.yudao.module.im.enums.ImContentTypeEnum#MATERIAL}锛坱ype=125锛夈��
+ * 瀹㈡埛绔寜鏈瓧娈甸泦娓叉煋鍥炬枃鍗$墖锛�
+ * 瀵屾枃鏈鏂囦笉鍦ㄦ湰 payload 涓紶閫掞紝鐐瑰嚮璇︽儏鏃跺彟璋� /im/channel/material/get-content?id= 鎸夐渶鎷夊彇銆�
+ */
+@Data
+@Accessors(chain = true)
+public class MaterialMessage {
+
+ /**
+ * 绱犳潗缂栧彿
+ */
+ private Long materialId;
+ /**
+ * 棰戦亾缂栧彿
+ * <p>
+ * 鍐椾綑鍒� payload 鍐咃紱杞彂鍒扮鑱� / 缇よ亰鍚庡鎴风鐢ㄦ湰瀛楁瀹氫綅棰戦亾锛屾覆鏌撳崱鐗囧簳閮ㄧ殑棰戦亾澶村儚 + 鍚嶇О
+ */
+ private Long channelId;
+ /**
+ * 绱犳潗鍐呭绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link cn.iocoder.yudao.module.im.enums.channel.ImChannelMaterialTypeEnum}
+ * 瀹㈡埛绔寜鏈瓧娈靛垽瀹氱偣鍑昏涓猴細CONTENT 璧扮珯鍐呰鎯呴〉鎷夊瘜鏂囨湰锛汱INK 璺� url
+ */
+ private Integer type;
+ /**
+ * 鏍囬
+ */
+ private String title;
+ /**
+ * 灏侀潰鍥�
+ */
+ private String coverUrl;
+ /**
+ * 鎽樿
+ */
+ private String summary;
+ /**
+ * 璺宠浆閾炬帴
+ */
+ private String url;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/MergeMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/MergeMessage.java
new file mode 100644
index 0000000..9bc675b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/MergeMessage.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 鍚堝苟杞彂娑堟伅鍐呭
+ * <p>
+ * payload 鍐呭祵瀹屾暣蹇収锛屽師娑堟伅鎾ゅ洖 / 鍒犻櫎涓嶅奖鍝嶅凡杞彂鐨勫悎骞舵秷鎭�
+ */
+@Data
+public class MergeMessage {
+
+ /**
+ * 鍚堝苟鏍囬
+ */
+ private String title;
+ /**
+ * 鍐呭祵鐨勫畬鏁存秷鎭揩鐓�
+ */
+ private List<Item> messages;
+
+ /**
+ * 鍗曟潯鍐呭祵娑堟伅蹇収
+ */
+ @Data
+ public static class Item {
+
+ /**
+ * 鍘熸秷鎭紪鍙�
+ */
+ private Long messageId;
+ /**
+ * 鍙戦�佷汉缂栧彿
+ */
+ private Long senderId;
+ /**
+ * 鍙戦�佷汉鏄电О蹇収锛涙帴鏀舵柟鍙兘涓嶅湪鍘熶細璇濋噷锛屾棤娉曞疄鏃舵煡鍒�
+ */
+ private String senderNickname;
+ /**
+ * 鍙戦�佷汉澶村儚蹇収
+ */
+ private String senderAvatar;
+ /**
+ * 娑堟伅绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImContentTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 鍘熸秷鎭� content锛圝SON锛�
+ */
+ private String content;
+ /**
+ * 鍙戦�佹椂闂存埑锛堟绉掞級
+ */
+ private Long sendTime;
+
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/QuoteMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/QuoteMessage.java
new file mode 100644
index 0000000..a06d417
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/QuoteMessage.java
@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 寮曠敤娑堟伅鍐呭
+ * <p>
+ * 瀹㈡埛绔湪 content.quote 閲屽啓鍏� messageId 琛ㄨ揪"寮曠敤浜嗗摢鏉℃秷鎭�"锛屾湇鍔$鍙嶆煡鍘熸秷鎭悗閲嶇畻 QuoteMessage 瑕嗙洊瀹㈡埛绔啓鍏ワ紝
+ * 閬垮厤浼�犲彂閫佷汉 / 绫诲瀷 / 鎽樿
+ *
+ * @see TextMessage 绛夌瓑娑堟伅鍐呭閲� quote 瀛楁
+ */
+@Data
+@Accessors(chain = true)
+public class QuoteMessage {
+
+ /**
+ * content JSON 閲� quote 瀛楁鍚�
+ */
+ public static final String FIELD_NAME = "quote";
+
+ /**
+ * QuoteMessage 閲� messageId 瀛楁鍚�
+ */
+ public static final String FIELD_MESSAGE_ID = "messageId";
+
+ /**
+ * 琚紩鐢ㄦ秷鎭紪鍙�
+ */
+ private Long messageId;
+ /**
+ * 琚紩鐢ㄦ秷鎭彂閫佷汉缂栧彿
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long senderId;
+ /**
+ * 琚紩鐢ㄦ秷鎭被鍨�
+ * <p>
+ * 鏋氫妇 {@link ImContentTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 鍘熸秷鎭畬鏁� content(JSON);鏈嶅姟绔鍒舵椂浼� removeQuote 闃插祵濂�
+ */
+ private String content;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/RecallMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/RecallMessage.java
new file mode 100644
index 0000000..a9ba575
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/RecallMessage.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 鎾ゅ洖鎻愮ず娑堟伅鍐呭
+ */
+@Data
+@Accessors(chain = true)
+public class RecallMessage {
+
+ /**
+ * 琚挙鍥炵殑鍘熸秷鎭紪鍙�
+ */
+ private Long messageId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/TextMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/TextMessage.java
new file mode 100644
index 0000000..4d8a66c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/TextMessage.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+
+/**
+ * 鏂囨湰娑堟伅鍐呭
+ */
+@Data
+public class TextMessage {
+
+ /**
+ * 鏂囨湰鍐呭
+ */
+ private String content;
+
+ /**
+ * 寮曠敤娑堟伅锛堝彲閫夛級
+ */
+ private QuoteMessage quote;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/VideoMessage.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/VideoMessage.java
new file mode 100644
index 0000000..5bceef1
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/VideoMessage.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
+
+import lombok.Data;
+
+/**
+ * 瑙嗛娑堟伅鍐呭
+ */
+@Data
+public class VideoMessage {
+
+ /**
+ * 瑙嗛鏂囦欢 URL
+ */
+ private String url;
+ /**
+ * 瑙嗛灏侀潰 URL
+ */
+ private String coverUrl;
+ /**
+ * 瑙嗛鏃堕暱锛堢锛�
+ */
+ private Integer duration;
+ /**
+ * 瑙嗛瀹藉害
+ */
+ private Integer width;
+ /**
+ * 瑙嗛楂樺害
+ */
+ private Integer height;
+ /**
+ * 鏂囦欢澶у皬锛堝瓧鑺傦級
+ */
+ private Long size;
+
+ /**
+ * 寮曠敤娑堟伅锛堝彲閫夛級
+ */
+ private QuoteMessage quote;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcCallDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcCallDO.java
new file mode 100644
index 0000000..e6453d1
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcCallDO.java
@@ -0,0 +1,93 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.rtc;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallEndReasonEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallMediaTypeEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallStatusEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 閫氳瘽璁板綍 DO锛堟埧闂寸骇 / 涓昏〃锛�
+ * <p>
+ * 涓�閫氶�氳瘽涓�琛岋紱鐘舵�佹満 CREATED 鈫� RUNNING 鈫� ENDED锛涘拰鏄庣粏琛� {@link ImRtcParticipantDO} 閫氳繃 {@link #room} 鍏宠仈
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_rtc_call")
+@KeySequence("im_rtc_call_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷锛汳ySQL 绛夋暟鎹簱鍙笉鍐�
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImRtcCallDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 涓氬姟閫氳瘽缂栧彿锛圲UID锛屽悓鏃朵綔涓� LiveKit 鎴块棿鍚嶏級锛涘敮涓�
+ */
+ private String room;
+ /**
+ * 浼氳瘽绫诲瀷
+ *
+ * 鏋氫妇 {@link ImConversationTypeEnum}
+ */
+ private Integer conversationType;
+ /**
+ * 濯掍綋绫诲瀷
+ *
+ * 鏋氫妇 {@link ImRtcCallMediaTypeEnum}
+ */
+ private Integer mediaType;
+ /**
+ * 鍙戣捣浜虹敤鎴风紪鍙�
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long inviterUserId;
+ /**
+ * 缇ょ紪鍙凤紱绉佽亰涓� NULL
+ * <p>
+ * 鍏宠仈 {@link ImGroupDO#getId()}
+ */
+ private Long groupId;
+ /**
+ * 閫氳瘽鐘舵��
+ *
+ * 鏋氫妇 {@link ImRtcCallStatusEnum}
+ */
+ private Integer status;
+ /**
+ * 缁撴潫鍘熷洜锛涢�氳瘽鏈粨鏉熸椂涓� NULL
+ *
+ * 鏋氫妇 {@link ImRtcCallEndReasonEnum}
+ */
+ private Integer endReason;
+ /**
+ * 鍙戣捣鏃堕棿
+ */
+ private LocalDateTime startTime;
+ /**
+ * 鎺ラ�氭椂闂�
+ *
+ * 棣栦釜闈炲彂璧蜂汉鍔犲叆鏃跺啓鍏ワ紱鏈帴閫氫繚鎸� NULL
+ */
+ private LocalDateTime acceptTime;
+ /**
+ * 閫氳瘽缁撴潫鏃堕棿
+ */
+ private LocalDateTime endTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcParticipantDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcParticipantDO.java
new file mode 100644
index 0000000..4282baa
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcParticipantDO.java
@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.rtc;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantRoleEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantStatusEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 閫氳瘽鍙備笌鑰� DO锛堢敤鎴风骇 / 鏄庣粏琛級
+ * <p>
+ * 涓�閫氶�氳瘽姣忎釜鍙備笌鑰呬竴琛岋紱閫氳繃 {@link #room} 鍏宠仈涓昏〃 {@link ImRtcCallDO}
+ * <p>
+ * 缁堟�侀棴鍚堬細閫氳瘽 ENDED 鏃舵墍鏈夋槑缁� status 蹇呭睘 {LEFT / REJECTED / NO_ANSWER} 涔嬩竴
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_rtc_participant")
+@KeySequence("im_rtc_participant_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷锛汳ySQL 绛夋暟鎹簱鍙笉鍐�
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImRtcParticipantDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 閫氳瘽缂栧彿
+ * <p>
+ * 鍏宠仈 {@link ImRtcCallDO#getId()}
+ */
+ private Long callId;
+ /**
+ * 涓氬姟閫氳瘽缂栧彿
+ * <p>
+ * 鍏宠仈 {@link ImRtcCallDO#getRoom()}
+ */
+ private String room;
+ /**
+ * 鍙備笌鑰呯敤鎴风紪鍙�
+ * <p>
+ * 鍏宠仈 AdminUserDO 鐨� id 瀛楁
+ */
+ private Long userId;
+ /**
+ * 鍙備笌瑙掕壊
+ *
+ * 鏋氫妇 {@link ImRtcParticipantRoleEnum}
+ */
+ private Integer role;
+ /**
+ * 鍙備笌鐘舵��
+ *
+ * 鏋氫妇 {@link ImRtcParticipantStatusEnum}
+ */
+ private Integer status;
+ /**
+ * 琚個璇锋椂闂达紱鍙戣捣浜哄彇閫氳瘽 startTime
+ */
+ private LocalDateTime inviteTime;
+ /**
+ * 鎺ュ惉鏃堕棿锛涙湭鎺ュ惉 NULL
+ */
+ private LocalDateTime acceptTime;
+ /**
+ * 绂诲紑鏃堕棿锛涙湭鍔犲叆 NULL
+ */
+ private LocalDateTime leaveTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/sensitiveword/ImSensitiveWordDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/sensitiveword/ImSensitiveWordDO.java
new file mode 100644
index 0000000..4f6d1fc
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/sensitiveword/ImSensitiveWordDO.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.im.dal.dataobject.sensitiveword;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * IM 鏁忔劅璇� DO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("im_sensitive_word")
+@KeySequence("im_sensitive_word_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImSensitiveWordDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 鏁忔劅璇�
+ */
+ private String word;
+ /**
+ * 鐘舵��
+ * <p>
+ * 鏋氫妇 {@link CommonStatusEnum}
+ */
+ private Integer status;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/channel/ImChannelMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/channel/ImChannelMapper.java
new file mode 100644
index 0000000..faab2b5
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/channel/ImChannelMapper.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.im.dal.mysql.channel;
+
+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.module.im.controller.admin.manager.channel.vo.channel.ImChannelPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * IM 棰戦亾 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImChannelMapper extends BaseMapperX<ImChannelDO> {
+
+ default ImChannelDO selectByCode(String code) {
+ return selectOne(ImChannelDO::getCode, code);
+ }
+
+ default List<ImChannelDO> selectListByStatusOrderBySort(Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImChannelDO>()
+ .eq(ImChannelDO::getStatus, status)
+ .orderByAsc(ImChannelDO::getSort));
+ }
+
+ default PageResult<ImChannelDO> selectPage(ImChannelPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImChannelDO>()
+ .likeIfPresent(ImChannelDO::getCode, reqVO.getCode())
+ .likeIfPresent(ImChannelDO::getName, reqVO.getName())
+ .eqIfPresent(ImChannelDO::getStatus, reqVO.getStatus())
+ .orderByAsc(ImChannelDO::getSort)
+ .orderByDesc(ImChannelDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/channel/ImChannelMaterialMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/channel/ImChannelMaterialMapper.java
new file mode 100644
index 0000000..421bae8
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/channel/ImChannelMaterialMapper.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.im.dal.mysql.channel;
+
+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.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * IM 棰戦亾绱犳潗 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImChannelMaterialMapper extends BaseMapperX<ImChannelMaterialDO> {
+
+ default Long selectCountByChannelId(Long channelId) {
+ return selectCount(ImChannelMaterialDO::getChannelId, channelId);
+ }
+
+ default List<ImChannelMaterialDO> selectListByChannelId(Long channelId) {
+ return selectList(new LambdaQueryWrapperX<ImChannelMaterialDO>()
+ .eq(ImChannelMaterialDO::getChannelId, channelId)
+ .orderByDesc(ImChannelMaterialDO::getId));
+ }
+
+ default PageResult<ImChannelMaterialDO> selectPage(ImChannelMaterialPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImChannelMaterialDO>()
+ .eqIfPresent(ImChannelMaterialDO::getChannelId, reqVO.getChannelId())
+ .eqIfPresent(ImChannelMaterialDO::getType, reqVO.getType())
+ .likeIfPresent(ImChannelMaterialDO::getTitle, reqVO.getTitle())
+ .betweenIfPresent(ImChannelMaterialDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(ImChannelMaterialDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationReadMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationReadMapper.java
new file mode 100644
index 0000000..45a702f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationReadMapper.java
@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.module.im.dal.mysql.conversation;
+
+import cn.hutool.core.date.LocalDateTimeUtil;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationReadDO;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 浼氳瘽璇讳綅缃� Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImConversationReadMapper extends BaseMapperX<ImConversationReadDO> {
+
+ default ImConversationReadDO selectByUserIdAndConversation(Long userId, Integer conversationType, Long conversationId) {
+ return selectOne(new LambdaQueryWrapperX<ImConversationReadDO>()
+ .eq(ImConversationReadDO::getUserId, userId)
+ .eq(ImConversationReadDO::getConversationType, conversationType)
+ .eq(ImConversationReadDO::getTargetId, conversationId));
+ }
+
+ default List<ImConversationReadDO> selectListByConversation(Integer conversationType, Long conversationId) {
+ return selectList(new LambdaQueryWrapperX<ImConversationReadDO>()
+ .eq(ImConversationReadDO::getConversationType, conversationType)
+ .eq(ImConversationReadDO::getTargetId, conversationId));
+ }
+
+ default List<ImConversationReadDO> selectListByUserIdAndConversations(Long userId, Integer conversationType,
+ Collection<Long> conversationIds) {
+ return selectList(new LambdaQueryWrapperX<ImConversationReadDO>()
+ .eq(ImConversationReadDO::getUserId, userId)
+ .eq(ImConversationReadDO::getConversationType, conversationType)
+ .in(ImConversationReadDO::getTargetId, conversationIds));
+ }
+
+ /**
+ * 澧為噺鎷夊彇褰撳墠鐢ㄦ埛鐨勪細璇濊浣嶇疆锛堟寜 update_time + id 姝e悜娓告爣锛�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param lastUpdateTime 涓婃鎷夊彇鍒扮殑鏇存柊鏃堕棿锛涢娆℃媺鍙栦紶 null
+ * @param lastId 涓婃鎷夊彇鍒扮殑璁板綍缂栧彿锛涢娆℃媺鍙栦紶 null
+ * @param limit 鎷夊彇鏁伴噺
+ * @return 浼氳瘽璇讳綅缃垪琛�
+ */
+ default List<ImConversationReadDO> selectPullListByUserId(Long userId, Long lastUpdateTime, Long lastId, Integer limit) {
+ LambdaQueryWrapperX<ImConversationReadDO> query = new LambdaQueryWrapperX<ImConversationReadDO>()
+ .eq(ImConversationReadDO::getUserId, userId);
+ if (lastUpdateTime != null && lastId != null) {
+ LocalDateTime lastTime = LocalDateTimeUtil.of(lastUpdateTime);
+ query.and(w -> w.gt(ImConversationReadDO::getUpdateTime, lastTime)
+ .or(n -> n.eq(ImConversationReadDO::getUpdateTime, lastTime).gt(ImConversationReadDO::getId, lastId)));
+ }
+ return selectList(query.orderByAsc(ImConversationReadDO::getUpdateTime).orderByAsc(ImConversationReadDO::getId)
+ .last("LIMIT " + limit));
+ }
+
+ /**
+ * 鍗曡皟閫掑鏇存柊璇讳綅缃細浠呭綋鏂颁綅缃洿澶ф椂鎵嶆洿鏂�
+ * <p>
+ * 閫氳繃 {@code read_message_id < messageId} 鐨� CAS 鏉′欢锛屼繚璇佷贡搴� / 骞跺彂涓婃姤鏃惰浣嶇疆涓嶄細鍥為��銆�
+ *
+ * @param id 璁板綍缂栧彿
+ * @param messageId 鏂扮殑鏈�澶у凡璇绘秷鎭紪鍙�
+ * @param readTime 宸茶鏃堕棿
+ * @return 褰卞搷琛屾暟锛�0 琛ㄧず鏂颁綅缃笉澶т簬宸叉湁浣嶇疆锛屾湭鏇存柊
+ */
+ default int updateReadMessageIdToLarger(Long id, Long messageId, LocalDateTime readTime) {
+ return update(null, Wrappers.<ImConversationReadDO>lambdaUpdate()
+ .set(ImConversationReadDO::getMessageId, messageId)
+ .set(ImConversationReadDO::getReadTime, readTime)
+ .set(ImConversationReadDO::getUpdateTime, readTime)
+ .eq(ImConversationReadDO::getId, id)
+ .lt(ImConversationReadDO::getMessageId, messageId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackItemMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackItemMapper.java
new file mode 100644
index 0000000..622a319
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackItemMapper.java
@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.im.dal.mysql.face;
+
+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.module.im.controller.admin.manager.face.vo.item.ImFacePackItemPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 琛ㄦ儏鍖呴」 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImFacePackItemMapper extends BaseMapperX<ImFacePackItemDO> {
+
+ default List<ImFacePackItemDO> selectListByPackIdsAndStatus(Collection<Long> packIds, Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImFacePackItemDO>()
+ .in(ImFacePackItemDO::getPackId, packIds)
+ .eq(ImFacePackItemDO::getStatus, status)
+ .orderByAsc(ImFacePackItemDO::getPackId)
+ .orderByAsc(ImFacePackItemDO::getSort)
+ .orderByAsc(ImFacePackItemDO::getId));
+ }
+
+ default Long selectCountByPackId(Long packId) {
+ return selectCount(new LambdaQueryWrapperX<ImFacePackItemDO>()
+ .eq(ImFacePackItemDO::getPackId, packId));
+ }
+
+ default Long selectCountByPackIds(Collection<Long> packIds) {
+ return selectCount(new LambdaQueryWrapperX<ImFacePackItemDO>()
+ .in(ImFacePackItemDO::getPackId, packIds));
+ }
+
+ default PageResult<ImFacePackItemDO> selectPage(ImFacePackItemPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImFacePackItemDO>()
+ .eqIfPresent(ImFacePackItemDO::getPackId, reqVO.getPackId())
+ .likeIfPresent(ImFacePackItemDO::getName, reqVO.getName())
+ .eqIfPresent(ImFacePackItemDO::getStatus, reqVO.getStatus())
+ .orderByAsc(ImFacePackItemDO::getSort)
+ .orderByDesc(ImFacePackItemDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackMapper.java
new file mode 100644
index 0000000..2864d61
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackMapper.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.im.dal.mysql.face;
+
+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.module.im.controller.admin.manager.face.vo.pack.ImFacePackPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * IM 琛ㄦ儏鍖� Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImFacePackMapper extends BaseMapperX<ImFacePackDO> {
+
+ default List<ImFacePackDO> selectListByStatusOrderBySort(Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImFacePackDO>()
+ .eq(ImFacePackDO::getStatus, status)
+ .orderByAsc(ImFacePackDO::getSort)
+ .orderByAsc(ImFacePackDO::getId));
+ }
+
+ default PageResult<ImFacePackDO> selectPage(ImFacePackPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImFacePackDO>()
+ .likeIfPresent(ImFacePackDO::getName, reqVO.getName())
+ .eqIfPresent(ImFacePackDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(ImFacePackDO::getCreateTime, reqVO.getCreateTime())
+ .orderByAsc(ImFacePackDO::getSort)
+ .orderByDesc(ImFacePackDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java
new file mode 100644
index 0000000..5eb2dc7
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.im.dal.mysql.face;
+
+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.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * IM 鐢ㄦ埛绉佹湁琛ㄦ儏 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImFaceUserItemMapper extends BaseMapperX<ImFaceUserItemDO> {
+
+ default List<ImFaceUserItemDO> selectListByUserId(Long userId) {
+ return selectList(new LambdaQueryWrapperX<ImFaceUserItemDO>()
+ .eq(ImFaceUserItemDO::getUserId, userId)
+ .orderByAsc(ImFaceUserItemDO::getSort)
+ .orderByDesc(ImFaceUserItemDO::getId));
+ }
+
+ default ImFaceUserItemDO selectByUserIdAndUrl(Long userId, String url) {
+ return selectOne(new LambdaQueryWrapperX<ImFaceUserItemDO>()
+ .eq(ImFaceUserItemDO::getUserId, userId)
+ .eq(ImFaceUserItemDO::getUrl, url));
+ }
+
+ default Long selectCountByUserId(Long userId) {
+ return selectCount(ImFaceUserItemDO::getUserId, userId);
+ }
+
+ default PageResult<ImFaceUserItemDO> selectPage(ImFaceUserItemManagerPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImFaceUserItemDO>()
+ .eqIfPresent(ImFaceUserItemDO::getUserId, reqVO.getUserId())
+ .likeIfPresent(ImFaceUserItemDO::getName, reqVO.getName())
+ .betweenIfPresent(ImFaceUserItemDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(ImFaceUserItemDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendMapper.java
new file mode 100644
index 0000000..8673100
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendMapper.java
@@ -0,0 +1,110 @@
+package cn.iocoder.yudao.module.im.dal.mysql.friend;
+
+import cn.hutool.core.date.LocalDateTimeUtil;
+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.module.im.controller.admin.manager.friend.vo.ImFriendManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 濂藉弸鍏崇郴 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImFriendMapper extends BaseMapperX<ImFriendDO> {
+
+ default ImFriendDO selectByUserIdAndFriendUserId(Long userId, Long friendUserId) {
+ return selectOne(new LambdaQueryWrapperX<ImFriendDO>()
+ .eq(ImFriendDO::getUserId, userId)
+ .eq(ImFriendDO::getFriendUserId, friendUserId));
+ }
+
+ default List<ImFriendDO> selectListByUserId(Long userId) {
+ return selectList(new LambdaQueryWrapperX<ImFriendDO>()
+ .eq(ImFriendDO::getUserId, userId)
+ .orderByDesc(ImFriendDO::getId));
+ }
+
+ /**
+ * 澧為噺鎷夊彇褰撳墠鐢ㄦ埛鐨勫ソ鍙嬪叧绯伙紙鍚凡鍒犻櫎锛屾寜 update_time + id 姝e悜娓告爣锛�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param lastUpdateTime 涓婃鎷夊彇鍒扮殑鏇存柊鏃堕棿锛涢娆℃媺鍙栦紶 null
+ * @param lastId 涓婃鎷夊彇鍒扮殑璁板綍缂栧彿锛涢娆℃媺鍙栦紶 null
+ * @param limit 鎷夊彇鏁伴噺
+ * @return 濂藉弸鍏崇郴鍒楄〃
+ */
+ default List<ImFriendDO> selectPullListByUserId(Long userId, Long lastUpdateTime, Long lastId, Integer limit) {
+ LambdaQueryWrapperX<ImFriendDO> query = new LambdaQueryWrapperX<ImFriendDO>()
+ .eq(ImFriendDO::getUserId, userId);
+ if (lastUpdateTime != null && lastId != null) {
+ LocalDateTime lastTime = LocalDateTimeUtil.of(lastUpdateTime);
+ query.and(w -> w.gt(ImFriendDO::getUpdateTime, lastTime)
+ .or(n -> n.eq(ImFriendDO::getUpdateTime, lastTime).gt(ImFriendDO::getId, lastId)));
+ }
+ return selectList(query.orderByAsc(ImFriendDO::getUpdateTime).orderByAsc(ImFriendDO::getId)
+ .last("LIMIT " + limit));
+ }
+
+ default List<ImFriendDO> selectListByUserIdAndStatus(Long userId, Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImFriendDO>()
+ .eq(ImFriendDO::getUserId, userId)
+ .eq(ImFriendDO::getStatus, status)
+ .orderByDesc(ImFriendDO::getId));
+ }
+
+ default List<ImFriendDO> selectListByUserIdAndFriendUserIdsAndStatus(Long userId,
+ Collection<Long> friendUserIds,
+ Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImFriendDO>()
+ .eq(ImFriendDO::getUserId, userId)
+ .in(ImFriendDO::getFriendUserId, friendUserIds)
+ .eq(ImFriendDO::getStatus, status));
+ }
+
+ default List<ImFriendDO> selectListByUserIdsAndFriendUserIdAndStatus(Collection<Long> userIds,
+ Long friendUserId,
+ Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImFriendDO>()
+ .in(ImFriendDO::getUserId, userIds)
+ .eq(ImFriendDO::getFriendUserId, friendUserId)
+ .eq(ImFriendDO::getStatus, status));
+ }
+
+ default PageResult<ImFriendDO> selectPage(ImFriendManagerPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImFriendDO>()
+ .eqIfPresent(ImFriendDO::getUserId, reqVO.getUserId())
+ .eqIfPresent(ImFriendDO::getFriendUserId, reqVO.getFriendUserId())
+ .eqIfPresent(ImFriendDO::getStatus, reqVO.getStatus())
+ .eqIfPresent(ImFriendDO::getSilent, reqVO.getSilent())
+ .betweenIfPresent(ImFriendDO::getAddTime, reqVO.getAddTime())
+ .orderByDesc(ImFriendDO::getId));
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateReAddFields(Long id, Integer status, LocalDateTime addTime,
+ LocalDateTime updateTime,
+ Boolean silent, Boolean pinned, Boolean blocked,
+ String displayName, Integer addSource) {
+ return update(null, Wrappers.<ImFriendDO>lambdaUpdate()
+ .eq(ImFriendDO::getId, id)
+ .set(ImFriendDO::getStatus, status)
+ .set(ImFriendDO::getAddTime, addTime)
+ .set(ImFriendDO::getUpdateTime, updateTime)
+ .set(ImFriendDO::getSilent, silent)
+ .set(ImFriendDO::getPinned, pinned)
+ .set(ImFriendDO::getBlocked, blocked)
+ .set(ImFriendDO::getDisplayName, displayName)
+ .set(ImFriendDO::getAddSource, addSource)
+ .set(ImFriendDO::getDeleteTime, null));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapper.java
new file mode 100644
index 0000000..6dffaa5
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapper.java
@@ -0,0 +1,110 @@
+package cn.iocoder.yudao.module.im.dal.mysql.friend;
+
+import cn.hutool.core.date.LocalDateTimeUtil;
+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.module.im.controller.admin.manager.friend.vo.ImFriendRequestManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendRequestHandleResultEnum;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * IM 濂藉弸鐢宠璁板綍 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImFriendRequestMapper extends BaseMapperX<ImFriendRequestDO> {
+
+ default ImFriendRequestDO selectByFromUserIdAndToUserId(Long fromUserId, Long toUserId) {
+ return selectOne(new LambdaQueryWrapperX<ImFriendRequestDO>()
+ .eq(ImFriendRequestDO::getFromUserId, fromUserId)
+ .eq(ImFriendRequestDO::getToUserId, toUserId));
+ }
+
+ /**
+ * 鎷夊彇銆屾垜鐩稿叧銆嶇殑濂藉弸鐢宠鍒楄〃
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param maxRequestUpdateTime 璧峰鏇存柊鏃堕棿锛涢娆℃媺鍙栦紶 null
+ * @param maxId 璧峰璁板綍缂栧彿锛涢娆℃媺鍙栦紶 null
+ * @param limit 鎷夊彇鏁伴噺
+ * @return 濂藉弸鐢宠鍒楄〃
+ */
+ default List<ImFriendRequestDO> selectMyList(Long userId, LocalDateTime maxRequestUpdateTime,
+ Long maxId, int limit) {
+ LambdaQueryWrapperX<ImFriendRequestDO> wrapper = new LambdaQueryWrapperX<>();
+ wrapper.and(w -> w.eq(ImFriendRequestDO::getFromUserId, userId)
+ .or().eq(ImFriendRequestDO::getToUserId, userId));
+ if (maxRequestUpdateTime != null && maxId != null) {
+ wrapper.and(w -> w.lt(ImFriendRequestDO::getUpdateTime, maxRequestUpdateTime)
+ .or(n -> n.eq(ImFriendRequestDO::getUpdateTime, maxRequestUpdateTime)
+ .lt(ImFriendRequestDO::getId, maxId)));
+ }
+ wrapper.orderByDesc(ImFriendRequestDO::getUpdateTime)
+ .orderByDesc(ImFriendRequestDO::getId)
+ .last("LIMIT " + limit);
+ return selectList(wrapper);
+ }
+
+ /**
+ * 澧為噺鎷夊彇銆屾垜鐩稿叧銆嶇殑濂藉弸鐢宠锛堝弻鍚� OR锛屾寜 update_time + id 姝e悜娓告爣锛�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param lastUpdateTime 涓婃鎷夊彇鍒扮殑鏇存柊鏃堕棿锛涢娆℃媺鍙栦紶 null
+ * @param lastId 涓婃鎷夊彇鍒扮殑璁板綍缂栧彿锛涢娆℃媺鍙栦紶 null
+ * @param limit 鎷夊彇鏁伴噺
+ * @return 濂藉弸鐢宠鍒楄〃
+ */
+ default List<ImFriendRequestDO> selectPullListByUserId(Long userId, Long lastUpdateTime, Long lastId, Integer limit) {
+ LambdaQueryWrapperX<ImFriendRequestDO> query = new LambdaQueryWrapperX<>();
+ query.and(w -> w.eq(ImFriendRequestDO::getFromUserId, userId)
+ .or().eq(ImFriendRequestDO::getToUserId, userId));
+ if (lastUpdateTime != null && lastId != null) {
+ LocalDateTime lastTime = LocalDateTimeUtil.of(lastUpdateTime);
+ query.and(w -> w.gt(ImFriendRequestDO::getUpdateTime, lastTime)
+ .or(n -> n.eq(ImFriendRequestDO::getUpdateTime, lastTime).gt(ImFriendRequestDO::getId, lastId)));
+ }
+ return selectList(query.orderByAsc(ImFriendRequestDO::getUpdateTime).orderByAsc(ImFriendRequestDO::getId)
+ .last("LIMIT " + limit));
+ }
+
+ default int updateByIdAndHandleResult(Long id, Integer handleResult, ImFriendRequestDO updateObj) {
+ return update(updateObj, new LambdaUpdateWrapper<ImFriendRequestDO>()
+ .eq(ImFriendRequestDO::getId, id).eq(ImFriendRequestDO::getHandleResult, handleResult));
+ }
+
+ /**
+ * 澶嶇敤 (fromUserId, toUserId) 鏃х敵璇疯褰曪細瑕嗙洊鐢宠鐞嗙敱 / 澶囨敞 / 鏉ユ簮锛岄噸缃负鏈鐞� + 娓呯┖鏃у鐞嗙棔杩�
+ * <p>
+ * handleContent / handleTime 璧� LambdaUpdateWrapper.set 鏄惧紡缃� null锛寀pdateById 榛樿浼氬拷鐣� null 瀛楁
+ */
+ default int updateByIdReset(Long id, String applyContent, String displayName, Integer addSource,
+ LocalDateTime updateTime) {
+ return update(null, new LambdaUpdateWrapper<ImFriendRequestDO>()
+ .eq(ImFriendRequestDO::getId, id)
+ .set(ImFriendRequestDO::getApplyContent, applyContent)
+ .set(ImFriendRequestDO::getDisplayName, displayName)
+ .set(ImFriendRequestDO::getAddSource, addSource)
+ .set(ImFriendRequestDO::getHandleResult, ImFriendRequestHandleResultEnum.UNHANDLED.getResult())
+ .set(ImFriendRequestDO::getHandleContent, null)
+ .set(ImFriendRequestDO::getHandleTime, null)
+ .set(ImFriendRequestDO::getUpdateTime, updateTime));
+ }
+
+ default PageResult<ImFriendRequestDO> selectPage(ImFriendRequestManagerPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImFriendRequestDO>()
+ .eqIfPresent(ImFriendRequestDO::getFromUserId, reqVO.getFromUserId())
+ .eqIfPresent(ImFriendRequestDO::getToUserId, reqVO.getToUserId())
+ .eqIfPresent(ImFriendRequestDO::getHandleResult, reqVO.getHandleResult())
+ .eqIfPresent(ImFriendRequestDO::getAddSource, reqVO.getAddSource())
+ .betweenIfPresent(ImFriendRequestDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(ImFriendRequestDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMapper.java
new file mode 100644
index 0000000..7f56a1a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMapper.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.im.dal.mysql.group;
+
+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.module.im.controller.admin.manager.group.vo.ImGroupManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * IM 缇� Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImGroupMapper extends BaseMapperX<ImGroupDO> {
+
+ default ImGroupDO selectByIdForUpdate(Long id) {
+ return selectOne(new LambdaQueryWrapperX<ImGroupDO>()
+ .eq(ImGroupDO::getId, id)
+ .last("FOR UPDATE"));
+ }
+
+ default PageResult<ImGroupDO> selectPage(ImGroupManagerPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImGroupDO>()
+ .likeIfPresent(ImGroupDO::getName, reqVO.getName())
+ .eqIfPresent(ImGroupDO::getOwnerUserId, reqVO.getOwnerUserId())
+ .eqIfPresent(ImGroupDO::getStatus, reqVO.getStatus())
+ .eqIfPresent(ImGroupDO::getBanned, reqVO.getBanned())
+ .betweenIfPresent(ImGroupDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(ImGroupDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMemberMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMemberMapper.java
new file mode 100644
index 0000000..2afa559
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMemberMapper.java
@@ -0,0 +1,137 @@
+package cn.iocoder.yudao.module.im.dal.mysql.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * IM 缇ゆ垚鍛� Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImGroupMemberMapper extends BaseMapperX<ImGroupMemberDO> {
+
+ default List<ImGroupMemberDO> selectListByGroupId(Long groupId) {
+ return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>().eq(ImGroupMemberDO::getGroupId, groupId));
+ }
+
+ default ImGroupMemberDO selectByGroupIdAndUserId(Long groupId, Long userId) {
+ return selectOne(new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getGroupId, groupId)
+ .eq(ImGroupMemberDO::getUserId, userId));
+ }
+
+ default List<ImGroupMemberDO> selectListByGroupIdAndUserIds(Long groupId, Collection<Long> userIds) {
+ return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getGroupId, groupId)
+ .in(ImGroupMemberDO::getUserId, userIds));
+ }
+
+ default List<ImGroupMemberDO> selectListByGroupIdAndStatus(Long groupId, Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getGroupId, groupId)
+ .eq(ImGroupMemberDO::getStatus, status));
+ }
+
+ default List<ImGroupMemberDO> selectListByGroupIdAndStatusAndRoles(Long groupId, Integer status,
+ Collection<Integer> roles) {
+ return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getGroupId, groupId)
+ .eq(ImGroupMemberDO::getStatus, status)
+ .in(ImGroupMemberDO::getRole, roles));
+ }
+
+ default List<ImGroupMemberDO> selectListByUserIdAndStatus(Long userId, Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getUserId, userId)
+ .eq(ImGroupMemberDO::getStatus, status));
+ }
+
+ default List<ImGroupMemberDO> selectListByUserId(Long userId) {
+ return selectList(ImGroupMemberDO::getUserId, userId);
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateByGroupIdAndStatus(Long groupId, Integer oldStatus, ImGroupMemberDO updateObj) {
+ return update(updateObj, new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getGroupId, groupId)
+ .eq(ImGroupMemberDO::getStatus, oldStatus));
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateByGroupIdAndUserIdsAndStatus(Long groupId, Collection<Long> userIds,
+ Integer oldStatus, ImGroupMemberDO updateObj) {
+ return update(updateObj, new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getGroupId, groupId)
+ .in(ImGroupMemberDO::getUserId, userIds)
+ .eq(ImGroupMemberDO::getStatus, oldStatus));
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateListByGroupIdAndUserIds(Long groupId, Collection<Long> userIds, ImGroupMemberDO updateObj) {
+ return update(updateObj, new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getGroupId, groupId)
+ .in(ImGroupMemberDO::getUserId, userIds));
+ }
+
+ default Long selectCountByGroupIdAndRoleAndStatus(Long groupId, Integer role, Integer status) {
+ return selectCount(new LambdaQueryWrapperX<ImGroupMemberDO>()
+ .eq(ImGroupMemberDO::getGroupId, groupId)
+ .eq(ImGroupMemberDO::getRole, role)
+ .eq(ImGroupMemberDO::getStatus, status));
+ }
+
+ /**
+ * 鎵归噺鎸� group_id 缁熻鎸囧畾鐘舵�佺殑鎴愬憳鏁�
+ */
+ default Map<Long, Long> selectCountMapByGroupIdsAndStatus(Collection<Long> groupIds, Integer status) {
+ if (CollUtil.isEmpty(groupIds)) {
+ return Collections.emptyMap();
+ }
+ List<Map<String, Object>> rows = selectMaps(Wrappers.<ImGroupMemberDO>query()
+ .select("group_id AS groupId", "COUNT(*) AS cnt")
+ .in("group_id", groupIds)
+ .eq("status", status)
+ .groupBy("group_id"));
+ // 杞崲鎴� Map<Long, Long>
+ Map<Long, Long> result = new HashMap<>(rows.size());
+ rows.forEach(row -> result.put(
+ ((Number) row.get("groupId")).longValue(),
+ ((Number) row.get("cnt")).longValue()));
+ return result;
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateMuteEndTimeNull(Long id) {
+ return update(null, Wrappers.<ImGroupMemberDO>lambdaUpdate()
+ .eq(ImGroupMemberDO::getId, id)
+ .set(ImGroupMemberDO::getMuteEndTime, null));
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateRejoinFields(Long id, Integer status, LocalDateTime joinTime,
+ Integer role, Integer addSource, Long inviterUserId) {
+ return update(null, Wrappers.<ImGroupMemberDO>lambdaUpdate()
+ .eq(ImGroupMemberDO::getId, id)
+ .set(ImGroupMemberDO::getStatus, status)
+ .set(ImGroupMemberDO::getJoinTime, joinTime)
+ .set(ImGroupMemberDO::getRole, role)
+ .set(ImGroupMemberDO::getAddSource, addSource)
+ .set(ImGroupMemberDO::getInviterUserId, inviterUserId)
+ .set(ImGroupMemberDO::getQuitTime, null)
+ .set(ImGroupMemberDO::getMuteEndTime, null)
+ .set(ImGroupMemberDO::getUpdateTime, joinTime));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupRequestMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupRequestMapper.java
new file mode 100644
index 0000000..c344493
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupRequestMapper.java
@@ -0,0 +1,116 @@
+package cn.iocoder.yudao.module.im.dal.mysql.group;
+
+import cn.hutool.core.date.LocalDateTimeUtil;
+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.module.im.controller.admin.manager.group.vo.ImGroupRequestManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupRequestDO;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupRequestHandleResultEnum;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 鍔犵兢鐢宠璁板綍 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImGroupRequestMapper extends BaseMapperX<ImGroupRequestDO> {
+
+ default ImGroupRequestDO selectByGroupIdAndUserId(Long groupId, Long userId) {
+ return selectOne(new LambdaQueryWrapperX<ImGroupRequestDO>()
+ .eq(ImGroupRequestDO::getGroupId, groupId)
+ .eq(ImGroupRequestDO::getUserId, userId));
+ }
+
+ default List<ImGroupRequestDO> selectListByGroupIdsAndHandleResult(Collection<Long> groupIds, Integer handleResult) {
+ return selectList(new LambdaQueryWrapperX<ImGroupRequestDO>()
+ .in(ImGroupRequestDO::getGroupId, groupIds)
+ .eq(ImGroupRequestDO::getHandleResult, handleResult)
+ .orderByDesc(ImGroupRequestDO::getUpdateTime)
+ .orderByDesc(ImGroupRequestDO::getId));
+ }
+
+ default List<ImGroupRequestDO> selectListByGroupId(Long groupId) {
+ // 鍚屼笂锛寀pdate_time 鍊掑簭浼樺厛浜� id
+ return selectList(new LambdaQueryWrapperX<ImGroupRequestDO>()
+ .eq(ImGroupRequestDO::getGroupId, groupId)
+ .orderByDesc(ImGroupRequestDO::getUpdateTime)
+ .orderByDesc(ImGroupRequestDO::getId));
+ }
+
+ /**
+ * 澧為噺鎷夊彇銆屾垜绠$悊鐨勭兢銆嶄笅鐨勫姞缇ょ敵璇凤紙鍚凡澶勭悊锛屾寜 update_time + id 姝e悜娓告爣锛�
+ *
+ * @param groupIds 缇ょ紪鍙烽泦鍚�
+ * @param lastUpdateTime 涓婃鎷夊彇鍒扮殑鏇存柊鏃堕棿锛涢娆℃媺鍙栦紶 null
+ * @param lastId 涓婃鎷夊彇鍒扮殑璁板綍缂栧彿锛涢娆℃媺鍙栦紶 null
+ * @param limit 鎷夊彇鏁伴噺
+ * @return 鍔犵兢鐢宠鍒楄〃
+ */
+ default List<ImGroupRequestDO> selectPullListByGroupIds(Collection<Long> groupIds, Long lastUpdateTime,
+ Long lastId, Integer limit) {
+ LambdaQueryWrapperX<ImGroupRequestDO> query = new LambdaQueryWrapperX<ImGroupRequestDO>()
+ .in(ImGroupRequestDO::getGroupId, groupIds);
+ if (lastUpdateTime != null && lastId != null) {
+ LocalDateTime lastTime = LocalDateTimeUtil.of(lastUpdateTime);
+ query.and(w -> w.gt(ImGroupRequestDO::getUpdateTime, lastTime)
+ .or(n -> n.eq(ImGroupRequestDO::getUpdateTime, lastTime).gt(ImGroupRequestDO::getId, lastId)));
+ }
+ return selectList(query.orderByAsc(ImGroupRequestDO::getUpdateTime).orderByAsc(ImGroupRequestDO::getId)
+ .last("LIMIT " + limit));
+ }
+
+ default int updateByIdAndHandleResult(Long id, Integer expectedHandleResult, ImGroupRequestDO updateObj) {
+ return update(updateObj, new LambdaUpdateWrapper<ImGroupRequestDO>()
+ .eq(ImGroupRequestDO::getId, id).eq(ImGroupRequestDO::getHandleResult, expectedHandleResult));
+ }
+
+ /**
+ * 澶嶇敤涓诲姩鐢宠鐨勬棫璁板綍锛氳鐩栫敵璇风悊鐢� / 鏉ユ簮锛岄噸缃负鏈鐞� + 娓呯┖鏃у鐞嗙棔杩� + 鍒� update_time
+ * <p>
+ * update_time 鏄惧紡 set锛屽洜涓� update(null, wrapper) 涓嶄細瑙﹀彂 MetaObjectHandler.updateFill锛�
+ * 鍒楄〃鏌ヨ鎸� update_time 鍊掑簭锛屽鐢ㄨ褰曞繀椤诲埛杩欎竴鍒楁墠浼氭帓鍒版渶鍓�
+ */
+ default int updateApplyByIdReset(Long id, String applyContent, Integer addSource, LocalDateTime updateTime) {
+ return update(null, new LambdaUpdateWrapper<ImGroupRequestDO>()
+ .eq(ImGroupRequestDO::getId, id)
+ .set(ImGroupRequestDO::getApplyContent, applyContent)
+ .set(ImGroupRequestDO::getAddSource, addSource)
+ .set(ImGroupRequestDO::getHandleResult, ImGroupRequestHandleResultEnum.UNHANDLED.getResult())
+ .set(ImGroupRequestDO::getInviterUserId, null)
+ .set(ImGroupRequestDO::getHandleUserId, null)
+ .set(ImGroupRequestDO::getHandleContent, null)
+ .set(ImGroupRequestDO::getHandleTime, null)
+ .set(ImGroupRequestDO::getUpdateTime, updateTime));
+ }
+
+ default int updateInviteByIdReset(Long id, Long inviterUserId, Integer addSource, LocalDateTime updateTime) {
+ return update(null, new LambdaUpdateWrapper<ImGroupRequestDO>()
+ .eq(ImGroupRequestDO::getId, id)
+ .set(ImGroupRequestDO::getInviterUserId, inviterUserId)
+ .set(ImGroupRequestDO::getAddSource, addSource)
+ .set(ImGroupRequestDO::getHandleResult, ImGroupRequestHandleResultEnum.UNHANDLED.getResult())
+ .set(ImGroupRequestDO::getHandleUserId, null)
+ .set(ImGroupRequestDO::getHandleContent, null)
+ .set(ImGroupRequestDO::getHandleTime, null)
+ .set(ImGroupRequestDO::getUpdateTime, updateTime));
+ }
+
+ default PageResult<ImGroupRequestDO> selectPage(ImGroupRequestManagerPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImGroupRequestDO>()
+ .eqIfPresent(ImGroupRequestDO::getGroupId, reqVO.getGroupId())
+ .eqIfPresent(ImGroupRequestDO::getUserId, reqVO.getUserId())
+ .eqIfPresent(ImGroupRequestDO::getInviterUserId, reqVO.getInviterUserId())
+ .eqIfPresent(ImGroupRequestDO::getHandleResult, reqVO.getHandleResult())
+ .eqIfPresent(ImGroupRequestDO::getAddSource, reqVO.getAddSource())
+ .betweenIfPresent(ImGroupRequestDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(ImGroupRequestDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImChannelMessageMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImChannelMessageMapper.java
new file mode 100644
index 0000000..6f1cd1a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImChannelMessageMapper.java
@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.im.dal.mysql.message;
+
+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.im.controller.admin.manager.message.vo.channel.ImChannelMessagePageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * IM 棰戦亾娑堟伅 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImChannelMessageMapper extends BaseMapperX<ImChannelMessageDO> {
+
+ /**
+ * 鎷夊彇鎸囧畾鐢ㄦ埛搴旀敹鐨勯閬撴秷鎭�
+ * <p>
+ * 鍛戒腑鏉′欢锛歩d 澶т簬娓告爣 + (receiver_user_ids 涓虹┖琛ㄧず鍏ㄥ憳 OR 閫楀彿鍒嗛殧鍒楄〃閲屽寘鍚綋鍓� userId)
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param minId 娓告爣锛涜繑鍥炲ぇ浜庢鍊肩殑娑堟伅
+ * @param size 杩斿洖鏉℃暟
+ * @return 棰戦亾娑堟伅鍒楄〃锛涙寜 id 鍗囧簭
+ */
+ default List<ImChannelMessageDO> selectListByUserAndMinId(Long userId, Long minId, Integer size) {
+ return selectList(new LambdaQueryWrapperX<ImChannelMessageDO>()
+ .gt(ImChannelMessageDO::getId, minId)
+ .and(w -> w.isNull(ImChannelMessageDO::getReceiverUserIds)
+ .or().eq(ImChannelMessageDO::getReceiverUserIds, "")
+ .or().apply(MyBatisUtils.findInSet("receiver_user_ids"), userId))
+ .orderByAsc(ImChannelMessageDO::getId)
+ .last("LIMIT " + size));
+ }
+
+ default Long selectCountByMaterialId(Long materialId) {
+ return selectCount(ImChannelMessageDO::getMaterialId, materialId);
+ }
+
+ default PageResult<ImChannelMessageDO> selectPage(ImChannelMessagePageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImChannelMessageDO>()
+ .eqIfPresent(ImChannelMessageDO::getChannelId, reqVO.getChannelId())
+ .eqIfPresent(ImChannelMessageDO::getMaterialId, reqVO.getMaterialId())
+ .betweenIfPresent(ImChannelMessageDO::getSendTime, reqVO.getSendTime())
+ .orderByDesc(ImChannelMessageDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImGroupMessageMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImGroupMessageMapper.java
new file mode 100644
index 0000000..d0d5584
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImGroupMessageMapper.java
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.im.dal.mysql.message;
+
+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.query.QueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group.ImGroupMessageManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 缇よ亰娑堟伅 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImGroupMessageMapper extends BaseMapperX<ImGroupMessageDO> {
+
+ /**
+ * 鏍规嵁 minId + 鏃堕棿绐楀彛澧為噺鎷夊彇缇よ亰娑堟伅
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param groupIds 鍊欓�夌兢缂栧彿闆嗗悎锛堝綋鍓嶅湪缇� 鈭� 绐楀彛鍐呴��缇わ級锛屼笉鑳戒负绌�
+ * @param minId 鏈�灏忔秷鎭� id锛堜笉鍚級
+ * @param minSendTime 鏈�鏃╁彂閫佹椂闂达紙涓嶅惈锛夛紝闄愬埗绂荤嚎娑堟伅鏃堕棿绐楀彛
+ * @param size 鎷夊彇鏁伴噺
+ * @return 娑堟伅鍒楄〃锛堟寜 id 鍗囧簭锛�
+ */
+ default List<ImGroupMessageDO> selectListByMinId(Long userId, Collection<Long> groupIds, Long minId,
+ LocalDateTime minSendTime, Integer size) {
+ QueryWrapperX<ImGroupMessageDO> wrapper = new QueryWrapperX<>();
+ wrapper.in("group_id", groupIds)
+ .gt("id", minId)
+ .gt("send_time", minSendTime)
+ .apply(MyBatisUtils.findInSet("receiver_user_ids"), userId)
+ .orderByAsc("id");
+ wrapper.limitN(size);
+ return selectList(wrapper);
+ }
+
+ /**
+ * 鏌ヨ缇よ亰鍘嗗彶娑堟伅锛堟父鏍囨媺鍙栵級
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param groupId 缇ょ紪鍙�
+ * @param maxId 璧峰娑堟伅 id锛堜笉鍚級锛屼负绌哄垯浠庢渶鏂板紑濮�
+ * @param limit 鎷夊彇鏁伴噺
+ * @return 娑堟伅鍒楄〃锛堟寜 id 鍊掑簭锛�
+ */
+ default List<ImGroupMessageDO> selectHistoryListByUser(Long userId, Long groupId, Long maxId, Integer limit) {
+ QueryWrapperX<ImGroupMessageDO> wrapper = new QueryWrapperX<>();
+ wrapper.eq("group_id", groupId)
+ .lt(maxId != null, "id", maxId)
+ .apply(MyBatisUtils.findInSet("receiver_user_ids"), userId)
+ .orderByDesc("id");
+ wrapper.limitN(limit);
+ return selectList(wrapper);
+ }
+
+ default ImGroupMessageDO selectBySenderIdAndClientMessageId(Long senderId, String clientMessageId) {
+ return selectOne(new LambdaQueryWrapperX<ImGroupMessageDO>()
+ .eq(ImGroupMessageDO::getSenderId, senderId)
+ .eq(ImGroupMessageDO::getClientMessageId, clientMessageId));
+ }
+
+ /**
+ * 鏌ヨ缇ゅ唴鎸囧畾鑼冨洿鍐呭緟鍥炴墽鐨勬秷鎭�
+ * <p>
+ * 浠呭湪鐢ㄦ埛"宸茶浣嶇疆鍓嶈繘"鏃惰皟鐢紝閬垮厤鍏ㄩ噺鎵弿锛�
+ * 鍙湁浣嶄簬 (minId, maxId] 鑼冨洿鍐呫�佷笖浠嶅浜� PENDING 鐨勫洖鎵ф秷鎭彲鑳藉洜鏈宸茶鑰岀姸鎬佸彉鍖栥��
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param minId 璧峰娑堟伅 id锛堜笉鍚紝涓婁竴娆″凡璇讳綅缃級
+ * @param maxId 缁撴潫娑堟伅 id锛堝惈锛屾湰娆″凡璇讳綅缃級
+ * @return 寰呭洖鎵ф秷鎭垪琛�
+ */
+ default List<ImGroupMessageDO> selectListByGroupIdAndPendingReceipt(Long groupId, Long minId, Long maxId) {
+ return selectList(new LambdaQueryWrapperX<ImGroupMessageDO>()
+ .eq(ImGroupMessageDO::getGroupId, groupId)
+ .eq(ImGroupMessageDO::getReceiptStatus, ImMessageReceiptStatusEnum.PENDING.getStatus())
+ .gt(minId != null, ImGroupMessageDO::getId, minId)
+ .le(ImGroupMessageDO::getId, maxId)
+ .ne(ImGroupMessageDO::getStatus, ImMessageStatusEnum.RECALL.getStatus()));
+ }
+
+ default PageResult<ImGroupMessageDO> selectPage(ImGroupMessageManagerPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImGroupMessageDO>()
+ .eqIfPresent(ImGroupMessageDO::getGroupId, reqVO.getGroupId())
+ .eqIfPresent(ImGroupMessageDO::getSenderId, reqVO.getSenderId())
+ .eqIfPresent(ImGroupMessageDO::getType, reqVO.getType())
+ .likeIfPresent(ImGroupMessageDO::getContent, reqVO.getContent())
+ .eqIfPresent(ImGroupMessageDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(ImGroupMessageDO::getSendTime, reqVO.getSendTime())
+ .orderByDesc(ImGroupMessageDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapper.java
new file mode 100644
index 0000000..b666dfb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapper.java
@@ -0,0 +1,99 @@
+package cn.iocoder.yudao.module.im.dal.mysql.message;
+
+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.query.QueryWrapperX;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates.ImPrivateMessageManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * IM 绉佽亰娑堟伅 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImPrivateMessageMapper extends BaseMapperX<ImPrivateMessageDO> {
+
+ /**
+ * 鏍规嵁 minId + 鏃堕棿绐楀彛澧為噺鎷夊彇绉佽亰娑堟伅
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param minId 鏈�灏忔秷鎭� id锛堜笉鍚級
+ * @param minSendTime 鏈�鏃╁彂閫佹椂闂达紙涓嶅惈锛夛紝闄愬埗绂荤嚎娑堟伅鏃堕棿绐楀彛
+ * @param size 鎷夊彇鏁伴噺
+ * @return 娑堟伅鍒楄〃
+ */
+ default List<ImPrivateMessageDO> selectListByMinId(Long userId, Long minId,
+ LocalDateTime minSendTime, Integer size) {
+ QueryWrapperX<ImPrivateMessageDO> wrapper = new QueryWrapperX<>();
+ wrapper.and(w -> w.eq("sender_id", userId)
+ .or()
+ .eq("receiver_id", userId))
+ .gt("id", minId)
+ .gt("send_time", minSendTime)
+ .orderByAsc("id");
+ wrapper.limitN(size);
+ return selectList(wrapper);
+ }
+
+ /**
+ * 鏌ヨ绉佽亰鍘嗗彶娑堟伅锛堟父鏍囨媺鍙栵級
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param receiverId 瀵规柟鐢ㄦ埛缂栧彿
+ * @param maxId 璧峰娑堟伅 id锛堜笉鍚級锛屼负绌哄垯浠庢渶鏂板紑濮�
+ * @param limit 鎷夊彇鏁伴噺
+ * @return 娑堟伅鍒楄〃锛堟寜 id 鍊掑簭锛�
+ */
+ default List<ImPrivateMessageDO> selectHistoryList(Long userId, Long receiverId, Long maxId, Integer limit) {
+ QueryWrapperX<ImPrivateMessageDO> wrapper = new QueryWrapperX<>();
+ wrapper.and(w -> w.eq("sender_id", userId).eq("receiver_id", receiverId)
+ .or()
+ .eq("sender_id", receiverId).eq("receiver_id", userId))
+ .lt(maxId != null, "id", maxId)
+ .orderByDesc("id");
+ wrapper.limitN(limit);
+ return selectList(wrapper);
+ }
+
+ default ImPrivateMessageDO selectBySenderIdAndClientMessageId(Long senderId, String clientMessageId) {
+ return selectOne(new LambdaQueryWrapperX<ImPrivateMessageDO>()
+ .eq(ImPrivateMessageDO::getSenderId, senderId)
+ .eq(ImPrivateMessageDO::getClientMessageId, clientMessageId));
+ }
+
+ default int updateBySenderIdAndReceiverIdAndIdLeAndReceiptStatus(Long senderId, Long receiverId, Long maxMessageId,
+ Integer whereReceiptStatus, ImPrivateMessageDO updateObj) {
+ return update(updateObj, new LambdaQueryWrapperX<ImPrivateMessageDO>()
+ .eq(ImPrivateMessageDO::getSenderId, senderId)
+ .eq(ImPrivateMessageDO::getReceiverId, receiverId)
+ .le(ImPrivateMessageDO::getId, maxMessageId)
+ .eq(ImPrivateMessageDO::getReceiptStatus, whereReceiptStatus));
+ }
+
+ default PageResult<ImPrivateMessageDO> selectPage(ImPrivateMessageManagerPageReqVO reqVO) {
+ LambdaQueryWrapperX<ImPrivateMessageDO> query = new LambdaQueryWrapperX<>();
+ if (reqVO.getSenderId() != null && reqVO.getReceiverId() != null) {
+ query.and(w -> w.eq(ImPrivateMessageDO::getSenderId, reqVO.getSenderId())
+ .eq(ImPrivateMessageDO::getReceiverId, reqVO.getReceiverId())
+ .or()
+ .eq(ImPrivateMessageDO::getSenderId, reqVO.getReceiverId())
+ .eq(ImPrivateMessageDO::getReceiverId, reqVO.getSenderId()));
+ } else {
+ query.eqIfPresent(ImPrivateMessageDO::getSenderId, reqVO.getSenderId())
+ .eqIfPresent(ImPrivateMessageDO::getReceiverId, reqVO.getReceiverId());
+ }
+ return selectPage(reqVO, query
+ .eqIfPresent(ImPrivateMessageDO::getType, reqVO.getType())
+ .likeIfPresent(ImPrivateMessageDO::getContent, reqVO.getContent())
+ .eqIfPresent(ImPrivateMessageDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(ImPrivateMessageDO::getSendTime, reqVO.getSendTime())
+ .orderByDesc(ImPrivateMessageDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcCallMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcCallMapper.java
new file mode 100644
index 0000000..65f21a5
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcCallMapper.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.im.dal.mysql.rtc;
+
+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.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 閫氳瘽璁板綍 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImRtcCallMapper extends BaseMapperX<ImRtcCallDO> {
+
+ default ImRtcCallDO selectByRoom(String room) {
+ return selectOne(ImRtcCallDO::getRoom, room);
+ }
+
+ default ImRtcCallDO selectLastOneByGroupIdAndStatusIn(Long groupId, Collection<Integer> statuses) {
+ return selectLastOne(new LambdaQueryWrapperX<ImRtcCallDO>()
+ .eq(ImRtcCallDO::getGroupId, groupId)
+ .in(ImRtcCallDO::getStatus, statuses));
+ }
+
+ default int updateByIdAndStatus(Long id, Integer oldStatus, ImRtcCallDO updateObj) {
+ return update(updateObj, Wrappers.<ImRtcCallDO>lambdaUpdate()
+ .eq(ImRtcCallDO::getId, id)
+ .eq(ImRtcCallDO::getStatus, oldStatus));
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateByIdAndStatusIn(Long id, Collection<Integer> statuses, ImRtcCallDO updateObj) {
+ return update(updateObj, Wrappers.<ImRtcCallDO>lambdaUpdate()
+ .eq(ImRtcCallDO::getId, id)
+ .in(ImRtcCallDO::getStatus, statuses));
+ }
+
+ default List<ImRtcCallDO> selectListByStatusInAndStartTimeBefore(Collection<Integer> statuses,
+ LocalDateTime startTimeBefore) {
+ return selectList(new LambdaQueryWrapperX<ImRtcCallDO>()
+ .in(ImRtcCallDO::getStatus, statuses)
+ .lt(ImRtcCallDO::getStartTime, startTimeBefore));
+ }
+
+ default PageResult<ImRtcCallDO> selectPage(ImRtcCallManagerPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImRtcCallDO>()
+ .eqIfPresent(ImRtcCallDO::getInviterUserId, reqVO.getInviterUserId())
+ .eqIfPresent(ImRtcCallDO::getConversationType, reqVO.getConversationType())
+ .eqIfPresent(ImRtcCallDO::getMediaType, reqVO.getMediaType())
+ .eqIfPresent(ImRtcCallDO::getStatus, reqVO.getStatus())
+ .eqIfPresent(ImRtcCallDO::getEndReason, reqVO.getEndReason())
+ .betweenIfPresent(ImRtcCallDO::getStartTime, reqVO.getStartTime())
+ .orderByDesc(ImRtcCallDO::getId));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcParticipantMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcParticipantMapper.java
new file mode 100644
index 0000000..49d8c12
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcParticipantMapper.java
@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.im.dal.mysql.rtc;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcParticipantDO;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 閫氳瘽鍙備笌鑰� Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImRtcParticipantMapper extends BaseMapperX<ImRtcParticipantDO> {
+
+ default ImRtcParticipantDO selectByRoomAndUserId(String room, Long userId) {
+ return selectOne(new LambdaQueryWrapperX<ImRtcParticipantDO>()
+ .eq(ImRtcParticipantDO::getRoom, room)
+ .eq(ImRtcParticipantDO::getUserId, userId));
+ }
+
+ default List<ImRtcParticipantDO> selectListByRoom(String room) {
+ return selectList(ImRtcParticipantDO::getRoom, room);
+ }
+
+ default List<ImRtcParticipantDO> selectListByCallId(Long callId) {
+ return selectList(ImRtcParticipantDO::getCallId, callId);
+ }
+
+ default List<ImRtcParticipantDO> selectListByStatusAndInviteTimeBefore(Integer status, LocalDateTime threshold) {
+ return selectList(new LambdaQueryWrapperX<ImRtcParticipantDO>()
+ .eq(ImRtcParticipantDO::getStatus, status)
+ .lt(ImRtcParticipantDO::getInviteTime, threshold));
+ }
+
+ default List<ImRtcParticipantDO> selectListByRoomAndStatusAndInviteTimeBefore(String room, Integer status, LocalDateTime threshold) {
+ return selectList(new LambdaQueryWrapperX<ImRtcParticipantDO>()
+ .eq(ImRtcParticipantDO::getRoom, room)
+ .eq(ImRtcParticipantDO::getStatus, status)
+ .lt(ImRtcParticipantDO::getInviteTime, threshold));
+ }
+
+ default ImRtcParticipantDO selectLastOneByUserIdAndStatus(Long userId, Collection<Integer> statuses) {
+ return selectLastOne(new LambdaQueryWrapperX<ImRtcParticipantDO>()
+ .eq(ImRtcParticipantDO::getUserId, userId)
+ .in(ImRtcParticipantDO::getStatus, statuses));
+ }
+
+ default ImRtcParticipantDO selectLastOneByUserIdAndStatusInAndRoomNot(Long userId, Collection<Integer> statuses, String room) {
+ return selectLastOne(new LambdaQueryWrapperX<ImRtcParticipantDO>()
+ .eq(ImRtcParticipantDO::getUserId, userId)
+ .in(ImRtcParticipantDO::getStatus, statuses)
+ .ne(ImRtcParticipantDO::getRoom, room));
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateByIdAndStatus(Long id, Integer oldStatus, ImRtcParticipantDO updateObj) {
+ return update(updateObj, Wrappers.<ImRtcParticipantDO>lambdaUpdate()
+ .eq(ImRtcParticipantDO::getId, id)
+ .eq(ImRtcParticipantDO::getStatus, oldStatus));
+ }
+
+ @SuppressWarnings("UnusedReturnValue")
+ default int updateByRoomAndStatus(String room, Integer oldStatus, ImRtcParticipantDO updateObj) {
+ return update(updateObj, Wrappers.<ImRtcParticipantDO>lambdaUpdate()
+ .eq(ImRtcParticipantDO::getRoom, room)
+ .eq(ImRtcParticipantDO::getStatus, oldStatus));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/sensitiveword/ImSensitiveWordMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/sensitiveword/ImSensitiveWordMapper.java
new file mode 100644
index 0000000..ccf3f2b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/sensitiveword/ImSensitiveWordMapper.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.im.dal.mysql.sensitiveword;
+
+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.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.sensitiveword.ImSensitiveWordDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * IM 鏁忔劅璇� Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImSensitiveWordMapper extends BaseMapperX<ImSensitiveWordDO> {
+
+ default List<ImSensitiveWordDO> selectListByStatus(Integer status) {
+ return selectList(new LambdaQueryWrapperX<ImSensitiveWordDO>()
+ .eq(ImSensitiveWordDO::getStatus, status));
+ }
+
+ default ImSensitiveWordDO selectByWord(String word) {
+ return selectOne(new LambdaQueryWrapperX<ImSensitiveWordDO>()
+ .eq(ImSensitiveWordDO::getWord, word));
+ }
+
+ default PageResult<ImSensitiveWordDO> selectPage(ImSensitiveWordPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<ImSensitiveWordDO>()
+ .likeIfPresent(ImSensitiveWordDO::getWord, reqVO.getWord())
+ .eqIfPresent(ImSensitiveWordDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(ImSensitiveWordDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(ImSensitiveWordDO::getId));
+ }
+
+ @Select("SELECT MAX(update_time) FROM im_sensitive_word")
+ LocalDateTime selectMaxUpdateTime(@Param("tenantId") Long tenantId);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapper.java
new file mode 100644
index 0000000..26e3d98
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapper.java
@@ -0,0 +1,191 @@
+package cn.iocoder.yudao.module.im.dal.mysql.statistics;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * IM 鏁版嵁鐪嬫澘 Mapper
+ * <p>
+ * 鐙珛浜庝笟鍔� Mapper锛氭墍鏈夌粺璁� SQL 闆嗕腑鍦ㄦ锛屼粎鏈嶅姟浜� manager 鐪嬫澘锛屼笉琚叾瀹冧笟鍔¤皟鐢紝淇濇寔鍚勪笟鍔� Mapper / Service 涓嶅彈缁熻闇�姹傛薄鏌撱��
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface ImStatisticsManagerMapper {
+
+ String NORMAL_MESSAGE_CONDITION = "type IN (101,102,103,104,105,107,108,115,125) AND status <> 2";
+
+ // ==================== 鐢ㄦ埛 ====================
+
+ /**
+ * 鐢ㄦ埛鎬绘暟锛坰ystem_users锛�
+ */
+ @Select("SELECT COUNT(*) FROM system_users WHERE deleted = 0")
+ Long selectTotalUserCount();
+
+ /**
+ * 鍖洪棿鍐呮柊澧炵敤鎴锋暟
+ */
+ @Select("SELECT COUNT(*) FROM system_users " +
+ "WHERE deleted = 0 AND create_time >= #{beginTime} AND create_time < #{endTime}")
+ Long selectNewUserCount(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 鍖洪棿鍐呮椿璺冪敤鎴锋暟锛氱鑱婃垨缇よ亰鍙戣繃娑堟伅鐨勫幓閲嶇敤鎴锋暟
+ */
+ @Select("SELECT COUNT(DISTINCT user_id) FROM (" +
+ " SELECT sender_id AS user_id FROM im_private_message " +
+ " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}" +
+ " UNION ALL " +
+ " SELECT sender_id AS user_id FROM im_group_message " +
+ " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}" +
+ ") t")
+ Long selectActiveUserCount(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 鍖洪棿鍐呮瘡鏃ユ柊澧炵敤鎴锋暟锛堟寜澶╁垎缁勶級
+ *
+ * @return [{date: "yyyy-MM-dd", count: 123}, ...]
+ */
+ @Select("SELECT DATE(create_time) AS date, COUNT(*) AS count FROM system_users " +
+ "WHERE deleted = 0 AND create_time >= #{beginTime} AND create_time < #{endTime} " +
+ "GROUP BY DATE(create_time)")
+ List<Map<String, Object>> selectNewUserDailyCount(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 鍖洪棿鍐呮瘡鏃ユ椿璺冪敤鎴锋暟锛堟寜澶╁垎缁勩�佽法绉佽亰+缇よ亰鍘婚噸锛�
+ */
+ @Select("SELECT day AS date, COUNT(DISTINCT user_id) AS count FROM (" +
+ " SELECT DATE(send_time) AS day, sender_id AS user_id FROM im_private_message " +
+ " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}" +
+ " UNION ALL " +
+ " SELECT DATE(send_time) AS day, sender_id AS user_id FROM im_group_message " +
+ " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}" +
+ ") t GROUP BY day")
+ List<Map<String, Object>> selectActiveUserDailyCount(@Param("beginTime") LocalDateTime beginTime, @Param("endTime") LocalDateTime endTime);
+
+ // ==================== 缇� ====================
+
+ /**
+ * 褰撳墠鏈夋晥缇ゆ�绘暟
+ */
+ @Select("SELECT COUNT(*) FROM im_group WHERE deleted = 0 AND status = 0")
+ Long selectTotalGroupCount();
+
+ /**
+ * 鍖洪棿鍐呮柊寤虹兢鏁�
+ */
+ @Select("SELECT COUNT(*) FROM im_group " +
+ "WHERE deleted = 0 AND create_time >= #{beginTime} AND create_time < #{endTime}")
+ Long selectNewGroupCount(@Param("beginTime") LocalDateTime beginTime, @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 缇よ妯″垎甯冿紙鎸夌兢鎴愬憳鏁板垎妗讹級
+ *
+ * @return [{range: "1-9 浜�", count: 123}, ...]
+ */
+ @Select("SELECT " +
+ " CASE " +
+ " WHEN cnt < 10 THEN '1-9 浜�' " +
+ " WHEN cnt < 50 THEN '10-49 浜�' " +
+ " WHEN cnt < 200 THEN '50-199 浜�' " +
+ " ELSE '200+ 浜�' " +
+ " END AS `range`, COUNT(*) AS count " +
+ "FROM (" +
+ " SELECT g.id, COUNT(m.id) AS cnt " +
+ " FROM im_group g " +
+ " LEFT JOIN im_group_member m ON m.group_id = g.id AND m.status = 0 AND m.deleted = 0 " +
+ " WHERE g.deleted = 0 AND g.status = 0 " +
+ " GROUP BY g.id" +
+ ") t " +
+ "GROUP BY `range`")
+ List<Map<String, Object>> selectGroupSizeDistribution();
+
+ // ==================== 娑堟伅 ====================
+
+ /**
+ * 鍖洪棿鍐呯鑱婃秷鎭暟
+ */
+ @Select("SELECT COUNT(*) FROM im_private_message " +
+ "WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}")
+ Long selectPrivateMessageCount(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 鍖洪棿鍐呯兢鑱婃秷鎭暟
+ */
+ @Select("SELECT COUNT(*) FROM im_group_message " +
+ "WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}")
+ Long selectGroupMessageCount(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 鍖洪棿鍐呮瘡鏃ョ鑱婃秷鎭暟锛堟寜澶╁垎缁勶級
+ */
+ @Select("SELECT DATE(send_time) AS date, COUNT(*) AS count FROM im_private_message " +
+ "WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime} " +
+ "GROUP BY DATE(send_time)")
+ List<Map<String, Object>> selectPrivateMessageDailyCount(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 鍖洪棿鍐呮瘡鏃ョ兢鑱婃秷鎭暟锛堟寜澶╁垎缁勶級
+ */
+ @Select("SELECT DATE(send_time) AS date, COUNT(*) AS count FROM im_group_message " +
+ "WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime} " +
+ "GROUP BY DATE(send_time)")
+ List<Map<String, Object>> selectGroupMessageDailyCount(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 鍖洪棿鍐呭唴瀹圭被鍨嬪垎甯冿紙绉佽亰+缇よ亰鍚堝苟锛�
+ *
+ * @return [{type: 0, count: 123}, ...]
+ */
+ @Select("SELECT type, COUNT(*) AS count FROM (" +
+ " SELECT type FROM im_private_message " +
+ " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}" +
+ " UNION ALL " +
+ " SELECT type FROM im_group_message " +
+ " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}" +
+ ") t GROUP BY type")
+ List<Map<String, Object>> selectMessageTypeDistribution(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime);
+
+ /**
+ * 鍖洪棿鍐� TOP 鍙戦�佽�咃紙绉佽亰+缇よ亰鍚堝苟锛屾寜娑堟伅鏁板�掑簭锛�
+ *
+ * @return [{userId: 1024, messageCount: 1500}, ...]
+ */
+ @Select("SELECT user_id AS userId, COUNT(*) AS messageCount FROM (" +
+ " SELECT sender_id AS user_id FROM im_private_message " +
+ " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}" +
+ " UNION ALL " +
+ " SELECT sender_id AS user_id FROM im_group_message " +
+ " WHERE deleted = 0 AND " + NORMAL_MESSAGE_CONDITION +
+ " AND send_time >= #{beginTime} AND send_time < #{endTime}" +
+ ") t GROUP BY user_id ORDER BY messageCount DESC LIMIT #{limit}")
+ List<Map<String, Object>> selectTopSenders(@Param("beginTime") LocalDateTime beginTime,
+ @Param("endTime") LocalDateTime endTime,
+ @Param("limit") int limit);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/redis/RedisKeyConstants.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/redis/RedisKeyConstants.java
new file mode 100644
index 0000000..92d3890
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/redis/RedisKeyConstants.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.im.dal.redis;
+
+
+/**
+ * IM Redis Key 鏋氫妇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface RedisKeyConstants {
+
+ /**
+ * 濂藉弸鍏崇郴鐘舵�佺紦瀛橈紙鍚堝苟銆屾槸鍚﹀ソ鍙嬨��+銆屾槸鍚︽媺榛戙�嶄袱鎬侊級
+ * <p>
+ * KEY 鏍煎紡锛歠riend_state:{userId}_{friendUserId}
+ * VALUE 鏁版嵁绫诲瀷锛歿@link cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum}
+ */
+ String FRIEND_STATE = "friend_state";
+
+ /**
+ * 缇や俊鎭紦瀛�
+ * <p>
+ * KEY 鏍煎紡锛歡roup:{groupId}
+ * VALUE 鏁版嵁绫诲瀷锛欼mGroupDO
+ */
+ String GROUP = "group";
+
+ /**
+ * 缇ゆ湁鏁堟垚鍛� userId 鍒楄〃缂撳瓨锛堜粎 ENABLE 鐘舵�侊級
+ * <p>
+ * KEY 鏍煎紡锛歡roup_member_ids:{groupId}
+ * VALUE 鏁版嵁绫诲瀷锛歀ist<Long>
+ * <p>
+ * 璇存槑锛氬彧缂撳瓨杞婚噺鐨� userId 鍒楄〃锛岄�傚悎銆岀兢娑堟伅鎺ㄩ�佺洰鏍囥�嶈繖绫诲彧鍏冲績 userId 鐨勫満鏅�
+ */
+ String GROUP_MEMBER_IDS = "group_member_ids";
+
+ /**
+ * 閫氳瘽鍚屽 / 鍚岀兢娲昏穬鍞竴鎬х殑鍒嗗竷寮忛攣
+ * <p>
+ * KEY 鏍煎紡锛歩m_rtc_call:{conversationType}:{suffix}
+ * 绉佽亰锛坈onversationType=1锛夛細suffix = {灏� userId}_{澶� userId}
+ * 缇よ亰锛坈onversationType=2锛夛細suffix = {groupId}
+ * VALUE 鏁版嵁鏍煎紡锛欻ASH // RLock.class锛歊edisson 鐨� Lock 閿侊紝浣跨敤 Hash 鏁版嵁缁撴瀯
+ * 杩囨湡鏃堕棿锛氫笉鍥哄畾锛坙ock 鏃舵樉寮忎紶 timeoutMillis锛�
+ */
+ String IM_RTC_CALL_LOCK = "im_rtc_call:%d:%s";
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/redis/rtc/ImRtcCallLockRedisDAO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/redis/rtc/ImRtcCallLockRedisDAO.java
new file mode 100644
index 0000000..0384bf4
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/redis/rtc/ImRtcCallLockRedisDAO.java
@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.module.im.dal.redis.rtc;
+
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.stereotype.Repository;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.IM_RTC_CALL_LOCK;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.RTC_INVITE_BUSY;
+
+/**
+ * IM 閫氳瘽鍚屽 / 鍚岀兢娲昏穬鍞竴鎬х殑閿� Redis DAO
+ * <p>
+ * invite 鍏ュ彛鍖呬竴灞傦紱閿佸唴鍋氥�孲ELECT 宸叉湁娲昏穬閫氳瘽 鈫� 鍛戒腑鍗冲姞鍏ュ垎鏀紱鍚﹀垯 INSERT 鏂伴�氳瘽銆�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Repository
+@Slf4j
+public class ImRtcCallLockRedisDAO {
+
+ /**
+ * 绛夊緟鑾峰彇閿佺殑鏈�闀挎椂闂达紱瓒呮椂鎶� RTC_INVITE_BUSY
+ */
+ private static final long LOCK_WAIT_MS = 5_000L;
+ /**
+ * 鎸佹湁閿佺殑鏈�闀挎椂闂达紱鑷姩閲婃斁鍏滃簳锛涚粰 LiveKit / DB / 鎺ㄩ�佸伓鍙戞參鐣欎綑鍦�
+ */
+ private static final long LOCK_LEASE_MS = 30_000L;
+
+ @Resource
+ private RedissonClient redissonClient;
+
+ /**
+ * 绉佽亰閫氳瘽閿侊紱鎸� userId 鎺掑簭鎷� key 淇濆绉帮紙鍚屽鍛煎彨鍜屽弽鍚戝懠鍙叡鐢ㄤ竴鎶婇攣锛�
+ */
+ public <V> V lockPrivate(Long userIdA, Long userIdB, Callable<V> callable) throws Exception {
+ String key = String.format(IM_RTC_CALL_LOCK, ImConversationTypeEnum.PRIVATE.getType(),
+ Math.min(userIdA, userIdB)+ "_" + Math.max(userIdA, userIdB));
+ return doLock(key, callable);
+ }
+
+ /**
+ * 缇ら�氳瘽閿侊紱鍚岀兢鎵�鏈� invite 涓茶
+ */
+ public <V> V lockGroup(Long groupId, Callable<V> callable) throws Exception {
+ String key = String.format(IM_RTC_CALL_LOCK, ImConversationTypeEnum.GROUP.getType(), groupId);
+ return doLock(key, callable);
+ }
+
+ /**
+ * tryLock(waitTime, leaseTime, unit)锛歸aitTime 鍐呮嬁涓嶅埌閿佺洿鎺ユ姏绻佸繖锛涙嬁鍒板悗 leaseTime 鑷姩閲婃斁
+ * <p>
+ * unlock 鍓嶇敤 isHeldByCurrentThread 鍏滃簳锛涗笟鍔¤秴杩� leaseTime 鏃堕攣宸茶嚜鍔ㄩ噴鏀撅紝涓嶅啀鎶� IllegalMonitorStateException
+ */
+ private <V> V doLock(String lockKey, Callable<V> callable) throws Exception {
+ RLock lock = redissonClient.getLock(lockKey);
+ boolean acquired = lock.tryLock(LOCK_WAIT_MS, LOCK_LEASE_MS, TimeUnit.MILLISECONDS);
+ if (!acquired) {
+ log.error("[doLock][lockKey={} 绛夊緟 {}ms 浠嶆湭鑾峰彇鍒伴攣]", lockKey, LOCK_WAIT_MS);
+ throw exception(RTC_INVITE_BUSY);
+ }
+ try {
+ return callable.call();
+ } finally {
+ if (lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ } else {
+ log.error("[doLock][lockKey={} 涓氬姟瓒呰繃 leaseTime={}ms锛岄攣宸茶 Redisson 鑷姩閲婃斁]", lockKey, LOCK_LEASE_MS);
+ }
+ }
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ErrorCodeConstants.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ErrorCodeConstants.java
new file mode 100644
index 0000000..eb34dab
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ErrorCodeConstants.java
@@ -0,0 +1,108 @@
+package cn.iocoder.yudao.module.im.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+/**
+ * IM 閿欒鐮佹灇涓剧被
+ * <p>
+ * im 绯荤粺锛屼娇鐢� 1-040-000-000 娈�
+ */
+public interface ErrorCodeConstants {
+
+ // ========== 娑堟伅 (1-040-300-000) ==========
+ ErrorCode MESSAGE_NOT_EXISTS = new ErrorCode(1_040_300_000, "娑堟伅涓嶅瓨鍦�");
+ ErrorCode MESSAGE_RECALL_DENIED = new ErrorCode(1_040_300_002, "鍙兘鎾ゅ洖鑷繁鍙戦�佺殑娑堟伅");
+ ErrorCode MESSAGE_ALREADY_RECALLED = new ErrorCode(1_040_300_003, "娑堟伅宸叉挙鍥�");
+ ErrorCode MESSAGE_SENSITIVE_WORD_BLOCKED = new ErrorCode(1_040_300_004, "娑堟伅鍖呭惈鏁忔劅璇嶏紝鏃犳硶鍙戦��");
+ ErrorCode MESSAGE_PULL_SIZE_EXCEEDED = new ErrorCode(1_040_300_005, "鍗曟鎷夊彇娑堟伅鏁伴噺涓嶈兘瓒呰繃 {} 鏉�");
+ ErrorCode MESSAGE_RECALL_TIMEOUT = new ErrorCode(1_040_300_007, "瓒呰繃 {} 鍒嗛挓鐨勬秷鎭棤娉曟挙鍥�");
+ ErrorCode MESSAGE_QUOTE_INVALID = new ErrorCode(1_040_300_008, "寮曠敤鐨勬秷鎭笉鍙敤");
+ ErrorCode MESSAGE_NOT_IN_GROUP = new ErrorCode(1_040_300_009, "娑堟伅涓嶅睘浜庤缇�");
+ ErrorCode MESSAGE_PRIVATE_READ_DISABLED = new ErrorCode(1_040_300_010, "绉佽亰宸茶鍔熻兘宸插叧闂�");
+ ErrorCode MESSAGE_GROUP_READ_DISABLED = new ErrorCode(1_040_300_011, "缇よ亰宸茶鍔熻兘宸插叧闂�");
+ ErrorCode MESSAGE_CONTENT_INVALID = new ErrorCode(1_040_300_013, "娑堟伅鍐呭鏍煎紡涓嶆纭�");
+
+ // ========== 缇� (1-040-400-000) ==========
+ ErrorCode GROUP_NOT_EXISTS = new ErrorCode(1_040_400_000, "缇や笉瀛樺湪");
+ ErrorCode GROUP_BANNED = new ErrorCode(1_040_400_001, "缇ゅ凡琚皝绂�");
+ ErrorCode GROUP_DISSOLVED = new ErrorCode(1_040_400_002, "缇ゅ凡瑙f暎");
+ ErrorCode GROUP_NOT_OWNER = new ErrorCode(1_040_400_003, "浠呯兢涓诲彲鎵ц璇ユ搷浣�");
+ ErrorCode GROUP_NOT_OWNER_OR_ADMIN = new ErrorCode(1_040_400_004, "浠呯兢涓绘垨绠$悊鍛樺彲鎵ц璇ユ搷浣�");
+ ErrorCode GROUP_TRANSFER_OWNER_TO_SELF = new ErrorCode(1_040_400_005, "涓嶈兘灏嗙兢涓昏浆璁╃粰鑷繁");
+ ErrorCode GROUP_MESSAGE_PIN_MAX_LIMIT = new ErrorCode(1_040_400_006, "缇ょ疆椤舵秷鎭暟閲忎笉鑳借秴杩� {} 鏉�");
+ ErrorCode GROUP_MESSAGE_ALREADY_PINNED = new ErrorCode(1_040_400_007, "璇ユ秷鎭凡缃《");
+ ErrorCode GROUP_MESSAGE_NOT_PINNED = new ErrorCode(1_040_400_008, "璇ユ秷鎭湭缃《");
+ ErrorCode GROUP_MESSAGE_PIN_DIRECTED_DENIED = new ErrorCode(1_040_400_009, "瀹氬悜娑堟伅涓嶆敮鎸佺疆椤�");
+
+ // ========== 缇ゆ垚鍛� (1-040-500-000) ==========
+ ErrorCode GROUP_MEMBER_NOT_IN_GROUP = new ErrorCode(1_040_500_001, "鎮ㄥ凡涓嶅湪璇ョ兢涓�");
+ ErrorCode GROUP_OWNER_CANNOT_QUIT = new ErrorCode(1_040_500_003, "缇や富涓嶈兘閫�鍑虹兢鑱婏紝璇峰厛杞缇や富鎴栬В鏁g兢鑱�");
+ ErrorCode GROUP_CANNOT_REMOVE_SELF = new ErrorCode(1_040_500_004, "涓嶈兘灏嗚嚜宸辩Щ鍑虹兢鑱�");
+ ErrorCode GROUP_MEMBER_EXCEED = new ErrorCode(1_040_500_005, "缇よ亰浜烘暟涓嶈兘瓒呰繃 {} 浜�");
+ ErrorCode GROUP_INVITE_NOT_FRIEND = new ErrorCode(1_040_500_006, "'{}' 涓嶆槸鎮ㄧ殑濂藉弸锛岄個璇峰け璐�");
+ ErrorCode GROUP_ADMIN_TARGET_NOT_IN_GROUP = new ErrorCode(1_040_500_007, "鐩爣鐢ㄦ埛宸蹭笉鍦ㄨ缇や腑");
+ ErrorCode GROUP_ADMIN_TARGET_IS_OWNER = new ErrorCode(1_040_500_008, "缇や富鏃犳硶琚涓烘垨鎾ら攢绠$悊鍛�");
+ ErrorCode GROUP_ADMIN_MAX_LIMIT = new ErrorCode(1_040_500_009, "缇ょ鐞嗗憳鏁伴噺涓嶈兘瓒呰繃 {} 浜�");
+ ErrorCode GROUP_REMOVE_OWNER_DENIED = new ErrorCode(1_040_500_010, "缇や富鏃犳硶琚Щ鍑虹兢鑱�");
+ ErrorCode GROUP_REMOVE_ADMIN_DENIED = new ErrorCode(1_040_500_011, "绠$悊鍛樻棤娉曠Щ鍑哄叾浠栫鐞嗗憳锛岃鍏堢敱缇や富鎾ら攢鍏剁鐞嗗憳韬唤");
+ ErrorCode GROUP_MUTED_CANNOT_SEND = new ErrorCode(1_040_500_012, "缇ゅ凡鍏ㄥ眬绂佽█锛屼粎缇や富鍜岀鐞嗗憳鍙彂閫佹秷鎭�");
+ ErrorCode GROUP_MEMBER_MUTED_CANNOT_SEND = new ErrorCode(1_040_500_013, "鎮ㄥ凡琚瑷�锛岃В闄ゆ椂闂达細{}");
+ ErrorCode GROUP_MUTE_MEMBER_SELF = new ErrorCode(1_040_500_014, "涓嶈兘绂佽█鑷繁");
+ ErrorCode GROUP_MUTE_OWNER_DENIED = new ErrorCode(1_040_500_015, "缇や富鏃犳硶琚瑷�");
+ ErrorCode GROUP_MUTE_ADMIN_DENIED = new ErrorCode(1_040_500_016, "绠$悊鍛樻棤娉曠瑷�鍏朵粬绠$悊鍛�");
+
+ // ========== 濂藉弸 (1-040-600-000) ==========
+ ErrorCode FRIEND_NOT_FRIEND = new ErrorCode(1_040_600_001, "瀵规柟涓嶆槸鎮ㄧ殑濂藉弸");
+ ErrorCode FRIEND_ADD_SELF = new ErrorCode(1_040_600_002, "涓嶅厑璁告坊鍔犺嚜宸变负濂藉弸");
+ ErrorCode FRIEND_NOT_BLOCKED = new ErrorCode(1_040_600_003, "瀵规柟鏈湪榛戝悕鍗曚腑");
+ ErrorCode FRIEND_BLOCKED_BY_PEER = new ErrorCode(1_040_600_004, "鎮ㄥ凡琚鏂规媺鍏ラ粦鍚嶅崟锛屾棤娉曞彂閫佹秷鎭�");
+
+ // ========== 鍔犵兢鐢宠 (1-040-510-000) ==========
+ ErrorCode GROUP_REQUEST_NOT_EXISTS = new ErrorCode(1_040_510_001, "鍔犵兢鐢宠涓嶅瓨鍦�");
+ ErrorCode GROUP_REQUEST_HANDLED = new ErrorCode(1_040_510_002, "鍔犵兢鐢宠宸插鐞�");
+ ErrorCode GROUP_REQUEST_NOT_TO_ME = new ErrorCode(1_040_510_003, "浠呯兢涓绘垨绠$悊鍛樺彲澶勭悊鍔犵兢鐢宠");
+ ErrorCode GROUP_REQUEST_ALREADY_MEMBER = new ErrorCode(1_040_510_004, "鎮ㄥ凡鍦ㄨ缇や腑锛屾棤闇�閲嶅鐢宠");
+
+ // ========== 濂藉弸鐢宠 (1-040-610-000) ==========
+ ErrorCode FRIEND_REQUEST_NOT_EXISTS = new ErrorCode(1_040_610_001, "濂藉弸鐢宠涓嶅瓨鍦�");
+ ErrorCode FRIEND_REQUEST_HANDLED = new ErrorCode(1_040_610_002, "濂藉弸鐢宠宸插鐞�");
+ ErrorCode FRIEND_REQUEST_NOT_TO_ME = new ErrorCode(1_040_610_003, "涓嶈兘澶勭悊鍒汉鐨勫ソ鍙嬬敵璇�");
+ ErrorCode FRIEND_REQUEST_ALREADY_FRIEND = new ErrorCode(1_040_610_005, "鎮ㄥ凡鏄� TA 鐨勫ソ鍙嬶紝鏃犻渶閲嶅娣诲姞");
+ ErrorCode FRIEND_REQUEST_BLOCKED_BY_PEER = new ErrorCode(1_040_610_006, "鎮ㄥ凡琚鏂规媺鍏ラ粦鍚嶅崟锛屾棤娉曟坊鍔犱负濂藉弸");
+
+ // ========== 鏁忔劅璇� (1-040-700-000) ==========
+ ErrorCode SENSITIVE_WORD_NOT_EXISTS = new ErrorCode(1_040_700_000, "鏁忔劅璇嶄笉瀛樺湪");
+ ErrorCode SENSITIVE_WORD_DUPLICATED = new ErrorCode(1_040_700_001, "鏁忔劅璇� '{}' 宸插瓨鍦�");
+
+ // ========== 琛ㄦ儏鍖� (1-040-800-000) ==========
+ ErrorCode FACE_PACK_NOT_EXISTS = new ErrorCode(1_040_800_000, "琛ㄦ儏鍖呬笉瀛樺湪");
+ ErrorCode FACE_PACK_HAS_ITEMS = new ErrorCode(1_040_800_001, "琛ㄦ儏鍖呬笅杩樻湁琛ㄦ儏锛屾棤娉曞垹闄�");
+ ErrorCode FACE_PACK_ITEM_NOT_EXISTS = new ErrorCode(1_040_800_002, "琛ㄦ儏涓嶅瓨鍦�");
+ ErrorCode FACE_USER_ITEM_NOT_EXISTS = new ErrorCode(1_040_800_010, "涓汉琛ㄦ儏涓嶅瓨鍦�");
+ ErrorCode FACE_USER_ITEM_NOT_OWN = new ErrorCode(1_040_800_011, "涓嶈兘鎿嶄綔浠栦汉鐨勮〃鎯�");
+ ErrorCode FACE_USER_ITEM_DUPLICATED = new ErrorCode(1_040_800_013, "璇ヨ〃鎯呭凡娣诲姞鍒颁釜浜鸿〃鎯�");
+ ErrorCode FACE_USER_ITEM_MAX_LIMIT = new ErrorCode(1_040_800_014, "涓汉琛ㄦ儏鏁伴噺涓嶈兘瓒呰繃 {} 涓�");
+
+ // ========== 棰戦亾 (1-040-810-000) ==========
+ ErrorCode IM_CHANNEL_NOT_EXISTS = new ErrorCode(1_040_810_000, "棰戦亾涓嶅瓨鍦�");
+ ErrorCode IM_CHANNEL_CODE_DUPLICATED = new ErrorCode(1_040_810_001, "棰戦亾缂栫爜 '{}' 宸插瓨鍦�");
+ ErrorCode IM_CHANNEL_HAS_MATERIAL = new ErrorCode(1_040_810_002, "棰戦亾涓嬭繕鏈夌礌鏉愶紝鏃犳硶鍒犻櫎");
+ ErrorCode IM_CHANNEL_MATERIAL_NOT_EXISTS = new ErrorCode(1_040_810_010, "绱犳潗涓嶅瓨鍦�");
+ ErrorCode IM_CHANNEL_MATERIAL_USED = new ErrorCode(1_040_810_011, "绱犳潗宸茶鎺ㄩ�佽繃锛屾棤娉曞垹闄�");
+ ErrorCode IM_CHANNEL_MESSAGE_NOT_EXISTS = new ErrorCode(1_040_810_020, "棰戦亾娑堟伅涓嶅瓨鍦�");
+
+ // ========== 瀹炴椂閫氳瘽 (1-040-900-000) ==========
+ ErrorCode RTC_NOT_ENABLED = new ErrorCode(1_040_900_000, "閫氳瘽鍔熻兘鏈紑鍚�");
+ ErrorCode RTC_SESSION_NOT_EXISTS = new ErrorCode(1_040_900_001, "閫氳瘽宸茬粨鏉�");
+ ErrorCode RTC_PEER_BUSY = new ErrorCode(1_040_900_002, "瀵规柟姝e湪閫氳瘽涓�");
+ ErrorCode RTC_SELF_BUSY = new ErrorCode(1_040_900_003, "鎮ㄦ鍦ㄩ�氳瘽涓�");
+ ErrorCode RTC_NOT_PARTICIPANT = new ErrorCode(1_040_900_004, "鎮ㄤ笉鍦ㄨ閫氳瘽涓�");
+ ErrorCode RTC_INVITE_SELF = new ErrorCode(1_040_900_005, "涓嶈兘鍛煎彨鑷繁");
+ ErrorCode RTC_PRIVATE_INVITEE_REQUIRED = new ErrorCode(1_040_900_006, "绉佽亰閫氳瘽蹇呴』鎸囧畾瀵规柟");
+ ErrorCode RTC_GROUP_REQUIRED = new ErrorCode(1_040_900_007, "缇よ亰閫氳瘽蹇呴』鎸囧畾缇ょ紪鍙�");
+ ErrorCode RTC_INVITE_BUSY = new ErrorCode(1_040_900_008, "閫氳瘽鍙戣捣绻佸繖锛岃绋嶅悗鍐嶈瘯");
+ ErrorCode RTC_GROUP_CALL_ACTIVE = new ErrorCode(1_040_900_009, "璇ョ兢宸叉湁杩涜涓�氳瘽锛岃閫氳繃鑳跺泭鏉″姞鍏�");
+ ErrorCode RTC_GROUP_INVITEE_OVER_LIMIT = new ErrorCode(1_040_900_010, "缇ら�氳瘽閭�璇蜂汉鏁拌秴杩囨渶澶у��");
+ ErrorCode RTC_GROUP_INVITEE_REQUIRED = new ErrorCode(1_040_900_011, "缇ら�氳瘽蹇呴』閫夋嫨琚個璇蜂汉");
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImCommonConstants.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImCommonConstants.java
new file mode 100644
index 0000000..404d2fb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImCommonConstants.java
@@ -0,0 +1,17 @@
+package cn.iocoder.yudao.module.im.enums;
+
+/**
+ * IM 閫氱敤甯搁噺
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImCommonConstants {
+
+ /**
+ * 缇ゆ秷鎭� @ 鎵�鏈変汉鐨勭壒娈婄敤鎴风紪鍙�
+ * <p>
+ * 鍓嶅悗绔崗璁绾﹀�硷紱atUserIds 鏁扮粍閲屽嚭鐜拌鍊艰〃绀� @ 鍏ㄤ綋鎴愬憳
+ */
+ long AT_USER_ID_ALL = -1L;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImContentTypeEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImContentTypeEnum.java
new file mode 100644
index 0000000..2f68ad8
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImContentTypeEnum.java
@@ -0,0 +1,422 @@
+package cn.iocoder.yudao.module.im.enums;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ArrayUtil;
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.Set;
+
+/**
+ * IM 鍐呭绫诲瀷鏋氫妇
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Getter
+@RequiredArgsConstructor
+public enum ImContentTypeEnum implements ArrayValuable<Integer> {
+
+ // ========== 鐢ㄦ埛鑱婂ぉ娑堟伅锛�101-105 鐩存帴澶嶇敤 OpenIM 娈典綅缂栧彿锛� ==========
+ /**
+ * 瀵瑰簲 OpenIM锛歍ext 101
+ * 瀵瑰簲鑷繁鐨勭被锛歍extMessage
+ */
+ TEXT(101, "鏂囨湰", true, true),
+ /**
+ * 瀵瑰簲 OpenIM锛歅icture 102
+ * 瀵瑰簲鑷繁鐨勭被锛欼mageMessage
+ */
+ IMAGE(102, "鍥剧墖", true, true),
+ /**
+ * 瀵瑰簲 OpenIM锛歋ound 103
+ * 瀵瑰簲鑷繁鐨勭被锛欰udioMessage
+ */
+ VOICE(103, "璇煶", true, true),
+ /**
+ * 瀵瑰簲 OpenIM锛歏ideo 104
+ * 瀵瑰簲鑷繁鐨勭被锛歏ideoMessage
+ */
+ VIDEO(104, "瑙嗛", true, true),
+ /**
+ * 瀵瑰簲 OpenIM锛欶ile 105
+ * 瀵瑰簲鑷繁鐨勭被锛欶ileMessage
+ */
+ FILE(105, "鏂囦欢", true, true),
+ /**
+ * 瀵瑰簲 OpenIM锛歁erger 107
+ * 瀵瑰簲鑷繁鐨勭被锛歁ergeMessage
+ */
+ MERGE(107, "鍚堝苟杞彂", true, true),
+ /**
+ * 瀵瑰簲 OpenIM锛欳ard 108锛圤penIM 浠呯敤鎴峰悕鐗囷紱鏈郴缁熸墿灞曚负鐢ㄦ埛 / 缇ゅ弻绫诲瀷锛屾寜 targetType 鍖哄垎锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欳ardMessage
+ * 鍦烘櫙锛氭妸鐢ㄦ埛鍚嶇墖 / 缇ゅ悕鐗囨帹鑽愮粰鍏朵粬浼氳瘽锛涚敤鎴峰悕鐗囩偣鍑绘墦寮� UserInfoCard锛岀兢鍚嶇墖鐐瑰嚮銆屽凡鍔犵兢璺充細璇� / 鏈姞缇ゅ脊鐢宠鍔犵兢銆�
+ */
+ CARD(108, "鍚嶇墖", true, true),
+ /**
+ * 瀵瑰簲 OpenIM锛欶ace 115
+ * 瀵瑰簲鑷繁鐨勭被锛欶aceMessage
+ * 鍦烘櫙锛氳〃鎯呰创鍥撅紙杩愯惀閰嶇疆鐨勭郴缁熻〃鎯呭寘 + 鐢ㄦ埛绉佹湁琛ㄦ儏鍖咃級锛沀nicode emoji 浠嶈蛋 TEXT
+ */
+ FACE(115, "琛ㄦ儏", true, true),
+
+ // ========== 棰戦亾娑堟伅鎵╁睍娈碉紙125+锛汷penIM 122 涔嬪悗鏈崰鐢紝鏈郴缁熷湪 125 璧锋缁欓閬� / 鍏紬鍙风被娑堟伅鎵╁睍锛� ==========
+ /**
+ * 瀵瑰簲 OpenIM锛氭棤锛�125 娈典綅 OpenIM 鏈崰鐢紝浣滀负棰戦亾娑堟伅鎵╁睍璧峰浣嶏級
+ * 瀵瑰簲鑷繁鐨勭被锛歁aterialMessage
+ * 鍦烘櫙锛氶閬撹繍钀ユ帹閫佺殑绱犳潗娑堟伅锛涘綋鍓嶅舰鎬佷负鍥炬枃鍗$墖锛坱itle + coverUrl + summary + url锛�
+ * 璇︽儏锛歶rl 闈炵┖璺� url锛泆rl 涓虹┖鏃跺鎴风鎸� materialId 鎷� /get-content 娓叉煋瀵屾枃鏈鏂�
+ */
+ MATERIAL(125, "绱犳潗", true, true),
+
+ // ========== 淇″彿绫伙紙2101 / 2200 鐩存帴澶嶇敤 OpenIM 娈典綅缂栧彿锛�2201 鑷湁鎵╁睍锛� ==========
+ /**
+ * 瀵瑰簲 OpenIM锛歊evokeNotification 2101
+ * 瀵瑰簲鑷繁鐨勭被锛歊ecallMessage
+ */
+ RECALL(2101, "鎾ゅ洖", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欻asReadReceipt 2200
+ * 瀵瑰簲鑷繁鐨勭被锛氭棤锛坧ayload 璧� ImXxxMessageDTO 椤跺眰瀛楁锛�
+ */
+ RECEIPT(2200, "鍥炴墽", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛氭棤锛堣嚜鏈夋墿灞曪紝OpenIM 璧� ConversationChangeNotification 1300 璺緞锛�
+ * 瀵瑰簲鑷繁鐨勭被锛氭棤锛坧ayload 璧� ImXxxMessageDTO 椤跺眰瀛楁锛�
+ */
+ READ(2201, "宸茶", false, false),
+
+ // ========== 瀹炴椂閫氳瘽淇′护锛�1601-1605 娈典綅涓� OpenIM 瀵归綈锛�1610+ 鑷湁鎵╁睍锛� ==========
+ /**
+ * 瀵瑰簲 OpenIM锛歋ignalingNotification 1601锛堥�氳瘽淇′护缁熶竴鍏ュ彛锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欼mRtcCallNotification
+ * 鍦烘櫙锛氶�氳瘽淇′护锛涗笉鍏ュ簱锛岃蛋 imWebSocketService 浠呮帹鍙備笌鏂癸紱status 澶嶇敤鍙備笌鑰呯姸鎬佹灇涓惧尯鍒� INVITING / JOINED / REJECTED / NO_ANSWER / LEFT
+ */
+ RTC_CALL(1601, "閫氳瘽淇′护", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歊oomParticipantsConnectedNotification 1602
+ * 瀵瑰簲鑷繁鐨勭被锛欼mRtcParticipantConnectedNotification
+ * 鍦烘櫙锛氶�氳瘽鍙備笌鑰呭姞鍏ワ紱LiveKit webhook participant_joined 瑙﹀彂锛涚鑱婃帹 peer 澶氱 + inviter 澶氱锛岀兢鑱婂叏缇ゅ箍鎾紱涓嶅叆搴�
+ */
+ RTC_PARTICIPANT_CONNECTED(1602, "閫氳瘽鍙備笌鑰呭姞鍏�", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歊oomParticipantsDisconnectedNotification 1603
+ * 瀵瑰簲鑷繁鐨勭被锛欼mRtcParticipantDisconnectedNotification
+ * 鍦烘櫙锛氶�氳瘽鍙備笌鑰呯寮�锛汱iveKit webhook participant_left 瑙﹀彂锛涙帹閫佽寖鍥村悓 1602锛涗笉鍏ュ簱
+ */
+ RTC_PARTICIPANT_DISCONNECTED(1603, "閫氳瘽鍙備笌鑰呯寮�", false, false),
+ // 1604-1609 OpenIM 宸茬敤 / 鐣欎綔鎵╁睍锛屾湰绯荤粺鏆備笉浣跨敤
+ /**
+ * 瀵瑰簲 OpenIM锛氭棤锛堣嚜鏈夋墿灞曪紝OpenIM 閫氳瘽浜嬩欢涓嶅叆娑堟伅娴侊級
+ * 瀵瑰簲鑷繁鐨勭被锛欼mRtcCallStartNotification
+ * 鍦烘櫙锛氶�氳瘽寮�濮嬶紱缇よ亰鍏� im_group_message 鍏ㄧ兢骞挎挱锛屽墠绔覆鏌撹亰澶� tip銆寋inviterNickname} 鍙戣捣浜嗚闊抽�氳瘽銆嶏紱
+ * 绉佽亰鍏� im_private_message 瀹氬悜缁欒鍙紝浠呯敤浜庝細璇濆垪琛ㄩ瑙堝睍绀恒�孾璇煶閫氳瘽]銆嶏紙涓嶆覆鏌撹亰澶� tip锛�
+ * <p>
+ * 涓� RTC_CALL_END(1611) 涓ゆ寮忛厤瀵癸細START 涓�瀹氬厛浜� END 鍏ュ簱锛圫TART 鍦� invite 鎺ュ彛浜嬪姟閲屻�丒ND 鍦� cancel/leave 鎺ュ彛浜嬪姟閲岋紝鑷劧鎸夎姹傞『搴忎覆琛岋級
+ */
+ RTC_CALL_START(1610, "閫氳瘽寮�濮�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛氭棤锛堣嚜鏈夋墿灞曪紝OpenIM 閫氳瘽浜嬩欢涓嶅叆娑堟伅娴侊級
+ * 瀵瑰簲鑷繁鐨勭被锛欼mRtcCallEndNotification
+ * 鍦烘櫙锛氶�氳瘽缁撴潫锛涘叆 im_private_message / im_group_message锛涚鑱婃覆鏌撳噯姘旀场锛岀兢鑱婃覆鏌� tip銆岃闊抽�氳瘽宸茬粡缁撴潫銆�
+ * <p>
+ * 涓� RTC_CALL_START(1610) 涓ゆ寮忛厤瀵�
+ */
+ RTC_CALL_END(1611, "閫氳瘽缁撴潫", true, false),
+
+ // ========== 濂藉弸閫氱煡锛�1201-1210 鐩存帴澶嶇敤 OpenIM 娈典綅缂栧彿锛� ==========
+ /**
+ * 瀵瑰簲 OpenIM锛欶riendApplicationApprovedNotification 1201
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendRequestApprovedNotification
+ * 鍦烘櫙锛欱 鍚屾剰 A 鐨勫ソ鍙嬬敵璇凤紝鎺ㄧ粰 A 澶氱
+ */
+ FRIEND_REQUEST_APPROVED(1201, "濂藉弸鐢宠琚悓鎰�", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欶riendApplicationRejectedNotification 1202
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendRequestRejectedNotification
+ * 鍦烘櫙锛欱 鎷掔粷 A 鐨勫ソ鍙嬬敵璇凤紝鎺ㄧ粰 A 澶氱
+ */
+ FRIEND_REQUEST_REJECTED(1202, "濂藉弸鐢宠琚嫆缁�", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欶riendApplicationNotification 1203
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendRequestNotification
+ * 鍦烘櫙锛欰 鐢宠鍔� B锛屾帹缁� B 澶氱锛屽墠绔惤鍒般�屾柊鐨勬湅鍙嬨�嶅垪琛�
+ */
+ FRIEND_REQUEST_RECEIVED(1203, "鏀跺埌鏂扮殑濂藉弸鐢宠", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欶riendAddedNotification 1204锛圤penIM friendAdded.isSendMsg=false 榛樿涓嶅叆娑堟伅娴侊紱鏈郴缁熸敼涓哄叆搴撳綋浼氳瘽姘旀场锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendAddNotification
+ * 鍦烘櫙锛氬弻鏂瑰缓绔嬪ソ鍙嬪叧绯伙紝鍗曟潯鍏ュ簱锛坰ender=fromUserId, receiver=toUserId锛夛紱鍙屽悜 WebSocket 鑷姩瑕嗙洊鍙屾柟澶氱
+ * 娉ㄦ剰锛歴ilentReAddFriend 鍗曡竟璇箟鍦烘櫙锛屽彂閫佹椂鏄惧紡 setPersistent(false) 瑕嗙洊榛樿鍊�
+ */
+ FRIEND_ADD(1204, "鏂板濂藉弸", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欶riendDeletedNotification 1205
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendDeleteNotification
+ * 鍦烘櫙锛欰 鍒犻櫎 B锛屾帹缁� A銆丅 鍙屾柟澶氱
+ */
+ FRIEND_DELETE(1205, "濂藉弸琚垹闄�", false, false),
+ // 1206 瀵瑰簲 OpenIM FriendRemarkSetNotification锛涙湰绯荤粺骞跺叆 FRIEND_UPDATE(1210) 缁熶竴鎺ㄩ�侊紝鍗曚竴瀛楁鍙樻洿涓嶅啀鐙珛閫氶亾
+ /**
+ * 瀵瑰簲 OpenIM锛欱lackAddedNotification 1207
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendBlockNotification
+ * 鍦烘櫙锛欰 鎷夐粦 B锛屼粎鎺� A 澶氱
+ */
+ FRIEND_BLOCK(1207, "鍔犲叆榛戝悕鍗�", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欱lackDeletedNotification 1208
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendUnblockNotification
+ * 鍦烘櫙锛欰 绉诲嚭 B 鐨勯粦鍚嶅崟锛屼粎鎺� A 澶氱
+ */
+ FRIEND_UNBLOCK(1208, "绉诲嚭榛戝悕鍗�", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欶riendInfoUpdatedNotification 1209
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendInfoUpdatedNotification
+ * 鍦烘櫙锛欱 鏀逛簡鏄电О / 澶村儚鍚庯紝鎺ㄧ粰 B 鐨勬墍鏈夊ソ鍙�
+ * 瑙﹀彂锛歴ystem 妯″潡鍙� AdminUserProfileUpdateMessage锛孖M 娑堣垂鑰� AdminUserProfileUpdateConsumer 鎵归噺鎺ㄦ閫氱煡
+ */
+ FRIEND_INFO_UPDATED(1209, "濂藉弸璧勬枡鍙樻洿", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欶riendsInfoUpdateNotification 1210锛堢獎鍖栧埌 silent / pinned 鍗曡竟灞炴�э級
+ * 瀵瑰簲鑷繁鐨勭被锛欶riendUpdateNotification
+ * 鍦烘櫙锛欰 鏀逛簡 silent / pinned 绛夊崟杈瑰睘鎬э紝鎺� A 澶氱
+ */
+ FRIEND_UPDATE(1210, "濂藉弸淇℃伅鎵归噺鏇存柊", false, false),
+
+ // ========== 缇や簨浠讹紙1501-1520 鐩存帴澶嶇敤 OpenIM 娈典綅缂栧彿锛�1530+ 鎴戜滑鐙湁鎵╁睍锛� ==========
+ // 1500 瀵瑰簲 OpenIM GroupNotificationBegin 璧峰浣嶏紝浠呬綔鍗犱綅锛屼笉浣跨敤
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupCreatedTips锛圙roupCreatedNotification 1501锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupCreateNotification
+ * 鍦烘櫙锛氱敤鎴峰垱寤虹兢锛堝悓鏃堕個璇峰垵濮嬫垚鍛橈級锛屽叏鍛樺箍鎾紙鍚垱寤鸿�呭绔悓姝� + 鍒濆鎴愬憳锛�
+ */
+ GROUP_CREATE(1501, "缇ゅ垱寤�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupInfoSetTips锛圙roupInfoSetNotification 1502锛孨AME / NOTICE 涔嬪瀛楁鐨� generic 鍏滃簳锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupInfoUpdateNotification
+ * 鍦烘櫙锛氱兢涓讳慨鏀圭兢澶村儚 / 绠�浠嬬瓑瀛楁鍚庡叏鍛樺箍鎾�
+ */
+ GROUP_INFO_UPDATE(1502, "缇や俊鎭彉鏇�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.JoinGroupApplicationTips锛圝oinGroupApplicationNotification 1503锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupRequestReceivedNotification
+ * 鍦烘櫙锛氱敤鎴风敵璇峰姞缇� / 鏅�氭垚鍛橀個璇峰緟瀹℃壒锛屽畾鍚戠鑱婃帹閫佺粰缇や富 + 鍏ㄩ儴绠$悊鍛橈紙澶氱鍚屾锛夛紱涓嶅叆缇ゆ秷鎭祦
+ */
+ GROUP_REQUEST_RECEIVED(1503, "鏀跺埌鏂扮殑鍏ョ兢鐢宠", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.MemberQuitTips锛圡emberQuitNotification 1504锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMemberQuitNotification
+ * 鍦烘櫙锛氭垚鍛樹富鍔ㄩ��缇わ紙send-before-remove锛夛紝鍏ㄥ憳骞挎挱锛堝惈 quitter锛夛紱quitter 鑷垽 operatorUserId === self 鈫� removeGroup
+ */
+ GROUP_MEMBER_QUIT(1504, "鎴愬憳閫�缇�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupApplicationAcceptedTips锛圙roupApplicationAcceptedNotification 1505锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupRequestApprovedNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樺悓鎰忕敵璇凤紝瀹氬悜绉佽亰鎺ㄩ�佺粰鐢宠浜� + 缇や富 + 鍏ㄩ儴绠$悊鍛橈紱鐢宠浜轰晶寮� toast锛宎dmin 渚� pendingRequestCount-1锛涗笉鍏ョ兢娑堟伅娴�
+ */
+ GROUP_REQUEST_APPROVED(1505, "鍏ョ兢鐢宠琚悓鎰�", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupApplicationRejectedTips锛圙roupApplicationRejectedNotification 1506锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupRequestRejectedNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樻嫆缁濈敵璇凤紝瀹氬悜绉佽亰鎺ㄩ�佺粰鐢宠浜� + 缇や富 + 鍏ㄩ儴绠$悊鍛橈紱涓嶅叆缇ゆ秷鎭祦
+ */
+ GROUP_REQUEST_REJECTED(1506, "鍏ョ兢鐢宠琚嫆缁�", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupOwnerTransferredTips锛圙roupOwnerTransferredNotification 1507锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupOwnerTransferNotification
+ * 鍦烘櫙锛氱兢涓昏浆璁╋紝鍏ㄥ憳骞挎挱锛涘墠绔� transferOwner 鎶� ownerUserId 鍒囧埌鏂板�� + 鏃х兢涓� role 鈫� NORMAL / 鏂扮兢涓� role 鈫� OWNER
+ */
+ GROUP_OWNER_TRANSFER(1507, "缇や富杞", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.MemberKickedTips锛圡emberKickedNotification 1508锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMemberKickNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樼Щ鍑烘垚鍛橈紙send-before-remove锛夛紝鍏ㄥ憳骞挎挱锛堝惈琚涪鑰咃級锛涜韪㈣�呰嚜鍒� memberUserIds 鍚� self 鈫� removeGroup
+ */
+ GROUP_MEMBER_KICK(1508, "鎴愬憳琚Щ鍑�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.MemberInvitedTips锛圡emberInvitedNotification 1509锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMemberInviteNotification
+ * 鍦烘櫙锛氭垚鍛橀個璇锋柊浜哄叆缇わ紝鍏ㄥ憳骞挎挱锛堝惈琚個璇疯�咃級锛涜閭�璇蜂汉鍓嶇鎸� memberUserIds 鍚嚜宸辫嚜鍒わ紝鍒濇鎷夊彇 fetchGroupInfo + fetchGroupMembers
+ */
+ GROUP_MEMBER_INVITE(1509, "鎴愬憳鍔犲叆", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.MemberEnterTips锛圡emberEnterNotification 1510锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMemberEnterNotification
+ * 鍦烘櫙锛氱敤鎴风粡鎼滅储 / 浜岀淮鐮� / 鍒嗕韩閾炬帴鑷敱杩涚兢锛團REE 妯″紡鎴栧鎵归�氳繃鍚庯級锛屽叏鍛樺箍鎾紱鍓嶇鎸� entrantUserId 灞�閮ㄦ坊鍔犳垚鍛�
+ */
+ GROUP_MEMBER_ENTER(1510, "鑷敱杩涚兢", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupDismissedTips锛圙roupDismissedNotification 1511锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupDissolveNotification
+ * 鍦烘櫙锛氱兢涓昏В鏁g兢锛坰end-before-remove锛夛紝鍏ㄥ憳骞挎挱锛堝惈缇や富澶氱鍚屾锛夛紱鍓嶇 removeGroup 娓呯兢锛涚鍦虹敤鎴风绾� pull 閫氳繃 quit 璺緞锛坰end_time < quit_time锛変篃鑳芥媺鍒�
+ */
+ GROUP_DISSOLVE(1511, "缇よВ鏁�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupMemberMutedTips锛圙roupMemberMutedNotification 1512锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMemberMutedNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樼瑷�鏌愭垚鍛橈紝鍏ㄥ憳骞挎挱
+ */
+ GROUP_MEMBER_MUTED(1512, "鎴愬憳绂佽█", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupMemberCancelMutedTips锛圙roupMemberCancelMutedNotification 1513锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMemberCancelMutedNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樺彇娑堟煇鎴愬憳绂佽█锛屽叏鍛樺箍鎾�
+ */
+ GROUP_MEMBER_CANCEL_MUTED(1513, "鎴愬憳鍙栨秷绂佽█", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupMutedTips锛圙roupMutedNotification 1514锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMutedNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樺紑鍚叏缇ょ瑷�锛屽叏鍛樺箍鎾�
+ */
+ GROUP_MUTED(1514, "鍏ㄧ兢绂佽█", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupCancelMutedTips锛圙roupCancelMutedNotification 1515锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupCancelMutedNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樺彇娑堝叏缇ょ瑷�锛屽叏鍛樺箍鎾�
+ */
+ GROUP_CANCEL_MUTED(1515, "鍏ㄧ兢鍙栨秷绂佽█", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupMemberInfoSetTips锛圙roupMemberInfoSetNotification 1516锛岀獎鍖栧埌 displayUserName锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMemberNicknameUpdateNotification
+ * 鍦烘櫙锛氭垚鍛樹慨鏀硅嚜宸卞湪缇ら噷鐨勬樀绉帮紝鍦ㄧ嚎鎴愬憳鍚屾瀵瑰簲 member
+ */
+ GROUP_MEMBER_NICKNAME_UPDATE(1516, "鎴愬憳鏄电О鍙樻洿", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欸roupMemberSetToAdminNotification 1517
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupAdminAddNotification
+ * 鍦烘櫙锛氱兢涓昏缃鐞嗗憳锛屽叏鍛樺箍鎾紱鍓嶇 updateMembersRole 鎶婂搴旀垚鍛� role 鎻愬崌涓� ADMIN
+ */
+ GROUP_ADMIN_ADD(1517, "娣诲姞绠$悊鍛�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛欸roupMemberSetToOrdinaryUserNotification 1518
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupAdminRemoveNotification
+ * 鍦烘櫙锛氱兢涓绘挙閿�绠$悊鍛橈紝鍏ㄥ憳骞挎挱锛涘墠绔� updateMembersRole 鎶婂搴旀垚鍛� role 闄嶇骇涓� NORMAL
+ */
+ GROUP_ADMIN_REMOVE(1518, "鎾ら攢绠$悊鍛�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupInfoSetAnnouncementTips锛圙roupInfoSetAnnouncementNotification 1519锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupNoticeUpdateNotification
+ * 鍦烘櫙锛氱兢涓讳慨鏀圭兢鍏憡鍚庡叏鍛樺箍鎾�
+ */
+ GROUP_NOTICE_UPDATE(1519, "缇ゅ叕鍛婂彉鏇�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛歴dkws.GroupInfoSetNameTips锛圙roupInfoSetNameNotification 1520锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupNameUpdateNotification
+ * 鍦烘櫙锛氱兢涓讳慨鏀圭兢鍚嶅悗鍏ㄥ憳骞挎挱
+ */
+ GROUP_NAME_UPDATE(1520, "缇ゅ悕鍙樻洿", true, false),
+
+ // 1530+ 鎴戜滑鐙湁鎵╁睍娈碉紙OpenIM 1500-1520 娈典綅鏃犲搴旂墿锛�
+ /**
+ * 瀵瑰簲 OpenIM锛氭棤鐩存帴瀵瑰簲锛圤penIM 璧� ConversationChangeNotification 1300 鍗曡亰璺緞锛�
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMemberSettingUpdateNotification
+ * 鍦烘櫙锛氱敤鎴锋敼鑷繁鐨勭兢鍏嶆墦鎵� / 缇ゅ娉紝浠呮帹璇ョ敤鎴峰叾浠栧湪绾跨粓绔仛澶氱鍚屾
+ */
+ GROUP_MEMBER_SETTING_UPDATE(1530, "缇ゆ垚鍛樹釜浜鸿缃彉鏇�", false, false),
+ /**
+ * 瀵瑰簲 OpenIM锛氭棤锛圤penIM 鏃犵兢娑堟伅缃《鍔熻兘锛岃嚜鏈夋墿灞曪級
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMessagePinNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樼疆椤朵竴鏉$兢娑堟伅锛屽叏鍛樺箍鎾紱payload 鐩存帴甯︽秷鎭璞★紝鍓嶇鎶� message push 杩� group.pinnedMessages
+ */
+ GROUP_MESSAGE_PIN(1531, "缇ゆ秷鎭疆椤�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛氭棤锛圤penIM 鏃犵兢娑堟伅缃《鍔熻兘锛岃嚜鏈夋墿灞曪級
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupMessageUnpinNotification
+ * 鍦烘櫙锛氱兢涓� / 绠$悊鍛樺彇娑堢疆椤讹紝鍏ㄥ憳骞挎挱锛涘墠绔寜 messageId 浠� group.pinnedMessages 绉婚櫎
+ */
+ GROUP_MESSAGE_UNPIN(1532, "缇ゆ秷鎭彇娑堢疆椤�", true, false),
+ /**
+ * 瀵瑰簲 OpenIM锛氭棤锛圤penIM 鏃犵兢灏佺姒傚康锛岃嚜鏈夋墿灞曪級
+ * 瀵瑰簲鑷繁鐨勭被锛欸roupBannedNotification
+ * 鍦烘櫙锛氱鐞嗗悗鍙板皝绂� / 瑙e皝缇わ紝鍏ㄥ憳骞挎挱锛涘墠绔寜 banned 瀛楁鍒囨崲杈撳叆鏍忓皝绂佽鐩栧眰
+ */
+ GROUP_BANNED(1533, "缇ゅ皝绂佸彉鏇�", true, false);
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImContentTypeEnum::getType).toArray(Integer[]::new);
+
+ private static final Set<Integer> FRIEND_NOTIFICATION_TYPES = CollUtil.newHashSet(
+ FRIEND_REQUEST_APPROVED.type,
+ FRIEND_REQUEST_REJECTED.type,
+ FRIEND_REQUEST_RECEIVED.type,
+ FRIEND_ADD.type,
+ FRIEND_DELETE.type,
+ FRIEND_BLOCK.type,
+ FRIEND_UNBLOCK.type,
+ FRIEND_INFO_UPDATED.type,
+ FRIEND_UPDATE.type);
+
+ private static final Set<Integer> GROUP_REQUEST_NOTIFICATION_TYPES = CollUtil.newHashSet(
+ GROUP_REQUEST_RECEIVED.type,
+ GROUP_REQUEST_APPROVED.type,
+ GROUP_REQUEST_REJECTED.type);
+
+ private static final Set<Integer> RTC_NOTIFICATION_TYPES = CollUtil.newHashSet(
+ RTC_CALL.type,
+ RTC_PARTICIPANT_CONNECTED.type,
+ RTC_PARTICIPANT_DISCONNECTED.type);
+
+ /**
+ * 绫诲瀷
+ */
+ private final Integer type;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+ /**
+ * 鏄惁鍏ュ簱
+ * <p>
+ * true锛氭彃鍏� im_xxx_message 娑堟伅琛紝绂荤嚎 pull 鑳芥媺鍒帮紱
+ * false锛氫粎 WebSocket 鎺ㄩ�侊紝绂荤嚎涓㈠純锛涚姸鎬佺敱涓撶敤瀛樺偍缁存姢锛堝 READ 璧� Redis 娓告爣锛�
+ */
+ private final boolean persistent;
+ /**
+ * 鏄笉鏄敤鎴疯亰澶╂秷鎭紙normal vs event 浜屽垎锛�
+ * <p>
+ * true锛氱敤鎴蜂富鍔ㄥ彂鐨勮亰澶╂秷鎭紝璁″叆浼氳瘽鏈鏁帮紙鎺ユ敹鏂归潪婵�娲讳細璇濇椂 unreadCount + 1锛夛紱鐢ㄦ埛鍙戦�佸叆鍙d粎鍏佽杩欑被锛�
+ * false锛氱郴缁熶簨浠� / 淇″彿 / 鎻愮ず锛屼笉鍙備笌鏈璁℃暟
+ */
+ private final boolean normal;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ /**
+ * 鏍¢獙 type 宸叉敞鍐岋紝骞惰繑鍥炲搴旀灇涓撅紱鏈敞鍐岀珛鍒绘姏寮傚父锛岄伩鍏嶆柊澧� type 鏃舵紡閰� persistent / normal 灞炴��
+ *
+ * @param type 娑堟伅绫诲瀷
+ * @return 鏋氫妇瀹炰緥
+ */
+ public static ImContentTypeEnum validate(Integer type) {
+ ImContentTypeEnum result = ArrayUtil.firstMatch(item -> item.type.equals(type), values());
+ Assert.notNull(result, "鏈敞鍐岀殑娑堟伅绫诲瀷 type={}", type);
+ return result;
+ }
+
+ /**
+ * 鍒ゆ柇鏄惁涓哄ソ鍙嬮�氱煡
+ */
+ public static boolean isFriendNotification(Integer type) {
+ return type != null && FRIEND_NOTIFICATION_TYPES.contains(type);
+ }
+
+ /**
+ * 鍒ゆ柇鏄惁涓虹兢鐢宠瀹氬悜閫氱煡
+ */
+ public static boolean isGroupRequestNotification(Integer type) {
+ return type != null && GROUP_REQUEST_NOTIFICATION_TYPES.contains(type);
+ }
+
+ /**
+ * 鍒ゆ柇鏄惁涓洪�氳瘽淇′护閫氱煡
+ */
+ public static boolean isRtcNotification(Integer type) {
+ return type != null && RTC_NOTIFICATION_TYPES.contains(type);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImConversationTypeEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImConversationTypeEnum.java
new file mode 100644
index 0000000..eb3c053
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/ImConversationTypeEnum.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.im.enums;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * IM 浼氳瘽绫诲瀷鏋氫妇
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImConversationTypeEnum implements ArrayValuable<Integer> {
+
+ NONE(0, "鏃犱細璇�"), // 鏃犱細璇�
+ PRIVATE(1, "绉佽亰"), // 绉佽亰
+ GROUP(2, "缇よ亰"), // 缇よ亰
+ CHANNEL(3, "棰戦亾"); // 棰戦亾 / 鍏紬鍙�
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImConversationTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 绫诲瀷
+ */
+ private final Integer type;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isNone(Integer type) {
+ return Objects.equals(NONE.type, type);
+ }
+
+ public static boolean isPrivate(Integer type) {
+ return Objects.equals(PRIVATE.type, type);
+ }
+
+ public static boolean isGroup(Integer type) {
+ return Objects.equals(GROUP.type, type);
+ }
+
+ public static boolean isChannel(Integer type) {
+ return Objects.equals(CHANNEL.type, type);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/channel/ImChannelMaterialTypeEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/channel/ImChannelMaterialTypeEnum.java
new file mode 100644
index 0000000..55982c7
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/channel/ImChannelMaterialTypeEnum.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.enums.channel;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * IM 棰戦亾绱犳潗鍐呭绫诲瀷鏋氫妇
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Getter
+@AllArgsConstructor
+public enum ImChannelMaterialTypeEnum implements ArrayValuable<Integer> {
+
+ /**
+ * 绔欏唴瀵屾枃鏈紱鐐瑰嚮绱犳潗鍦ㄥ鎴风鍐呯疆璇︽儏椤垫媺 content 娓叉煋
+ */
+ CONTENT(1, "绔欏唴瀵屾枃鏈�"),
+ /**
+ * 澶栭摼锛涚偣鍑荤礌鏉愯烦 url 鎵撳紑娴忚鍣�
+ */
+ LINK(2, "澶栭摼");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImChannelMaterialTypeEnum::getType).toArray(Integer[]::new);
+
+ private final Integer type;
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendAddSourceEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendAddSourceEnum.java
new file mode 100644
index 0000000..55ad7ac
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendAddSourceEnum.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.im.enums.friend;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * IM 濂藉弸娣诲姞鏉ユ簮鏋氫妇
+ * <p>
+ * 鐢卞彂璧锋柟璋冪敤 apply 鎺ュ彛鏃朵紶鍏ワ紱鍚屾剰鍚庡悓姝ュ啓鍏� im_friend.add_source锛堝弻鍚戯級
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImFriendAddSourceEnum implements ArrayValuable<Integer> {
+
+ SEARCH(1, "鎼滅储"), // FriendAddDialog 鎼滅储娴佺▼
+ GROUP(2, "缇よ亰"), // 缇ゆ垚鍛樹富椤� 鈫� UserInfo銆屽姞涓哄ソ鍙嬨�嶅叆鍙�
+ QR_CODE(3, "鎵爜"), // TODO @鑺嬭壙锛氬悗缁疄鐜版壂鐮佸姞濂藉弸
+ CARD(4, "鍚嶇墖"); // TODO @鑺嬭壙锛氬悗缁疄鐜伴�氳繃鍚嶇墖鍔犲ソ鍙嬶紝绫讳技寰俊鐨勩�屾壂涓�鎵� - 鍚嶇墖銆嶅姛鑳斤紝鎴栬�呫�岄�氳褰� - 鎺ㄨ崘濂藉弸銆嶅姛鑳�
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImFriendAddSourceEnum::getSource).toArray(Integer[]::new);
+
+ /**
+ * 鏉ユ簮
+ */
+ private final Integer source;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendRequestHandleResultEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendRequestHandleResultEnum.java
new file mode 100644
index 0000000..d5d2bf8
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendRequestHandleResultEnum.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.im.enums.friend;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * IM 濂藉弸鐢宠澶勭悊缁撴灉鏋氫妇
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImFriendRequestHandleResultEnum implements ArrayValuable<Integer> {
+
+ UNHANDLED(0, "鏈鐞�"),
+ AGREED(1, "鍚屾剰"),
+ REFUSED(2, "鎷掔粷");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImFriendRequestHandleResultEnum::getResult).toArray(Integer[]::new);
+
+ /**
+ * 缁撴灉
+ */
+ private final Integer result;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ /**
+ * 鍒ゆ柇鐢宠鏄惁杩樻湭澶勭悊
+ */
+ public static boolean isUnhandled(Integer result) {
+ return Objects.equals(UNHANDLED.result, result);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendStateEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendStateEnum.java
new file mode 100644
index 0000000..888f6a9
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/friend/ImFriendStateEnum.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.im.enums.friend;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * IM 濂藉弸鍏崇郴鐘舵�侊紙鍚堝苟銆屾槸鍚﹀ソ鍙嬨��+銆屾槸鍚︽媺榛戙�嶄袱鎬侊級
+ * <p>
+ * 鐢� state 鑰岄潪 status锛氶伩鍏嶅拰 ImFriendDO 鐨� status 鐗╃悊瀛楁锛圕ommonStatusEnum锛欵NABLE / DISABLE锛夋贩娣嗐��
+ * <p>
+ * 鐢ㄤ簬 ImFriendService.getFriendState 杩斿洖鍊间笌 FRIEND_STATE 缂撳瓨鍊硷細绉佽亰鍙戦�佺儹鐐硅矾寰勪笅锛宻ender 璋冪紦瀛樺嵆鍙悓鏃跺垽瀹氥�岃兘鍚﹀彂銆嶅拰銆屾槸鍚﹀睆钄芥帴鏀舵柟銆�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImFriendStateEnum implements ArrayValuable<Integer> {
+
+ NONE(0, "闈炲ソ鍙� / 宸插垹闄�"),
+ FRIEND(1, "濂藉弸"),
+ BLOCKED(2, "濂藉弸涓斿凡琚鏂规媺榛�");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImFriendStateEnum::getState).toArray(Integer[]::new);
+
+ /**
+ * 鐘舵�佸��
+ */
+ private final Integer state;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isNone(Integer state) {
+ return Objects.equals(NONE.state, state);
+ }
+
+ public static boolean isFriend(Integer state) {
+ return Objects.equals(FRIEND.state, state);
+ }
+
+ public static boolean isBlocked(Integer state) {
+ return Objects.equals(BLOCKED.state, state);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupAddSourceEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupAddSourceEnum.java
new file mode 100644
index 0000000..d12e098
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupAddSourceEnum.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.im.enums.group;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * IM 鍔犲叆缇よ亰鏉ユ簮鏋氫妇
+ * <p>
+ * 鐢卞彂璧锋柟鍦ㄧ敵璇� / 閭�璇锋椂浼犲叆锛涘悓鎰忓悗鍚屾鍐欏叆 ImGroupMemberDO 鐨� addSource 瀛楁
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImGroupAddSourceEnum implements ArrayValuable<Integer> {
+
+ SEARCH(1, "鎼滅储"), // TODO @鑺嬭壙锛歋EARCH 鏆傛湭瀹炵幇锛屽師鍥� - 鎼滅兢鍏ュ彛灏氭湭寮�鍙�
+ INVITE(2, "閭�璇�"),
+ QR_CODE(3, "鎵爜"), // TODO @鑺嬭壙锛歈R_CODE 鏆傛湭瀹炵幇锛屽師鍥� - 缇や簩缁寸爜鎵爜杩涚兢鍏ュ彛灏氭湭寮�鍙�
+ SHARE_LINK(4, "鍒嗕韩閾炬帴"); // TODO @鑺嬭壙锛歋HARE_LINK 鏆傛湭瀹炵幇锛屽師鍥� - 缇ゅ垎浜摼鎺ヨ繘缇ゅ叆鍙e皻鏈紑鍙�
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImGroupAddSourceEnum::getSource).toArray(Integer[]::new);
+
+ /**
+ * 鏉ユ簮
+ */
+ private final Integer source;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupMemberRoleEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupMemberRoleEnum.java
new file mode 100644
index 0000000..48a4e79
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupMemberRoleEnum.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.im.enums.group;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * IM 缇ゆ垚鍛樿鑹叉灇涓�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImGroupMemberRoleEnum implements ArrayValuable<Integer> {
+
+ OWNER(1, "缇や富"),
+ ADMIN(2, "绠$悊鍛�"),
+ NORMAL(3, "鏅�氭垚鍛�");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImGroupMemberRoleEnum::getRole).toArray(Integer[]::new);
+
+ /**
+ * 瑙掕壊
+ */
+ private final Integer role;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isOwner(Integer role) {
+ return Objects.equals(OWNER.role, role);
+ }
+
+ public static boolean isAdmin(Integer role) {
+ return Objects.equals(ADMIN.role, role);
+ }
+
+ public static boolean isOwnerOrAdmin(Integer role) {
+ return isOwner(role) || isAdmin(role);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupRequestHandleResultEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupRequestHandleResultEnum.java
new file mode 100644
index 0000000..1be6df5
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/group/ImGroupRequestHandleResultEnum.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.im.enums.group;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * IM 鍔犵兢鐢宠澶勭悊缁撴灉鏋氫妇
+ * <p>
+ * 鍙栧�间笌 {@link cn.iocoder.yudao.module.im.enums.friend.ImFriendRequestHandleResultEnum} 骞宠锛屼究浜庡鐢ㄥ績鏅烘ā鍨�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImGroupRequestHandleResultEnum implements ArrayValuable<Integer> {
+
+ UNHANDLED(0, "鏈鐞�"),
+ AGREED(1, "鍚屾剰"),
+ REFUSED(2, "鎷掔粷");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImGroupRequestHandleResultEnum::getResult).toArray(Integer[]::new);
+
+ /**
+ * 缁撴灉
+ */
+ private final Integer result;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ /**
+ * 鍒ゆ柇鐢宠鏄惁杩樻湭澶勭悊
+ */
+ public static boolean isUnhandled(Integer result) {
+ return Objects.equals(UNHANDLED.result, result);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageReceiptStatusEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageReceiptStatusEnum.java
new file mode 100644
index 0000000..41e3cf0
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageReceiptStatusEnum.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.im.enums.message;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * IM 娑堟伅鍥炴墽鐘舵�佹灇涓�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Getter
+@AllArgsConstructor
+public enum ImMessageReceiptStatusEnum implements ArrayValuable<Integer> {
+
+ NO_RECEIPT(0, "涓嶉渶瑕佸洖鎵�"),
+ PENDING(1, "寰呭畬鎴�"),
+ DONE(2, "宸插畬鎴�");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImMessageReceiptStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 鐘舵��
+ */
+ private final Integer status;
+
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java
new file mode 100644
index 0000000..537f95c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.im.enums.message;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * IM 娑堟伅鐘舵�佹灇涓�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImMessageStatusEnum implements ArrayValuable<Integer> {
+
+ SENDING(-1, "鍙戦�佷腑"), // 浠呭鎴风浣跨敤
+ NORMAL(0, "姝e父"), // 绉佽亰 / 缇よ亰鐨勬甯革紙鍒濆锛夌姸鎬�
+ RECALL(2, "宸叉挙鍥�");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImMessageStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 鐘舵��
+ */
+ private final Integer status;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallEndReasonEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallEndReasonEnum.java
new file mode 100644
index 0000000..51099b4
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallEndReasonEnum.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.im.enums.rtc;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * IM 閫氳瘽缁撴潫鍘熷洜鏋氫妇锛涜惤鍘嗗彶娑堟伅鏃惰绠� content 鏂囨
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImRtcCallEndReasonEnum implements ArrayValuable<Integer> {
+
+ HANGUP(1, "閫氳瘽缁撴潫"), // 鎺ラ�氬悗浠讳竴鏂逛富鍔ㄦ寕鏂�
+ REJECT(2, "宸叉嫆缁�"), // 琚彨鎺ラ�氬墠鐐规嫆鎺�
+ CANCEL(3, "宸插彇娑�"), // 涓诲彨鎺ラ�氬墠涓诲姩鍙栨秷
+ NO_ANSWER(4, "鏃犱汉鎺ュ惉"), // 鎸搩瓒呮椂鏈帴閫氾紱鐢卞弬涓庤�呰秴鏃� Job 瑙﹀彂
+ BUSY(5, "瀵规柟姝e繖"), // 绉佽亰鍛煎彨鏃跺鏂瑰湪鍙︿竴閫氳瘽
+ ERROR(9, "閫氳瘽寮傚父"); // 缃戠粶涓柇銆佽澶囧け璐ョ瓑
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImRtcCallEndReasonEnum::getReason).toArray(Integer[]::new);
+
+ /**
+ * 鍘熷洜鍊�
+ */
+ private final Integer reason;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallMediaTypeEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallMediaTypeEnum.java
new file mode 100644
index 0000000..9f767b9
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallMediaTypeEnum.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.im.enums.rtc;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * IM 閫氳瘽濯掍綋绫诲瀷鏋氫妇
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImRtcCallMediaTypeEnum implements ArrayValuable<Integer> {
+
+ VOICE(1, "璇煶"), // 浠呴煶棰�
+ VIDEO(2, "瑙嗛"); // 闊抽 + 瑙嗛
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImRtcCallMediaTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 绫诲瀷
+ */
+ private final Integer type;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isVoice(Integer type) {
+ return Objects.equals(VOICE.type, type);
+ }
+
+ public static boolean isVideo(Integer type) {
+ return Objects.equals(VIDEO.type, type);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallStatusEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallStatusEnum.java
new file mode 100644
index 0000000..42b3cda
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcCallStatusEnum.java
@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.im.enums.rtc;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * IM 閫氳瘽鐘舵�佹灇涓撅紙涓昏〃 status锛�
+ * <p>
+ * 鐘舵�佹満锛欳REATED 鈫� RUNNING 鈫� ENDED锛汣REATED 鐩存帴鍒� ENDED 琛ㄧず鏃犱汉鎺ュ惉 / 涓诲彨鍙栨秷
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImRtcCallStatusEnum implements ArrayValuable<Integer> {
+
+ CREATED(10, "鍒涘缓"), // 閫氳瘽宸插垱寤猴紱绉佽亰锛氱瓑琚彨鎺ュ惉锛涚兢鑱婏細鍙戣捣浜哄凡杩涙埧锛岀瓑鍏朵粬浜哄姞鍏�
+ RUNNING(20, "杩涜涓�"), // 绗竴涓潪鍙戣捣浜烘帴閫氬悗杩涘叆
+ ENDED(30, "宸茬粨鏉�"); // 浠讳竴鏂规寕鏂� / 涓诲彨 cancel / Webhook 鍏滃簳
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImRtcCallStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 娲昏穬鐘舵�侀泦鍚堬紱閫氳瘽鏈粨鏉燂紙CREATED / RUNNING锛�
+ */
+ public static final List<Integer> ACTIVE_STATUSES = ListUtil.of(CREATED.getStatus(), RUNNING.getStatus());
+
+ /**
+ * 鐘舵�佸��
+ */
+ private final Integer status;
+ /**
+ * 鐘舵�佸悕
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isCreated(Integer status) {
+ return Objects.equals(CREATED.status, status);
+ }
+
+ public static boolean isRunning(Integer status) {
+ return Objects.equals(RUNNING.status, status);
+ }
+
+ public static boolean isEnded(Integer status) {
+ return Objects.equals(ENDED.status, status);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcParticipantRoleEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcParticipantRoleEnum.java
new file mode 100644
index 0000000..125c5f0
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcParticipantRoleEnum.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.im.enums.rtc;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * IM 閫氳瘽鍙備笌鑰呰鑹叉灇涓�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImRtcParticipantRoleEnum implements ArrayValuable<Integer> {
+
+ INVITER(1, "鍙戣捣浜�"),
+ INVITEE(2, "琚個璇疯��"),
+ JOINER(3, "涓诲姩鍔犲叆鑰�"); // 浠呯兢閫氳瘽鍦烘櫙锛氭梺瑙傝�呯偣鑳跺泭鏉″姞鍏ュ凡鏈夐�氳瘽
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImRtcParticipantRoleEnum::getRole).toArray(Integer[]::new);
+
+ /**
+ * 瑙掕壊
+ */
+ private final Integer role;
+ /**
+ * 鍚嶅瓧
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcParticipantStatusEnum.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcParticipantStatusEnum.java
new file mode 100644
index 0000000..c4af81b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/rtc/ImRtcParticipantStatusEnum.java
@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.im.enums.rtc;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * IM 閫氳瘽鍙備笌鑰呯姸鎬佹灇涓撅紙鏄庣粏琛� status锛�
+ * <p>
+ * 缁堟�侀棴鍚堬細閫氳瘽 ENDED 鏃舵墍鏈夋槑缁� status 蹇呭睘 {LEFT / REJECTED / NO_ANSWER}
+ * <p>
+ * 1銆両NVITING 鈫� JOINED 鈫� LEFT锛堟帴閫氬悗鎸傛柇 / 绂诲紑锛夛紱
+ * 2銆両NVITING 鈫� REJECTED锛堟帴閫氬墠鐐规嫆鎺ワ級锛�
+ * 3銆両NVITING 鈫� NO_ANSWER锛堥�氳瘽缁撴潫浠嶆湭搴旂瓟锛�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@RequiredArgsConstructor
+@Getter
+public enum ImRtcParticipantStatusEnum implements ArrayValuable<Integer> {
+
+ INVITING(10, "閭�璇蜂腑"), // 宸插彂鍑� invite锛岀瓑琚彨鍝嶅簲
+ JOINED(20, "宸插姞鍏�"), // 宸� connect 杩� LiveKit 鎴块棿
+ REJECTED(30, "宸叉嫆缁�"), // 鎺ラ�氬墠鐐规嫆鎺�
+ NO_ANSWER(40, "鏈簲绛�"), // 閫氳瘽宸茬粨鏉熶粛鏈簲绛旓紱endSession 鎵归噺鏀�
+ LEFT(50, "宸茬寮�"); // 鎺ラ�氬悗鎸傛柇 / Webhook 鍏滃簳
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(ImRtcParticipantStatusEnum::getStatus).toArray(Integer[]::new);
+
+ /**
+ * 娲昏穬鐘舵�侀泦鍚堬紱灏氭湭绂诲紑閫氳瘽锛圛NVITING / JOINED锛�
+ */
+ public static final List<Integer> ACTIVE_STATUSES = ListUtil.of(INVITING.getStatus(), JOINED.getStatus());
+
+ /**
+ * 鐘舵�佸��
+ */
+ private final Integer status;
+ /**
+ * 鐘舵�佸悕
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isInviting(Integer status) {
+ return Objects.equals(INVITING.status, status);
+ }
+
+ public static boolean isJoined(Integer status) {
+ return Objects.equals(JOINED.status, status);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/config/ImProperties.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/config/ImProperties.java
new file mode 100644
index 0000000..8a8192f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/config/ImProperties.java
@@ -0,0 +1,195 @@
+package cn.iocoder.yudao.module.im.framework.config;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.annotation.Validated;
+
+/**
+ * IM 妯″潡鍏ㄥ眬閰嶇疆
+ * <p>
+ * 鍚勫瓙妯″潡鐢ㄥ祵濂� inner class 鍖哄垎锛坒riend / group / face / message / rtc 绛夛級锛�
+ * yaml 璺緞淇濇寔 yudao.im.{module}.{key} 涓庡師鏈夐儴缃蹭繚鎸佸吋瀹�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Component
+@ConfigurationProperties(prefix = "yudao.im")
+@Validated
+@Data
+public class ImProperties {
+
+ private Friend friend = new Friend();
+
+ private Group group = new Group();
+
+ private Face face = new Face();
+
+ private Message message = new Message();
+
+ @Valid
+ private Rtc rtc = new Rtc();
+
+ /**
+ * 濂藉弸妯″潡閰嶇疆
+ */
+ @Data
+ public static class Friend {
+
+ /**
+ * 鏄惁鑷姩閫氳繃鎵�鏈夊ソ鍙嬬敵璇凤紙鍏ㄥ眬寮�鍏筹級
+ * <p>
+ * 榛樿 false锛屾櫘閫氱敤鎴峰繀椤昏蛋鐢宠-瀹℃壒娴佺▼锛涘紑鍚悗鎵�鏈夌敤鎴风殑濂藉弸鐢宠浼氱珛鍗冲悓鎰忥紝涓昏鐢ㄤ簬鍏ㄥ憳寮�鏀惧瀷 IM 閮ㄧ讲銆�
+ * 濡傞渶缁嗗寲鍒般�屼粎鐗瑰畾鐢ㄦ埛鑷姩閫氳繃銆嶏紙濡傛満鍣ㄤ汉 / AI 璐﹀彿锛夛紝璇峰湪 system 鐢ㄦ埛琛ㄥ姞瀛楁锛屽苟鍦� applyFriend 鍐呮寜鐢ㄦ埛绾у紑鍏崇煭璺�
+ */
+ private boolean autoAccept = false;
+
+ }
+
+ /**
+ * 缇ゆā鍧楅厤缃�
+ */
+ @Data
+ public static class Group {
+
+ /**
+ * 缇ゆ渶澶ф垚鍛樹汉鏁�
+ */
+ private int maxMember = 500;
+
+ /**
+ * 鍗曠兢绠$悊鍛樹汉鏁颁笂闄�
+ */
+ private int adminMaxCount = 3;
+
+ /**
+ * 鍗曠兢缃《娑堟伅鏉℃暟涓婇檺
+ */
+ private int pinMaxCount = 5;
+
+ }
+
+ /**
+ * 琛ㄦ儏妯″潡閰嶇疆
+ */
+ @Data
+ public static class Face {
+
+ /**
+ * 涓汉琛ㄦ儏鏁伴噺涓婇檺
+ */
+ private int userItemMaxCount = 200;
+
+ }
+
+ /**
+ * 娑堟伅妯″潡閰嶇疆
+ */
+ @Data
+ public static class Message {
+
+ /**
+ * 鏄惁鍚敤绉佽亰宸茶鍔熻兘
+ * <p>
+ * 鍏抽棴鍚庯細private read 鎺ュ彛鐩存帴鎶涗笟鍔″紓甯革紱鏈嶅姟绔笉鍐嶄笅鍙戠鑱� READ / RECEIPT 浜嬩欢淇″彿銆�
+ * 瀹㈡埛绔晶闇�闀滃儚姝ゅ紑鍏筹紝闅愯棌绉佽亰姘旀场鐨勩�屽凡璇� / 鏈銆嶆爣绛�
+ */
+ private boolean privateReadEnabled = true;
+
+ /**
+ * 鏄惁鍚敤缇よ亰宸茶鍔熻兘锛堝惈缇ゆ秷鎭洖鎵э級
+ * <p>
+ * 鍏抽棴鍚庯細group read 鎺ュ彛鐩存帴鎶涗笟鍔″紓甯革紱鏈嶅姟绔笉鍐嶄笅鍙戠兢 READ / RECEIPT 浜嬩欢淇″彿锛�
+ * 缇ゆ秷鎭洖鎵� receiptStatus 涓�骞跺仠鐢紙鍗充娇鍙戦�佹柟浼� receipt=true 涔熷己鍒惰惤 NO_RECEIPT锛屼笉鍐嶇畻銆孨 浜哄凡璇汇�嶏級銆�
+ * 瀹㈡埛绔晶闇�闀滃儚姝ゅ紑鍏筹紝闅愯棌缇ゅ洖鎵� popover 涓庛�屽彂閫佸洖鎵ф秷鎭�嶅叆鍙�
+ */
+ private boolean groupReadEnabled = true;
+
+ /**
+ * pull 鏈�澶ф媺鍙栨暟閲�
+ */
+ private int maxPullSize = 1000;
+
+ /**
+ * 娑堟伅鎾ゅ洖鏃堕棿闄愬埗锛堝垎閽燂級
+ */
+ private int recallTimeoutMinutes = 5;
+
+ /**
+ * 绉佽亰绂荤嚎娑堟伅鏈�澶ф媺鍙栧ぉ鏁�
+ * <p>
+ * 瀹㈡埛绔�氳繃 pull 鎺ュ彛澧為噺鎷夊彇绉佽亰绂荤嚎娑堟伅鏃讹紝浠呰繑鍥炴渶杩� N 澶╁唴浜х敓鐨勬秷鎭紝
+ * 瓒呰繃璇ョ獥鍙g殑鑰佹秷鎭笉鍐嶄富鍔ㄦ帹閫侊紙鍙�氳繃鍘嗗彶娑堟伅鎺ュ彛鎸夐渶鍊掔炕锛夈��
+ */
+ private int privatePullMaxDays = 30;
+
+ /**
+ * 缇よ亰绂荤嚎娑堟伅鏈�澶ф媺鍙栧ぉ鏁�
+ * <p>
+ * 瀹㈡埛绔�氳繃 pull 鎺ュ彛澧為噺鎷夊彇缇よ亰绂荤嚎娑堟伅鏃讹紝浠呰繑鍥炴渶杩� N 澶╁唴浜х敓鐨勬秷鎭紱
+ * 閫�缇ゅ墠娑堟伅鐨勮ˉ榻愪篃浠ヨ绐楀彛涓哄熀鍑嗭紙鏃╀簬绐楀彛鐨勯��缇ょ兢涓嶅啀鎵弿锛夛紝閬垮厤鑰佺敤鎴烽娆�
+ * 鎷夊彇鏃跺鍘嗗彶閫�缇ょ兢鍋氬ぇ閲忔煡璇€��
+ */
+ private int groupPullMaxDays = 30;
+
+ }
+
+ /**
+ * 瀹炴椂閫氳瘽妯″潡閰嶇疆
+ * <p>
+ * 濯掍綋璧� LiveKit SFU锛涘悗绔彧绛� Token + 閫氳繃 IM 闀胯繛鎺ユ帹閫佹潵鐢� / 鎺ラ�� / 缁撴潫涓夌淇′护銆�
+ * 鍏抽棴鍚庢墍鏈� RTC 鎺ュ彛鐩存帴鎶� RTC_NOT_ENABLED锛涘墠绔彲鎹闅愯棌閫氳瘽鎸夐挳銆�
+ */
+ @Data
+ public static class Rtc {
+
+ /**
+ * 鏄惁鍚敤瀹炴椂閫氳瘽鍔熻兘
+ */
+ private boolean enabled = true;
+
+ /**
+ * LiveKit Server WebSocket 鍦板潃锛涘鎴风 connect 鏃朵娇鐢紝閫氬父 ws://host:7880 鎴� wss://host
+ */
+ @NotBlank(message = "LiveKit URL 涓嶈兘涓虹┖")
+ private String livekitUrl = "ws://127.0.0.1:7880";
+
+ /**
+ * LiveKit API Key
+ */
+ @NotBlank(message = "LiveKit API Key 涓嶈兘涓虹┖")
+ private String apiKey = "devkey";
+
+ /**
+ * LiveKit API Secret锛涚敓浜у繀椤绘敼涓哄己闅忔満鍊�
+ */
+ @NotBlank(message = "LiveKit API Secret 涓嶈兘涓虹┖")
+ @Size(min = 32, message = "LiveKit API Secret 闀垮害闇� 鈮� 32 浣�")
+ private String apiSecret = "secret-poc-key-min-32-chars-required-here";
+
+ /**
+ * 鍗曟绛惧彂鐨� Token 鏈夋晥鏈燂紙灏忔椂锛�
+ */
+ private int tokenTtlHours = 6;
+
+ /**
+ * 缇ら�氳瘽鏈�澶у悓鏃跺湪鎴挎垚鍛樻暟锛涜秴杩� invite 鐩存帴鎷掔粷
+ */
+ private int groupMaxParticipants = 16;
+
+ /**
+ * 鍍靛案閫氳瘽娓呯悊闃堝�硷紙鍒嗛挓锛夛紱閫氳瘽鍒涘缓瓒呰繃姝ゅ�间粛鏈粨鏉熸墠绾冲叆鎵弿锛岄伩寮�銆屽垰鍙戣捣杩樺湪鍝嶉搩銆嶇殑鍚堢悊闆朵汉鎬�
+ */
+ private int cleanupZombieThresholdMinutes = 5;
+
+ /**
+ * 鎸搩瓒呮椂闃堝�硷紙鍒嗛挓锛夛紱琚彨 INVITING 瓒呰繃姝ゅ�兼湭鎺ラ�� 鈫� 鏍� NO_ANSWER + 鎺� RTC_CALL(REJECT) 璁� banner 鏀舵暃
+ */
+ private int inviteTimeoutMinutes = 1;
+
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/package-info.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/package-info.java
new file mode 100644
index 0000000..61b6dae
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * 灞炰簬 erp 妯″潡鐨� framework 灏佽
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+package cn.iocoder.yudao.module.im.framework;
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/config/ImRtcConfiguration.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/config/ImRtcConfiguration.java
new file mode 100644
index 0000000..12bf2e1
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/config/ImRtcConfiguration.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.im.framework.rtc.config;
+
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.framework.rtc.core.LiveKitClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * im 妯″潡鐨� RTC 缁勪欢鐨� Configuration
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Configuration(proxyBeanMethods = false)
+public class ImRtcConfiguration {
+
+ /**
+ * LiveKit 瀹㈡埛绔�
+ */
+ @Bean
+ public LiveKitClient liveKitClient(ImProperties imProperties) {
+ return new LiveKitClient(imProperties);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitClient.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitClient.java
new file mode 100644
index 0000000..9aea183
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitClient.java
@@ -0,0 +1,244 @@
+package cn.iocoder.yudao.module.im.framework.rtc.core;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONUtil;
+import cn.hutool.jwt.JWT;
+import cn.hutool.jwt.signers.JWTSignerUtil;
+import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import lombok.extern.slf4j.Slf4j;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * LiveKit 瀹㈡埛绔�
+ * <p>
+ * 鍘傚晢缁戝畾灞傚皝瑁咃細Token 绛惧彂锛坖oin / admin锛夈�丼erver API锛圖eleteRoom / ListParticipants锛夈�乮dentity 鎷兼帴 / 瑙f瀽
+ * <p>
+ * 鐢� {@link cn.iocoder.yudao.module.im.framework.rtc.config.ImRtcConfiguration} 娉ㄥ唽涓� Bean锛屾湰绫讳笉甯� {@code @Component}
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+public class LiveKitClient {
+
+ /**
+ * Twirp 绔偣璺緞
+ */
+ private static final String TWIRP_DELETE_ROOM = "/twirp/livekit.RoomService/DeleteRoom";
+ private static final String TWIRP_LIST_PARTICIPANTS = "/twirp/livekit.RoomService/ListParticipants";
+
+ /**
+ * 绠$悊 Token 鏈夋晥鏈燂紱Server API 涓�娆¤皟鐢ㄥ嵆寮冿紝10 绉掕冻澶�
+ */
+ private static final Duration ADMIN_TOKEN_TTL = Duration.ofSeconds(10);
+
+ /**
+ * Server API HTTP 璋冪敤鐨勮秴鏃朵笂闄愶紱瓒呮椂鍚庣洿鎺ユ姤閿欙紝閬垮厤 LiveKit 寮傚父 / 缃戠粶鎶栧姩鏃朵笟鍔¢暱鏃堕棿闃诲
+ */
+ private static final int SERVER_API_TIMEOUT_MS = 10_000;
+
+ private final ImProperties imProperties;
+
+ /**
+ * @param imProperties IM 鍏ㄥ眬閰嶇疆锛涗粠涓 livekitUrl / apiKey / apiSecret / tokenTtlHours
+ */
+ public LiveKitClient(ImProperties imProperties) {
+ this.imProperties = imProperties;
+ }
+
+ /**
+ * 绛惧彂瀹㈡埛绔繘鎴� Token锛涙湁鏁堟湡浠� {@link ImProperties.Rtc#getTokenTtlHours()} 璇诲彇
+ *
+ * @param identity 鐢ㄦ埛鍞竴鏍囪瘑锛涘啓鍏� sub claim锛涘悓 identity 閲嶈繛浼氳涪鍓嶄竴涓繛鎺�
+ * @param displayName 瀹㈡埛绔睍绀哄悕锛涘彲绌�
+ * @param room 鎴块棿鍚�
+ * @return JWT 瀛楃涓�
+ */
+ public String signJoinToken(String identity, String displayName, String room) {
+ Assert.notBlank(identity, "identity 涓嶅彲涓虹┖");
+ Assert.notBlank(room, "room 涓嶅彲涓虹┖");
+ ImProperties.Rtc cfg = imProperties.getRtc();
+
+ // video claim锛氶檺瀹氬鎴风鑳藉湪璇ユ埧闂村唴鍋氫粈涔�
+ Map<String, Object> video = new HashMap<>();
+ video.put("roomJoin", true); // 鍏佽鍔犲叆鎴块棿
+ video.put("room", room); // 闄愬畾鍙兘鍔犲叆杩欎釜鎴块棿
+ video.put("canPublish", true); // 鍏佽鍙戝竷濯掍綋锛堟帹娴侊級
+ video.put("canSubscribe", true); // 鍏佽璁㈤槄濯掍綋锛堟媺娴侊級
+ video.put("canPublishData", true); // 鍏佽鍙戦�� data channel 娑堟伅
+
+ long nowSec = Instant.now().getEpochSecond();
+ long ttlSec = Duration.ofHours(cfg.getTokenTtlHours()).getSeconds();
+ JWT jwt = JWT.create()
+ .setIssuer(cfg.getApiKey())
+ .setSubject(identity)
+ .setNotBefore(new Date(nowSec * 1000))
+ .setExpiresAt(new Date((nowSec + ttlSec) * 1000))
+ .setPayload("video", video)
+ .setSigner(JWTSignerUtil.hs256(cfg.getApiSecret().getBytes(StandardCharsets.UTF_8)));
+ if (StrUtil.isNotEmpty(displayName)) {
+ jwt.setPayload("name", displayName);
+ }
+ return jwt.sign();
+ }
+
+ /**
+ * 璋冪敤 LiveKit Server API 鍒犻櫎鎴块棿锛氱敤浜庨�氳瘽缁撴潫鏃讹紝寮哄埗鏂紑寮傚父娈嬬暀瀹㈡埛绔�
+ *
+ * @param room 鎴块棿鍚�
+ */
+ @SuppressWarnings("EmptyTryBlock")
+ public void deleteRoom(String room) {
+ try (HttpResponse ignored = postTwirp(TWIRP_DELETE_ROOM, room)) {
+ // 鐘舵�佺爜涓嶅尯鍒嗭紱璋冪敤鏂瑰け璐ュ嵆鍏滃簳
+ }
+ }
+
+ /**
+ * 璋冪敤 LiveKit Server API 鏌ヨ鏌愭埧闂村唴鐨勫弬涓庤�呮暟閲忥細鐢ㄤ簬瀹氭椂鎵弿鍍靛案閫氳瘽
+ * <p>
+ * 鎴块棿涓嶅瓨鍦� LiveKit 杩斿洖 404锛岃鍚� 0 浜�
+ *
+ * @param room 鎴块棿鍚�
+ * @return 鍙備笌鑰呮暟閲忥紱HTTP 澶辫触杩斿洖 -1
+ */
+ public int listParticipants(String room) {
+ try (HttpResponse response = postTwirp(TWIRP_LIST_PARTICIPANTS, room)) {
+ if (response.getStatus() == 404) {
+ return 0;
+ }
+ if (!response.isOk()) {
+ log.warn("[listParticipants][LiveKit 杩斿洖闈� 2xx status={} room={} body={}]",
+ response.getStatus(), room, response.body());
+ return -1;
+ }
+ JSONArray participants = JSONUtil.parseObj(response.body()).getJSONArray("participants");
+ return CollUtil.size(participants);
+ }
+ }
+
+ /**
+ * 鎷兼帴 LiveKit identity锛涘綋鍓嶅崟绔� = userId 瀛楃涓�
+ * <p>
+ * 澶氱鎵╁睍鏃舵敼 {@code userId + "#" + terminal} 鏍煎紡锛岃皟鐢ㄦ柟鏃犻渶鏀�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return identity 瀛楃涓�
+ */
+ public String buildIdentity(Long userId) {
+ Assert.notNull(userId, "userId 涓嶅彲涓虹┖");
+ return String.valueOf(userId);
+ }
+
+ /**
+ * 浠� LiveKit identity 瑙f瀽涓氬姟 userId
+ * <p>
+ * 褰撳墠 identity 鐩存帴鏄� userId 瀛楃涓诧紱棰勭暀 {@code userId#terminal} 澶氱鏍煎紡
+ *
+ * @param identity LiveKit identity
+ * @return 鐢ㄦ埛缂栧彿锛涜В鏋愬け璐ヨ繑鍥� null
+ */
+ public Long parseUserId(String identity) {
+ if (StrUtil.isBlank(identity)) {
+ return null;
+ }
+ int sep = identity.indexOf('#');
+ String idPart = sep >= 0 ? identity.substring(0, sep) : identity;
+ try {
+ return Long.parseLong(idPart);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+ /**
+ * 鏍¢獙 LiveKit Webhook 绛惧悕锛涙祦绋嬪弬瑙�
+ * <a href="https://docs.livekit.io/home/server/webhook/#receiving-webhooks">webhook 鏂囨。</a>
+ * <p>
+ * 鏍¢獙涓ゆ锛�
+ * 1.1 JWT HS256 绛惧悕楠岃瘉锛涘瘑閽ヤ娇鐢� LiveKit API Secret
+ * 1.2 body 鐨� sha256 涓� JWT 鍐� claim 涓�鑷达紱闃叉鎶撳埌 token 鍚庣鏀� body
+ *
+ * @param authHeader 璇锋眰澶� Authorization 鍘熷�硷紙鍚� "Bearer " 鍓嶇紑锛�
+ * @param rawBody 璇锋眰鍘熷 body
+ * @return 鏄惁閫氳繃锛涚鍚嶅紓甯镐竴寰嬭涓轰笉閫氳繃
+ */
+ public boolean verifyWebhookSignature(String authHeader, String rawBody) {
+ if (StrUtil.isBlank(authHeader)) {
+ return false;
+ }
+ String token = StrUtil.removePrefix(authHeader, "Bearer ").trim();
+ ImProperties.Rtc cfg = imProperties.getRtc();
+ try {
+ JWT jwt = JWT.of(token);
+ // JWT HS256 绛惧悕楠岃瘉
+ if (!jwt.setKey(cfg.getApiSecret().getBytes(StandardCharsets.UTF_8)).verify()) {
+ return false;
+ }
+ // body sha256 涓�鑷存�ф牎楠�
+ Object expectedSha = jwt.getPayload("sha256");
+ if (expectedSha == null) {
+ return false;
+ }
+ // 璁$畻 body 鐨� sha256锛屽苟涓� JWT 鍐� claim 瀵规瘮
+ String actualSha = Base64.encode(DigestUtil.sha256(rawBody));
+ return Objects.equals(expectedSha.toString(), actualSha);
+ } catch (Exception e) {
+ log.warn("[verifyWebhookSignature][绛惧悕瑙f瀽寮傚父 bodyLength={}]",
+ rawBody == null ? 0 : rawBody.length(), e);
+ return false;
+ }
+ }
+
+ /**
+ * 绛惧彂绠$悊 Token锛涚敤浜庤皟 Server API锛圖eleteRoom / ListParticipants / RemoveParticipant 绛夛級
+ *
+ * @return JWT 瀛楃涓�
+ */
+ private String signAdminToken() {
+ ImProperties.Rtc cfg = imProperties.getRtc();
+ // roomAdmin claim 缁欑鐞嗙被 API 蹇呭
+ long nowSec = Instant.now().getEpochSecond();
+ return JWT.create()
+ .setIssuer(cfg.getApiKey())
+ .setNotBefore(new Date(nowSec * 1000))
+ .setExpiresAt(new Date((nowSec + ADMIN_TOKEN_TTL.getSeconds()) * 1000))
+ .setPayload("video", MapUtil.of("roomAdmin", true))
+ .setSigner(JWTSignerUtil.hs256(cfg.getApiSecret().getBytes(StandardCharsets.UTF_8)))
+ .sign();
+ }
+
+ /**
+ * Twirp 鍗忚 POST 璋冪敤锛涚粺涓�澶勭悊 ws鈫抙ttp 鍗忚鍒囨崲銆佺 admin token銆丅earer 澶淬�丣SON body銆佽秴鏃�
+ *
+ * @param path Twirp 绔偣璺緞锛屼緥濡� {@code /twirp/livekit.RoomService/DeleteRoom}
+ * @param room 鎴块棿鍚嶏紱鍐欏叆 JSON body 鐨� room 瀛楁
+ * @return HTTP 鍝嶅簲锛涜皟鐢ㄦ柟璐熻矗 close 涓庣姸鎬佺爜鍒ゆ柇
+ */
+ private HttpResponse postTwirp(String path, String room) {
+ Assert.notBlank(room, "room 涓嶅彲涓虹┖");
+ String token = signAdminToken();
+ return HttpRequest.post(HttpUtils.wsUrlToHttp(imProperties.getRtc().getLivekitUrl()) + path)
+ .header("Authorization", "Bearer " + token)
+ .header("Content-Type", "application/json")
+ .body(JSONUtil.toJsonStr(MapUtil.of("room", room)))
+ .timeout(SERVER_API_TIMEOUT_MS)
+ .execute();
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitWebhookEventDTO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitWebhookEventDTO.java
new file mode 100644
index 0000000..bb53501
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitWebhookEventDTO.java
@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.module.im.framework.rtc.core;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+/**
+ * LiveKit Webhook 浜嬩欢杞借嵎锛涘彧鍙嶅簭鍒楀寲鎴戜滑鍏冲績鐨勫瓧娈碉紝鍏朵綑蹇界暐
+ * <p>
+ * 鏂囨。鍙傝�冿細<a href="https://docs.livekit.io/home/server/webhook/">webhook 鏂囨。</a>
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class LiveKitWebhookEventDTO {
+
+ /**
+ * 鎴块棿鍒涘缓锛氶涓� participant 鍔犲叆鏃惰Е鍙�
+ */
+ public static final String EVENT_ROOM_STARTED = "room_started";
+ /**
+ * 鎴块棿閿�姣侊細鏈�鍚庝竴涓� participant 绂诲紑 / 鏄惧紡 DeleteRoom 鍚庤Е鍙戯紱鐢ㄤ簬涓氬姟渚у厹搴曞叧鎴�
+ */
+ public static final String EVENT_ROOM_FINISHED = "room_finished";
+ /**
+ * 鍙備笌鑰呭姞鍏ユ埧闂�
+ */
+ public static final String EVENT_PARTICIPANT_JOINED = "participant_joined";
+ /**
+ * 鍙備笌鑰呯寮�鎴块棿锛氬叧 tab / 缃戠粶鏂� / 鏄惧紡 disconnect 閮戒細瑙﹀彂锛涚敤浜庝笟鍔′晶鍏滃簳娓呯悊
+ */
+ public static final String EVENT_PARTICIPANT_LEFT = "participant_left";
+ /**
+ * 鍙備笌鑰呭彂甯冨獟浣撹建閬擄紙鎽勫儚澶� / 楹﹀厠椋� / 灞忓箷鍏变韩锛�
+ */
+ public static final String EVENT_TRACK_PUBLISHED = "track_published";
+
+ /**
+ * 浜嬩欢 id锛氱敤浜庡箓绛夊幓閲�
+ */
+ private String id;
+
+ /**
+ * 浜嬩欢绫诲瀷锛涘彇鍊煎弬瑙佹湰绫� EVENT_* 甯搁噺
+ */
+ private String event;
+
+ /**
+ * 鎴块棿鍏冧俊鎭細room_started / room_finished 蹇呭~
+ */
+ private RoomInfo room;
+
+ /**
+ * 鍙備笌鑰呭厓淇℃伅锛歱articipant_* 浜嬩欢蹇呭~
+ */
+ private ParticipantInfo participant;
+
+ @Data
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class RoomInfo {
+
+ private String sid;
+ private String name;
+ private Long creationTime;
+ private Integer numParticipants;
+
+ }
+
+ @Data
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class ParticipantInfo {
+
+ private String sid;
+ /**
+ * 鐢ㄦ埛韬唤锛氱 token 鏃跺啓鍏� userId 瀛楃涓诧紝鍚庣画鏀寔澶氱浼氭嫾鎴� userId#terminal
+ */
+ private String identity;
+ private String name;
+ private Long joinedAt;
+
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/config/ImWebConfiguration.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/config/ImWebConfiguration.java
new file mode 100644
index 0000000..7e2b2ed
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/config/ImWebConfiguration.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.framework.web.config;
+
+import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration;
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * im 妯″潡鐨� web 缁勪欢鐨� Configuration
+ */
+@Configuration(proxyBeanMethods = false)
+public class ImWebConfiguration {
+
+ /**
+ * im 妯″潡鐨� API 鍒嗙粍
+ */
+ @Bean
+ public GroupedOpenApi imGroupedOpenApi() {
+ return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("im");
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/package-info.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/package-info.java
new file mode 100644
index 0000000..b21d0fe
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/web/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * IM 妯″潡鐨� web 閰嶇疆
+ */
+package cn.iocoder.yudao.module.im.framework.web;
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/job/rtc/ImRtcCallCleanupJob.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/job/rtc/ImRtcCallCleanupJob.java
new file mode 100644
index 0000000..664e3cf
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/job/rtc/ImRtcCallCleanupJob.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.im.job.rtc;
+
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
+import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.rtc.ImRtcCallService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 鍍靛案閫氳瘽娓呯悊 Job锛氬厹搴� LiveKit Webhook 涓㈠け / 瀹㈡埛绔紓甯稿叧闂瓑鏈皟 leave 鐨勫満鏅�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Component
+@Slf4j
+public class ImRtcCallCleanupJob implements JobHandler {
+
+ @Resource
+ private ImRtcCallService rtcCallService;
+
+ @Resource
+ private ImProperties imProperties;
+
+ /**
+ * 鎵ц娓呯悊
+ *
+ * @param param 闃堝�硷紙鍒嗛挓锛夛紱涓虹┖ / 闈炴硶璧� {@link ImProperties.Rtc#getCleanupZombieThresholdMinutes()} 榛樿鍊�
+ * @return 娓呯悊鏁伴噺鎻忚堪
+ */
+ @Override
+ @TenantJob
+ public String execute(String param) {
+ int thresholdMinutes = resolveThresholdMinutes(param);
+ int cleaned = rtcCallService.cleanupZombieCalls(thresholdMinutes);
+ log.info("[execute][娓呯悊鍍靛案閫氳瘽鏁伴噺 ({}) 涓猐", cleaned);
+ return String.format("娓呯悊鍍靛案閫氳瘽 %s 涓�", cleaned);
+ }
+
+ /**
+ * 瑙f瀽 quartz param 涓哄垎閽熼槇鍊硷紱闈炴硶 / 闈炴鏁拌蛋閰嶇疆榛樿鍊�
+ *
+ * @param param quartz 璋冨害鍏ュ弬瀛楃涓�
+ * @return 鍒嗛挓闃堝��
+ */
+ private int resolveThresholdMinutes(String param) {
+ int defaultMinutes = imProperties.getRtc().getCleanupZombieThresholdMinutes();
+ if (StrUtil.isBlank(param) || !NumberUtil.isInteger(param)) {
+ return defaultMinutes;
+ }
+ int minutes = Integer.parseInt(param);
+ return minutes > 0 ? minutes : defaultMinutes;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/job/rtc/ImRtcParticipantTimeoutJob.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/job/rtc/ImRtcParticipantTimeoutJob.java
new file mode 100644
index 0000000..f551dee
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/job/rtc/ImRtcParticipantTimeoutJob.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.im.job.rtc;
+
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
+import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.rtc.ImRtcCallService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 鎸搩瓒呮椂 Job锛氭壂 INVITING 瓒呰繃闃堝�肩殑鍙備笌鑰咃紝鍗曚汉绮掑害鏍� NO_ANSWER + 鎺� RTC_CALL(REJECT) 璁╁墠绔� banner 鏀舵暃
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Component
+@Slf4j
+public class ImRtcParticipantTimeoutJob implements JobHandler {
+
+ @Resource
+ private ImRtcCallService rtcCallService;
+
+ @Resource
+ private ImProperties imProperties;
+
+ /**
+ * 鎵ц瓒呮椂鎵弿
+ *
+ * @param param 闃堝�硷紙鍒嗛挓锛夛紱涓虹┖ / 闈炴硶璧� {@link ImProperties.Rtc#getInviteTimeoutMinutes()} 榛樿鍊�
+ * @return 瓒呮椂澶勭悊鏁伴噺鎻忚堪
+ */
+ @Override
+ @TenantJob
+ public String execute(String param) {
+ int thresholdMinutes = resolveThresholdMinutes(param);
+ int timedOut = rtcCallService.timeoutInvitingParticipants(thresholdMinutes);
+ log.info("[execute][鎸搩瓒呮椂鍙備笌鑰呮暟閲� ({}) 涓猐", timedOut);
+ return String.format("鎸搩瓒呮椂 %s 涓�", timedOut);
+ }
+
+ /**
+ * 瑙f瀽 quartz param 涓哄垎閽熼槇鍊硷紱闈炴硶 / 闈炴鏁拌蛋閰嶇疆榛樿鍊�
+ *
+ * @param param quartz 璋冨害鍏ュ弬瀛楃涓�
+ * @return 鍒嗛挓闃堝��
+ */
+ private int resolveThresholdMinutes(String param) {
+ int defaultMinutes = imProperties.getRtc().getInviteTimeoutMinutes();
+ if (StrUtil.isBlank(param) || !NumberUtil.isInteger(param)) {
+ return defaultMinutes;
+ }
+ int minutes = Integer.parseInt(param);
+ return minutes > 0 ? minutes : defaultMinutes;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java
new file mode 100644
index 0000000..13eeee6
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java
@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.module.im.mq.consumer.friend;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.friend.FriendInfoUpdatedNotification;
+import cn.iocoder.yudao.module.system.api.message.user.AdminUserProfileUpdateMessage;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.event.TransactionPhase;
+import org.springframework.transaction.event.TransactionalEventListener;
+
+import java.util.List;
+
+/**
+ * 鐩戝惉 system 妯″潡鐨� {@link AdminUserProfileUpdateMessage} 娑堟伅锛屽悜銆岃祫鏂欒鏀圭殑浜恒�嶇殑鎵�鏈夊ソ鍙嬫帹閫� FRIEND_INFO_UPDATED 閫氱煡
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@Component
+public class AdminUserProfileUpdateConsumer {
+
+ @Resource
+ private ImFriendService friendService;
+ @Resource
+ private ImWebSocketService websocketService;
+
+ @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true)
+ @Async // Spring Event 榛樿鍦� Producer 鍙戦�佺殑绾跨▼锛岄�氳繃 @Async 瀹炵幇寮傛锛涗簨鍔℃彁浜ゅ悗瑙﹀彂锛岄伩鍏嶅洖婊氳鎺ㄥ菇鐏甸�氱煡 / Consumer 鎶㈠湪 commit 鍓嶈鏃у��
+ public void onMessage(AdminUserProfileUpdateMessage message) {
+ try {
+ log.info("[onMessage][娑堟伅鍐呭({})]", message);
+ // 1. 杩囨护鍙屽悜鏈夋晥濂藉弸
+ if (message == null || message.getUserId() == null) {
+ return;
+ }
+ Long userId = message.getUserId();
+ List<ImFriendDO> friends = friendService.getMutualEnableFriendList(userId);
+ if (CollUtil.isEmpty(friends)) {
+ return;
+ }
+
+ // 2. 缁欐瘡涓ソ鍙嬬殑澶氱鎺� FRIEND_INFO_UPDATED锛沺ayload 閲� operatorUserId / friendUserId 閮芥槸銆岃祫鏂欒鏀圭殑浜恒��
+ int successCount = 0;
+ for (ImFriendDO friend : friends) {
+ try {
+ FriendInfoUpdatedNotification payload = (FriendInfoUpdatedNotification) new FriendInfoUpdatedNotification()
+ .setOperatorUserId(userId).setFriendUserId(userId);
+ websocketService.sendNotificationAsync(friend.getFriendUserId(),
+ ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.FRIEND_INFO_UPDATED.getType(), payload);
+ successCount++;
+ } catch (Exception e) {
+ log.warn("[onMessage][userId({}) friendUserId({}) 鎺ㄩ�佸け璐",
+ userId, friend.getFriendUserId(), e);
+ }
+ }
+ log.info("[onMessage][userId({}) 鎺ㄩ�� FRIEND_INFO_UPDATED 缁� {} 浣嶅ソ鍙媇", userId, successCount);
+ } catch (Exception e) {
+ log.error("[onMessage][娑堟伅鍐呭({}) 澶勭悊澶辫触]", message, e);
+ }
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/package-info.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/package-info.java
new file mode 100644
index 0000000..9bf6bc3
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * im 妯″潡锛屾垜浠斁鍗虫椂閫氳涓氬姟銆�
+ * 渚嬪璇达細鍗曡亰銆佺兢鑱娿�佹秷鎭敹鍙戙�佹秷鎭挙鍥炪�佹秷鎭凡璇荤瓑绛�
+ *
+ * 1. Controller URL锛氫互 /im/ 寮�澶达紝閬垮厤鍜屽叾瀹� Module 鍐茬獊
+ * 2. DataObject 琛ㄥ悕锛氫互 im_ 寮�澶达紝鏂逛究鍦ㄦ暟鎹簱涓尯鍒�
+ */
+package cn.iocoder.yudao.module.im;
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelMaterialService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelMaterialService.java
new file mode 100644
index 0000000..44fc204
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelMaterialService.java
@@ -0,0 +1,106 @@
+package cn.iocoder.yudao.module.im.service.channel;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
+import jakarta.validation.Valid;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+
+/**
+ * IM 棰戦亾绱犳潗 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImChannelMaterialService {
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ /**
+ * 鏍¢獙绱犳潗瀛樺湪
+ *
+ * @param id 绱犳潗缂栧彿
+ * @return 绱犳潗 DO
+ */
+ ImChannelMaterialDO validateMaterialExists(Long id);
+
+ /**
+ * 鎸夌紪鍙锋壒閲忔煡璇㈢礌鏉�
+ *
+ * @param ids 绱犳潗缂栧彿鍒楄〃
+ * @return 绱犳潗鍒楄〃
+ */
+ List<ImChannelMaterialDO> getMaterialList(Collection<Long> ids);
+
+ /**
+ * 鎸夌紪鍙锋壒閲忔煡璇㈢礌鏉� Map
+ *
+ * @param ids 绱犳潗缂栧彿鍒楄〃
+ * @return id -> 绱犳潗 Map
+ */
+ default Map<Long, ImChannelMaterialDO> getMaterialMap(Collection<Long> ids) {
+ return convertMap(getMaterialList(ids), ImChannelMaterialDO::getId);
+ }
+
+ /**
+ * 缁熻鎸囧畾棰戦亾涓嬬殑绱犳潗鏁伴噺
+ *
+ * @param channelId 棰戦亾缂栧彿
+ * @return 鏁伴噺
+ */
+ Long getMaterialCountByChannelId(Long channelId);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 鎸夐閬撴煡璇㈢礌鏉愮簿绠�鍒楄〃
+ *
+ * @param channelId 棰戦亾缂栧彿
+ * @return 绱犳潗鍒楄〃
+ */
+ List<ImChannelMaterialDO> getMaterialListByChannelId(Long channelId);
+
+ /**
+ * 鍒嗛〉鏌ヨ绱犳潗
+ *
+ * @param reqVO 鍒嗛〉鏌ヨ鏉′欢
+ * @return 绱犳潗鍒嗛〉
+ */
+ PageResult<ImChannelMaterialDO> getMaterialPage(ImChannelMaterialPageReqVO reqVO);
+
+ /**
+ * 鑾峰彇绱犳潗璇︽儏锛堝惈 content 瀵屾枃鏈級
+ *
+ * @param id 绱犳潗缂栧彿
+ * @return 绱犳潗 DO
+ */
+ ImChannelMaterialDO getMaterial(Long id);
+
+ /**
+ * 鏂板绱犳潗
+ *
+ * @param reqVO 鏂板璇锋眰
+ * @return 鏂板绱犳潗缂栧彿
+ */
+ Long createMaterial(@Valid ImChannelMaterialSaveReqVO reqVO);
+
+ /**
+ * 淇敼绱犳潗
+ *
+ * @param reqVO 淇敼璇锋眰
+ */
+ void updateMaterial(@Valid ImChannelMaterialSaveReqVO reqVO);
+
+ /**
+ * 鍒犻櫎绱犳潗锛涚礌鏉愬凡琚帹閫佽繃鏃舵嫆缁濓紝閬垮厤鍘嗗彶娑堟伅鏃犳硶鍥炴煡
+ *
+ * @param id 绱犳潗缂栧彿
+ */
+ void deleteMaterial(Long id);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelMaterialServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelMaterialServiceImpl.java
new file mode 100644
index 0000000..ec1d8c3
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelMaterialServiceImpl.java
@@ -0,0 +1,113 @@
+package cn.iocoder.yudao.module.im.service.channel;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.material.ImChannelMaterialSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
+import cn.iocoder.yudao.module.im.dal.mysql.channel.ImChannelMaterialMapper;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImChannelMessageMapper;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.IM_CHANNEL_MATERIAL_NOT_EXISTS;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.IM_CHANNEL_MATERIAL_USED;
+
+/**
+ * IM 棰戦亾绱犳潗 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class ImChannelMaterialServiceImpl implements ImChannelMaterialService {
+
+ @Resource
+ private ImChannelMaterialMapper channelMaterialMapper;
+ @Resource
+ private ImChannelService channelService;
+ @Resource
+ private ImChannelMessageMapper channelMessageMapper;
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ @Override
+ public ImChannelMaterialDO validateMaterialExists(Long id) {
+ ImChannelMaterialDO material = channelMaterialMapper.selectById(id);
+ if (material == null) {
+ throw exception(IM_CHANNEL_MATERIAL_NOT_EXISTS);
+ }
+ return material;
+ }
+
+ @Override
+ public List<ImChannelMaterialDO> getMaterialList(Collection<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return Collections.emptyList();
+ }
+ return channelMaterialMapper.selectByIds(ids);
+ }
+
+ @Override
+ public Long getMaterialCountByChannelId(Long channelId) {
+ return channelMaterialMapper.selectCountByChannelId(channelId);
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public List<ImChannelMaterialDO> getMaterialListByChannelId(Long channelId) {
+ return channelMaterialMapper.selectListByChannelId(channelId);
+ }
+
+ @Override
+ public PageResult<ImChannelMaterialDO> getMaterialPage(ImChannelMaterialPageReqVO reqVO) {
+ return channelMaterialMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public ImChannelMaterialDO getMaterial(Long id) {
+ return channelMaterialMapper.selectById(id);
+ }
+
+ @Override
+ public Long createMaterial(ImChannelMaterialSaveReqVO reqVO) {
+ // 1. 鏍¢獙鎵�灞為閬撳瓨鍦�
+ channelService.validateChannelExists(reqVO.getChannelId());
+
+ // 2. 鎻掑叆绱犳潗
+ ImChannelMaterialDO material = BeanUtils.toBean(reqVO, ImChannelMaterialDO.class);
+ channelMaterialMapper.insert(material);
+ return material.getId();
+ }
+
+ @Override
+ public void updateMaterial(ImChannelMaterialSaveReqVO reqVO) {
+ // 1.1 鏍¢獙瀛樺湪
+ validateMaterialExists(reqVO.getId());
+ // 1.2 鏍¢獙鎵�灞為閬撳瓨鍦�
+ channelService.validateChannelExists(reqVO.getChannelId());
+
+ // 2. 鏇存柊绱犳潗
+ ImChannelMaterialDO updateObj = BeanUtils.toBean(reqVO, ImChannelMaterialDO.class);
+ channelMaterialMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteMaterial(Long id) {
+ validateMaterialExists(id);
+ // 闃叉鍒犻櫎绱犳潗瀵艰嚧鍘嗗彶 channel_message 鍙嶆煡涓嶅埌鍐呭
+ if (channelMessageMapper.selectCountByMaterialId(id) > 0) {
+ throw exception(IM_CHANNEL_MATERIAL_USED);
+ }
+ channelMaterialMapper.deleteById(id);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelService.java
new file mode 100644
index 0000000..b318743
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelService.java
@@ -0,0 +1,99 @@
+package cn.iocoder.yudao.module.im.service.channel;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
+import jakarta.validation.Valid;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+
+/**
+ * IM 棰戦亾 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImChannelService {
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ /**
+ * 鎸夌姸鎬佹煡璇㈤閬撳垪琛紝鎸� sort 鍗囧簭
+ *
+ * @param status 鐘舵�侊紱瀵瑰簲 CommonStatusEnum
+ * @return 棰戦亾鍒楄〃
+ */
+ List<ImChannelDO> getChannelListByStatus(Integer status);
+
+ /**
+ * 鎸夌紪鍙锋壒閲忔煡璇㈤閬�
+ *
+ * @param ids 棰戦亾缂栧彿鍒楄〃
+ * @return 棰戦亾鍒楄〃
+ */
+ List<ImChannelDO> getChannelList(Collection<Long> ids);
+
+ /**
+ * 鎸夌紪鍙锋壒閲忔煡璇㈤閬� Map
+ *
+ * @param ids 棰戦亾缂栧彿鍒楄〃
+ * @return id -> 棰戦亾 Map
+ */
+ default Map<Long, ImChannelDO> getChannelMap(Collection<Long> ids) {
+ return convertMap(getChannelList(ids), ImChannelDO::getId);
+ }
+
+ /**
+ * 鏍¢獙棰戦亾瀛樺湪
+ *
+ * @param id 棰戦亾缂栧彿
+ * @return 棰戦亾 DO
+ */
+ @SuppressWarnings("UnusedReturnValue")
+ ImChannelDO validateChannelExists(Long id);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 鍒嗛〉鏌ヨ棰戦亾
+ *
+ * @param reqVO 鍒嗛〉鏌ヨ鏉′欢
+ * @return 棰戦亾鍒嗛〉
+ */
+ PageResult<ImChannelDO> getChannelPage(ImChannelPageReqVO reqVO);
+
+ /**
+ * 鑾峰彇棰戦亾璇︽儏
+ *
+ * @param id 棰戦亾缂栧彿
+ * @return 棰戦亾 DO
+ */
+ ImChannelDO getChannel(Long id);
+
+ /**
+ * 鏂板棰戦亾
+ *
+ * @param reqVO 鏂板璇锋眰
+ * @return 鏂板棰戦亾缂栧彿
+ */
+ Long createChannel(@Valid ImChannelSaveReqVO reqVO);
+
+ /**
+ * 淇敼棰戦亾
+ *
+ * @param reqVO 淇敼璇锋眰
+ */
+ void updateChannel(@Valid ImChannelSaveReqVO reqVO);
+
+ /**
+ * 鍒犻櫎棰戦亾锛涢閬撲笅鏈夌礌鏉愭垨娑堟伅鏃舵嫆缁�
+ *
+ * @param id 棰戦亾缂栧彿
+ */
+ void deleteChannel(Long id);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelServiceImpl.java
new file mode 100644
index 0000000..6df27e1
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/channel/ImChannelServiceImpl.java
@@ -0,0 +1,120 @@
+package cn.iocoder.yudao.module.im.service.channel;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.channel.vo.channel.ImChannelSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelDO;
+import cn.iocoder.yudao.module.im.dal.mysql.channel.ImChannelMapper;
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+
+/**
+ * IM 棰戦亾 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class ImChannelServiceImpl implements ImChannelService {
+
+ @Resource
+ private ImChannelMapper channelMapper;
+ @Resource
+ @Lazy // 寤惰繜鍔犺浇锛岃В鍐冲惊鐜緷璧�
+ private ImChannelMaterialService channelMaterialService;
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ @Override
+ public List<ImChannelDO> getChannelListByStatus(Integer status) {
+ return channelMapper.selectListByStatusOrderBySort(status);
+ }
+
+ @Override
+ public List<ImChannelDO> getChannelList(Collection<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return Collections.emptyList();
+ }
+ return channelMapper.selectByIds(ids);
+ }
+
+ @Override
+ public ImChannelDO validateChannelExists(Long id) {
+ ImChannelDO channel = channelMapper.selectById(id);
+ if (channel == null) {
+ throw exception(IM_CHANNEL_NOT_EXISTS);
+ }
+ return channel;
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImChannelDO> getChannelPage(ImChannelPageReqVO reqVO) {
+ return channelMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public ImChannelDO getChannel(Long id) {
+ return channelMapper.selectById(id);
+ }
+
+ @Override
+ public Long createChannel(ImChannelSaveReqVO reqVO) {
+ // 鏍¢獙 code 鍞竴
+ validateCodeUnique(null, reqVO.getCode());
+
+ // 鎻掑叆
+ ImChannelDO channel = BeanUtils.toBean(reqVO, ImChannelDO.class);
+ channelMapper.insert(channel);
+ return channel.getId();
+ }
+
+ @Override
+ public void updateChannel(ImChannelSaveReqVO reqVO) {
+ // 1.1 鏍¢獙瀛樺湪
+ validateChannelExists(reqVO.getId());
+ // 1.2 鏍¢獙 code 鍞竴
+ validateCodeUnique(reqVO.getId(), reqVO.getCode());
+
+ // 2. 鏇存柊
+ ImChannelDO updateObj = BeanUtils.toBean(reqVO, ImChannelDO.class);
+ channelMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteChannel(Long id) {
+ // 1.1 鏍¢獙瀛樺湪
+ validateChannelExists(id);
+ // 1.2 闃叉璇垹棰戦亾瀵艰嚧鍘嗗彶绱犳潗 / 娑堟伅鍥炴煡涓嶅埌褰掑睘
+ if (channelMaterialService.getMaterialCountByChannelId(id) > 0) {
+ throw exception(IM_CHANNEL_HAS_MATERIAL);
+ }
+
+ // 2. 鍒犻櫎棰戦亾
+ channelMapper.deleteById(id);
+ }
+
+ private void validateCodeUnique(Long id, String code) {
+ ImChannelDO exist = channelMapper.selectByCode(code);
+ if (exist == null) {
+ return;
+ }
+ if (id == null || ObjUtil.notEqual(exist.getId(), id)) {
+ throw exception(IM_CHANNEL_CODE_DUPLICATED, code);
+ }
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationReadService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationReadService.java
new file mode 100644
index 0000000..9c057ae
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationReadService.java
@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.im.service.conversation;
+
+import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationReadDO;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * IM 浼氳瘽璇讳綅缃� Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImConversationReadService {
+
+ /**
+ * 鏇存柊鐢ㄦ埛鍦ㄦ煇浼氳瘽鐨勬渶澶у凡璇讳綅缃紙鍗曡皟閫掑锛屼贡搴� / 骞跺彂涓婃姤涓嶄細鍥為��锛�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param conversationType 浼氳瘽绫诲瀷
+ * @param conversationId 浼氳瘽缂栧彿
+ * @param readMessageId 宸茶鍒扮殑鏈�澶ф秷鎭紪鍙�
+ * @return 璇讳綅缃槸鍚﹀墠杩涳紱true 鏃惰皟鐢ㄦ柟鎵嶉渶瑕佷笅鍙戝凡璇� / 鍥炴墽浜嬩欢
+ */
+ boolean updateConversationReadPosition(Long userId, Integer conversationType, Long conversationId, Long readMessageId);
+
+ /**
+ * 鑾峰彇鐢ㄦ埛鍦ㄦ煇浼氳瘽鐨勬渶澶у凡璇讳綅缃�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param conversationType 浼氳瘽绫诲瀷
+ * @param conversationId 浼氳瘽缂栧彿
+ * @return 鏈�澶у凡璇绘秷鎭紪鍙凤紱涓嶅瓨鍦ㄥ垯杩斿洖 null
+ */
+ Long getConversationReadMessageId(Long userId, Integer conversationType, Long conversationId);
+
+ /**
+ * 鑾峰彇鏌愪細璇濆唴鎵�鏈夌敤鎴风殑璇讳綅缃紙鐢ㄤ簬缇ゅ洖鎵т汉鏁拌仛鍚堬級
+ *
+ * @param conversationType 浼氳瘽绫诲瀷
+ * @param conversationId 浼氳瘽缂栧彿
+ * @return userId 鈫� 鏈�澶у凡璇绘秷鎭紪鍙�
+ */
+ Map<Long, Long> getUserReadMessageIdMap(Integer conversationType, Long conversationId);
+
+ /**
+ * 鎵归噺鑾峰彇鏌愮敤鎴峰湪澶氫釜浼氳瘽鐨勮浣嶇疆锛堢敤浜庨閬撴壒閲忚浣嶇疆銆侀噸杩炲悗鎸夋椿璺冧細璇濊ˉ鍋匡級
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param conversationType 浼氳瘽绫诲瀷
+ * @param conversationIds 浼氳瘽缂栧彿闆嗗悎
+ * @return conversationId 鈫� 鏈�澶у凡璇绘秷鎭紪鍙�
+ */
+ Map<Long, Long> getConversationReadMessageIdMap(Long userId, Integer conversationType, Collection<Long> conversationIds);
+
+ /**
+ * 澧為噺鎷夊彇褰撳墠鐢ㄦ埛鐨勪細璇濊浣嶇疆锛堥噸杩� / 绂荤嚎琛ュ伩锛氭寜 update_time + id 娓告爣锛�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param lastUpdateTime 涓婃鎷夊彇鍒扮殑鏈�鏂版洿鏂版椂闂达紙姣鏃堕棿鎴筹級锛涢娆℃媺鍙栦紶 null
+ * @param lastId 涓婃鎷夊彇鍒扮殑鏈�鍚庝竴鏉¤褰� id锛涢娆℃媺鍙栦紶 null
+ * @param limit 鍗曟鎷夊彇鏉℃暟
+ * @return 浼氳瘽璇讳綅缃垪琛紝鎸夋洿鏂版椂闂淬�乮d 姝e簭
+ */
+ List<ImConversationReadDO> pullConversationReadList(Long userId, Long lastUpdateTime, Long lastId, Integer limit);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationReadServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationReadServiceImpl.java
new file mode 100644
index 0000000..a22d616
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationReadServiceImpl.java
@@ -0,0 +1,86 @@
+package cn.iocoder.yudao.module.im.service.conversation;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationReadDO;
+import cn.iocoder.yudao.module.im.dal.mysql.conversation.ImConversationReadMapper;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+
+/**
+ * IM 浼氳瘽璇讳綅缃� Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Slf4j
+public class ImConversationReadServiceImpl implements ImConversationReadService {
+
+ @Resource
+ private ImConversationReadMapper conversationReadMapper;
+
+ @Override
+ public boolean updateConversationReadPosition(Long userId, Integer conversationType, Long conversationId, Long readMessageId) {
+ LocalDateTime now = LocalDateTime.now();
+ // 1. 涓嶅瓨鍦ㄥ垯鎻掑叆锛涘苟鍙戜笅鍞竴閿啿绐侊紝闄嶇骇涓哄洖鏌� + CAS 鏇存柊
+ ImConversationReadDO existing = conversationReadMapper.selectByUserIdAndConversation(
+ userId, conversationType, conversationId);
+ if (existing == null) {
+ try {
+ conversationReadMapper.insert(new ImConversationReadDO().setUserId(userId)
+ .setConversationType(conversationType).setTargetId(conversationId)
+ .setMessageId(readMessageId).setReadTime(now));
+ return true;
+ } catch (DuplicateKeyException e) {
+ log.warn("[updateConversationReadPosition][userId({}) type({}) conversationId({}) 骞跺彂鎻掑叆鍐茬獊锛屽洖鏌ユ洿鏂癩",
+ userId, conversationType, conversationId);
+ existing = conversationReadMapper.selectByUserIdAndConversation(userId, conversationType, conversationId);
+ }
+ }
+ if (existing == null) {
+ return false;
+ }
+
+ // 2. CAS 鍗曡皟鏇存柊锛歮apper 鍐� WHERE message_id < ? 淇濊瘉涔卞簭 / 骞跺彂涓嶅洖閫�锛涘奖鍝嶈鏁� > 0 鍗宠浣嶇疆鍓嶈繘
+ return conversationReadMapper.updateReadMessageIdToLarger(existing.getId(), readMessageId, now) > 0;
+ }
+
+ @Override
+ public Long getConversationReadMessageId(Long userId, Integer conversationType, Long conversationId) {
+ ImConversationReadDO read = conversationReadMapper.selectByUserIdAndConversation(
+ userId, conversationType, conversationId);
+ return read != null ? read.getMessageId() : null;
+ }
+
+ @Override
+ public Map<Long, Long> getUserReadMessageIdMap(Integer conversationType, Long conversationId) {
+ return convertMap(conversationReadMapper.selectListByConversation(conversationType, conversationId),
+ ImConversationReadDO::getUserId, ImConversationReadDO::getMessageId);
+ }
+
+ @Override
+ public Map<Long, Long> getConversationReadMessageIdMap(Long userId, Integer conversationType,
+ Collection<Long> conversationIds) {
+ if (CollUtil.isEmpty(conversationIds)) {
+ return Collections.emptyMap();
+ }
+ List<ImConversationReadDO> list = conversationReadMapper.selectListByUserIdAndConversations(
+ userId, conversationType, conversationIds);
+ return convertMap(list, ImConversationReadDO::getTargetId, ImConversationReadDO::getMessageId);
+ }
+
+ @Override
+ public List<ImConversationReadDO> pullConversationReadList(Long userId, Long lastUpdateTime, Long lastId, Integer limit) {
+ return conversationReadMapper.selectPullListByUserId(userId, lastUpdateTime, lastId, limit);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java
new file mode 100644
index 0000000..c9f913e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java
@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO;
+import jakarta.validation.Valid;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 琛ㄦ儏鍖呴」 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImFacePackItemService {
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ /**
+ * 鎸� packIds 鎵归噺鍙栧惎鐢ㄩ」锛岀粰鍓嶇鑱氬悎鎺ュ彛鐢�
+ *
+ * @param packIds 琛ㄦ儏鍖呯紪鍙峰垪琛�
+ * @return 鍚敤鐘舵�佺殑琛ㄦ儏鍒楄〃
+ */
+ List<ImFacePackItemDO> getEnabledItemListByPackIds(Collection<Long> packIds);
+
+ /**
+ * 鍙栨煇涓〃鎯呭寘涓嬬殑琛ㄦ儏鏁伴噺锛汭mFacePackService 鍒犻櫎鍓嶆牎楠屻�屽寘涓嬫棤椤广�嶇敤
+ *
+ * @param packId 琛ㄦ儏鍖呯紪鍙�
+ * @return 鏁伴噺
+ */
+ Long getFacePackItemCount(Long packId);
+
+ /**
+ * 鍙栧涓〃鎯呭寘涓嬬殑琛ㄦ儏鏁伴噺鍚堣锛汭mFacePackService 鎵归噺鍒犻櫎鍓嶆牎楠岀敤
+ *
+ * @param packIds 琛ㄦ儏鍖呯紪鍙峰垪琛�
+ * @return 鏁伴噺鍚堣
+ */
+ Long getFacePackItemCount(Collection<Long> packIds);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 鍒嗛〉鏌ヨ琛ㄦ儏鍖呴」
+ *
+ * @param reqVO 鍒嗛〉鏌ヨ鏉′欢
+ * @return 琛ㄦ儏鍖呴」鍒嗛〉
+ */
+ PageResult<ImFacePackItemDO> getFacePackItemPage(ImFacePackItemPageReqVO reqVO);
+
+ /**
+ * 鑾峰彇琛ㄦ儏鍖呴」璇︽儏
+ *
+ * @param id 琛ㄦ儏鍖呴」缂栧彿
+ * @return 琛ㄦ儏鍖呴」 DO
+ */
+ ImFacePackItemDO getFacePackItem(Long id);
+
+ /**
+ * 鏂板琛ㄦ儏鍖呴」
+ *
+ * @param reqVO 鏂板璇锋眰
+ * @return 鏂板琛ㄦ儏鍖呴」缂栧彿
+ */
+ Long createFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO);
+
+ /**
+ * 淇敼琛ㄦ儏鍖呴」
+ *
+ * @param reqVO 淇敼璇锋眰
+ */
+ void updateFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO);
+
+ /**
+ * 鍒犻櫎琛ㄦ儏鍖呴」
+ *
+ * @param id 琛ㄦ儏鍖呴」缂栧彿
+ */
+ void deleteFacePackItem(Long id);
+
+ /**
+ * 鎵归噺鍒犻櫎琛ㄦ儏鍖呴」
+ *
+ * @param ids 琛ㄦ儏鍖呴」缂栧彿鍒楄〃
+ */
+ void deleteFacePackItemList(List<Long> ids);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImpl.java
new file mode 100644
index 0000000..9f8d545
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImpl.java
@@ -0,0 +1,117 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO;
+import cn.iocoder.yudao.module.im.dal.mysql.face.ImFacePackItemMapper;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_ITEM_NOT_EXISTS;
+
+/**
+ * IM 琛ㄦ儏鍖呴」 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class ImFacePackItemServiceImpl implements ImFacePackItemService {
+
+ @Resource
+ private ImFacePackItemMapper facePackItemMapper;
+ @Resource
+ private ImFacePackService facePackService;
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ @Override
+ public List<ImFacePackItemDO> getEnabledItemListByPackIds(Collection<Long> packIds) {
+ if (CollUtil.isEmpty(packIds)) {
+ return Collections.emptyList();
+ }
+ return facePackItemMapper.selectListByPackIdsAndStatus(packIds, CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public Long getFacePackItemCount(Long packId) {
+ return facePackItemMapper.selectCountByPackId(packId);
+ }
+
+ @Override
+ public Long getFacePackItemCount(Collection<Long> packIds) {
+ if (CollUtil.isEmpty(packIds)) {
+ return 0L;
+ }
+ return facePackItemMapper.selectCountByPackIds(packIds);
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImFacePackItemDO> getFacePackItemPage(ImFacePackItemPageReqVO reqVO) {
+ return facePackItemMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public ImFacePackItemDO getFacePackItem(Long id) {
+ return facePackItemMapper.selectById(id);
+ }
+
+ @Override
+ public Long createFacePackItem(ImFacePackItemSaveReqVO reqVO) {
+ // 1. 鏍¢獙鎵�灞炶〃鎯呭寘瀛樺湪
+ facePackService.validateFacePackExists(reqVO.getPackId());
+
+ // 2. 鍏ュ簱
+ ImFacePackItemDO item = BeanUtils.toBean(reqVO, ImFacePackItemDO.class);
+ facePackItemMapper.insert(item);
+ return item.getId();
+ }
+
+ @Override
+ public void updateFacePackItem(ImFacePackItemSaveReqVO reqVO) {
+ // 1.1 鏍¢獙瀛樺湪
+ validateFacePackItemExists(reqVO.getId());
+ // 1.2 鏍¢獙鎵�灞炶〃鎯呭寘瀛樺湪
+ facePackService.validateFacePackExists(reqVO.getPackId());
+
+ // 2. 鏇存柊
+ ImFacePackItemDO updateObj = BeanUtils.toBean(reqVO, ImFacePackItemDO.class);
+ facePackItemMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteFacePackItem(Long id) {
+ // 1. 鏍¢獙瀛樺湪
+ validateFacePackItemExists(id);
+
+ // 2. 鍒犻櫎
+ facePackItemMapper.deleteById(id);
+ }
+
+ @Override
+ public void deleteFacePackItemList(List<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return;
+ }
+ facePackItemMapper.deleteByIds(ids);
+ }
+
+ private void validateFacePackItemExists(Long id) {
+ if (facePackItemMapper.selectById(id) == null) {
+ throw exception(FACE_PACK_ITEM_NOT_EXISTS);
+ }
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java
new file mode 100644
index 0000000..d579fbf
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java
@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
+import jakarta.validation.Valid;
+
+import java.util.List;
+
+/**
+ * IM 琛ㄦ儏鍖� Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImFacePackService {
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ /**
+ * 鑾峰彇鎵�鏈夊惎鐢ㄧ殑琛ㄦ儏鍖咃紝鎸� sort 鍗囧簭
+ *
+ * @return 鍚敤鐨勮〃鎯呭寘鍒楄〃
+ */
+ List<ImFacePackDO> getEnabledFacePackList();
+
+ /**
+ * 鏍¢獙琛ㄦ儏鍖呭瓨鍦�
+ *
+ * @param id 琛ㄦ儏鍖呯紪鍙�
+ * @return 琛ㄦ儏鍖� DO
+ */
+ @SuppressWarnings("UnusedReturnValue")
+ ImFacePackDO validateFacePackExists(Long id);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 鍒嗛〉鏌ヨ琛ㄦ儏鍖�
+ *
+ * @param reqVO 鍒嗛〉鏌ヨ鏉′欢
+ * @return 琛ㄦ儏鍖呭垎椤�
+ */
+ PageResult<ImFacePackDO> getFacePackPage(ImFacePackPageReqVO reqVO);
+
+ /**
+ * 鑾峰彇琛ㄦ儏鍖呰鎯�
+ *
+ * @param id 琛ㄦ儏鍖呯紪鍙�
+ * @return 琛ㄦ儏鍖� DO
+ */
+ ImFacePackDO getFacePack(Long id);
+
+ /**
+ * 鏂板琛ㄦ儏鍖�
+ *
+ * @param reqVO 鏂板璇锋眰
+ * @return 鏂板琛ㄦ儏鍖呯紪鍙�
+ */
+ Long createFacePack(@Valid ImFacePackSaveReqVO reqVO);
+
+ /**
+ * 淇敼琛ㄦ儏鍖�
+ *
+ * @param reqVO 淇敼璇锋眰
+ */
+ void updateFacePack(@Valid ImFacePackSaveReqVO reqVO);
+
+ /**
+ * 鍒犻櫎琛ㄦ儏鍖咃紱鍖呬笅瀛樺湪琛ㄦ儏鏃舵嫆缁濓紝閬垮厤鍘嗗彶 face 娑堟伅鏃犳硶鍥炴煡褰掑睘
+ *
+ * @param id 琛ㄦ儏鍖呯紪鍙�
+ */
+ void deleteFacePack(Long id);
+
+ /**
+ * 鎵归噺鍒犻櫎琛ㄦ儏鍖咃紱浠讳竴鍖呬笅瀛樺湪琛ㄦ儏鏃舵暣鎵规嫆缁濓紝閬垮厤銆屽彧鍒犱竴鍗娿�嶄腑闂存��
+ *
+ * @param ids 琛ㄦ儏鍖呯紪鍙峰垪琛�
+ */
+ void deleteFacePackList(List<Long> ids);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImpl.java
new file mode 100644
index 0000000..e86a397
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImpl.java
@@ -0,0 +1,113 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
+import cn.iocoder.yudao.module.im.dal.mysql.face.ImFacePackMapper;
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_HAS_ITEMS;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_NOT_EXISTS;
+
+/**
+ * IM 琛ㄦ儏鍖� Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class ImFacePackServiceImpl implements ImFacePackService {
+
+ @Resource
+ private ImFacePackMapper facePackMapper;
+
+ /**
+ * @Lazy 瑙e喅涓� ImFacePackItemServiceImpl 鐨勫惊鐜緷璧栵紙item.create / update 鏍¢獙鎵�灞炲寘瀛樺湪 鈫� 鍙嶅悜璋冪敤鏈被锛�
+ */
+ @Resource
+ @Lazy
+ private ImFacePackItemService facePackItemService;
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ @Override
+ public List<ImFacePackDO> getEnabledFacePackList() {
+ return facePackMapper.selectListByStatusOrderBySort(CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public ImFacePackDO validateFacePackExists(Long id) {
+ ImFacePackDO pack = facePackMapper.selectById(id);
+ if (pack == null) {
+ throw exception(FACE_PACK_NOT_EXISTS);
+ }
+ return pack;
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImFacePackDO> getFacePackPage(ImFacePackPageReqVO reqVO) {
+ return facePackMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public ImFacePackDO getFacePack(Long id) {
+ return facePackMapper.selectById(id);
+ }
+
+ @Override
+ public Long createFacePack(ImFacePackSaveReqVO reqVO) {
+ ImFacePackDO pack = BeanUtils.toBean(reqVO, ImFacePackDO.class);
+ facePackMapper.insert(pack);
+ return pack.getId();
+ }
+
+ @Override
+ public void updateFacePack(ImFacePackSaveReqVO reqVO) {
+ // 1. 鏍¢獙瀛樺湪
+ validateFacePackExists(reqVO.getId());
+
+ // 2. 鏇存柊
+ ImFacePackDO updateObj = BeanUtils.toBean(reqVO, ImFacePackDO.class);
+ facePackMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteFacePack(Long id) {
+ // 1.1 鏍¢獙瀛樺湪
+ validateFacePackExists(id);
+ // 1.2 鏍¢獙琛ㄦ儏鍖呬笅娌℃湁琛ㄦ儏锛涢槻姝㈣鍒犺〃鎯呭寘瀵艰嚧鍘嗗彶 face 娑堟伅鏃犳硶鍥炴煡褰掑睘
+ if (facePackItemService.getFacePackItemCount(id) > 0) {
+ throw exception(FACE_PACK_HAS_ITEMS);
+ }
+
+ // 2. 鍒犻櫎
+ facePackMapper.deleteById(id);
+ }
+
+ @Override
+ public void deleteFacePackList(List<Long> ids) {
+ // 1. 浠讳竴瀛樺湪琛ㄦ儏鍒欐嫆缁濇暣鎵瑰垹闄わ紝閬垮厤銆屽彧鍒犱竴鍗娿�嶇殑涓棿鎬�
+ if (CollUtil.isEmpty(ids)) {
+ return;
+ }
+ if (facePackItemService.getFacePackItemCount(ids) > 0) {
+ throw exception(FACE_PACK_HAS_ITEMS);
+ }
+
+ // 2. 鍒犻櫎
+ facePackMapper.deleteByIds(ids);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java
new file mode 100644
index 0000000..68ae78c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java
@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO;
+import jakarta.validation.Valid;
+
+import java.util.List;
+
+/**
+ * IM 鐢ㄦ埛绉佹湁琛ㄦ儏 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImFaceUserItemService {
+
+ /**
+ * 鑾峰彇鎸囧畾鐢ㄦ埛鐨勪釜浜鸿〃鎯呭垪琛�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return 涓汉琛ㄦ儏鍒楄〃
+ */
+ List<ImFaceUserItemDO> getFaceUserItemList(Long userId);
+
+ /**
+ * 娣诲姞涓汉琛ㄦ儏
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param reqVO 娣诲姞璇锋眰
+ * @return 鏂板琛ㄦ儏缂栧彿
+ */
+ Long createFaceUserItem(Long userId, @Valid ImFaceUserItemSaveReqVO reqVO);
+
+ /**
+ * 鍒犻櫎鎸囧畾鐢ㄦ埛鐨勬煇鏉′釜浜鸿〃鎯�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param id 琛ㄦ儏缂栧彿
+ */
+ void deleteFaceUserItem(Long userId, Long id);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 鍒嗛〉鏌ヨ鎵�鏈夌敤鎴风殑涓汉琛ㄦ儏锛涚鐞嗗悗鍙板璁� / 鍒犻櫎杩濊鍥剧敤
+ *
+ * @param reqVO 鍒嗛〉鏌ヨ鏉′欢
+ * @return 涓汉琛ㄦ儏鍒嗛〉
+ */
+ PageResult<ImFaceUserItemDO> getFaceUserItemPage(ImFaceUserItemManagerPageReqVO reqVO);
+
+ /**
+ * 绠$悊鍚庡彴鐩存帴鍒犻櫎鏌愭潯涓汉琛ㄦ儏锛涗笉鍋氬綊灞炴牎楠�
+ *
+ * @param id 琛ㄦ儏缂栧彿
+ */
+ void deleteFaceUserItem(Long id);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java
new file mode 100644
index 0000000..e559805
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java
@@ -0,0 +1,99 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO;
+import cn.iocoder.yudao.module.im.dal.mysql.face.ImFaceUserItemMapper;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import jakarta.annotation.Resource;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_DUPLICATED;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_MAX_LIMIT;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_NOT_EXISTS;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_NOT_OWN;
+
+/**
+ * IM 鐢ㄦ埛绉佹湁琛ㄦ儏 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class ImFaceUserItemServiceImpl implements ImFaceUserItemService {
+
+ @Resource
+ private ImFaceUserItemMapper faceUserItemMapper;
+ @Resource
+ private ImProperties imProperties;
+
+ @Override
+ public List<ImFaceUserItemDO> getFaceUserItemList(Long userId) {
+ return faceUserItemMapper.selectListByUserId(userId);
+ }
+
+ @Override
+ public Long createFaceUserItem(Long userId, ImFaceUserItemSaveReqVO reqVO) {
+ // 1.1 鍚� URL 宸插瓨鍦ㄥ垯鎶ラ敊
+ if (faceUserItemMapper.selectByUserIdAndUrl(userId, reqVO.getUrl()) != null) {
+ throw exception(FACE_USER_ITEM_DUPLICATED);
+ }
+ // 1.2 瓒呰繃鏈�澶ф暟閲忛檺鍒跺垯鎶ラ敊
+ int maxCount = imProperties.getFace().getUserItemMaxCount();
+ if (faceUserItemMapper.selectCountByUserId(userId) >= maxCount) {
+ throw exception(FACE_USER_ITEM_MAX_LIMIT, maxCount);
+ }
+
+ // 2. 鍏ュ簱
+ ImFaceUserItemDO item = BeanUtils.toBean(reqVO, ImFaceUserItemDO.class).setUserId(userId);
+ try {
+ faceUserItemMapper.insert(item);
+ } catch (DuplicateKeyException ex) {
+ throw exception(FACE_USER_ITEM_DUPLICATED);
+ }
+ return item.getId();
+ }
+
+ @Override
+ public void deleteFaceUserItem(Long userId, Long id) {
+ // 1.1 鏍¢獙瀛樺湪
+ ImFaceUserItemDO item = faceUserItemMapper.selectById(id);
+ if (item == null) {
+ throw exception(FACE_USER_ITEM_NOT_EXISTS);
+ }
+ // 1.2 鏍¢獙褰掑睘锛氶槻姝� A 鐢ㄦ埛浼� B 鐢ㄦ埛鐨勮〃鎯� id 鍒犲埆浜虹殑
+ if (ObjectUtil.notEqual(item.getUserId(), userId)) {
+ throw exception(FACE_USER_ITEM_NOT_OWN);
+ }
+
+ // 2. 鍒犻櫎
+ faceUserItemMapper.deleteById(id);
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImFaceUserItemDO> getFaceUserItemPage(ImFaceUserItemManagerPageReqVO reqVO) {
+ return faceUserItemMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public void deleteFaceUserItem(Long id) {
+ // 1. 鏍¢獙瀛樺湪
+ if (faceUserItemMapper.selectById(id) == null) {
+ throw exception(FACE_USER_ITEM_NOT_EXISTS);
+ }
+
+ // 2. 鍒犻櫎
+ faceUserItemMapper.deleteById(id);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestService.java
new file mode 100644
index 0000000..8470206
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestService.java
@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.module.im.service.friend;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.request.ImFriendRequestApplyReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendRequestManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+
+import java.util.List;
+
+/**
+ * IM 濂藉弸鐢宠 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImFriendRequestService {
+
+ /**
+ * 鍙戣捣濂藉弸鐢宠
+ *
+ * @param fromUserId 鍙戣捣鏂圭敤鎴风紪鍙�
+ * @param reqVO 鐢宠璇锋眰
+ * @return 鐢宠璁板綍
+ */
+ ImFriendRequestDO applyFriend(Long fromUserId, ImFriendRequestApplyReqVO reqVO);
+
+ /**
+ * 鍚屾剰濂藉弸鐢宠
+ *
+ * @param userId 鎿嶄綔浜虹敤鎴风紪鍙�
+ * @param requestId 鐢宠璁板綍缂栧彿
+ */
+ void agreeFriendRequest(Long userId, Long requestId);
+
+ /**
+ * 鎷掔粷濂藉弸鐢宠
+ *
+ * @param userId 鎿嶄綔浜虹敤鎴风紪鍙�
+ * @param requestId 鐢宠璁板綍缂栧彿
+ * @param handleContent 鎷掔粷鐞嗙敱
+ */
+ void refuseFriendRequest(Long userId, Long requestId, String handleContent);
+
+ /**
+ * 鏌ヨ銆屾垜鐩稿叧銆嶇殑鐢宠鍒楄〃锛堝惈鎴戝彂璧风殑銆佸埆浜哄姞鎴戠殑锛夛紱娓告爣鍒嗛〉锛氫紶 maxId 鎷夋洿鏃╀竴椤�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param maxId 褰撳墠鍒楄〃鏈�鏃ц褰曠殑 id锛涢椤典紶 null
+ * @param limit 鍗曟鎷夊彇鏉℃暟锛坧age size锛岀敱鍓嶇甯搁噺鎺у埗锛�
+ * @return 鐢宠璁板綍鍒楄〃锛屾寜鏇存柊鏃堕棿銆乮d 鍊掑簭
+ */
+ List<ImFriendRequestDO> getMyFriendRequestList(Long userId, Long maxId, Integer limit);
+
+ /**
+ * 澧為噺鎷夊彇銆屾垜鐩稿叧銆嶇殑濂藉弸鐢宠锛堥噸杩� / 绂荤嚎琛ュ伩锛氬弻鍚� OR锛屾寜 update_time + id 娓告爣锛�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param lastUpdateTime 涓婃鎷夊彇鍒扮殑鏈�鏂版洿鏂版椂闂达紙姣鏃堕棿鎴筹級锛涢娆℃媺鍙栦紶 null
+ * @param lastId 涓婃鎷夊彇鍒扮殑鏈�鍚庝竴鏉¤褰� id锛涢娆℃媺鍙栦紶 null
+ * @param limit 鍗曟鎷夊彇鏉℃暟
+ * @return 鐢宠璁板綍鍒楄〃锛屾寜鏇存柊鏃堕棿銆乮d 姝e簭
+ */
+ List<ImFriendRequestDO> pullFriendRequestList(Long userId, Long lastUpdateTime, Long lastId, Integer limit);
+
+ /**
+ * 鎸� id 鍗曟煡鐢宠璁板綍锛涢�氱敤璇绘帴鍙o紝璋冪敤鏂硅嚜琛屽仛瓒婃潈杩囨护
+ */
+ ImFriendRequestDO getFriendRequest(Long id);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝垎椤垫煡璇㈠ソ鍙嬬敵璇疯褰�
+ */
+ PageResult<ImFriendRequestDO> getFriendRequestPage(ImFriendRequestManagerPageReqVO reqVO);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImpl.java
new file mode 100644
index 0000000..eeed457
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImpl.java
@@ -0,0 +1,270 @@
+package cn.iocoder.yudao.module.im.service.friend;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.request.ImFriendRequestApplyReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendRequestManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+import cn.iocoder.yudao.module.im.dal.mysql.friend.ImFriendRequestMapper;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendRequestHandleResultEnum;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.friend.FriendRequestApprovedNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.friend.FriendRequestNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.friend.FriendRequestRejectedNotification;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+
+/**
+ * IM 濂藉弸鐢宠 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@Service
+@Validated
+public class ImFriendRequestServiceImpl implements ImFriendRequestService {
+
+ @Resource
+ private ImFriendRequestMapper friendRequestMapper;
+
+ @Resource
+ private ImFriendService friendService;
+ @Resource
+ private ImWebSocketService websocketService;
+
+ @Resource
+ private ImProperties imProperties;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public ImFriendRequestDO applyFriend(Long fromUserId, ImFriendRequestApplyReqVO reqVO) {
+ Long toUserId = reqVO.getToUserId();
+ // 1.1 鏍¢獙锛氫笉鑳藉姞鑷繁
+ if (Objects.equals(fromUserId, toUserId)) {
+ throw exception(FRIEND_ADD_SELF);
+ }
+ // 1.2 鏍¢獙瀵规柟瀛樺湪涓斿惎鐢�
+ adminUserApi.validateUser(toUserId);
+ // 1.3 宸叉槸濂藉弸 / 琚鏂规媺榛戯細鐩存帴鎶ラ敊锛坰tate 涓�娆℃嬁鍒板弻鍚戠姸鎬侊紝鐪佷袱娆″崟杈规煡璇級
+ // 閿欒鐮佷笌 ImFriendService#validateFriend 涓嶅悓锛堣涔変负銆岀敵璇疯鎷掋�嶏級锛屾晠淇濈暀 inline
+ Integer state = friendService.getFriendState(fromUserId, toUserId);
+ if (ImFriendStateEnum.isFriend(state)) {
+ throw exception(FRIEND_REQUEST_ALREADY_FRIEND);
+ }
+ if (ImFriendStateEnum.isBlocked(state)) {
+ throw exception(FRIEND_REQUEST_BLOCKED_BY_PEER);
+ }
+ // 1.4 鍗曞悜濂藉弸锛堟垜宸插垹 + 瀵规柟浠嶆妸鎴戝綋濂藉弸锛夛細闈欓粯閲嶆柊鍚敤鎴戜晶鍏崇郴锛岄伩鍏嶅鏂规劅鐭ユ垜鏇惧垹闄�
+ ImFriendDO peerFriend = friendService.getFriend(toUserId, fromUserId);
+ if (peerFriend != null && CommonStatusEnum.isEnable(peerFriend.getStatus())) {
+ // 瀵规柟宸叉媺榛戯細闈欓粯鎭㈠绛変簬缁曡繃鎷夐粦鍥炲埌濂藉弸鍒楄〃锛屽繀椤诲厛鎷掓帀锛�
+ // getFriendState 鍦ㄦ垜渚� DISABLE 鏃剁洿鎺ヨ繑鍥� NONE锛屾嬁涓嶅埌 BLOCKED 淇″彿锛岃繖閲屾樉寮忚ˉ涓�娆℃牎楠�
+ if (BooleanUtil.isTrue(peerFriend.getBlocked())) {
+ throw exception(FRIEND_REQUEST_BLOCKED_BY_PEER);
+ }
+ friendService.silentReAddFriend(fromUserId, toUserId, reqVO.getDisplayName(), reqVO.getAddSource());
+ return null;
+ }
+
+ // 2. 钀藉簱锛氬悓涓�鐢宠浜哄拰鎺ユ敹浜哄敮涓�锛屽凡鏈夎褰曡鐩栫敵璇峰唴瀹瑰苟閲嶇疆涓烘湭澶勭悊
+ ImFriendRequestDO request = createOrResetRequest(fromUserId, reqVO);
+
+ // 3. 鎺ㄩ�� FRIEND_REQUEST_RECEIVED 缁� toUser 澶氱锛沺ayload 鎼哄甫鐢宠鏂规樀绉� / 澶村儚锛屽墠绔寜 requestId 鐩存帹 push 杩涘垪琛�
+ AdminUserRespDTO fromUser = adminUserApi.getUser(fromUserId);
+ FriendRequestNotification payload = (FriendRequestNotification) new FriendRequestNotification()
+ .setRequestId(request.getId()).setApplyContent(request.getApplyContent()).setAddSource(request.getAddSource())
+ .setOperatorUserId(fromUserId).setFriendUserId(fromUserId);
+ if (fromUser != null) {
+ payload.setFromNickname(fromUser.getNickname()).setFromAvatar(fromUser.getAvatar());
+ }
+ websocketService.sendNotificationAsync(toUserId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.FRIEND_REQUEST_RECEIVED.getType(), payload);
+
+ // 4. 鍏ㄥ眬鑷姩閫氳繃寮�鍏筹細娉ㄥ唽 afterCommit 鍥炶皟锛屼簨鍔℃彁浜ゅ悗鍐嶈蛋鍚屾剰娴佺▼
+ // 鍥炶皟鍐� try/catch 鍏滃簳 鈥斺�� afterCommit 寮傚父浼氳 Spring 闈欓粯鍚炴帀锛屽惁鍒欏悓鎰忓け璐ユ椂鐢宠鏂规案杩滅瓑涓嶅埌 APPROVED
+ if (imProperties.getFriend().isAutoAccept()) {
+ Long requestId = request.getId();
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
+
+ @Override
+ public void afterCommit() {
+ try {
+ getSelf().agreeFriendRequest(toUserId, requestId);
+ } catch (Exception e) {
+ log.error("[applyFriend][autoAccept fromUserId={} toUserId={} requestId={} 鑷姩閫氳繃澶辫触]",
+ fromUserId, toUserId, requestId, e);
+ }
+ }
+
+ });
+ }
+ return request;
+ }
+
+ /**
+ * 鍒涘缓鎴栭噸缃ソ鍙嬬敵璇�
+ *
+ * @param fromUserId 鐢宠浜虹敤鎴风紪鍙�
+ * @param reqVO 鐢宠璇锋眰
+ * @return 鐢宠璁板綍
+ */
+ private ImFriendRequestDO createOrResetRequest(Long fromUserId, ImFriendRequestApplyReqVO reqVO) {
+ Long toUserId = reqVO.getToUserId();
+ ImFriendRequestDO request = friendRequestMapper.selectByFromUserIdAndToUserId(fromUserId, toUserId);
+ if (request == null) {
+ // 1. 鏃犳棫鐢宠锛氬垱寤烘柊鐢宠锛涘敮涓�閿啿绐佹椂鍥炴煡骞跺鐢ㄥ苟鍙戝啓鍏ョ殑璁板綍
+ request = BeanUtils.toBean(reqVO, ImFriendRequestDO.class)
+ .setFromUserId(fromUserId).setToUserId(toUserId)
+ .setHandleResult(ImFriendRequestHandleResultEnum.UNHANDLED.getResult());
+ try {
+ friendRequestMapper.insert(request);
+ return request;
+ } catch (DuplicateKeyException ex) {
+ request = friendRequestMapper.selectByFromUserIdAndToUserId(fromUserId, toUserId);
+ if (request == null) {
+ throw ex;
+ }
+ }
+ }
+
+ // 2. 澶嶇敤鏃х敵璇凤細瑕嗙洊鏈鐢宠鍐呭锛屽苟閲嶇疆涓烘湭澶勭悊
+ LocalDateTime now = LocalDateTime.now();
+ friendRequestMapper.updateByIdReset(request.getId(),
+ reqVO.getApplyContent(), reqVO.getDisplayName(), reqVO.getAddSource(), now);
+ // 鍚屾鍐呭瓨瀵硅薄锛屽悗缁�氱煡鍜岃嚜鍔ㄩ�氳繃鐩存帴澶嶇敤
+ request.setApplyContent(reqVO.getApplyContent()).setDisplayName(reqVO.getDisplayName())
+ .setAddSource(reqVO.getAddSource())
+ .setHandleResult(ImFriendRequestHandleResultEnum.UNHANDLED.getResult())
+ .setHandleContent(null).setHandleTime(null).setUpdateTime(now);
+ return request;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void agreeFriendRequest(Long userId, Long requestId) {
+ // 1.1 鏍¢獙鐢宠瀛樺湪銆佹湭澶勭悊銆佹搷浣滀汉鏄帴鏀舵柟
+ ImFriendRequestDO request = validateRequestForHandle(userId, requestId);
+
+ // 2. 涔愯閿佹洿鏂扮敵璇峰鐞嗙粨鏋�
+ ImFriendRequestDO updateObj = new ImFriendRequestDO()
+ .setHandleResult(ImFriendRequestHandleResultEnum.AGREED.getResult()).setHandleTime(LocalDateTime.now());
+ int affected = friendRequestMapper.updateByIdAndHandleResult(request.getId(),
+ ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), updateObj);
+ if (affected == 0) {
+ throw exception(FRIEND_REQUEST_HANDLED);
+ }
+ request.setHandleResult(ImFriendRequestHandleResultEnum.AGREED.getResult()).setHandleTime(updateObj.getHandleTime());
+
+ // 3. 鍙屽悜寤虹珛濂藉弸鍏崇郴
+ friendService.becomeFriends(request);
+
+ // 4. 鎺� FRIEND_REQUEST_APPROVED 缁� fromUser 澶氱
+ FriendRequestApprovedNotification payload = (FriendRequestApprovedNotification)
+ new FriendRequestApprovedNotification().setRequestId(request.getId())
+ .setOperatorUserId(userId).setFriendUserId(userId);
+ websocketService.sendNotificationAsync(request.getFromUserId(), ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.FRIEND_REQUEST_APPROVED.getType(), payload);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void refuseFriendRequest(Long userId, Long requestId, String handleContent) {
+ // 1. 鏍¢獙鐢宠瀛樺湪 + 鏈鐞� + 鎿嶄綔浜烘槸鎺ユ敹鏂癸紙fail-fast锛涘苟鍙戝満鏅粛鐢变笅闈㈢殑涔愯閿佸厹搴曪級
+ ImFriendRequestDO request = validateRequestForHandle(userId, requestId);
+
+ // 2. 涔愯閿佹洿鏂扮敵璇凤細handleResult=REFUSED + handleContent + handleTime锛涘苟鍙戞嫆缁濅細鏈変竴鏂� affectedRows=0
+ ImFriendRequestDO updateObj = new ImFriendRequestDO()
+ .setHandleResult(ImFriendRequestHandleResultEnum.REFUSED.getResult())
+ .setHandleContent(handleContent).setHandleTime(LocalDateTime.now());
+ int affected = friendRequestMapper.updateByIdAndHandleResult(request.getId(),
+ ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), updateObj);
+ if (affected == 0) {
+ throw exception(FRIEND_REQUEST_HANDLED);
+ }
+
+ // 3. 鎺� FRIEND_REQUEST_REJECTED 缁� fromUser 澶氱
+ FriendRequestRejectedNotification payload = (FriendRequestRejectedNotification)
+ new FriendRequestRejectedNotification().setRequestId(request.getId())
+ .setHandleContent(handleContent)
+ .setOperatorUserId(userId).setFriendUserId(userId);
+ websocketService.sendNotificationAsync(request.getFromUserId(), ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.FRIEND_REQUEST_REJECTED.getType(), payload);
+ }
+
+ @Override
+ public List<ImFriendRequestDO> getMyFriendRequestList(Long userId, Long maxId, Integer limit) {
+ ImFriendRequestDO maxRequest = maxId != null ? friendRequestMapper.selectById(maxId) : null;
+ if (maxId != null && maxRequest == null) {
+ return ListUtil.of();
+ }
+ return friendRequestMapper.selectMyList(userId,
+ maxRequest != null ? maxRequest.getUpdateTime() : null,
+ maxRequest != null ? maxRequest.getId() : null,
+ limit);
+ }
+
+ @Override
+ public List<ImFriendRequestDO> pullFriendRequestList(Long userId, Long lastUpdateTime, Long lastId, Integer limit) {
+ return friendRequestMapper.selectPullListByUserId(userId, lastUpdateTime, lastId, limit);
+ }
+
+ @Override
+ public ImFriendRequestDO getFriendRequest(Long id) {
+ return friendRequestMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult<ImFriendRequestDO> getFriendRequestPage(ImFriendRequestManagerPageReqVO reqVO) {
+ return friendRequestMapper.selectPage(reqVO);
+ }
+
+ /**
+ * 鏍¢獙鐢宠鍙銆屽綋鍓嶇敤鎴枫�嶅鐞嗭細鐢宠瀛樺湪 + 鏈鐞� + 鎿嶄綔浜� = 鎺ユ敹鏂�
+ */
+ private ImFriendRequestDO validateRequestForHandle(Long userId, Long requestId) {
+ ImFriendRequestDO request = friendRequestMapper.selectById(requestId);
+ if (request == null) {
+ throw exception(FRIEND_REQUEST_NOT_EXISTS);
+ }
+ if (ObjUtil.notEqual(request.getToUserId(), userId)) {
+ throw exception(FRIEND_REQUEST_NOT_TO_ME);
+ }
+ if (!ImFriendRequestHandleResultEnum.isUnhandled(request.getHandleResult())) {
+ throw exception(FRIEND_REQUEST_HANDLED);
+ }
+ return request;
+ }
+
+ private ImFriendRequestServiceImpl getSelf() {
+ return SpringUtil.getBean(getClass());
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java
new file mode 100644
index 0000000..1d1fc57
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java
@@ -0,0 +1,129 @@
+package cn.iocoder.yudao.module.im.service.friend;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.ImFriendUpdateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 濂藉弸鍏崇郴 Service 鎺ュ彛
+ * <p>
+ * 娉ㄦ剰锛氱敤鎴风銆屽姞濂藉弸銆嶈蛋 {@link ImFriendRequestService#applyFriend} 鐢宠-瀹℃壒娴佺▼锛�
+ * 涓嶅啀寮�鏀剧洿鎺� add 鎺ュ彛锛涘彧鏈� {@link #becomeFriends} 鏄唴閮ㄥ叆鍙o紙琚� agree 鍚屾剰 / 绠$悊鍛� import 瑙﹀彂锛夈��
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImFriendService {
+
+ /**
+ * 鑾峰彇 userId 瑙嗚涓嬩笌 friendUserId 鐨勫ソ鍙嬪叧绯荤姸鎬侊紙绉佽亰鍙戦�佺儹鐐硅矾寰勶級
+ * <p>
+ * 鍙傝 {@link ImFriendStateEnum} 鏋氫妇绫�
+ */
+ Integer getFriendState(Long userId, Long friendUserId);
+
+ /**
+ * 鏍¢獙銆岃兘鍚﹀ peerUserId 鍙戣捣绉佽亰璇箟鍔ㄤ綔銆嶏紙娑堟伅鍙戦�� 锛� RTC 閭�璇凤級
+ * <p>
+ * 濂藉弸 锛� 榛戝悕鍗曟牎楠岋細鍜岀鑱婃秷鎭彂閫佸悓涓�濂楄涔夛紱NONE 宸插垹 锛� 鏈姞锛孊LOCKED 琚鏂规媺榛�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param peerUserId 瀵规柟鐢ㄦ埛缂栧彿
+ */
+ void validateFriend(Long userId, Long peerUserId);
+
+ /**
+ * 鑾峰緱褰撳墠鐢ㄦ埛鐨勫ソ鍙嬪垪琛紙鍚凡鍒犻櫎鐘舵�侊級
+ */
+ List<ImFriendDO> getFriendList(Long userId);
+
+ /**
+ * 澧為噺鎷夊彇褰撳墠鐢ㄦ埛鐨勫ソ鍙嬪叧绯伙紙閲嶈繛 / 绂荤嚎琛ュ伩锛氬惈宸插垹闄わ紝鎸� update_time + id 娓告爣锛�
+ */
+ List<ImFriendDO> pullFriendList(Long userId, Long lastUpdateTime, Long lastId, Integer limit);
+
+ /**
+ * 鑾峰緱褰撳墠鐢ㄦ埛鐨勬湁鏁堝ソ鍙嬪垪琛紙浠� ENABLE 鐘舵�侊級
+ */
+ List<ImFriendDO> getEnableFriendList(Long userId);
+
+ /**
+ * 鑾峰緱褰撳墠鐢ㄦ埛鐨勫弻鍚戞湁鏁堝ソ鍙嬪垪琛紙鍙屾柟鍧� ENABLE 鐘舵�侊級
+ */
+ List<ImFriendDO> getMutualEnableFriendList(Long userId);
+
+ /**
+ * 鑾峰緱褰撳墠鐢ㄦ埛涓庢寚瀹氱敤鎴蜂箣闂寸殑鏈夋晥濂藉弸鍒楄〃锛堜粎 ENABLE 鐘舵�侊級
+ */
+ List<ImFriendDO> getActiveFriendList(Long userId, Collection<Long> friendUserIds);
+
+ /**
+ * 鏌ヨ涓�涓ソ鍙嬪叧绯昏褰�
+ */
+ ImFriendDO getFriend(Long userId, Long friendUserId);
+
+ // ==================== 鍐呴儴鍏ュ彛 ====================
+
+ /**
+ * 鍙屽悜寤虹珛濂藉弸鍏崇郴锛堝唴閮ㄥ叆鍙o級
+ * <p>
+ * 鐢� {@link ImFriendRequestService#agreeFriendRequest} 鍚屾剰鐢宠 / 绠$悊鍚庡彴瀵煎叆瑙﹀彂锛�
+ * A 渚� displayName / addSource 鍙栬嚜鐢宠璁板綍锛汢 渚� displayName 涓虹┖銆乤ddSource 鍚屾潵婧愩��
+ * 鍐欏簱鍚庢帹閫� FRIEND_ADD 閫氱煡缁� A銆丅 鍙屾柟澶氱锛屽苟涓嬪彂 TIP 绯荤粺娑堟伅銆�
+ *
+ * @param request 宸插悓鎰忕殑鐢宠璁板綍锛堝喅瀹� fromUserId / toUserId / addSource / displayName锛�
+ */
+ void becomeFriends(ImFriendRequestDO request);
+
+ /**
+ * 鍗曞悜闈欓粯閲嶆柊寤虹珛濂藉弸鍏崇郴
+ * <p>
+ * 浠呯敤浜� {@link ImFriendRequestService#applyFriend} 鍦ㄣ�屾垜宸插垹闄� + 瀵规柟浠嶆妸鎴戝綋濂藉弸銆嶅満鏅細
+ * 鐩存帴鎭㈠ userId 杩欒竟鐨� friend 璁板綍锛屼笉璧扮敵璇峰鎵癸紱涓嶄笅鍙� TIP / 涓嶉�氱煡瀵规柟锛屼粎 FRIEND_ADD 缁� userId 澶氱锛岄伩鍏嶅鏂规劅鐭ユ垜鏇惧垹闄ゃ��
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param friendUserId 瀵规柟鐢ㄦ埛缂栧彿
+ * @param displayName 澶囨敞锛堝彇鑷敵璇� VO锛�
+ * @param addSource 娣诲姞鏉ユ簮锛堝彇鑷敵璇� VO锛�
+ */
+ void silentReAddFriend(Long userId, Long friendUserId, String displayName, Integer addSource);
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ /**
+ * 鍒犻櫎濂藉弸锛堝崟鍚戣蒋鍒犻櫎锛�
+ * <p>
+ * 浠呭垹闄� userId 瑙嗚涓嬬殑濂藉弸鍏崇郴锛涘绔� friendUserId 鐨勮瑙掍笉鍙楀奖鍝嶏紙鍗曡竟鍒犻櫎璇箟锛�
+ *
+ * @param clear 鏄惁绾ц仈娓呯悊鏈鐩稿叧鏁版嵁锛堝綋鍓嶅寘鍚鑱婁細璇濓紱閫氳繃 FRIEND_DELETE 閫氱煡閫忎紶缁欏绔級
+ */
+ void deleteFriend(Long userId, Long friendUserId, Boolean clear);
+
+ /**
+ * 鏇存柊濂藉弸鍗曡竟灞炴�э紙澶囨敞 / 鍏嶆墦鎵� / 鑱旂郴浜虹疆椤讹級
+ */
+ void updateFriend(Long userId, ImFriendUpdateReqVO reqVO);
+
+ /**
+ * 鎷夐粦濂藉弸锛堝繀椤诲厛鏄ソ鍙嬶級
+ */
+ void blockFriend(Long userId, Long friendUserId);
+
+ /**
+ * 绉诲嚭榛戝悕鍗�
+ */
+ void unblockFriend(Long userId, Long friendUserId);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝垎椤垫煡璇㈠ソ鍙嬪叧绯�
+ */
+ PageResult<ImFriendDO> getFriendPage(ImFriendManagerPageReqVO reqVO);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java
new file mode 100644
index 0000000..f9dd452
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java
@@ -0,0 +1,339 @@
+package cn.iocoder.yudao.module.im.service.friend;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.ImFriendUpdateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.friend.vo.ImFriendManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+import cn.iocoder.yudao.module.im.dal.mysql.friend.ImFriendMapper;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.service.message.ImPrivateMessageService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.friend.*;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.annotation.Caching;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
+import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.FRIEND_STATE;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_BLOCKED_BY_PEER;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_NOT_BLOCKED;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_NOT_FRIEND;
+
+/**
+ * IM 濂藉弸鍏崇郴 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@Service
+@Validated
+public class ImFriendServiceImpl implements ImFriendService {
+
+ @Resource
+ private ImFriendMapper friendMapper;
+
+ @Resource
+ private ImWebSocketService websocketService;
+ @Resource
+ @Lazy
+ private ImPrivateMessageService privateMessageService;
+
+ @Override
+ @Cacheable(cacheNames = FRIEND_STATE, key = "#userId + '_' + #friendUserId", unless = "#result == null")
+ public Integer getFriendState(Long userId, Long friendUserId) {
+ // 1.1 鎴戜晶璁板綍锛氭垜鏂瑰垹浜嗭紝閮界畻闈炲ソ鍙�
+ ImFriendDO mine = friendMapper.selectByUserIdAndFriendUserId(userId, friendUserId);
+ if (mine == null || !CommonStatusEnum.isEnable(mine.getStatus())) {
+ return ImFriendStateEnum.NONE.getState();
+ }
+ // 1.2 瀵规柟渚ц褰曪細瀵规柟鍒犱簡 = 涓嶆槸濂藉弸
+ ImFriendDO peer = friendMapper.selectByUserIdAndFriendUserId(friendUserId, userId);
+ if (peer == null || !CommonStatusEnum.isEnable(peer.getStatus())) {
+ return ImFriendStateEnum.NONE.getState();
+ }
+ // 2. 浠呭綋鍙屾柟閮芥槸 ENABLE 鐘舵�侊紝鎵嶇畻濂藉弸鍏崇郴锛涙鏃跺鏂规媺榛戞垜锛屽垯鏄� BLOCKED
+ return BooleanUtil.isTrue(peer.getBlocked()) ? ImFriendStateEnum.BLOCKED.getState() : ImFriendStateEnum.FRIEND.getState();
+ }
+
+ @Override
+ public void validateFriend(Long userId, Long peerUserId) {
+ // 濂藉弸 锛� 榛戝悕鍗曟牎楠岋細鍜岀鑱婃秷鎭彂閫佸悓涓�濂楄涔夛紱NONE 宸插垹 锛� 鏈姞锛孊LOCKED 琚鏂规媺榛�
+ Integer state = getSelf().getFriendState(userId, peerUserId);
+ if (ImFriendStateEnum.isNone(state)) {
+ throw exception(FRIEND_NOT_FRIEND);
+ }
+ if (ImFriendStateEnum.isBlocked(state)) {
+ throw exception(FRIEND_BLOCKED_BY_PEER);
+ }
+ }
+
+ private ImFriendService getSelf() {
+ return SpringUtil.getBean(getClass());
+ }
+
+ @Override
+ public List<ImFriendDO> getFriendList(Long userId) {
+ return friendMapper.selectListByUserId(userId);
+ }
+
+ @Override
+ public List<ImFriendDO> pullFriendList(Long userId, Long lastUpdateTime, Long lastId, Integer limit) {
+ return friendMapper.selectPullListByUserId(userId, lastUpdateTime, lastId, limit);
+ }
+
+ @Override
+ public List<ImFriendDO> getEnableFriendList(Long userId) {
+ return friendMapper.selectListByUserIdAndStatus(userId, CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public List<ImFriendDO> getMutualEnableFriendList(Long userId) {
+ // 1. 鏌ヨ鏈鍚敤濂藉弸
+ List<ImFriendDO> friends = getEnableFriendList(userId);
+ if (CollUtil.isEmpty(friends)) {
+ return Collections.emptyList();
+ }
+
+ // 2. 鏌ヨ瀵圭鍚敤濂藉弸鍏崇郴
+ Set<Long> friendUserIds = convertSet(friends, ImFriendDO::getFriendUserId);
+ List<ImFriendDO> mutualFriends = friendMapper.selectListByUserIdsAndFriendUserIdAndStatus(friendUserIds, userId,
+ CommonStatusEnum.ENABLE.getStatus());
+ Set<Long> mutualUserIds = convertSet(mutualFriends, ImFriendDO::getUserId);
+
+ // 3. 杩囨护鍙屽悜鍚敤濂藉弸
+ return filterList(friends, friend -> mutualUserIds.contains(friend.getFriendUserId()));
+ }
+
+ @Override
+ public List<ImFriendDO> getActiveFriendList(Long userId, Collection<Long> friendUserIds) {
+ if (CollUtil.isEmpty(friendUserIds)) {
+ return Collections.emptyList();
+ }
+ return friendMapper.selectListByUserIdAndFriendUserIdsAndStatus(userId, friendUserIds,
+ CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public ImFriendDO getFriend(Long userId, Long friendUserId) {
+ return friendMapper.selectByUserIdAndFriendUserId(userId, friendUserId);
+ }
+
+ @Override
+ public void updateFriend(Long userId, ImFriendUpdateReqVO reqVO) {
+ // 1.1 鏍¢獙锛氳嚦灏戞敼涓�涓瓧娈碉紙鏃犲瓧娈靛彉鏇达紝鐩存帴缁撴潫锛�
+ if (reqVO.getDisplayName() == null && reqVO.getSilent() == null && reqVO.getPinned() == null) {
+ return;
+ }
+ // 1.2 鏍¢獙濂藉弸鍏崇郴鍚敤
+ ImFriendDO friend = friendMapper.selectByUserIdAndFriendUserId(userId, reqVO.getFriendUserId());
+ if (friend == null || !CommonStatusEnum.isEnable(friend.getStatus())) {
+ throw exception(FRIEND_NOT_FRIEND);
+ }
+
+ // 2. 鏇存柊濂藉弸灞炴�э紙澶囨敞 / 鍏嶆墦鎵� / 鑱旂郴浜虹疆椤讹級
+ friendMapper.updateById(new ImFriendDO().setId(friend.getId())
+ .setSilent(reqVO.getSilent()).setDisplayName(reqVO.getDisplayName()).setPinned(reqVO.getPinned()));
+
+ // 3. 鎺� FRIEND_UPDATE 缁� A 澶氱锛氭墍鏈夊崟杈瑰睘鎬у彉鏇村悎骞朵负鍗曟潯閫氱煡锛岄伩鍏嶅閫氱煡椤哄簭绔炰簤
+ FriendUpdateNotification payload = (FriendUpdateNotification) new FriendUpdateNotification()
+ .setDisplayName(reqVO.getDisplayName()).setSilent(reqVO.getSilent()).setPinned(reqVO.getPinned())
+ .setOperatorUserId(userId).setFriendUserId(reqVO.getFriendUserId());
+ websocketService.sendNotificationAsync(userId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.FRIEND_UPDATE.getType(), payload);
+ }
+
+ @Override
+ @Caching(evict = {
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#request.fromUserId + '_' + #request.toUserId"),
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#request.toUserId + '_' + #request.fromUserId")
+ })
+ @Transactional(rollbackFor = Exception.class)
+ public void becomeFriends(ImFriendRequestDO request) {
+ Long fromUserId = request.getFromUserId();
+ Long toUserId = request.getToUserId();
+ // 1. 鍙屽悜寤虹珛鍏崇郴锛欰 渚у甫鐢宠鐨� displayName / addSource锛汢 渚� displayName 涓虹┖銆乤ddSource 鍚屾潵婧�
+ // FRIEND_STATE 鍙屽悜澶辨晥鐢辨柟娉曚笂鐨� @Caching 娉ㄨВ澶勭悊锛沠ramework 宸插紑 transactionAware 鑷姩寤惰繜鍒� afterCommit
+ addFriend0(fromUserId, toUserId, request.getDisplayName(), request.getAddSource());
+ addFriend0(toUserId, fromUserId, null, request.getAddSource());
+
+ // 2. 鍙戦�� FRIEND_ADD 鍏ュ簱锛堝弻鏂规媺鍘嗗彶閮借兘鐪嬪埌銆屼綘浠凡鎴愪负濂藉弸銆嶄細璇濇皵娉★級+ 鍙屽悜 WebSocket 鑷姩瑕嗙洊鍙屾柟澶氱
+ // operatorUserId=fromUserId 鏍囪鐢宠鍙戣捣鏂癸紱鍓嶇鎸� (currentUserId === operatorUserId) 鍖哄垎瑙嗚锛屾枃妗堝浐瀹氫笉渚濊禆姝ゅ瓧娈�
+ FriendAddNotification payload = (FriendAddNotification) new FriendAddNotification()
+ .setOperatorUserId(fromUserId).setFriendUserId(toUserId);
+ privateMessageService.sendPrivateMessage(fromUserId, new ImPrivateMessageSendDTO()
+ .setReceiverId(toUserId).setType(ImContentTypeEnum.FRIEND_ADD.getType()).setContent(payload));
+ }
+
+ @Override
+ @Caching(evict = {
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#userId + '_' + #friendUserId"),
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#friendUserId + '_' + #userId")
+ })
+ @Transactional(rollbackFor = Exception.class)
+ public void silentReAddFriend(Long userId, Long friendUserId, String displayName, Integer addSource) {
+ // 1. 鍗曡竟閲嶆柊鍚敤鎴戜晶濂藉弸鍏崇郴
+ addFriend0(userId, friendUserId, displayName, addSource);
+
+ // 2. 璧� sendPrivateMessage + persistent=false锛氫笉鍏ュ簱 + 浠呮帹 userId 澶氱锛堝鏂瑰畬鍏ㄤ笉鎰熺煡锛屼繚鎸併�屽鏂逛竴鐩存妸鎴戝綋濂藉弸銆嶉敊瑙夛級
+ // operatorUserId 濉� friendUserId锛堝鏂癸級锛氳 userId 澶氱 UI 鍛堢幇銆屽鏂瑰姞浜嗘垜銆嶈瑙掞紝涓� silent 璇箟瀵归綈
+ // 鍓嶇鎸� type=FRIEND_ADD 娓叉煋浼氳瘽姘旀场锛堢灛鏃讹紝涓嶅叆搴撳埛鏂板嵆娑堝け锛�
+ FriendAddNotification payload = (FriendAddNotification) new FriendAddNotification()
+ .setOperatorUserId(friendUserId).setFriendUserId(friendUserId);
+ privateMessageService.sendPrivateMessage(userId, new ImPrivateMessageSendDTO()
+ .setReceiverId(friendUserId).setType(ImContentTypeEnum.FRIEND_ADD.getType())
+ .setContent(payload).setPersistent(false));
+ }
+
+ @Override
+ @Caching(evict = {
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#userId + '_' + #friendUserId"),
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#friendUserId + '_' + #userId")
+ })
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteFriend(Long userId, Long friendUserId, Boolean clear) {
+ // 1. 鍗曡竟杞垹锛氫粎 userId 瑙嗚鐨勫叧绯荤疆 DISABLE锛沠riendUserId 瑙嗚涓嶅姩
+ if (!deleteFriend0(userId, friendUserId)) {
+ return;
+ }
+
+ // 2. 璧� sendPrivateMessage + persistent=false锛氫笉鍏ュ簱 + 浠呮帹 userId 澶氱锛坒riendUserId 涓嶆劅鐭ワ級锛沜lear 閫忎紶璁╁绔竻鐞嗗姩浣滀竴鑷�
+ // clear=false 鏃跺墠绔寜 type=FRIEND_DELETE 娓叉煋銆屼綘宸插垹闄ゅソ鍙嬨�嶄細璇濇皵娉★紙鐬椂锛夛紱
+ // clear=true 鏃跺墠绔寜 clear 瀛楁鐩存帴娓呬細璇濓紝璺宠繃姘旀场娓叉煋
+ FriendDeleteNotification payload = ((FriendDeleteNotification) new FriendDeleteNotification()
+ .setOperatorUserId(userId).setFriendUserId(friendUserId)).setClear(clear);
+ privateMessageService.sendPrivateMessage(userId, new ImPrivateMessageSendDTO()
+ .setReceiverId(friendUserId).setType(ImContentTypeEnum.FRIEND_DELETE.getType())
+ .setContent(payload).setPersistent(false));
+ }
+
+ @Override
+ @Caching(evict = {
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#userId + '_' + #friendUserId"),
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#friendUserId + '_' + #userId")
+ })
+ public void blockFriend(Long userId, Long friendUserId) {
+ // 1.1 鏍¢獙鏄ソ鍙�
+ ImFriendDO friend = friendMapper.selectByUserIdAndFriendUserId(userId, friendUserId);
+ if (friend == null || !CommonStatusEnum.isEnable(friend.getStatus())) {
+ throw exception(FRIEND_NOT_FRIEND);
+ }
+ // 1.2 宸叉媺榛戠洿鎺ヨ繑鍥烇紝骞傜瓑
+ if (BooleanUtil.isTrue(friend.getBlocked())) {
+ return;
+ }
+
+ // 2. 鍗曡竟鏇存柊
+ friendMapper.updateById(new ImFriendDO().setId(friend.getId()).setBlocked(true));
+
+ // 3. 鎺� FRIEND_BLOCK 缁� A 澶氱
+ FriendBlockNotification payload = (FriendBlockNotification) new FriendBlockNotification()
+ .setOperatorUserId(userId).setFriendUserId(friendUserId);
+ websocketService.sendNotificationAsync(userId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.FRIEND_BLOCK.getType(), payload);
+ }
+
+ @Override
+ @Caching(evict = {
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#userId + '_' + #friendUserId"),
+ @CacheEvict(cacheNames = FRIEND_STATE, key = "#friendUserId + '_' + #userId")
+ })
+ public void unblockFriend(Long userId, Long friendUserId) {
+ // 1.1 鏍¢獙鏄ソ鍙�
+ ImFriendDO friend = friendMapper.selectByUserIdAndFriendUserId(userId, friendUserId);
+ if (friend == null || !CommonStatusEnum.isEnable(friend.getStatus())) {
+ throw exception(FRIEND_NOT_FRIEND);
+ }
+ // 1.2 鏈媺榛戝垯鎶ラ敊
+ if (!BooleanUtil.isTrue(friend.getBlocked())) {
+ throw exception(FRIEND_NOT_BLOCKED);
+ }
+
+ // 2. 鍗曡竟鏇存柊
+ friendMapper.updateById(new ImFriendDO().setId(friend.getId()).setBlocked(false));
+
+ // 3. 鎺� FRIEND_UNBLOCK 缁� A 澶氱
+ FriendUnblockNotification payload = (FriendUnblockNotification) new FriendUnblockNotification()
+ .setOperatorUserId(userId).setFriendUserId(friendUserId);
+ websocketService.sendNotificationAsync(userId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.FRIEND_UNBLOCK.getType(), payload);
+ }
+
+ /**
+ * 鍗曞悜缁戝畾濂藉弸鍏崇郴锛堝唴閮ㄦ柟娉曪紝琚� {@link #becomeFriends} / {@link #silentReAddFriend} 璋冪敤锛夛細
+ * - 鎯呭喌涓�锛氬凡瀛樺湪 ENABLE 璁板綍 鈫� 宸叉槸濂藉弸锛屽箓绛夎烦杩囷紱涓嶉噸缃� silent / pinned / blocked锛岄伩鍏嶅巻鍙叉湭澶勭悊鐢宠鍐嶈鍚屾剰鏃舵竻鎺夌敤鎴风殑鎷夐粦 / 缃《 / 鍏嶆墦鎵拌缃�
+ * - 鎯呭喌浜岋細宸插瓨鍦� DISABLE 璁板綍 鈫� 澶嶇敤骞舵仮澶� ENABLE锛宻ilent / pinned / blocked 涓�骞堕噸缃负 false锛屽榻�"閲嶆柊鍔犲ソ鍙�"璇箟
+ * - 鎯呭喌涓夛細涓嶅瓨鍦ㄨ褰� 鈫� 鐩存帴鎻掑叆鏂拌褰�
+ * <p>
+ * 骞跺彂瀹夊叏锛歛gree 璺緞鐢� {@code friend_request.handle_result} 鐨勪箰瑙傞攣鍗曡竟鎺ㄨ繘锛�
+ * 鏋佺骞跺彂涓嬭嫢鎻掑叆鍞竴閿啿绐侊紝璁� DuplicateKeyException 鍚戝鎶涘嚭锛屽灞備簨鍔″洖婊氥��
+ * <p>
+ * FRIEND_STATE 缂撳瓨澶辨晥鐢辫皟鐢ㄦ柟鐨� @Caching 娉ㄨВ缁熶竴澶勭悊锛屾湰鏂规硶涓嶄富鍔� evict
+ */
+ public void addFriend0(Long userId, Long friendUserId, String displayName, Integer addSource) {
+ ImFriendDO exists = friendMapper.selectByUserIdAndFriendUserId(userId, friendUserId);
+ // 鎯呭喌涓�锛氬凡鏄� ENABLE 濂藉弸锛屽箓绛夎烦杩囷紱闃插尽鍘嗗彶鏈鐞嗙敵璇疯浜屾鍚屾剰鏃舵妸 blocked / silent / pinned 娓呭洖 false
+ if (exists != null && CommonStatusEnum.isEnable(exists.getStatus())) {
+ return;
+ }
+ // 鎯呭喌浜岋細澶嶇敤 DISABLE 鏃ц褰� 鈫� 鎭㈠ ENABLE + 閲嶇疆 silent / pinned / blocked锛屽榻�"閲嶆柊鍔犲ソ鍙�"璇箟
+ if (exists != null) {
+ LocalDateTime now = LocalDateTime.now();
+ friendMapper.updateReAddFields(exists.getId(), CommonStatusEnum.ENABLE.getStatus(), now, now,
+ false, false, false, displayName, addSource);
+ return;
+ }
+ // 鎯呭喌涓夛細涓嶅瓨鍦ㄨ褰� 鈫� 鐩存帴鎻掑叆鏂拌褰�
+ ImFriendDO friend = ImFriendDO.builder().userId(userId).friendUserId(friendUserId)
+ .silent(false).pinned(false).blocked(false)
+ .displayName(displayName).addSource(addSource)
+ .status(CommonStatusEnum.ENABLE.getStatus()).addTime(LocalDateTime.now()).build();
+ friendMapper.insert(friend);
+ }
+
+ /**
+ * 鍗曞悜瑙i櫎濂藉弸鍏崇郴锛坰tatus 璁句负 DISABLE锛岃褰� deleteTime锛�
+ * <p>
+ * blocked 涓嶄富鍔ㄩ噸缃細鍒犲ソ鍙嬫湡闂翠繚鐣欐媺榛戠姸鎬侊紱濡傛灉鏈潵鍐� addFriend0锛岀敱 addFriend0 缁熶竴閲嶇疆
+ * <p>
+ * FRIEND_STATE 缂撳瓨澶辨晥鐢辫皟鐢ㄦ柟鐨� @Caching 娉ㄨВ缁熶竴澶勭悊锛屾湰鏂规硶涓嶄富鍔� evict
+ */
+ public boolean deleteFriend0(Long userId, Long friendUserId) {
+ ImFriendDO exists = friendMapper.selectByUserIdAndFriendUserId(userId, friendUserId);
+ if (exists == null || CommonStatusEnum.isDisable(exists.getStatus())) {
+ return false;
+ }
+ friendMapper.updateById(new ImFriendDO().setId(exists.getId())
+ .setStatus(CommonStatusEnum.DISABLE.getStatus()).setDeleteTime(LocalDateTime.now()));
+ return true;
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImFriendDO> getFriendPage(ImFriendManagerPageReqVO reqVO) {
+ return friendMapper.selectPage(reqVO);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberService.java
new file mode 100644
index 0000000..a99c0f3
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberService.java
@@ -0,0 +1,244 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberUpdateReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import jakarta.validation.Valid;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 缇ゆ垚鍛� Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImGroupMemberService {
+
+ /**
+ * 鑾峰緱缇ゆ垚鍛�
+ *
+ * @param id 缂栧彿
+ * @return 缇ゆ垚鍛�
+ */
+ ImGroupMemberDO getGroupMember(Long id);
+
+ /**
+ * 鑾峰緱缇ゆ垚鍛�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return 缇ゆ垚鍛�
+ */
+ ImGroupMemberDO getGroupMember(Long groupId, Long userId);
+
+ /**
+ * 鎵归噺鏌ヨ缇ゆ垚鍛橈紙鍖呭惈鎵�鏈夌姸鎬侊級
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userIds 鐢ㄦ埛缂栧彿闆嗗悎
+ * @return 缇ゆ垚鍛樺垪琛�
+ */
+ List<ImGroupMemberDO> getGroupMembers(Long groupId, Collection<Long> userIds);
+
+ /**
+ * 鏍规嵁缇ょ粍 id 鏌ヨ缇ゆ垚鍛橈紙鍖呭惈鎵�鏈夌姸鎬侊級
+ *
+ * @param groupId 缇ょ粍id
+ * @return 缇ゆ垚鍛樺垪琛�
+ */
+ List<ImGroupMemberDO> getGroupMemberListByGroupId(Long groupId);
+
+ /**
+ * 鏍规嵁缇ょ紪鍙锋煡璇㈡湁鏁堟垚鍛樺垪琛紙浠� ENABLE 鐘舵�侊級
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @return 鏈夋晥缇ゆ垚鍛樺垪琛�
+ */
+ List<ImGroupMemberDO> getActiveGroupMemberListByGroupId(Long groupId);
+
+ /**
+ * 鑾峰彇缇ら噷娲昏穬鐨勭兢涓� + 绠$悊鍛橈紱鐢ㄤ簬瀹℃壒閫氱煡瀹氬悜鎺ㄩ��
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @return 缇や富 / 绠$悊鍛樼殑鎴愬憳璁板綍鍒楄〃锛堟寜鍏ョ兢鏃堕棿鍊掑簭鐨勫ぉ鐒舵垚鍛樿〃椤哄簭锛�
+ */
+ List<ImGroupMemberDO> getGroupMemberListByOwnerAndAdmin(Long groupId);
+
+ /**
+ * 鏍规嵁缇ょ紪鍙锋煡璇㈡湁鏁堟垚鍛樼殑 userId 鍒楄〃锛堜粎 ENABLE 鐘舵�侊級
+ * <p>
+ * 鐩告瘮 {@link #getActiveGroupMemberListByGroupId(Long)}锛屽彧杩斿洖 userId锛岀粨鏋滀綋绉皬锛屽苟甯︽湁 Redis 缂撳瓨銆�
+ * 閫傜敤浜�"缇ゆ秷鎭帹閫佺洰鏍�"绛夊彧闇�瑕� userId 鐨勫満鏅紱
+ * 闇�瑕� joinTime/quitTime/status 绛夊瓧娈靛仛鍘嗗彶娑堟伅鍙鎬у垽鏂椂锛屼粛搴斾娇鐢ㄥ畬鏁村垪琛ㄦ柟娉曘��
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @return 鏈夋晥缇ゆ垚鍛� userId 鍒楄〃
+ */
+ List<Long> getActiveGroupMemberUserIdsByGroupId(Long groupId);
+
+ /**
+ * 鏌ヨ鐢ㄦ埛鎵�鍦ㄧ殑鎵�鏈夌兢鐨勬湁鏁堟垚鍛樿褰曪紙浠� ENABLE 鐘舵�侊級
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return 鏈夋晥缇ゆ垚鍛樿褰曞垪琛�
+ */
+ List<ImGroupMemberDO> getActiveGroupMemberListByUserId(Long userId);
+
+ /**
+ * 鏌ヨ鐢ㄦ埛鏇剧粡鍔犲叆鐨勬墍鏈夌兢鎴愬憳璁板綍锛堝惈宸查��缇わ級
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return 缇ゆ垚鍛樿褰曞垪琛�
+ */
+ List<ImGroupMemberDO> getGroupMemberListByUserId(Long userId);
+
+ /**
+ * 娣诲姞缇ゆ垚鍛橈紙鍏ョ兢锛夛紝瑙掕壊榛樿 MEMBER
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return 缇ゆ垚鍛樿褰�
+ */
+ @SuppressWarnings("UnusedReturnValue")
+ ImGroupMemberDO addGroupMember(Long groupId, Long userId);
+
+ /**
+ * 娣诲姞缇ゆ垚鍛橈紙鍏ョ兢锛夛紝骞舵寚瀹氳鑹�
+ * <p>
+ * 閲嶇疆鏃ф垚鍛樿涔熶細寮哄埗閲嶇疆 role锛岄伩鍏嶇缇ゆ湡闂存畫鐣欑鐞嗗憳韬唤琚鐢ㄣ��
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param role 鎴愬憳瑙掕壊锛岃 {@link cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum}
+ * @return 缇ゆ垚鍛樿褰�
+ */
+ @SuppressWarnings("UnusedReturnValue")
+ ImGroupMemberDO addGroupMember(Long groupId, Long userId, Integer role);
+
+ /**
+ * 娣诲姞缇ゆ垚鍛橈紙鍏ョ兢锛夛紝骞舵寚瀹氳鑹� / 鍔犲叆鏉ユ簮 / 閭�璇蜂汉
+ * <p>
+ * 閲嶇疆鏃ф垚鍛樿涔熶細寮哄埗閲嶇疆 role / addSource / inviterUserId锛岀‘淇濈暀鐥曞弽鏄犮�屾湰娆″叆缇ゃ�嶄簨浠�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param role 鎴愬憳瑙掕壊
+ * @param addSource 鍔犲叆鏉ユ簮锛岃 {@link cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum}
+ * @param inviterUserId 閭�璇蜂汉鐢ㄦ埛缂栧彿锛汵ULL 琛ㄧず涓诲姩鐢宠
+ * @return 缇ゆ垚鍛樿褰�
+ */
+ @SuppressWarnings("UnusedReturnValue")
+ ImGroupMemberDO addGroupMember(Long groupId, Long userId, Integer role, Integer addSource, Long inviterUserId);
+
+ /**
+ * 鎵归噺娣诲姞缇ゆ垚鍛橈紙鍏ョ兢锛�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userIds 鐢ㄦ埛缂栧彿闆嗗悎
+ */
+ void addGroupMembers(Long groupId, Collection<Long> userIds);
+
+ /**
+ * 鎵归噺娣诲姞缇ゆ垚鍛橈紙鍏ョ兢锛夛紝缁熶竴鎼哄甫鍔犲叆鏉ユ簮 / 閭�璇蜂汉
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userIds 鐢ㄦ埛缂栧彿闆嗗悎
+ * @param addSource 鍔犲叆鏉ユ簮
+ * @param inviterUserId 閭�璇蜂汉鐢ㄦ埛缂栧彿锛汵ULL 琛ㄧず涓诲姩鐢宠
+ */
+ void addGroupMembers(Long groupId, Collection<Long> userIds, Integer addSource, Long inviterUserId);
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鏄惁涓虹兢鐨勬湁鏁堟垚鍛�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return 缇ゆ垚鍛樿褰�
+ */
+ ImGroupMemberDO validateMemberInGroup(Long groupId, Long userId);
+
+ /**
+ * 鎵归噺鏍¢獙鐢ㄦ埛閮芥槸璇ョ兢鐨勬湁鏁堟垚鍛橈紱浠讳竴缂哄け / 绂佺敤鍗虫姏 {@code GROUP_MEMBER_NOT_IN_GROUP}
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userIds 鐢ㄦ埛缂栧彿闆嗗悎锛涗负绌虹洿鎺ヨ繑鍥�
+ */
+ void validateMembersInGroup(Long groupId, Collection<Long> userIds);
+
+ /**
+ * 鏇存柊缇ゆ垚鍛樹俊鎭紙缇ゅ唴鏄电О銆佺兢鍚嶅娉ㄣ�佸厤鎵撴壈绛夛級
+ * <p>
+ * 鍐呴儴浼氭牎楠岀敤鎴锋槸鍚︿负缇ょ殑鏈夋晥鎴愬憳
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @param updateReqVO 鏇存柊淇℃伅
+ */
+ void updateGroupMember(Long userId, @Valid ImGroupMemberUpdateReqVO updateReqVO);
+
+ /**
+ * 鎵归噺鏇存柊缇ゆ垚鍛樿鑹�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userIds 鐢ㄦ埛缂栧彿闆嗗悎
+ * @param role 鏂拌鑹诧紝瑙� {@link cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum}
+ */
+ int updateGroupMemberRole(Long groupId, Collection<Long> userIds, Integer role);
+
+ /**
+ * 缁熻缇ゅ唴鎸囧畾 role 鐨勬椿璺冩垚鍛樻暟閲�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param role 鎴愬憳瑙掕壊
+ * @return 鏁伴噺
+ */
+ Long getGroupMemberCountByRole(Long groupId, Integer role);
+
+ /**
+ * 绉婚櫎鎸囧畾缇ゆ垚鍛橈紙璁剧疆涓� DISABLE 鐘舵�侊級
+ * <p>
+ * 鐢ㄤ簬閫�缇ゃ�佽涪鍑哄満鏅�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 鐢ㄦ埛缂栧彿
+ */
+ void removeGroupMember(Long groupId, Long userId);
+
+ /**
+ * 鎵归噺绉婚櫎鎸囧畾缇ゆ垚鍛橈紙璁剧疆涓� DISABLE 鐘舵�侊級
+ * <p>
+ * 鐢ㄤ簬鎵归噺韪㈠嚭鍦烘櫙
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userIds 鐢ㄦ埛缂栧彿闆嗗悎
+ */
+ void removeGroupMembers(Long groupId, Collection<Long> userIds);
+
+ /**
+ * 绉婚櫎缇ょ殑鍏ㄩ儴鎴愬憳锛堣缃负 DISABLE 鐘舵�侊級
+ * <p>
+ * 鐢ㄤ簬缇よВ鏁e満鏅�
+ *
+ * @param groupId 缇ょ紪鍙�
+ */
+ void removeGroupMembersByGroupId(Long groupId);
+
+ /**
+ * 鎵归噺鎸� group 缁熻娲昏穬鎴愬憳鏁帮細(group_id 鈫� count)
+ *
+ * @param groupIds 缇ょ紪鍙烽泦鍚�
+ * @return 缇ゆ垚鍛樻暟 Map
+ */
+ Map<Long, Long> getActiveMemberCountMap(Collection<Long> groupIds);
+
+ /**
+ * 鏇存柊鎴愬憳绂佽█鍒版湡鏃堕棿
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param muteEndTime 绂佽█鍒版湡鏃堕棿锛沶ull 琛ㄧず鍙栨秷绂佽█
+ */
+ void updateGroupMemberMuteEndTime(Long groupId, Long userId, LocalDateTime muteEndTime);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImpl.java
new file mode 100644
index 0000000..c712a0b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImpl.java
@@ -0,0 +1,323 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberUpdateReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMemberMapper;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.GROUP_MEMBER_IDS;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.GROUP_MEMBER_NOT_IN_GROUP;
+
+/**
+ * 缇ゆ垚鍛� Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@Service
+@Validated
+public class ImGroupMemberServiceImpl implements ImGroupMemberService {
+
+ @Resource
+ private ImGroupMemberMapper groupMemberMapper;
+
+ @Resource
+ @Lazy // 閬垮厤寰幆渚濊禆
+ private ImGroupMessageService groupMessageService;
+
+ @Override
+ public ImGroupMemberDO getGroupMember(Long id) {
+ return groupMemberMapper.selectById(id);
+ }
+
+ @Override
+ public ImGroupMemberDO getGroupMember(Long groupId, Long userId) {
+ return groupMemberMapper.selectByGroupIdAndUserId(groupId, userId);
+ }
+
+ @Override
+ public List<ImGroupMemberDO> getGroupMembers(Long groupId, Collection<Long> userIds) {
+ if (CollUtil.isEmpty(userIds)) {
+ return Collections.emptyList();
+ }
+ return groupMemberMapper.selectListByGroupIdAndUserIds(groupId, userIds);
+ }
+
+ @Override
+ public List<ImGroupMemberDO> getGroupMemberListByGroupId(Long groupId) {
+ return groupMemberMapper.selectListByGroupId(groupId);
+ }
+
+ @Override
+ public List<ImGroupMemberDO> getActiveGroupMemberListByGroupId(Long groupId) {
+ return groupMemberMapper.selectListByGroupIdAndStatus(groupId, CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public List<ImGroupMemberDO> getGroupMemberListByOwnerAndAdmin(Long groupId) {
+ return groupMemberMapper.selectListByGroupIdAndStatusAndRoles(groupId, CommonStatusEnum.ENABLE.getStatus(),
+ ListUtil.of(ImGroupMemberRoleEnum.OWNER.getRole(), ImGroupMemberRoleEnum.ADMIN.getRole()));
+ }
+
+ /**
+ * 鍙紦瀛� userId 鍒楄〃鑰岄潪鏁翠釜 {@link ImGroupMemberDO}锛岀悊鐢憋細
+ * <ul>
+ * <li>浣撶Н灏忥細500 浜虹兢绾� 4KB锛屽け鏁�/搴忓垪鍖栨垚鏈綆锛�</li>
+ * <li>澶辨晥闈㈢獎锛氫粎 {@link #addGroupMember}/{@link #addGroupMembers}/
+ * {@link #removeGroupMember}/{@link #removeGroupMembers}/{@link #removeGroupMembersByGroupId}
+ * 杩欑被褰卞搷鎴愬憳闆嗗悎鐨勫啓鎿嶄綔闇�瑕佸け鏁堬紱
+ * {@link #updateGroupMember}锛堟樀绉�/澶囨敞/鍏嶆墦鎵帮級涓嶄慨鏀归泦鍚堟垚鍛橈紝涓嶉渶瑕佸け鏁堛��</li>
+ * </ul>
+ */
+ @Override
+ @Cacheable(cacheNames = GROUP_MEMBER_IDS, key = "#groupId")
+ public List<Long> getActiveGroupMemberUserIdsByGroupId(Long groupId) {
+ List<ImGroupMemberDO> members = groupMemberMapper.selectListByGroupIdAndStatus(
+ groupId, CommonStatusEnum.ENABLE.getStatus());
+ return convertList(members, ImGroupMemberDO::getUserId);
+ }
+
+ @Override
+ public List<ImGroupMemberDO> getActiveGroupMemberListByUserId(Long userId) {
+ return groupMemberMapper.selectListByUserIdAndStatus(userId, CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public List<ImGroupMemberDO> getGroupMemberListByUserId(Long userId) {
+ return groupMemberMapper.selectListByUserId(userId);
+ }
+
+ @Override
+ public ImGroupMemberDO addGroupMember(Long groupId, Long userId) {
+ return addGroupMember(groupId, userId, ImGroupMemberRoleEnum.NORMAL.getRole(), null, null);
+ }
+
+ @Override
+ public ImGroupMemberDO addGroupMember(Long groupId, Long userId, Integer role) {
+ return addGroupMember(groupId, userId, role, null, null);
+ }
+
+ /**
+ * 骞跺彂瀹夊叏锛氫緷闈� im_group_member 琛ㄧ殑鍞竴绱㈠紩 uk_im_group_member_group_user(group_id, user_id) 淇濊瘉骞傜瓑锛�
+ * 褰撳苟鍙� insert 瑙﹀彂 {@link DuplicateKeyException} 鏃堕檷绾т负 select + update銆�
+ * <p>
+ * 閲嶇疆鏃ф垚鍛樿鏃跺己鍒堕噸缃� role / addSource / inviterUserId / quitTime / muteEndTime
+ */
+ @Override
+ @CacheEvict(cacheNames = GROUP_MEMBER_IDS, key = "#groupId")
+ public ImGroupMemberDO addGroupMember(Long groupId, Long userId, Integer role,
+ Integer addSource, Long inviterUserId) {
+ LocalDateTime now = LocalDateTime.now();
+ // 鎯呭喌涓�锛氬凡瀛樺湪璁板綍 鈫� 閲嶇疆鎴栬烦杩�
+ ImGroupMemberDO exists = groupMemberMapper.selectByGroupIdAndUserId(groupId, userId);
+ if (exists != null) {
+ if (CommonStatusEnum.isDisable(exists.getStatus())) {
+ groupMemberMapper.updateRejoinFields(exists.getId(), CommonStatusEnum.ENABLE.getStatus(), now,
+ role, addSource, inviterUserId);
+ exists.setStatus(CommonStatusEnum.ENABLE.getStatus()).setJoinTime(now).setRole(role)
+ .setAddSource(addSource).setInviterUserId(inviterUserId)
+ .setQuitTime(null).setMuteEndTime(null);
+ }
+ return exists;
+ }
+ // 鎯呭喌浜岋細鏂板鎴愬憳
+ ImGroupMemberDO member = new ImGroupMemberDO()
+ .setGroupId(groupId).setUserId(userId)
+ .setStatus(CommonStatusEnum.ENABLE.getStatus()).setJoinTime(now)
+ .setRole(role).setAddSource(addSource).setInviterUserId(inviterUserId);
+ try {
+ groupMemberMapper.insert(member);
+ return member;
+ } catch (DuplicateKeyException e) {
+ // 骞跺彂鍦烘櫙锛氬彟涓�涓姹傚凡鍏堜竴姝ユ彃鍏ワ紝涓斿叾鎻掑叆鐨勫繀鐒舵槸 ENABLE 鐘舵�侊紙DISABLE 鍦烘櫙鍦ㄤ笂鏂瑰垎鏀凡澶勭悊锛夛紝鏌ヨ杩斿洖
+ log.warn("[addGroupMember][groupId({}) userId({}) 骞跺彂鎻掑叆鍐茬獊锛屾煡璇㈣繑鍥瀅", groupId, userId);
+ return groupMemberMapper.selectByGroupIdAndUserId(groupId, userId);
+ }
+ }
+
+ @Override
+ public void addGroupMembers(Long groupId, Collection<Long> userIds) {
+ addGroupMembers(groupId, userIds, null, null);
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP_MEMBER_IDS, key = "#groupId")
+ public void addGroupMembers(Long groupId, Collection<Long> userIds, Integer addSource, Long inviterUserId) {
+ LocalDateTime now = LocalDateTime.now();
+ Integer role = ImGroupMemberRoleEnum.NORMAL.getRole();
+ // 1.1 鏌ヨ宸叉湁璁板綍锛堝惈宸查��缇ょ殑 DISABLE 璁板綍锛�
+ List<ImGroupMemberDO> existMembers = groupMemberMapper.selectListByGroupIdAndUserIds(groupId, userIds);
+ Map<Long, ImGroupMemberDO> existMap = convertMap(existMembers, ImGroupMemberDO::getUserId);
+ // 1.2 鍒嗙被锛氬凡鏈夎褰� 鈫� UPDATE锛屾柊鎴愬憳 鈫� INSERT
+ List<ImGroupMemberDO> inserts = new ArrayList<>();
+ List<ImGroupMemberDO> updates = new ArrayList<>();
+ for (Long userId : userIds) {
+ ImGroupMemberDO exist = existMap.get(userId);
+ if (exist == null) {
+ inserts.add(new ImGroupMemberDO().setGroupId(groupId).setUserId(userId)
+ .setStatus(CommonStatusEnum.ENABLE.getStatus()).setRole(role).setJoinTime(now)
+ .setAddSource(addSource).setInviterUserId(inviterUserId));
+ } else if (CommonStatusEnum.DISABLE.getStatus().equals(exist.getStatus())) {
+ updates.add(new ImGroupMemberDO().setId(exist.getId())
+ .setStatus(CommonStatusEnum.ENABLE.getStatus()).setRole(role).setJoinTime(now)
+ .setAddSource(addSource).setInviterUserId(inviterUserId));
+ }
+ }
+
+ // 2.1 鍏堝仛 update锛寀pdate 娌℃湁骞跺彂鍐茬獊椋庨櫓
+ if (CollUtil.isNotEmpty(updates)) {
+ for (ImGroupMemberDO update : updates) {
+ groupMemberMapper.updateRejoinFields(update.getId(), update.getStatus(), update.getJoinTime(),
+ update.getRole(), update.getAddSource(), update.getInviterUserId());
+ }
+ }
+ // 2.2 鎵归噺 insert銆傚苟鍙戝満鏅笅鑻ュ叾瀹冭姹傚凡鍏堜竴姝ユ彃鍏ュ悓涓� (groupId, userId)锛�
+ // 浼氳Е鍙戝敮涓�绱㈠紩鍐茬獊锛屾鏃堕檷绾т负閫愪釜 addGroupMember锛堝埄鐢ㄥ叾鍏滃簳閫昏緫骞傜瓑澶勭悊锛夈��
+ if (CollUtil.isNotEmpty(inserts)) {
+ try {
+ groupMemberMapper.insertBatch(inserts);
+ } catch (DuplicateKeyException e) {
+ log.warn("[addGroupMembers][groupId({}) userIds({}) 鎵归噺鎻掑叆鍐茬獊锛岄檷绾т负閫愪釜澶勭悊]", groupId, userIds);
+ for (ImGroupMemberDO insert : inserts) {
+ addGroupMember(groupId, insert.getUserId(), role, addSource, inviterUserId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public ImGroupMemberDO validateMemberInGroup(Long groupId, Long userId) {
+ ImGroupMemberDO member = groupMemberMapper.selectByGroupIdAndUserId(groupId, userId);
+ if (member == null || CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())) {
+ throw exception(GROUP_MEMBER_NOT_IN_GROUP);
+ }
+ return member;
+ }
+
+ @Override
+ public void validateMembersInGroup(Long groupId, Collection<Long> userIds) {
+ if (CollUtil.isEmpty(userIds)) {
+ return;
+ }
+ // 涓�娆℃�ф媺鍙栫洰鏍� userId 鐨勬垚鍛樿褰曪紝浠呬繚鐣欐椿璺冪姸鎬�
+ List<ImGroupMemberDO> members = groupMemberMapper.selectListByGroupIdAndUserIds(groupId, userIds);
+ Set<Long> activeUserIds = convertSet(members, ImGroupMemberDO::getUserId,
+ member -> CommonStatusEnum.ENABLE.getStatus().equals(member.getStatus()));
+ // 浠讳竴 userId 涓嶅湪娲昏穬闆嗗悎鍗虫姏
+ for (Long userId : userIds) {
+ if (!activeUserIds.contains(userId)) {
+ throw exception(GROUP_MEMBER_NOT_IN_GROUP);
+ }
+ }
+ }
+
+ @Override
+ public int updateGroupMemberRole(Long groupId, Collection<Long> userIds, Integer role) {
+ if (CollUtil.isEmpty(userIds)) {
+ return 0;
+ }
+ return groupMemberMapper.updateListByGroupIdAndUserIds(groupId, userIds, new ImGroupMemberDO().setRole(role));
+ }
+
+ @Override
+ public Long getGroupMemberCountByRole(Long groupId, Integer role) {
+ return groupMemberMapper.selectCountByGroupIdAndRoleAndStatus(
+ groupId, role, CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public void updateGroupMember(Long userId, ImGroupMemberUpdateReqVO updateReqVO) {
+ Long groupId = updateReqVO.getGroupId();
+ // 1. 鏍¢獙鏄兢鐨勬湁鏁堟垚鍛�
+ ImGroupMemberDO member = validateMemberInGroup(groupId, userId);
+
+ // 2. 鏇存柊缇ゆ垚鍛樹俊鎭�
+ ImGroupMemberDO updateObj = BeanUtils.toBean(updateReqVO, ImGroupMemberDO.class)
+ .setId(member.getId());
+ groupMemberMapper.updateById(updateObj);
+
+ // 3.1 displayUserName 鏄叕寮�瀛楁锛屽崟鐙蛋 GROUP_MEMBER_NICKNAME_UPDATE 鍦ㄧ嚎鍚屾缁欏叏鍛橈紱绌轰覆瑙嗕负銆屾竻绌烘樀绉般�嶄篃瑕佸悓姝ワ紱涓庢棫鍊肩浉鍚岃烦杩�
+ if (updateReqVO.getDisplayUserName() != null
+ && ObjUtil.notEqual(updateReqVO.getDisplayUserName(), member.getDisplayUserName())) {
+ groupMessageService.sendGroupMessage(userId, ImGroupMessageSendDTO.ofGroupMemberNicknameUpdate(
+ groupId, userId, updateReqVO.getDisplayUserName()));
+ }
+ // 3.2 silent / groupRemark 鏄釜浜哄瓧娈碉紝浠呮帹鑷繁鍋氬绔悓姝ワ紱涓庢棫鍊奸兘鐩稿悓璺宠繃
+ boolean silentChanged = updateReqVO.getSilent() != null
+ && ObjUtil.notEqual(updateReqVO.getSilent(), member.getSilent());
+ boolean groupRemarkChanged = updateReqVO.getGroupRemark() != null
+ && ObjUtil.notEqual(updateReqVO.getGroupRemark(), member.getGroupRemark());
+ if (silentChanged || groupRemarkChanged) {
+ groupMessageService.sendGroupMessage(userId, ListUtil.of(userId), ImGroupMessageSendDTO.ofGroupMemberSettingUpdate(
+ groupId, userId, updateReqVO.getSilent(), updateReqVO.getGroupRemark()));
+ }
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP_MEMBER_IDS, key = "#groupId")
+ public void removeGroupMember(Long groupId, Long userId) {
+ // 1. 鏍¢獙鏄兢鐨勬湁鏁堟垚鍛�
+ ImGroupMemberDO member = validateMemberInGroup(groupId, userId);
+ // 2. 鏇存柊涓洪��缇ょ姸鎬�
+ groupMemberMapper.updateById(new ImGroupMemberDO().setId(member.getId())
+ .setStatus(CommonStatusEnum.DISABLE.getStatus())
+ .setQuitTime(LocalDateTime.now()));
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP_MEMBER_IDS, key = "#groupId")
+ public void removeGroupMembers(Long groupId, Collection<Long> userIds) {
+ groupMemberMapper.updateByGroupIdAndUserIdsAndStatus(groupId, userIds,
+ CommonStatusEnum.ENABLE.getStatus(),
+ new ImGroupMemberDO().setStatus(CommonStatusEnum.DISABLE.getStatus())
+ .setQuitTime(LocalDateTime.now()));
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP_MEMBER_IDS, key = "#groupId")
+ public void removeGroupMembersByGroupId(Long groupId) {
+ groupMemberMapper.updateByGroupIdAndStatus(groupId, CommonStatusEnum.ENABLE.getStatus(),
+ new ImGroupMemberDO().setStatus(CommonStatusEnum.DISABLE.getStatus())
+ .setQuitTime(LocalDateTime.now()));
+ }
+
+ @Override
+ public Map<Long, Long> getActiveMemberCountMap(Collection<Long> groupIds) {
+ return groupMemberMapper.selectCountMapByGroupIdsAndStatus(groupIds, CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Override
+ public void updateGroupMemberMuteEndTime(Long groupId, Long userId, LocalDateTime muteEndTime) {
+ ImGroupMemberDO member = validateMemberInGroup(groupId, userId);
+ if (muteEndTime != null) {
+ // 绂佽█锛氱洿鎺ユ洿鏂板埌鏈熸椂闂�
+ groupMemberMapper.updateById(new ImGroupMemberDO().setId(member.getId()).setMuteEndTime(muteEndTime));
+ } else {
+ // 鍙栨秷绂佽█
+ groupMemberMapper.updateMuteEndTimeNull(member.getId());
+ }
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestService.java
new file mode 100644
index 0000000..1c15d9b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestService.java
@@ -0,0 +1,105 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.request.ImGroupRequestApplyReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupRequestManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupRequestDO;
+import jakarta.validation.Valid;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 鍔犵兢鐢宠 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImGroupRequestService {
+
+ /**
+ * 鐢ㄦ埛涓诲姩鐢宠鍔犵兢
+ * <p>
+ * 缇ゆ湭寮�鍚鎵规椂鐩存帴鍏ョ兢 + 1510 鍏ㄥ憳骞挎挱锛涘紑鍚鎵瑰垯鍒涘缓鎴栧鐢ㄤ竴鏉″緟瀹℃壒璁板綍 + 1503 鎺ㄩ��
+ *
+ * @param userId 鐢宠浜虹敤鎴风紪鍙�
+ * @param reqVO 鐢宠璇锋眰
+ * @return 鐢宠璁板綍锛涜嚜鐢辫繘缇ょ洿杩涙椂杩斿洖 null
+ */
+ ImGroupRequestDO applyJoinGroup(Long userId, @Valid ImGroupRequestApplyReqVO reqVO);
+
+ /**
+ * 鍚屾剰鍔犵兢鐢宠锛堢兢涓绘垨绠$悊鍛橈級锛涘鐞嗗墠鏍¢獙鍏ョ兢浜烘暟涓婇檺
+ *
+ * @param userId 鎿嶄綔浜虹敤鎴风紪鍙�
+ * @param requestId 鐢宠璁板綍缂栧彿
+ */
+ void agreeGroupRequest(Long userId, Long requestId);
+
+ /**
+ * 鎷掔粷鍔犵兢鐢宠锛堢兢涓绘垨绠$悊鍛橈級
+ *
+ * @param userId 鎿嶄綔浜虹敤鎴风紪鍙�
+ * @param requestId 鐢宠璁板綍缂栧彿
+ * @param handleContent 鎷掔粷鐞嗙敱
+ */
+ void refuseGroupRequest(Long userId, Long requestId, String handleContent);
+
+ /**
+ * 閭�璇峰垱寤哄鎵圭敵璇凤紱inviteGroupMember 鍦ㄧ兢寮�鍚鎵规椂璋冪敤锛屾瘡涓閭�璇蜂汉鍒涘缓鎴栧鐢ㄤ竴鏉″緟瀹℃壒璁板綍
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param inviterUserId 閭�璇蜂汉鐢ㄦ埛缂栧彿
+ * @param invitedUserIds 琚個璇蜂汉鐢ㄦ埛缂栧彿闆嗗悎
+ */
+ void createInviteRequestList(Long groupId, Long inviterUserId, Collection<Long> invitedUserIds);
+
+ /**
+ * 鎷夊彇銆屾垜绠$悊鐨勬墍鏈夌兢銆嶄笅鐨勬湭澶勭悊鐢宠鍒楄〃
+ * <p>
+ * 鍓嶇 store 鎹娲剧敓锛氭瘡涓兢鐨勬湭澶勭悊鎬绘暟锛堢敤浜庣兢椤堕儴妯箙绾㈢偣锛�+ 鍒楄〃鍐呭锛堢敤浜� Drawer锛�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿锛涘悗绔寜 ImGroupMember.role 杩囨护鍑烘垜浣滀负 OWNER / ADMIN 鐨勭兢
+ * @return 鏈鐞嗙敵璇峰垪琛紙涓嶅垎椤碉級
+ */
+ List<ImGroupRequestDO> getUnhandledRequestListByOwnerOrAdmin(Long userId);
+
+ /**
+ * 澧為噺鎷夊彇銆屾垜绠$悊鐨勭兢銆嶄笅鐨勫姞缇ょ敵璇凤紙閲嶈繛 / 绂荤嚎琛ュ伩锛氬惈宸插鐞嗭紝鎸� update_time + id 娓告爣锛�
+ * <p>
+ * 浣滅敤鍩熶笌 {@link #getUnhandledRequestListByOwnerOrAdmin} 涓�鑷达細鎸� ImGroupMember.role 鍙栨垜浣滀负 OWNER / ADMIN 鐨勭兢
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param lastUpdateTime 娓告爣锛氫笂娆℃媺鍙栫殑鏈�鍚庝竴鏉℃洿鏂版椂闂存埑锛堟绉掞級
+ * @param lastId 娓告爣锛氫笂娆℃媺鍙栫殑鏈�鍚庝竴鏉$敵璇风紪鍙�
+ * @param limit 鍗曟鎷夊彇鏉℃暟
+ * @return 鐢宠璁板綍鍒楄〃
+ */
+ List<ImGroupRequestDO> pullGroupRequestList(Long userId, Long lastUpdateTime, Long lastId, Integer limit);
+
+ /**
+ * 鎷夊彇鎸囧畾缇や笅鐨勫叏閮ㄥ姞缇ょ敵璇凤紙鍚凡澶勭悊锛夛紱浠呯兢涓� / 绠$悊鍛樺彲鏌�
+ * <p>
+ * 鐢ㄤ簬缇ゃ�岃繘缇ょ敵璇枫�嶅瓙椤碉細鏈�鏂颁竴鏉″崱鐗囧寲绐佸嚭 + 鍘嗗彶鐢宠鎸� id 鍊掑簭
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿锛涚敤浜庢牎楠� owner / admin 韬唤
+ * @param groupId 缇ょ紪鍙�
+ * @return 鐢宠璁板綍鍒楄〃锛屾寜 id 鍊掑簭
+ */
+ List<ImGroupRequestDO> getGroupRequestListByGroupId(Long userId, Long groupId);
+
+ /**
+ * 鎸� id 鍗曟煡鐢宠璁板綍锛涢�氱敤璇绘帴鍙o紝瓒婃潈杩囨护浜ょ敱璋冪敤鏂�
+ *
+ * @param id 鐢宠璁板綍缂栧彿
+ * @return 鐢宠璁板綍
+ */
+ ImGroupRequestDO getGroupRequest(Long id);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝垎椤垫煡璇㈠姞缇ょ敵璇疯褰�
+ */
+ PageResult<ImGroupRequestDO> getGroupRequestPage(ImGroupRequestManagerPageReqVO reqVO);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImpl.java
new file mode 100644
index 0000000..40d1cad
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImpl.java
@@ -0,0 +1,425 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.request.ImGroupRequestApplyReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupRequestManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupRequestDO;
+import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupRequestMapper;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupRequestHandleResultEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.group.BaseGroupNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.group.GroupRequestApprovedNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.group.GroupRequestReceivedNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.group.GroupRequestRejectedNotification;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+
+/**
+ * IM 鍔犵兢鐢宠 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@Service
+@Validated
+public class ImGroupRequestServiceImpl implements ImGroupRequestService {
+
+ @Resource
+ private ImGroupRequestMapper groupRequestMapper;
+
+ @Resource
+ @Lazy // 閬垮厤寰幆渚濊禆
+ private ImGroupService groupService;
+ @Resource
+ @Lazy // 閬垮厤寰幆渚濊禆
+ private ImGroupMemberService groupMemberService;
+ @Resource
+ @Lazy // 閬垮厤寰幆渚濊禆
+ private ImGroupMessageService groupMessageService;
+
+ @Resource
+ private ImWebSocketService websocketService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public ImGroupRequestDO applyJoinGroup(Long userId, ImGroupRequestApplyReqVO reqVO) {
+ Long groupId = reqVO.getGroupId();
+ // 1.1 鏍¢獙缇ゅ瓨鍦� + 鏈皝绂� / 鏈В鏁�
+ ImGroupDO group = groupService.validateGroupExists(groupId);
+ // 1.2 鏍¢獙鏈湪缇や腑
+ ImGroupMemberDO member = groupMemberService.getGroupMember(groupId, userId);
+ if (member != null && !CommonStatusEnum.DISABLE.getStatus().equals(member.getStatus())) {
+ throw exception(GROUP_REQUEST_ALREADY_MEMBER);
+ }
+
+ // 2. 鎯呭喌涓�锛氱兢鏈紑鍚鎵癸紝鐩存帴鍏ョ兢锛涘啓缇ゆ垚鍛樼暀鐥� + 鎺� 1510 鍏ㄥ憳骞挎挱锛涗笉钀界敵璇疯褰�
+ if (!Boolean.TRUE.equals(group.getJoinApproval())) {
+ // 鍏ョ兢鍓嶆牎楠屼汉鏁颁笂闄�
+ groupService.validateMemberCountLimit(groupId, 1);
+ // 鍐欑兢鎴愬憳锛沘ddSource 鏉ヨ嚜鍓嶇鍏ュ彛锛堟悳绱� / 浜岀淮鐮� / 鍒嗕韩閾炬帴锛夛紝inviterUserId=null锛堜富鍔ㄧ敵璇凤級
+ groupMemberService.addGroupMember(groupId, userId,
+ ImGroupMemberRoleEnum.NORMAL.getRole(), reqVO.getAddSource(), null);
+ // 鎺� 1510 缁欏叏鍛橈紱payload 鍚繘缇よ�� + 鏉ユ簮锛屽墠绔寜 entrantUserId 灞�閮ㄦ彃鍏ユ柊鎴愬憳
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupMemberEnter(groupId, userId, reqVO.getAddSource()));
+ return null;
+ }
+
+ // 3. 鎯呭喌浜岋細缇ゅ紑鍚簡瀹℃壒锛屽垱寤烘垨澶嶇敤涓�鏉′富鍔ㄧ敵璇疯褰�
+ ImGroupRequestDO request = createOrResetApplyRequest(groupId, userId, reqVO);
+
+ // 4. 1503 瀹氬悜鎺ㄧ兢涓� + 鍏ㄩ儴绠$悊鍛橈紙澶氱鍚屾锛夛紱payload 鎼哄甫鐢宠鏂规樀绉� / 澶村儚
+ AdminUserRespDTO applyUser = adminUserApi.getUser(userId);
+ GroupRequestReceivedNotification payload = buildRequestNotification(group, request, applyUser);
+ for (Long receiverUserId : getGroupMemberListByOwnerAndAdminUserIds(group)) {
+ websocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.GROUP_REQUEST_RECEIVED.getType(), payload);
+ }
+ return request;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void agreeGroupRequest(Long userId, Long requestId) {
+ // 1.1 鏍¢獙鐢宠瀛樺湪 + 鏈鐞� + 鎿嶄綔浜烘槸 owner / admin
+ ImGroupRequestDO request = validateRequestForHandle(userId, requestId);
+ // 1.2 澶嶆牳缇ゅ綋鍓嶇姸鎬侊細鎷掔粷鍦ㄥ皝绂� / 瑙f暎鐨勭兢缁х画鏀句汉
+ groupService.validateGroupExists(request.getGroupId());
+ // 1.3 澶嶆牳鐢宠浜烘槸鍚﹀凡鍦ㄧ兢涓紱骞傜瓑閬垮厤閲嶅骞挎挱 1509 / 1510 鍏ョ兢浜嬩欢
+ ImGroupMemberDO applicant = groupMemberService.getGroupMember(request.getGroupId(), request.getUserId());
+ if (applicant != null && CommonStatusEnum.ENABLE.getStatus().equals(applicant.getStatus())) {
+ throw exception(GROUP_REQUEST_ALREADY_MEMBER);
+ }
+ // 2. 鍏ョ兢鍓嶆牎楠屼汉鏁颁笂闄愶紱缇ゅ凡婊℃姏閿欒鎿嶄綔浜洪�夋嫨鎷掔粷
+ groupService.validateMemberCountLimit(request.getGroupId(), 1);
+
+ // 3. 涔愯閿佹帹杩涚姸鎬�
+ LocalDateTime now = LocalDateTime.now();
+ ImGroupRequestDO updateObj = new ImGroupRequestDO()
+ .setHandleResult(ImGroupRequestHandleResultEnum.AGREED.getResult())
+ .setHandleUserId(userId).setHandleTime(now);
+ int affected = groupRequestMapper.updateByIdAndHandleResult(request.getId(),
+ ImGroupRequestHandleResultEnum.UNHANDLED.getResult(), updateObj);
+ if (affected == 0) {
+ throw exception(GROUP_REQUEST_HANDLED);
+ }
+ request.setHandleResult(ImGroupRequestHandleResultEnum.AGREED.getResult())
+ .setHandleUserId(userId).setHandleTime(now);
+
+ // 4. 鍐欑兢鎴愬憳锛沘ddSource / inviterUserId 娌跨敤鐢宠璁板綍涓婄殑鏉ユ簮淇℃伅
+ groupMemberService.addGroupMember(request.getGroupId(), request.getUserId(),
+ ImGroupMemberRoleEnum.NORMAL.getRole(), request.getAddSource(), request.getInviterUserId());
+
+ // 5.1 1505 瀹氬悜鎺ㄩ�佺粰鐢宠浜� + 缇や富 + 鍏ㄩ儴绠$悊鍛橈紙姣忕鍗曟帹锛�
+ GroupRequestApprovedNotification payload = (GroupRequestApprovedNotification) new GroupRequestApprovedNotification()
+ .setRequestId(request.getId()).setGroupId(request.getGroupId()).setUserId(request.getUserId())
+ .setOperatorUserId(userId);
+ broadcastToOwnerAdminsAndApplicant(request.getGroupId(), request.getUserId(), payload,
+ ImContentTypeEnum.GROUP_REQUEST_APPROVED.getType(), userId);
+ // 5.2 缇や簨浠讹細涓诲姩鐢宠 鈫� 1510 鑷敱杩涚兢锛涜閭�璇� 鈫� 1509 鎴愬憳鍔犲叆
+ if (request.getInviterUserId() == null) {
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupMemberEnter(request.getGroupId(),
+ request.getUserId(), request.getAddSource()));
+ } else {
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupMemberInvite(request.getGroupId(),
+ request.getInviterUserId(), Collections.singleton(request.getUserId())));
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void refuseGroupRequest(Long userId, Long requestId, String handleContent) {
+ // 1. 鏍¢獙
+ ImGroupRequestDO request = validateRequestForHandle(userId, requestId);
+
+ // 2. 涔愯閿佹帹杩�
+ ImGroupRequestDO updateObj = new ImGroupRequestDO()
+ .setHandleResult(ImGroupRequestHandleResultEnum.REFUSED.getResult())
+ .setHandleContent(handleContent)
+ .setHandleUserId(userId).setHandleTime(LocalDateTime.now());
+ int affected = groupRequestMapper.updateByIdAndHandleResult(request.getId(),
+ ImGroupRequestHandleResultEnum.UNHANDLED.getResult(), updateObj);
+ if (affected == 0) {
+ throw exception(GROUP_REQUEST_HANDLED);
+ }
+
+ // 3. 1506 瀹氬悜鎺ㄩ�佺粰鐢宠浜� + 缇や富 + 鍏ㄩ儴绠$悊鍛�
+ GroupRequestRejectedNotification payload = (GroupRequestRejectedNotification) new GroupRequestRejectedNotification()
+ .setRequestId(request.getId()).setGroupId(request.getGroupId()).setUserId(request.getUserId())
+ .setHandleContent(handleContent).setOperatorUserId(userId);
+ broadcastToOwnerAdminsAndApplicant(request.getGroupId(), request.getUserId(), payload,
+ ImContentTypeEnum.GROUP_REQUEST_REJECTED.getType(), userId);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void createInviteRequestList(Long groupId, Long inviterUserId, Collection<Long> invitedUserIds) {
+ if (CollUtil.isEmpty(invitedUserIds)) {
+ return;
+ }
+ ImGroupDO group = groupService.validateGroupExists(groupId);
+ Integer inviteSource = ImGroupAddSourceEnum.INVITE.getSource();
+ // 1. 閫愭潯鍒涘缓鎴栧鐢ㄩ個璇风敵璇�
+ List<ImGroupRequestDO> requests = convertList(invitedUserIds, userId ->
+ createOrResetInviteRequest(groupId, inviterUserId, userId, inviteSource));
+
+ // 2. 鎺� 1503 缁欑兢涓� + 鍏ㄩ儴绠$悊鍛橈紱澶氱鍚屾锛涙瘡鏉$敵璇峰崟鐙帹涓�甯�
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(invitedUserIds);
+ List<Long> ownerAndAdmins = getGroupMemberListByOwnerAndAdminUserIds(group);
+ for (ImGroupRequestDO request : requests) {
+ AdminUserRespDTO applyUser = userMap.get(request.getUserId());
+ GroupRequestReceivedNotification payload = buildRequestNotification(group, request, applyUser);
+ for (Long receiverUserId : ownerAndAdmins) {
+ websocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.GROUP_REQUEST_RECEIVED.getType(), payload);
+ }
+ }
+ }
+
+ @Override
+ public List<ImGroupRequestDO> getUnhandledRequestListByOwnerOrAdmin(Long userId) {
+ // 1. 鎵惧嚭褰撳墠鐢ㄦ埛浣滀负 OWNER / ADMIN 鐨勬墍鏈夌兢
+ List<ImGroupMemberDO> myMembers = groupMemberService.getActiveGroupMemberListByUserId(userId);
+ Set<Long> ownerOrAdminGroupIds = convertSet(myMembers,
+ ImGroupMemberDO::getGroupId, member -> ImGroupMemberRoleEnum.isOwnerOrAdmin(member.getRole()));
+ if (CollUtil.isEmpty(ownerOrAdminGroupIds)) {
+ return Collections.emptyList();
+ }
+ // 2. 涓�娆℃媺鎵�鏈夌兢鐨勬湭澶勭悊鐢宠
+ return groupRequestMapper.selectListByGroupIdsAndHandleResult(
+ ownerOrAdminGroupIds, ImGroupRequestHandleResultEnum.UNHANDLED.getResult());
+ }
+
+ @Override
+ public List<ImGroupRequestDO> pullGroupRequestList(Long userId, Long lastUpdateTime, Long lastId, Integer limit) {
+ // 1. 鎵惧嚭褰撳墠鐢ㄦ埛浣滀负 OWNER / ADMIN 鐨勬墍鏈夌兢
+ List<ImGroupMemberDO> myMembers = groupMemberService.getActiveGroupMemberListByUserId(userId);
+ Set<Long> ownerOrAdminGroupIds = convertSet(myMembers,
+ ImGroupMemberDO::getGroupId, member -> ImGroupMemberRoleEnum.isOwnerOrAdmin(member.getRole()));
+ if (CollUtil.isEmpty(ownerOrAdminGroupIds)) {
+ return Collections.emptyList();
+ }
+ // 2. 鎸夋父鏍囧閲忔媺鍙栬繖浜涚兢涓嬬殑鐢宠
+ return groupRequestMapper.selectPullListByGroupIds(ownerOrAdminGroupIds, lastUpdateTime, lastId, limit);
+ }
+
+ @Override
+ public List<ImGroupRequestDO> getGroupRequestListByGroupId(Long userId, Long groupId) {
+ // 1. 鏍¢獙缇ゅ瓨鍦� + 褰撳墠鐢ㄦ埛鏄兢涓� / 绠$悊鍛�
+ groupService.validateGroupExists(groupId);
+ ImGroupMemberDO operator = groupMemberService.validateMemberInGroup(groupId, userId);
+ if (!ImGroupMemberRoleEnum.isOwnerOrAdmin(operator.getRole())) {
+ throw exception(GROUP_REQUEST_NOT_TO_ME);
+ }
+ // 2. 鎷夊彇璇ョ兢涓嬪叏閮ㄧ敵璇凤紙鍚凡澶勭悊锛夛紱鎸� id 鍊掑簭锛屽墠绔鏉″崱鐗囧寲灞曠ず
+ return groupRequestMapper.selectListByGroupId(groupId);
+ }
+
+ @Override
+ public ImGroupRequestDO getGroupRequest(Long id) {
+ return groupRequestMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult<ImGroupRequestDO> getGroupRequestPage(ImGroupRequestManagerPageReqVO reqVO) {
+ return groupRequestMapper.selectPage(reqVO);
+ }
+
+ /**
+ * 鍒涘缓鎴栭噸缃富鍔ㄥ姞缇ょ敵璇�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 鐢宠浜虹敤鎴风紪鍙�
+ * @param reqVO 鐢宠璇锋眰
+ * @return 鐢宠璁板綍
+ */
+ private ImGroupRequestDO createOrResetApplyRequest(Long groupId, Long userId, ImGroupRequestApplyReqVO reqVO) {
+ // 1. 宸叉湁鐢宠锛氳鐩栨湰娆$敵璇峰唴瀹癸紝骞堕噸缃负鏈鐞�
+ ImGroupRequestDO request = groupRequestMapper.selectByGroupIdAndUserId(groupId, userId);
+ if (request != null) {
+ resetApplyRequest(request, reqVO);
+ return request;
+ }
+ // 2. 鏃犳棫鐢宠锛氬垱寤轰富鍔ㄧ敵璇疯褰�
+ request = BeanUtils.toBean(reqVO, ImGroupRequestDO.class)
+ .setUserId(userId).setInviterUserId(null)
+ .setHandleResult(ImGroupRequestHandleResultEnum.UNHANDLED.getResult());
+ try {
+ groupRequestMapper.insert(request);
+ return request;
+ } catch (DuplicateKeyException ex) {
+ // 3. 鍞竴閿啿绐侊細鍥炴煡骞跺鐢ㄥ苟鍙戝啓鍏ョ殑璁板綍
+ request = groupRequestMapper.selectByGroupIdAndUserId(groupId, userId);
+ if (request == null) {
+ throw ex;
+ }
+ resetApplyRequest(request, reqVO);
+ return request;
+ }
+ }
+
+ /**
+ * 鍒涘缓鎴栭噸缃個璇峰姞缇ょ敵璇�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param inviterUserId 閭�璇蜂汉鐢ㄦ埛缂栧彿
+ * @param userId 琚個璇蜂汉鐢ㄦ埛缂栧彿
+ * @param inviteSource 閭�璇锋潵婧�
+ * @return 鐢宠璁板綍
+ */
+ private ImGroupRequestDO createOrResetInviteRequest(Long groupId, Long inviterUserId,
+ Long userId, Integer inviteSource) {
+ // 1. 宸叉湁鐢宠锛氳鐩栭個璇蜂汉鍜屾潵婧愶紝骞堕噸缃负鏈鐞�
+ ImGroupRequestDO request = groupRequestMapper.selectByGroupIdAndUserId(groupId, userId);
+ if (request != null) {
+ resetInviteRequest(request, inviterUserId, inviteSource);
+ return request;
+ }
+ // 2. 鏃犳棫鐢宠锛氬垱寤洪個璇风敵璇疯褰�
+ request = new ImGroupRequestDO().setGroupId(groupId).setUserId(userId).setInviterUserId(inviterUserId)
+ .setAddSource(inviteSource).setHandleResult(ImGroupRequestHandleResultEnum.UNHANDLED.getResult());
+ try {
+ groupRequestMapper.insert(request);
+ return request;
+ } catch (DuplicateKeyException ex) {
+ // 3. 鍞竴閿啿绐侊細鍥炴煡骞跺鐢ㄥ苟鍙戝啓鍏ョ殑璁板綍
+ request = groupRequestMapper.selectByGroupIdAndUserId(groupId, userId);
+ if (request == null) {
+ throw ex;
+ }
+ resetInviteRequest(request, inviterUserId, inviteSource);
+ return request;
+ }
+ }
+
+ /**
+ * 閲嶇疆涓诲姩鍔犵兢鐢宠
+ *
+ * @param request 鐢宠璁板綍
+ * @param reqVO 鐢宠璇锋眰
+ */
+ private void resetApplyRequest(ImGroupRequestDO request, ImGroupRequestApplyReqVO reqVO) {
+ // 1. 鏇存柊鐢宠鍐呭銆佹潵婧愬拰澶勭悊鐘舵��
+ LocalDateTime now = LocalDateTime.now();
+ groupRequestMapper.updateApplyByIdReset(request.getId(),
+ reqVO.getApplyContent(), reqVO.getAddSource(), now);
+ // 2. 鍚屾鍐呭瓨瀵硅薄锛屽悗缁�氱煡鏋勫缓鐩存帴澶嶇敤
+ request.setApplyContent(reqVO.getApplyContent()).setAddSource(reqVO.getAddSource())
+ .setHandleResult(ImGroupRequestHandleResultEnum.UNHANDLED.getResult())
+ .setInviterUserId(null).setHandleUserId(null)
+ .setHandleContent(null).setHandleTime(null).setUpdateTime(now);
+ }
+
+ /**
+ * 閲嶇疆閭�璇峰姞缇ょ敵璇�
+ *
+ * @param request 鐢宠璁板綍
+ * @param inviterUserId 閭�璇蜂汉鐢ㄦ埛缂栧彿
+ * @param inviteSource 閭�璇锋潵婧�
+ */
+ private void resetInviteRequest(ImGroupRequestDO request, Long inviterUserId, Integer inviteSource) {
+ // 1. 鏇存柊閭�璇蜂汉銆佹潵婧愬拰澶勭悊鐘舵��
+ LocalDateTime now = LocalDateTime.now();
+ groupRequestMapper.updateInviteByIdReset(request.getId(), inviterUserId, inviteSource, now);
+ // 2. 鍚屾鍐呭瓨瀵硅薄锛屽悗缁�氱煡鏋勫缓鐩存帴澶嶇敤
+ request.setInviterUserId(inviterUserId).setAddSource(inviteSource)
+ .setHandleResult(ImGroupRequestHandleResultEnum.UNHANDLED.getResult())
+ .setHandleUserId(null).setHandleContent(null).setHandleTime(null)
+ .setUpdateTime(now);
+ }
+
+ /**
+ * 鏍¢獙鐢宠鍙銆屽綋鍓嶇敤鎴枫�嶅鐞嗭細鐢宠瀛樺湪 + 鏈鐞� + 鎿嶄綔浜烘槸缇や富 / 绠$悊鍛�
+ */
+ private ImGroupRequestDO validateRequestForHandle(Long userId, Long requestId) {
+ ImGroupRequestDO request = groupRequestMapper.selectById(requestId);
+ if (request == null) {
+ throw exception(GROUP_REQUEST_NOT_EXISTS);
+ }
+ if (!ImGroupRequestHandleResultEnum.isUnhandled(request.getHandleResult())) {
+ throw exception(GROUP_REQUEST_HANDLED);
+ }
+ ImGroupMemberDO operator = groupMemberService.validateMemberInGroup(request.getGroupId(), userId);
+ if (!ImGroupMemberRoleEnum.isOwnerOrAdmin(operator.getRole())) {
+ throw exception(GROUP_REQUEST_NOT_TO_ME);
+ }
+ return request;
+ }
+
+ /**
+ * 鏋勫缓 1503 閫氱煡 payload锛涜仛鍚堢敵璇锋柟鏄电О / 澶村儚渚涘墠绔洿鎺ユ覆鏌�
+ */
+ private GroupRequestReceivedNotification buildRequestNotification(ImGroupDO group, ImGroupRequestDO request,
+ AdminUserRespDTO applyUser) {
+ Long operatorUserId = request.getInviterUserId() != null ? request.getInviterUserId() : request.getUserId();
+ GroupRequestReceivedNotification payload = (GroupRequestReceivedNotification) new GroupRequestReceivedNotification()
+ .setRequestId(request.getId()).setGroupId(group.getId()).setUserId(request.getUserId())
+ .setInviterUserId(request.getInviterUserId())
+ .setApplyContent(request.getApplyContent()).setAddSource(request.getAddSource())
+ .setOperatorUserId(operatorUserId);
+ if (applyUser != null) {
+ payload.setUserNickname(applyUser.getNickname()).setUserAvatar(applyUser.getAvatar());
+ }
+ return payload;
+ }
+
+ /**
+ * 1505 / 1506 鍙椾紬锛氱敵璇蜂汉 + 缇や富 + 鍏ㄩ儴绠$悊鍛�
+ */
+ private void broadcastToOwnerAdminsAndApplicant(Long groupId, Long applicantUserId, BaseGroupNotification payload,
+ Integer messageType, Long operatorUserId) {
+ ImGroupDO group = groupService.getGroup(groupId);
+ if (group == null) {
+ return;
+ }
+ Set<Long> receivers = new LinkedHashSet<>(getGroupMemberListByOwnerAndAdminUserIds(group));
+ receivers.add(applicantUserId);
+ for (Long receiverUserId : receivers) {
+ websocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(),
+ messageType, payload);
+ }
+ }
+
+ /**
+ * 鍒楀嚭缇や富 + 鍏ㄩ儴绠$悊鍛樼殑鐢ㄦ埛缂栧彿
+ *
+ * @param group 缇や俊鎭�
+ * @return 缇や富 + 鍏ㄩ儴绠$悊鍛樼殑鐢ㄦ埛缂栧彿鍒楄〃
+ */
+ private List<Long> getGroupMemberListByOwnerAndAdminUserIds(ImGroupDO group) {
+ return convertList(groupMemberService.getGroupMemberListByOwnerAndAdmin(group.getId()),
+ ImGroupMemberDO::getUserId);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java
new file mode 100644
index 0000000..d3b4fd4
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java
@@ -0,0 +1,251 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminAddReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminRemoveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupCancelMuteMemberReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupCreateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupMuteAllReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupMuteMemberReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupTransferOwnerReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupUpdateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberInviteReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRemoveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerBanReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import jakarta.validation.Valid;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鐢ㄦ埛缇ょ兢 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImGroupService {
+
+ // ==================== 缇ょ殑鍐欐搷浣� ====================
+
+ /**
+ * 鍒涘缓缇�
+ * <p>
+ * 鍚屾椂灏嗗綋鍓嶇櫥褰曠敤鎴疯缃负缇や富锛屽苟鎻掑叆缇や富鐨勭兢鎴愬憳璁板綍
+ *
+ * @param createReqVO 鍒涘缓淇℃伅
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿锛堢兢涓伙級
+ * @return 鍒涘缓鍚庣殑缇や俊鎭�
+ */
+ ImGroupDO createGroup(@Valid ImGroupCreateReqVO createReqVO, Long userId);
+
+ /**
+ * 鏇存柊缇や俊鎭�
+ *
+ * @param updateReqVO 鏇存柊淇℃伅
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @return 鏇存柊鍚庣殑缇や俊鎭�
+ */
+ ImGroupDO updateGroup(@Valid ImGroupUpdateReqVO updateReqVO, Long userId);
+
+ /**
+ * 瑙f暎缇�
+ * <p>
+ * 浠呯兢涓诲彲鎵ц
+ *
+ * @param id 缇ょ紪鍙�
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ */
+ void dissolveGroup(Long id, Long userId);
+
+ // ==================== 缇ょ殑璇绘搷浣� ====================
+
+ /**
+ * 鑾峰緱缇�
+ *
+ * @param id 缂栧彿
+ * @return 缇�
+ */
+ ImGroupDO getGroup(Long id);
+
+ /**
+ * 鎵归噺鑾峰緱缇� Map
+ *
+ * @param ids 缇ょ紪鍙烽泦鍚�
+ * @return 缇� Map锛坘ey = 缇ょ紪鍙凤級
+ */
+ Map<Long, ImGroupDO> getGroupMap(Collection<Long> ids);
+
+ /**
+ * 鏍¢獙缇ゅ瓨鍦ㄤ笖鏈皝绂併�佹湭瑙f暎
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @return 缇や俊鎭�
+ */
+ ImGroupDO validateGroupExists(Long groupId);
+
+ /**
+ * 鏍¢獙鍏ョ兢浜烘暟涓婇檺
+ * <p>
+ * 璋冪敤鏂瑰満鏅細鑷敱杩涚兢 / 瀹℃壒閫氳繃绛変笉缁� inviteGroupMember 鐨勫叆缇よ矾寰勶紝闇�鍦ㄥ啓缇ゆ垚鍛樺墠涓诲姩鏍¢獙
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param addCount 鍗冲皢鏂板鐨勪汉鏁�
+ * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 缇ゅ凡婊℃姏 GROUP_MEMBER_EXCEED
+ */
+ void validateMemberCountLimit(Long groupId, int addCount);
+
+ /**
+ * 鑾峰彇鎸囧畾鐢ㄦ埛鐨勭兢鍒楄〃
+ * <p>
+ * 杩斿洖鐢ㄦ埛褰撳墠浠嶆湁鏁堢殑缇わ紝浠ュ強鏈�杩� yudao.im.message.group-pull-max-days 澶╁唴閫�缇ょ殑缇�
+ * 鈥斺�� 閫�缇ゅ墠鍙兘杩樻湁绂荤嚎娑堟伅闇�瑕佸睍绀猴紝鍓嶇闇�瑕佹妸杩欎簺缇や俊鎭綔涓虹紦瀛樸��
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return 缇ゅ垪琛�
+ */
+ List<ImGroupDO> getMyGroupList(Long userId);
+
+ // ==================== 缇ゆ垚鍛樼殑鍐欐搷浣� ====================
+ // 璇存槑锛氱兢鎴愬憳鐨勫啓鎿嶄綔缁熶竴鏀惧湪 ImGroupService锛岃�岄潪 ImGroupMemberService锛�
+ // 淇濇寔 ImGroupMemberService 鏃� WebSocket 鎺ㄩ�佺瓑澶栭儴渚濊禆锛岃亴璐f洿鍗曚竴銆�
+
+ /**
+ * 閭�璇风敤鎴峰姞鍏ョ兢
+ * <p>
+ * 缇ゆ垚鍛樺嵆鍙墽琛岋紝鏀寔鎵归噺銆�
+ * 鏍¢獙缇や汉鏁颁笂闄愶紝閭�璇峰悗鎺ㄩ�佹彁绀烘秷鎭拰缇ゅ垱寤轰簨浠剁粰琚個璇蜂汉銆�
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @param inviteReqVO 閭�璇蜂俊鎭�
+ */
+ void inviteGroupMember(Long userId, @Valid ImGroupMemberInviteReqVO inviteReqVO);
+
+ /**
+ * 閫�缇�
+ * <p>
+ * 缇や富涓嶅彲閫�缇わ紙鍙兘瑙f暎锛�
+ *
+ * @param groupId 缇ょ紪鍙�
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ */
+ void quitGroup(Long groupId, Long userId);
+
+ /**
+ * 绉婚櫎缇ゆ垚鍛橈紙韪汉锛�
+ * <p>
+ * 缇や富鍙涪绠$悊鍛樺拰鏅�氭垚鍛橈紱绠$悊鍛樹粎鑳借涪鏅�氭垚鍛橈紱缇や富涓嶅彲琚涪銆�
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @param removeReqVO 绉婚櫎淇℃伅
+ */
+ void removeGroupMember(Long userId, @Valid ImGroupMemberRemoveReqVO removeReqVO);
+
+ /**
+ * 娣诲姞缇ょ鐞嗗憳锛堜粎缇や富鍙墽琛岋級
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿锛堢兢涓伙級
+ * @param reqVO 娣诲姞淇℃伅锛堝惈缇ょ紪鍙枫�佺洰鏍囩敤鎴风紪鍙峰垪琛級
+ */
+ void addGroupAdmin(Long userId, @Valid ImGroupAdminAddReqVO reqVO);
+
+ /**
+ * 鎾ら攢缇ょ鐞嗗憳锛堜粎缇や富鍙墽琛岋級
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿锛堢兢涓伙級
+ * @param reqVO 鎾ら攢淇℃伅锛堝惈缇ょ紪鍙枫�佺洰鏍囩敤鎴风紪鍙峰垪琛級
+ */
+ void removeGroupAdmin(Long userId, @Valid ImGroupAdminRemoveReqVO reqVO);
+
+ /**
+ * 杞缇や富锛堜粎鑰佺兢涓诲彲鎵ц锛�
+ * <p>
+ * 杞鍚庯細鏃х兢涓� role 闄嶄负 MEMBER锛屾柊缇や富 role 鍗囦负 OWNER
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿锛堟棫缇や富锛�
+ * @param transferReqVO 杞淇℃伅
+ */
+ void transferGroupOwner(Long userId, @Valid ImGroupTransferOwnerReqVO transferReqVO);
+
+ /**
+ * 缃《缇ゆ秷鎭紙浠呯兢涓绘垨绠$悊鍛樺彲鎵ц锛�
+ * <p>
+ * 涓婇檺鐢� yudao.im.group.pin-max-count 鎺у埗锛涘箓绛夊け璐ユ椂鎶涗笟鍔″紓甯�
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @param groupId 缇ょ紪鍙�
+ * @param messageId 琚疆椤剁殑娑堟伅缂栧彿
+ */
+ void pinGroupMessage(Long userId, Long groupId, Long messageId);
+
+ /**
+ * 鍙栨秷缃《缇ゆ秷鎭紙浠呯兢涓绘垨绠$悊鍛樺彲鎵ц锛�
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @param groupId 缇ょ紪鍙�
+ * @param messageId 琚彇娑堢疆椤剁殑娑堟伅缂栧彿
+ */
+ void unpinGroupMessage(Long userId, Long groupId, Long messageId);
+
+ // ==================== 缇ょ瑷� ====================
+
+ /**
+ * 鍏ㄧ兢绂佽█ / 鍙栨秷锛堜粎缇や富鎴栫鐞嗗憳鍙墽琛岋級
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @param reqVO 绂佽█淇℃伅
+ */
+ void muteAll(Long userId, @Valid ImGroupMuteAllReqVO reqVO);
+
+ /**
+ * 绂佽█鍗曚釜鎴愬憳锛堜笁妗e垎灞傛潈闄愶級
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @param reqVO 绂佽█淇℃伅
+ */
+ void muteMember(Long userId, @Valid ImGroupMuteMemberReqVO reqVO);
+
+ /**
+ * 鍙栨秷鎴愬憳绂佽█锛堜笁妗e垎灞傛潈闄愶級
+ *
+ * @param userId 褰撳墠鐧诲綍鐢ㄦ埛缂栧彿
+ * @param reqVO 鍙栨秷绂佽█淇℃伅
+ */
+ void cancelMuteMember(Long userId, @Valid ImGroupCancelMuteMemberReqVO reqVO);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝垎椤垫煡璇㈢兢鍒楄〃
+ *
+ * @param pageReqVO 鍒嗛〉鏌ヨ鏉′欢
+ * @return 缇ゅ垎椤靛垪琛�
+ */
+ PageResult<ImGroupDO> getGroupPage(ImGroupManagerPageReqVO pageReqVO);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝皝绂佺兢
+ *
+ * @param operatorUserId 鎿嶄綔浜虹敤鎴风紪鍙�
+ * @param banReqVO 灏佺淇℃伅锛堝惈缇ょ紪鍙枫�佸皝绂佸師鍥狅級
+ */
+ void banGroup(Long operatorUserId, @Valid ImGroupManagerBanReqVO banReqVO);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戣В灏佺兢
+ *
+ * @param operatorUserId 鎿嶄綔浜虹敤鎴风紪鍙�
+ * @param id 缇ょ紪鍙�
+ */
+ void unbanGroup(Long operatorUserId, Long id);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戣В鏁g兢
+ *
+ * @param operatorUserId 鎿嶄綔浜虹敤鎴风紪鍙�
+ * @param id 缇ょ紪鍙�
+ */
+ void dissolveGroupByManager(Long operatorUserId, Long id);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java
new file mode 100644
index 0000000..93fa996
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java
@@ -0,0 +1,773 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.bean.copier.CopyOptions;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+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;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminAddReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminRemoveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupCancelMuteMemberReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupCreateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupMuteAllReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupMuteMemberReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupTransferOwnerReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupUpdateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberInviteReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRemoveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerBanReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerPageReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMapper;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import jakarta.annotation.Resource;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.GROUP;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+
+/**
+ * 鐢ㄦ埛缇� Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class ImGroupServiceImpl implements ImGroupService {
+
+ @Resource
+ private ImGroupMapper groupMapper;
+
+ @Resource
+ @Lazy // 閬垮厤寰幆渚濊禆
+ private ImGroupMemberService groupMemberService;
+ @Resource
+ @Lazy // 閬垮厤寰幆渚濊禆
+ private ImGroupMessageService groupMessageService;
+ @Resource
+ @Lazy // 閬垮厤寰幆渚濊禆
+ private ImGroupRequestService groupRequestService;
+
+ @Resource
+ private ImFriendService friendService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @Resource
+ private ImProperties imProperties;
+
+ // ==================== 缇ょ殑鍐欐搷浣� ====================
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public ImGroupDO createGroup(ImGroupCreateReqVO createReqVO, Long userId) {
+ // 1.1 澶勭悊鍒濆鎴愬憳鍒楄〃锛堝幓閲� + 鎺掗櫎鍒涘缓鑰呰嚜宸憋級
+ Set<Long> initialMemberUserIds = createReqVO.getMemberUserIds() == null
+ ? new HashSet<>() : new HashSet<>(createReqVO.getMemberUserIds());
+ initialMemberUserIds.remove(userId);
+ // 1.2 鏍¢獙鍒濆鎴愬憳閮芥槸鍒涘缓鑰呯殑濂藉弸
+ if (CollUtil.isNotEmpty(initialMemberUserIds)) {
+ List<ImFriendDO> friends = friendService.getActiveFriendList(userId, initialMemberUserIds);
+ Set<Long> friendUserIds = convertSet(friends, ImFriendDO::getFriendUserId);
+ Collection<Long> notFriendUserIds = CollUtil.subtract(initialMemberUserIds, friendUserIds);
+ if (CollUtil.isNotEmpty(notFriendUserIds)) {
+ throw exception(GROUP_INVITE_NOT_FRIEND, getUserNicknames(notFriendUserIds));
+ }
+ }
+ // 1.3 鏍¢獙缇や汉鏁颁笂闄愶紙鍒涘缓鑰� + 鍒濆鎴愬憳 鈮� 缇ゆ垚鍛樹笂闄愶級
+ int maxMember = imProperties.getGroup().getMaxMember();
+ if (initialMemberUserIds.size() + 1 > maxMember) {
+ throw exception(GROUP_MEMBER_EXCEED, maxMember);
+ }
+
+ // 2.1 鎻掑叆缇よ褰�
+ ImGroupDO group = BeanUtils.toBean(createReqVO, ImGroupDO.class)
+ .setOwnerUserId(userId).setStatus(CommonStatusEnum.ENABLE.getStatus());
+ groupMapper.insert(group);
+ // 2.2 鍒涘缓鑰呬綔涓� OWNER 鍏ョ兢
+ groupMemberService.addGroupMember(group.getId(), userId, ImGroupMemberRoleEnum.OWNER.getRole());
+ // 2.3 鎵归噺娣诲姞鍒濆鎴愬憳锛涙爣璁� addSource=INVITE / inviter=鍒涘缓鑰�
+ if (CollUtil.isNotEmpty(initialMemberUserIds)) {
+ groupMemberService.addGroupMembers(group.getId(), initialMemberUserIds,
+ ImGroupAddSourceEnum.INVITE.getSource(), userId);
+ }
+
+ // 3. 鎺ㄩ�� GROUP_CREATE 閫氱煡缁欏叏鍛橈紙鍚垱寤鸿�呭绔悓姝� + 鍒濆鎴愬憳锛�
+ List<Long> allMemberUserIds = CollectionUtils.of(userId, initialMemberUserIds);
+ groupMessageService.sendGroupMessage(userId, allMemberUserIds,
+ ImGroupMessageSendDTO.ofGroupCreate(group.getId(), userId, allMemberUserIds));
+ return group;
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#updateReqVO.id")
+ @Transactional(rollbackFor = Exception.class)
+ public ImGroupDO updateGroup(ImGroupUpdateReqVO updateReqVO, Long userId) {
+ // 1.1 鏍¢獙缇ゅ瓨鍦細group 鐣欎綔鑰佸�煎浠斤紝閫氱煡閲� oldXXX 瀛楁浠庤繖閲屽彇
+ ImGroupDO group = validateGroupExists(updateReqVO.getId());
+ // 1.2 鏍¢獙鎿嶄綔浜烘槸缇や富
+ if (ObjUtil.notEqual(group.getOwnerUserId(), userId)) {
+ throw exception(GROUP_NOT_OWNER);
+ }
+
+ // 2. 鏇存柊鏁版嵁搴擄紙newGroup 浠呭惈鍙樻洿瀛楁锛�
+ ImGroupDO newGroup = BeanUtils.toBean(updateReqVO, ImGroupDO.class);
+ groupMapper.updateById(newGroup);
+
+ // 3. 鎸夊彉鏇村瓧娈靛垎鍒帹閫� GROUP_NAME / NOTICE / INFO_UPDATE 閫氱煡锛涙椿璺冩垚鍛樺彧鏌ヤ竴娆″鐢紝閬垮厤 3 娆� Redis GET
+ // name / avatar 涓嶅厑璁哥┖涓诧紙涓氬姟涓婂繀椤婚潪绌猴級锛宯otice 鍏佽绌轰覆锛堟竻绌哄叕鍛婁篃鏄湁鏁堟搷浣滐級
+ Long groupId = group.getId();
+ boolean nameChanged = StrUtil.isNotEmpty(updateReqVO.getName());
+ boolean noticeChanged = updateReqVO.getNotice() != null;
+ boolean avatarChanged = StrUtil.isNotEmpty(updateReqVO.getAvatar());
+ boolean joinApprovalChanged = updateReqVO.getJoinApproval() != null
+ && ObjUtil.notEqual(group.getJoinApproval(), updateReqVO.getJoinApproval());
+ if (nameChanged || noticeChanged || avatarChanged || joinApprovalChanged) {
+ List<Long> memberUserIds = groupMemberService.getActiveGroupMemberUserIdsByGroupId(groupId);
+ if (nameChanged) {
+ groupMessageService.sendGroupMessage(userId, memberUserIds, ImGroupMessageSendDTO.ofGroupNameUpdate(
+ groupId, userId, group.getName(), updateReqVO.getName()));
+ }
+ if (noticeChanged) {
+ groupMessageService.sendGroupMessage(userId, memberUserIds, ImGroupMessageSendDTO.ofGroupNoticeUpdate(
+ groupId, userId, group.getNotice(), updateReqVO.getNotice()));
+ }
+ if (avatarChanged) {
+ groupMessageService.sendGroupMessage(userId, memberUserIds, ImGroupMessageSendDTO.ofGroupInfoUpdate(
+ groupId, userId, group.getAvatar(), updateReqVO.getAvatar(), null, null));
+ }
+ if (joinApprovalChanged) {
+ groupMessageService.sendGroupMessage(userId, memberUserIds, ImGroupMessageSendDTO.ofGroupInfoUpdate(
+ groupId, userId, null, null, group.getJoinApproval(), updateReqVO.getJoinApproval()));
+ }
+ }
+
+ // 4. 杩斿洖鍚堝苟鍚庣殑鏂扮兢淇℃伅锛坲pdateReqVO 闈炵┖瀛楁瑕嗙洊 group锛�
+ BeanUtil.copyProperties(updateReqVO, group, CopyOptions.create().ignoreNullValue());
+ return group;
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#id")
+ @Transactional(rollbackFor = Exception.class)
+ public void dissolveGroup(Long id, Long userId) {
+ // 1. 鏍¢獙缇ゅ瓨鍦� + 褰撳墠鐢ㄦ埛鏄兢涓�
+ ImGroupDO group = validateGroupNotDissolved(id);
+ if (ObjUtil.notEqual(group.getOwnerUserId(), userId)) {
+ throw exception(GROUP_NOT_OWNER);
+ }
+
+ // 2. 瑙f暎缇�
+ dissolveGroup0(id, userId);
+ }
+
+ private void dissolveGroup0(Long id, Long userId) {
+ // 1. 鍏堝彂 GROUP_DISSOLVE 閫氱煡锛氭斁鍦ㄦ垚鍛樼Щ闄ゅ墠锛宻endGroupMessage 鎵嶈兘鏌ュ埌鍏ㄥ憳
+ groupMessageService.sendGroupMessage(userId, ImGroupMessageSendDTO.ofGroupDissolve(id, userId));
+
+ // 2.1 鏇存柊缇ょ姸鎬佷负宸茶В鏁�
+ groupMapper.updateById(new ImGroupDO().setId(id)
+ .setStatus(CommonStatusEnum.DISABLE.getStatus()).setDissolvedTime(LocalDateTime.now()));
+ // 2.2 绉婚櫎鍏ㄩ儴缇ゆ垚鍛�
+ groupMemberService.removeGroupMembersByGroupId(id);
+ }
+
+ // ==================== 缇ゆ垚鍛樼殑鍐欐搷浣� ====================
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void inviteGroupMember(Long userId, ImGroupMemberInviteReqVO inviteReqVO) {
+ Long groupId = inviteReqVO.getGroupId();
+ // 1.1 鏍¢獙缇ゅ瓨鍦� + 褰撳墠鐢ㄦ埛鏄兢鎴愬憳锛涘悓鏃舵嬁鍒� role 渚涗笅闈㈠鎵瑰垎鏀垽鏂�
+ ImGroupDO group = validateGroupExists(groupId);
+ ImGroupMemberDO operator = groupMemberService.validateMemberInGroup(groupId, userId);
+ // 1.2 鍏ュ弬鍘婚噸 + 鎺掗櫎宸插湪缇や腑鐨勭敤鎴�
+ List<ImGroupMemberDO> activeMembers = groupMemberService.getActiveGroupMemberListByGroupId(groupId);
+ Set<Long> activeMemberUserIds = convertSet(activeMembers, ImGroupMemberDO::getUserId);
+ List<Long> memberUserIds = CollUtil.subtractToList(
+ CollUtil.distinct(inviteReqVO.getMemberUserIds()), activeMemberUserIds);
+ if (CollUtil.isEmpty(memberUserIds)) {
+ return;
+ }
+ // 1.3 鏍¢獙琚個璇蜂汉閮芥槸褰撳墠鐢ㄦ埛鐨勫ソ鍙�
+ List<ImFriendDO> friends = friendService.getActiveFriendList(userId, memberUserIds);
+ Set<Long> friendUserIds = convertSet(friends, ImFriendDO::getFriendUserId);
+ Collection<Long> notFriendUserIds = CollUtil.subtract(memberUserIds, friendUserIds);
+ if (CollUtil.isNotEmpty(notFriendUserIds)) {
+ throw exception(GROUP_INVITE_NOT_FRIEND, getUserNicknames(notFriendUserIds));
+ }
+ // 1.4 鏍¢獙缇や汉鏁颁笂闄�
+ int maxMember = imProperties.getGroup().getMaxMember();
+ if (activeMembers.size() + memberUserIds.size() > maxMember) {
+ throw exception(GROUP_MEMBER_EXCEED, maxMember);
+ }
+
+ // 2. 鎯呭喌涓�锛氱兢寮�鍚鎵� + 閭�璇蜂汉鏄櫘閫氭垚鍛橈紝钀� group_request 绛夌兢涓� / 绠$悊鍛樺鐞�
+ // 缇や富 / 绠$悊鍛橀個璇凤紝鐩存帴鎷変汉杩涚兢
+ if (Boolean.TRUE.equals(group.getJoinApproval())
+ && !ImGroupMemberRoleEnum.isOwnerOrAdmin(operator.getRole())) {
+ groupRequestService.createInviteRequestList(groupId, userId, memberUserIds);
+ return;
+ }
+
+ // 3. 鎯呭喌浜岋細鏈紑瀹℃壒 / 缇や富 / 绠$悊鍛橀個璇凤紝鐩磋繘锛涙壒閲忔坊鍔犵兢鎴愬憳锛屽啓 addSource=INVITE / inviterUserId=鎿嶄綔浜� 鐣欑棔
+ groupMemberService.addGroupMembers(groupId, memberUserIds,
+ ImGroupAddSourceEnum.INVITE.getSource(), userId);
+
+ // 4. 鍙� GROUP_MEMBER_INVITE 閫氱煡缁欏叏鍛橈紱鏈湴鎷� receivers锛堝凡鏌ョ殑 active + 鏂伴個璇凤級閬垮厤缂撳瓨鍒� evict 鍚庡己鍒惰蛋 DB
+ Set<Long> allReceivers = new HashSet<>(memberUserIds);
+ allReceivers.addAll(activeMemberUserIds);
+ groupMessageService.sendGroupMessage(userId, allReceivers,
+ ImGroupMessageSendDTO.ofGroupMemberInvite(groupId, userId, memberUserIds));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void quitGroup(Long groupId, Long userId) {
+ // 1.1 鏍¢獙缇ゅ瓨鍦ㄤ笖鏈В鏁�
+ ImGroupDO group = getSelf().getGroup(groupId);
+ if (group == null) {
+ throw exception(GROUP_NOT_EXISTS);
+ }
+ if (CommonStatusEnum.DISABLE.getStatus().equals(group.getStatus())) {
+ throw exception(GROUP_DISSOLVED);
+ }
+ // 1.2 缇や富涓嶅彲閫�缇�
+ if (ObjUtil.equal(group.getOwnerUserId(), userId)) {
+ throw exception(GROUP_OWNER_CANNOT_QUIT);
+ }
+ // 1.3 鏍¢獙褰撳墠鐢ㄦ埛鏄湁鏁堢兢鎴愬憳锛涢槻姝㈤潪鎴愬憳瑙﹀彂骞挎挱 + 鍚庣画 remove 澶辫触鏃舵棤娉曞洖婊氬凡鎺ㄩ�佺殑浜嬩欢
+ groupMemberService.validateMemberInGroup(groupId, userId);
+
+ // 2. 鍏堝彂骞挎挱锛屽悗绉绘垚鍛橈紙瑙佺被 javadoc锛�
+ groupMessageService.sendGroupMessage(userId, ImGroupMessageSendDTO.ofGroupMemberQuit(groupId, userId));
+
+ // 3. 绉婚櫎缇ゆ垚鍛�
+ groupMemberService.removeGroupMember(groupId, userId);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void removeGroupMember(Long userId, ImGroupMemberRemoveReqVO removeReqVO) {
+ Long groupId = removeReqVO.getGroupId();
+ Set<Long> targetUserIds = new HashSet<>(removeReqVO.getMemberUserIds());
+ // 1.1 鏍¢獙缇ゅ瓨鍦� + 鎿嶄綔鑰呮槸缇や富鎴栫鐞嗗憳
+ ImGroupMemberDO operator = validateGroupOwnerOrAdmin(groupId, userId);
+ // 1.2 涓嶈兘绉婚櫎鑷繁
+ if (targetUserIds.contains(userId)) {
+ throw exception(GROUP_CANNOT_REMOVE_SELF);
+ }
+ // 1.3 浠呬繚鐣欎粛鏈夋晥鐨勬垚鍛橈紱宸查��缇わ紙DISABLE锛�/ 鏌ユ棤璁板綍鐨勭洰鏍囩洿鎺ヨ烦杩囷紝鍙涪鏈夋晥鎴愬憳锛屼笉璁╂暣鎵瑰け璐�
+ List<ImGroupMemberDO> targets = filterList(groupMemberService.getGroupMembers(groupId, targetUserIds),
+ target -> CommonStatusEnum.ENABLE.getStatus().equals(target.getStatus()));
+ Set<Long> validTargetUserIds = convertSet(targets, ImGroupMemberDO::getUserId);
+ // 1.4 鐩爣鍏ㄩ儴宸蹭笉鍦ㄧ兢锛氭棤浜哄彲韪紝鐩存帴杩斿洖
+ if (CollUtil.isEmpty(validTargetUserIds)) {
+ return;
+ }
+ // 1.5 涓夋。鏉冮檺鏍¢獙锛氱兢涓讳笉鍙绉诲嚭锛涚鐞嗗憳涓嶈兘绉诲嚭绠$悊鍛�
+ boolean operatorIsAdmin = ImGroupMemberRoleEnum.isAdmin(operator.getRole());
+ for (ImGroupMemberDO target : targets) {
+ if (ImGroupMemberRoleEnum.isOwner(target.getRole())) {
+ throw exception(GROUP_REMOVE_OWNER_DENIED);
+ }
+ if (operatorIsAdmin && ImGroupMemberRoleEnum.isAdmin(target.getRole())) {
+ throw exception(GROUP_REMOVE_ADMIN_DENIED);
+ }
+ }
+
+ // 2. 鍏堝彂 GROUP_MEMBER_KICK 閫氱煡锛氭斁鍦ㄨ韪㈣�呯Щ闄ゅ墠锛宻endGroupMessage 鎵嶈兘鏌ュ埌鍏ㄥ憳锛堝惈琚涪鑰咃級
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupMemberKick(groupId, userId, validTargetUserIds));
+
+ // 3. 鎵归噺绉婚櫎缇ゆ垚鍛橈紱涓嶆竻鐞嗚浣嶇疆锛堜繚鐣欓��缇ゅ墠鍘嗗彶宸茶锛屼緵绂荤嚎琛ュ伩锛�
+ groupMemberService.removeGroupMembers(groupId, validTargetUserIds);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void addGroupAdmin(Long userId, ImGroupAdminAddReqVO reqVO) {
+ Long groupId = reqVO.getId();
+ Set<Long> targetUserIds = new HashSet<>(reqVO.getUserIds());
+ // 1.1 浠呯兢涓诲彲鎿嶄綔
+ validateGroupOwnerForUpdate(groupId, userId);
+ // 1.2 鏍¢獙鐩爣閮芥槸鏈夋晥鎴愬憳涓旈潪缇や富
+ Map<Long, ImGroupMemberDO> targetMap = convertMap(
+ groupMemberService.getGroupMembers(groupId, targetUserIds), ImGroupMemberDO::getUserId);
+ validateAdminTargets(targetUserIds, targetMap);
+ // 1.3 骞傜瓑杩囨护锛氳烦杩囧凡鏄� ADMIN
+ Set<Long> changedUserIds = convertSet(targetUserIds,
+ id -> id,
+ id -> !ImGroupMemberRoleEnum.isAdmin(targetMap.get(id).getRole()));
+ if (CollUtil.isEmpty(changedUserIds)) {
+ return;
+ }
+ // 1.4 鏍¢獙涓婇檺
+ Long existAdminCount = groupMemberService.getGroupMemberCountByRole(
+ groupId, ImGroupMemberRoleEnum.ADMIN.getRole());
+ int adminMaxCount = imProperties.getGroup().getAdminMaxCount();
+ if (existAdminCount + changedUserIds.size() > adminMaxCount) {
+ throw exception(GROUP_ADMIN_MAX_LIMIT, adminMaxCount);
+ }
+
+ // 2. 鎵归噺鏇存柊瑙掕壊
+ int affected = groupMemberService.updateGroupMemberRole(groupId, changedUserIds,
+ ImGroupMemberRoleEnum.ADMIN.getRole());
+ if (affected != changedUserIds.size()) {
+ throw exception(GROUP_ADMIN_TARGET_NOT_IN_GROUP);
+ }
+
+ // 3. 鎺ㄩ�� GROUP_ADMIN_ADD 閫氱煡缁欏叏鍛�
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupAdminAdd(groupId, userId, changedUserIds));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void removeGroupAdmin(Long userId, ImGroupAdminRemoveReqVO reqVO) {
+ Long groupId = reqVO.getId();
+ Set<Long> targetUserIds = new HashSet<>(reqVO.getUserIds());
+ // 1.1 浠呯兢涓诲彲鎿嶄綔
+ validateGroupOwnerForUpdate(groupId, userId);
+ // 1.2 鏍¢獙鐩爣閮芥槸鏈夋晥鎴愬憳涓旈潪缇や富
+ Map<Long, ImGroupMemberDO> targetMap = convertMap(
+ groupMemberService.getGroupMembers(groupId, targetUserIds), ImGroupMemberDO::getUserId);
+ validateAdminTargets(targetUserIds, targetMap);
+ // 1.3 骞傜瓑杩囨护锛氳烦杩囧凡鏄� MEMBER
+ Set<Long> changedUserIds = convertSet(targetUserIds,
+ id -> id,
+ id -> ImGroupMemberRoleEnum.isAdmin(targetMap.get(id).getRole()));
+ if (CollUtil.isEmpty(changedUserIds)) {
+ return;
+ }
+
+ // 2. 鎵归噺鏇存柊瑙掕壊
+ int affected = groupMemberService.updateGroupMemberRole(groupId, changedUserIds,
+ ImGroupMemberRoleEnum.NORMAL.getRole());
+ if (affected != changedUserIds.size()) {
+ throw exception(GROUP_ADMIN_TARGET_NOT_IN_GROUP);
+ }
+
+ // 3. 鎺ㄩ�� GROUP_ADMIN_REMOVE 閫氱煡缁欏叏鍛�
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupAdminRemove(groupId, userId, changedUserIds));
+ }
+
+ /**
+ * 鏍¢獙绠$悊鍛樺彉鏇寸洰鏍囬兘鏄綋鍓嶇兢鐨勬湁鏁堟垚鍛橈紙status=ENABLE锛変笖闈炵兢涓�
+ */
+ private void validateAdminTargets(Set<Long> targetUserIds, Map<Long, ImGroupMemberDO> targetMap) {
+ for (Long targetUserId : targetUserIds) {
+ ImGroupMemberDO target = targetMap.get(targetUserId);
+ if (target == null || CommonStatusEnum.DISABLE.getStatus().equals(target.getStatus())) {
+ throw exception(GROUP_ADMIN_TARGET_NOT_IN_GROUP);
+ }
+ if (ImGroupMemberRoleEnum.isOwner(target.getRole())) {
+ throw exception(GROUP_ADMIN_TARGET_IS_OWNER);
+ }
+ }
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#transferReqVO.id")
+ @Transactional(rollbackFor = Exception.class)
+ public void transferGroupOwner(Long userId, ImGroupTransferOwnerReqVO transferReqVO) {
+ Long groupId = transferReqVO.getId();
+ Long newOwnerUserId = transferReqVO.getNewOwnerUserId();
+ // 1.1 浠呰�佺兢涓诲彲鎵ц
+ validateGroupOwnerForUpdate(groupId, userId);
+ // 1.2 涓嶈兘杞缁欒嚜宸�
+ if (ObjUtil.equal(userId, newOwnerUserId)) {
+ throw exception(GROUP_TRANSFER_OWNER_TO_SELF);
+ }
+ // 1.3 鏂扮兢涓诲繀椤绘槸缇ょ殑鏈夋晥鎴愬憳
+ ImGroupMemberDO newOwner = groupMemberService.validateMemberInGroup(groupId, newOwnerUserId);
+
+ // 2.1 鏇存柊鎴愬憳瑙掕壊
+ int newOwnerAffected = groupMemberService.updateGroupMemberRole(groupId, CollUtil.newHashSet(newOwner.getUserId()),
+ ImGroupMemberRoleEnum.OWNER.getRole());
+ if (newOwnerAffected != 1) {
+ throw exception(GROUP_MEMBER_NOT_IN_GROUP);
+ }
+ int oldOwnerAffected = groupMemberService.updateGroupMemberRole(groupId, CollUtil.newHashSet(userId),
+ ImGroupMemberRoleEnum.NORMAL.getRole());
+ if (oldOwnerAffected != 1) {
+ throw exception(GROUP_MEMBER_NOT_IN_GROUP);
+ }
+ // 2.2 鏇存柊缇や富缂栧彿
+ groupMapper.updateById(new ImGroupDO().setId(groupId).setOwnerUserId(newOwnerUserId));
+
+ // 3. 鎺ㄩ�� GROUP_OWNER_TRANSFER 閫氱煡缁欏叏鍛�
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupOwnerTransfer(groupId, userId, newOwnerUserId));
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#groupId")
+ @Transactional(rollbackFor = Exception.class)
+ public void pinGroupMessage(Long userId, Long groupId, Long messageId) {
+ // 1.1 鏍¢獙缇や富 / 绠$悊鍛橈紱鍚屾椂鎷垮埌 group 澶嶇敤锛岄伩鍏嶅啀璧颁竴娆� @Cacheable
+ ImGroupDO group = validateOwnerOrAdminAndGetGroupForUpdate(groupId, userId);
+ // 1.2 鏍¢獙娑堟伅灞炰簬璇ョ兢銆佹槸鏅�氳亰澶╂秷鎭紙缁曡繃鍓嶇鑿滃崟涓嶅厑璁哥疆椤剁兢浜嬩欢 / 鎾ゅ洖浜嬩欢锛夈�佷笖鏈鎾ゅ洖
+ ImGroupMessageDO message = groupMessageService.getGroupMessage(messageId);
+ if (message == null || ObjUtil.notEqual(message.getGroupId(), groupId)) {
+ throw exception(MESSAGE_NOT_IN_GROUP);
+ }
+ if (!ImContentTypeEnum.validate(message.getType()).isNormal()
+ || ImMessageStatusEnum.RECALL.getStatus().equals(message.getStatus())) {
+ throw exception(MESSAGE_NOT_IN_GROUP);
+ }
+ // 1.3 瀹氬悜娑堟伅锛坮eceiverUserIds 闈炵┖锛変笉鍏佽缃《锛氱疆椤朵細鍚戝叏缇ゅ箍鎾紝娉勯湶鍘熸湰浠呴儴鍒嗕汉鍙鐨勫唴瀹�
+ if (CollUtil.isNotEmpty(message.getReceiverUserIds())) {
+ throw exception(GROUP_MESSAGE_PIN_DIRECTED_DENIED);
+ }
+
+ // 2. 骞傜瓑 + 涓婇檺鏍¢獙
+ List<Long> pinned = new ArrayList<>(CollUtil.emptyIfNull(group.getPinnedMessageIds()));
+ if (pinned.contains(messageId)) {
+ throw exception(GROUP_MESSAGE_ALREADY_PINNED);
+ }
+ int pinMaxCount = imProperties.getGroup().getPinMaxCount();
+ if (pinned.size() >= pinMaxCount) {
+ throw exception(GROUP_MESSAGE_PIN_MAX_LIMIT, pinMaxCount);
+ }
+ pinned.add(messageId);
+ groupMapper.updateById(new ImGroupDO().setId(groupId).setPinnedMessageIds(pinned));
+
+ // 3. 鎺ㄩ�� GROUP_MESSAGE_PIN 閫氱煡缁欏叏鍛�
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupMessagePin(groupId, userId, message));
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#groupId")
+ @Transactional(rollbackFor = Exception.class)
+ public void unpinGroupMessage(Long userId, Long groupId, Long messageId) {
+ // 1. 鏍¢獙缇や富 / 绠$悊鍛橈紱鍚屾椂鎷垮埌 group 澶嶇敤锛岄伩鍏嶅啀璧颁竴娆� @Cacheable
+ ImGroupDO group = validateOwnerOrAdminAndGetGroupForUpdate(groupId, userId);
+ // 2. 骞傜瓑鏍¢獙
+ List<Long> pinned = new ArrayList<>(CollUtil.emptyIfNull(group.getPinnedMessageIds()));
+ if (!pinned.contains(messageId)) {
+ throw exception(GROUP_MESSAGE_NOT_PINNED);
+ }
+ pinned.remove(messageId);
+ groupMapper.updateById(new ImGroupDO().setId(groupId).setPinnedMessageIds(pinned));
+
+ // 3. 鎺ㄩ�� GROUP_MESSAGE_UNPIN 閫氱煡缁欏叏鍛�
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupMessageUnpin(groupId, userId, messageId));
+ }
+
+ /**
+ * 鏍¢獙鐧诲綍鐢ㄦ埛鏄兢涓绘垨绠$悊鍛橈紝鍚屾椂杩斿洖缇や俊鎭�
+ */
+ private ImGroupDO validateOwnerOrAdminAndGetGroup(Long groupId, Long userId) {
+ ImGroupDO group = validateGroupExists(groupId);
+ ImGroupMemberDO member = groupMemberService.validateMemberInGroup(groupId, userId);
+ if (!ImGroupMemberRoleEnum.isOwnerOrAdmin(member.getRole())) {
+ throw exception(GROUP_NOT_OWNER_OR_ADMIN);
+ }
+ return group;
+ }
+
+ /**
+ * 鏍¢獙鐧诲綍鐢ㄦ埛鏄兢涓绘垨绠$悊鍛橈紝鍚屾椂閿佸畾缇や俊鎭�
+ */
+ private ImGroupDO validateOwnerOrAdminAndGetGroupForUpdate(Long groupId, Long userId) {
+ ImGroupDO group = validateGroupExistsForUpdate(groupId);
+ ImGroupMemberDO member = groupMemberService.validateMemberInGroup(groupId, userId);
+ if (!ImGroupMemberRoleEnum.isOwnerOrAdmin(member.getRole())) {
+ throw exception(GROUP_NOT_OWNER_OR_ADMIN);
+ }
+ return group;
+ }
+
+ // ==================== 缇ょ殑璇绘搷浣� ====================
+
+ @Override
+ public ImGroupDO validateGroupExists(Long id) {
+ ImGroupDO group = getSelf().getGroup(id);
+ if (group == null) {
+ throw exception(GROUP_NOT_EXISTS);
+ }
+ if (Boolean.TRUE.equals(group.getBanned())) {
+ throw exception(GROUP_BANNED);
+ }
+ if (CommonStatusEnum.DISABLE.getStatus().equals(group.getStatus())) {
+ throw exception(GROUP_DISSOLVED);
+ }
+ return group;
+ }
+
+ @Override
+ public void validateMemberCountLimit(Long groupId, int addCount) {
+ // 1. 閿佸畾缇よ褰�
+ validateGroupExistsForUpdate(groupId);
+ // 2. 鏍¢獙鎴愬憳鏁伴噺涓婇檺
+ int activeCount = groupMemberService.getActiveGroupMemberUserIdsByGroupId(groupId).size();
+ int maxMember = imProperties.getGroup().getMaxMember();
+ if (activeCount + addCount > maxMember) {
+ throw exception(GROUP_MEMBER_EXCEED, maxMember);
+ }
+ }
+
+ private ImGroupDO validateGroupOwnerForUpdate(Long groupId, Long userId) {
+ ImGroupDO group = validateGroupExistsForUpdate(groupId);
+ if (ObjUtil.notEqual(group.getOwnerUserId(), userId)) {
+ throw exception(GROUP_NOT_OWNER);
+ }
+ return group;
+ }
+
+ private ImGroupDO validateGroupExistsForUpdate(Long groupId) {
+ ImGroupDO group = groupMapper.selectByIdForUpdate(groupId);
+ if (group == null) {
+ throw exception(GROUP_NOT_EXISTS);
+ }
+ if (Boolean.TRUE.equals(group.getBanned())) {
+ throw exception(GROUP_BANNED);
+ }
+ if (CommonStatusEnum.DISABLE.getStatus().equals(group.getStatus())) {
+ throw exception(GROUP_DISSOLVED);
+ }
+ return group;
+ }
+
+ private ImGroupDO validateGroupNotDissolved(Long id) {
+ ImGroupDO group = getSelf().getGroup(id);
+ if (group == null) {
+ throw exception(GROUP_NOT_EXISTS);
+ }
+ if (CommonStatusEnum.DISABLE.getStatus().equals(group.getStatus())) {
+ throw exception(GROUP_DISSOLVED);
+ }
+ return group;
+ }
+
+ /**
+ * 鏍¢獙褰撳墠鐢ㄦ埛鏄兢涓绘垨绠$悊鍛橈紝鍚﹀垯鎶� GROUP_NOT_OWNER_OR_ADMIN
+ */
+ private ImGroupMemberDO validateGroupOwnerOrAdmin(Long groupId, Long userId) {
+ validateGroupExists(groupId);
+ ImGroupMemberDO member = groupMemberService.validateMemberInGroup(groupId, userId);
+ if (!ImGroupMemberRoleEnum.isOwnerOrAdmin(member.getRole())) {
+ throw exception(GROUP_NOT_OWNER_OR_ADMIN);
+ }
+ return member;
+ }
+
+ @Override
+ @Cacheable(cacheNames = GROUP, key = "#id", unless = "#result == null")
+ public ImGroupDO getGroup(Long id) {
+ return groupMapper.selectById(id);
+ }
+
+ @Override
+ public Map<Long, ImGroupDO> getGroupMap(Collection<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return Collections.emptyMap();
+ }
+ return convertMap(groupMapper.selectByIds(ids), ImGroupDO::getId);
+ }
+
+ @Override
+ public List<ImGroupDO> getMyGroupList(Long userId) {
+ // 1. 鏌ョ敤鎴锋浘缁忓姞鍏ョ殑鎵�鏈夌兢锛堝惈閫�缇わ紝鍓嶇鎸夐渶杩囨护锛夛紱閫�缇ゅ墠鐨勭绾挎秷鎭篃瑕佽兘灞曠ず
+ List<ImGroupMemberDO> members = groupMemberService.getGroupMemberListByUserId(userId);
+ if (CollUtil.isEmpty(members)) {
+ return Collections.emptyList();
+ }
+
+ // 2. 鎵归噺鏌ヨ缇や俊鎭紙涓嶆寜 status / banned 杩囨护锛屽凡瑙f暎 / 灏佺鐨勭兢涔熻杩斿洖锛屼緵鍓嶇灞曠ず鍘嗗彶娑堟伅鐨勭兢鍚� / 澶村儚锛�
+ Set<Long> groupIds = convertSet(members, ImGroupMemberDO::getGroupId);
+ return groupMapper.selectByIds(groupIds);
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImGroupDO> getGroupPage(ImGroupManagerPageReqVO pageReqVO) {
+ return groupMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#banReqVO.id")
+ public void banGroup(Long operatorUserId, ImGroupManagerBanReqVO banReqVO) {
+ // 1. 鏍¢獙缇ゅ瓨鍦ㄤ笖鏈В鏁�
+ ImGroupDO group = getSelf().getGroup(banReqVO.getId());
+ if (group == null) {
+ throw exception(GROUP_NOT_EXISTS);
+ }
+ if (CommonStatusEnum.DISABLE.getStatus().equals(group.getStatus())) {
+ throw exception(GROUP_DISSOLVED);
+ }
+ // 2. 骞傜瓑锛氬凡灏佺鐩存帴杩斿洖锛岄伩鍏嶉噸澶嶅箍鎾皝绂侀�氱煡
+ if (Boolean.TRUE.equals(group.getBanned())) {
+ return;
+ }
+
+ // 3. 鏇存柊灏佺鐘舵��
+ groupMapper.updateById(new ImGroupDO().setId(banReqVO.getId())
+ .setBanned(true).setBannedReason(banReqVO.getReason()).setBannedTime(LocalDateTime.now()));
+
+ // 4. 骞挎挱閫氱煡
+ groupMessageService.sendGroupMessage(operatorUserId,
+ ImGroupMessageSendDTO.ofGroupBanned(banReqVO.getId(), operatorUserId, true));
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#id")
+ public void unbanGroup(Long operatorUserId, Long id) {
+ // 1. 鏍¢獙缇ゅ瓨鍦�
+ if (getSelf().getGroup(id) == null) {
+ throw exception(GROUP_NOT_EXISTS);
+ }
+
+ // 2. 瑙e皝锛堜繚鐣� bannedReason / bannedTime 浣滀负鍘嗗彶璁板綍锛�
+ groupMapper.updateById(new ImGroupDO().setId(id).setBanned(false));
+
+ // 3. 骞挎挱閫氱煡
+ groupMessageService.sendGroupMessage(operatorUserId,
+ ImGroupMessageSendDTO.ofGroupBanned(id, operatorUserId, false));
+ }
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#id")
+ @Transactional(rollbackFor = Exception.class)
+ public void dissolveGroupByManager(Long operatorUserId, Long id) {
+ // 1. 鏍¢獙缇ゅ瓨鍦ㄤ笖鏈В鏁�
+ validateGroupNotDissolved(id);
+
+ // 2. 瑙f暎缇�
+ dissolveGroup0(id, operatorUserId);
+ }
+
+ // ==================== 缇ょ瑷� ====================
+
+ @Override
+ @CacheEvict(cacheNames = GROUP, key = "#reqVO.id")
+ @Transactional(rollbackFor = Exception.class)
+ public void muteAll(Long userId, ImGroupMuteAllReqVO reqVO) {
+ // 1. 鏍¢獙缇や富鎴栫鐞嗗憳
+ validateGroupOwnerOrAdmin(reqVO.getId(), userId);
+
+ // 2. 鏇存柊 mutedAll
+ groupMapper.updateById(new ImGroupDO().setId(reqVO.getId()).setMutedAll(reqVO.getMutedAll()));
+
+ // 3. 骞挎挱閫氱煡
+ ImGroupMessageSendDTO messageSendDTO = Boolean.TRUE.equals(reqVO.getMutedAll())
+ ? ImGroupMessageSendDTO.ofGroupMuted(reqVO.getId(), userId)
+ : ImGroupMessageSendDTO.ofGroupCancelMuted(reqVO.getId(), userId);
+ groupMessageService.sendGroupMessage(userId, messageSendDTO);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void muteMember(Long userId, ImGroupMuteMemberReqVO reqVO) {
+ // 1.1 涓嶈兘绂佽█鑷繁
+ if (ObjUtil.equal(userId, reqVO.getUserId())) {
+ throw exception(GROUP_MUTE_MEMBER_SELF);
+ }
+ // 1.2 鏍¢獙缇ゅ瓨鍦ㄤ笖鏈皝绂�
+ validateGroupExists(reqVO.getId());
+ // 1.3 鏍¢獙鎿嶄綔浜哄拰鐩爣閮藉湪缇や腑
+ ImGroupMemberDO operatorMember = groupMemberService.validateMemberInGroup(reqVO.getId(), userId);
+ ImGroupMemberDO targetMember = groupMemberService.validateMemberInGroup(reqVO.getId(), reqVO.getUserId());
+ // 1.4 涓夋。鏉冮檺鏍¢獙
+ validateMutePermission(operatorMember, targetMember);
+
+ // 2. 璁剧疆 muteEndTime
+ LocalDateTime muteEndTime = reqVO.getMutedSeconds() == 0
+ ? ImGroupMemberDO.PERMANENT_MUTE_END_TIME : LocalDateTime.now().plusSeconds(reqVO.getMutedSeconds());
+ groupMemberService.updateGroupMemberMuteEndTime(reqVO.getId(), reqVO.getUserId(), muteEndTime);
+
+ // 3. 骞挎挱閫氱煡
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupMemberMuted(reqVO.getId(), userId,
+ reqVO.getUserId(), muteEndTime));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void cancelMuteMember(Long userId, ImGroupCancelMuteMemberReqVO reqVO) {
+ // 1.1 鏍¢獙缇ゅ瓨鍦ㄤ笖鏈皝绂�
+ validateGroupExists(reqVO.getId());
+ // 1.2 鏍¢獙鎿嶄綔浜哄拰鐩爣閮藉湪缇や腑
+ ImGroupMemberDO operatorMember = groupMemberService.validateMemberInGroup(reqVO.getId(), userId);
+ ImGroupMemberDO targetMember = groupMemberService.validateMemberInGroup(reqVO.getId(), reqVO.getUserId());
+ // 1.3 涓夋。鏉冮檺鏍¢獙
+ validateMutePermission(operatorMember, targetMember);
+
+ // 2. 鍙栨秷绂佽█锛堟竻绌� muteEndTime锛�
+ groupMemberService.updateGroupMemberMuteEndTime(reqVO.getId(), reqVO.getUserId(), null);
+
+ // 3. 骞挎挱閫氱煡
+ groupMessageService.sendGroupMessage(userId,
+ ImGroupMessageSendDTO.ofGroupMemberCancelMuted(reqVO.getId(), userId, reqVO.getUserId()));
+ }
+
+ /**
+ * 涓夋。鍒嗗眰绂佽█鏉冮檺鏍¢獙
+ */
+ private void validateMutePermission(ImGroupMemberDO operator, ImGroupMemberDO target) {
+ // 鏅�氭垚鍛樹笉鑳界瑷�浠讳綍浜�
+ if (!ImGroupMemberRoleEnum.isOwnerOrAdmin(operator.getRole())) {
+ throw exception(GROUP_NOT_OWNER_OR_ADMIN);
+ }
+ // 缇や富涓嶅彲琚瑷�
+ if (ImGroupMemberRoleEnum.isOwner(target.getRole())) {
+ throw exception(GROUP_MUTE_OWNER_DENIED);
+ }
+ // 绠$悊鍛樹笉鑳界瑷�鍏朵粬绠$悊鍛�
+ if (ImGroupMemberRoleEnum.isAdmin(target.getRole()) && !ImGroupMemberRoleEnum.isOwner(operator.getRole())) {
+ throw exception(GROUP_MUTE_ADMIN_DENIED);
+ }
+ }
+
+ private ImGroupServiceImpl getSelf() {
+ return SpringUtil.getBean(getClass());
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛缂栧彿闆嗗悎锛屾嫾鎺ョ敤鎴锋樀绉板瓧绗︿覆锛堥�楀彿鍒嗛殧锛�
+ *
+ * @param userIds 鐢ㄦ埛缂栧彿闆嗗悎
+ * @return 鏄电О瀛楃涓诧紝濡� "寮犱笁,鏉庡洓"
+ */
+ private String getUserNicknames(Collection<Long> userIds) {
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
+ return userIds.stream()
+ .map(id -> userMap.containsKey(id) ? userMap.get(id).getNickname() : String.valueOf(id))
+ .collect(Collectors.joining(","));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageService.java
new file mode 100644
index 0000000..b1e00ee
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageService.java
@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessagePageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import jakarta.validation.Valid;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * IM 棰戦亾娑堟伅 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImChannelMessageService {
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ /**
+ * 鎷夊彇褰撳墠鐢ㄦ埛搴旀敹鐨勯閬撴秷鎭紙绂荤嚎澧為噺锛�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param minId 娓告爣锛涜繑鍥炲ぇ浜庢鍊肩殑娑堟伅
+ * @param size 杩斿洖鏉℃暟
+ * @return 棰戦亾娑堟伅鍒楄〃锛涙寜 id 鍗囧簭
+ */
+ List<ImChannelMessageDO> pullChannelMessageList(Long userId, Long minId, Integer size);
+
+ /**
+ * 涓婃姤棰戦亾娑堟伅宸茶浣嶇疆锛涘悓姝ユ帹 READ 浜嬩欢缁欒嚜宸卞绔�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param channelId 棰戦亾缂栧彿
+ * @param messageId 宸茶鍒扮殑鏈�澶ф秷鎭紪鍙�
+ */
+ void readChannelMessages(Long userId, Long channelId, Long messageId);
+
+ /**
+ * 鎵归噺鏌ヨ鐢ㄦ埛鍦ㄥ涓閬撲笅鐨勫凡璇绘父鏍�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param channelIds 棰戦亾缂栧彿闆嗗悎
+ * @return channelId 鈫� 宸茶鍒扮殑鏈�澶ф秷鎭紪鍙凤紙鏈鍒扮殑棰戦亾涓嶅嚭鐜板湪杩斿洖 map 涓級
+ */
+ Map<Long, Long> getChannelReadMaxMessageIdMap(Long userId, Collection<Long> channelIds);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 绔嬪嵆鎺ㄩ�侀閬撴秷鎭�
+ *
+ * @param reqVO 鎺ㄩ�佽姹�
+ * @return 娑堟伅缂栧彿
+ */
+ Long sendMessage(@Valid ImChannelMessageSendReqVO reqVO);
+
+ /**
+ * 鍒嗛〉鏌ヨ娑堟伅
+ *
+ * @param reqVO 鍒嗛〉鏌ヨ鏉′欢
+ * @return 娑堟伅鍒嗛〉
+ */
+ PageResult<ImChannelMessageDO> getMessagePage(ImChannelMessagePageReqVO reqVO);
+
+ /**
+ * 鍒犻櫎娑堟伅
+ *
+ * @param id 娑堟伅缂栧彿
+ */
+ void deleteMessage(Long id);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImpl.java
new file mode 100644
index 0000000..fc9ad8e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImpl.java
@@ -0,0 +1,148 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessagePageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.channel.ImChannelMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.channel.ImChannelMaterialDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImChannelMessageMapper;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.service.channel.ImChannelMaterialService;
+import cn.iocoder.yudao.module.im.service.conversation.ImConversationReadService;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImChannelMessageNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReadNotification;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.MaterialMessage;
+import jakarta.annotation.Resource;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.IM_CHANNEL_MESSAGE_NOT_EXISTS;
+
+/**
+ * IM 棰戦亾娑堟伅 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class ImChannelMessageServiceImpl implements ImChannelMessageService {
+
+ @Resource
+ private ImChannelMessageMapper channelMessageMapper;
+
+ @Resource
+ private ImChannelMaterialService channelMaterialService;
+ @Resource
+ private ImWebSocketService webSocketService;
+
+ @Resource
+ private ImConversationReadService conversationReadService;
+
+ // ==================== 鐢ㄦ埛绔� ====================
+
+ @Override
+ public List<ImChannelMessageDO> pullChannelMessageList(Long userId, Long minId, Integer size) {
+ return channelMessageMapper.selectListByUserAndMinId(userId, minId, size);
+ }
+
+ @Override
+ public Map<Long, Long> getChannelReadMaxMessageIdMap(Long userId, Collection<Long> channelIds) {
+ return conversationReadService.getConversationReadMessageIdMap(
+ userId, ImConversationTypeEnum.CHANNEL.getType(), channelIds);
+ }
+
+ @Override
+ public void readChannelMessages(Long userId, Long channelId, Long messageId) {
+ Assert.notNull(channelId, "棰戦亾缂栧彿涓嶈兘涓虹┖");
+ Assert.notNull(messageId, "宸茶娑堟伅缂栧彿涓嶈兘涓虹┖");
+ // 1.1 鏍¢獙娑堟伅鐪熷疄瀛樺湪涓斿睘浜庤棰戦亾锛岄伩鍏嶆湭鏉� / 浼�� messageId 姹℃煋璇讳綅缃�
+ ImChannelMessageDO message = channelMessageMapper.selectById(messageId);
+ if (message == null || ObjUtil.notEqual(message.getChannelId(), channelId)) {
+ return;
+ }
+ // 1.2 瀹氬悜娑堟伅鏍¢獙瀵瑰綋鍓嶇敤鎴峰彲瑙侊紙receiver_user_ids 涓虹┖琛ㄧず鍏ㄥ憳鍙锛�
+ if (CollUtil.isNotEmpty(message.getReceiverUserIds()) && !message.getReceiverUserIds().contains(userId)) {
+ return;
+ }
+
+ // 2. 鏇存柊棰戦亾宸茶浣嶇疆锛涜浣嶇疆鏈墠杩涘垯涓嶆帹
+ boolean advanced = conversationReadService.updateConversationReadPosition(
+ userId, ImConversationTypeEnum.CHANNEL.getType(), channelId, messageId);
+ if (!advanced) {
+ return;
+ }
+
+ // 3. 寮傛鎺� READ 浜嬩欢缁欒嚜宸卞绔悓姝�
+ getSelf().readChannelMessageEvent(userId, channelId, messageId);
+ }
+
+ /**
+ * 鍙戦�侀閬撳凡璇� READ 浜嬩欢缁欒嚜宸卞叾浠栫粓绔紱棰戦亾鏃犮�岀粰鍙戦�佹柟鍒峰洖鎵с�嶆蹇碉紝涓嶅箍鎾�
+ */
+ @Async
+ public void readChannelMessageEvent(Long userId, Long channelId, Long readId) {
+ webSocketService.sendNotificationAsync(userId, ImConversationTypeEnum.CHANNEL.getType(),
+ ImContentTypeEnum.READ.getType(), ImMessageReadNotification.ofChannel(channelId, readId));
+ }
+
+ private ImChannelMessageServiceImpl getSelf() {
+ return SpringUtil.getBean(getClass());
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long sendMessage(ImChannelMessageSendReqVO reqVO) {
+ // 1. 鏍¢獙绱犳潗瀛樺湪
+ ImChannelMaterialDO material = channelMaterialService.validateMaterialExists(reqVO.getMaterialId());
+
+ // 2.1 缁勮 payload锛堜笉甯﹀瘜鏂囨湰姝f枃锛夛紱瀛楁鍚屽悕鐩存帴 BeanUtils 鎷疯礉锛宮aterialId 鍗曠嫭 set 浠ュ吋瀹硅浆鍙戝満鏅�
+ MaterialMessage payload = BeanUtils.toBean(material, MaterialMessage.class).setMaterialId(material.getId());
+ String payloadJson = JsonUtils.toJsonString(payload);
+ // 2.2 钀藉簱 1 琛� message锛況eqVO 鍚屽悕瀛楁锛坢aterialId / receiverUserIds锛夎嚜鍔ㄦ嫹璐濓紝鍓╀綑瀛楁琛� set
+ ImChannelMessageDO message = BeanUtils.toBean(reqVO, ImChannelMessageDO.class).setChannelId(material.getChannelId())
+ .setType(ImContentTypeEnum.MATERIAL.getType()).setContent(payloadJson).setSendTime(LocalDateTime.now());
+ channelMessageMapper.insert(message);
+
+ // 3. 寮傛鎺� WebSocket锛氭寚瀹氱敤鎴疯蛋鐐瑰鐐癸紱鍏ㄥ憳锛坮eceiverUserIds 涓虹┖锛夎蛋骞挎挱
+ ImChannelMessageNotification dto = ImChannelMessageNotification.ofSend(message);
+ if (CollUtil.isNotEmpty(reqVO.getReceiverUserIds())) {
+ webSocketService.sendNotificationAsync(reqVO.getReceiverUserIds(), ImConversationTypeEnum.CHANNEL.getType(),
+ dto.getType(), dto);
+ } else {
+ webSocketService.broadcastNotificationAsync(ImConversationTypeEnum.CHANNEL.getType(), dto.getType(), dto);
+ }
+ return message.getId();
+ }
+
+ @Override
+ public PageResult<ImChannelMessageDO> getMessagePage(ImChannelMessagePageReqVO reqVO) {
+ return channelMessageMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public void deleteMessage(Long id) {
+ if (channelMessageMapper.selectById(id) == null) {
+ throw exception(IM_CHANNEL_MESSAGE_NOT_EXISTS);
+ }
+ channelMessageMapper.deleteById(id);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageService.java
new file mode 100644
index 0000000..77426d1
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageService.java
@@ -0,0 +1,130 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group.ImGroupMessageManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageListReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * IM 缇よ亰娑堟伅 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImGroupMessageService {
+
+ /**
+ * 銆愮敤鎴疯皟鐢ㄣ�戝彂閫佺兢鑱婃秷鎭�
+ * <p>
+ * 鐢ㄦ埛鍦� IM 瀹㈡埛绔彂閫� TEXT / IMAGE 绛夋秷鎭椂璋冪敤锛屽惈骞傜瓑銆佹晱鎰熻瘝銆乹uote銆丂 瑙f瀽绛変笟鍔℃牎楠屻��
+ * type 鏍¢獙鐢� VO 灞� {@code @InEnum} + {@code @AssertTrue} 瀹屾垚锛堜粎鍏佽 normal 绫诲瀷锛夈��
+ *
+ * @param senderId 鍙戦�佷汉缂栧彿
+ * @param reqVO 鍙戦�佽姹�
+ * @return 娑堟伅
+ */
+ ImGroupMessageDO sendGroupMessage(Long senderId, ImGroupMessageSendReqVO reqVO);
+
+ /**
+ * 銆愮郴缁熻皟鐢ㄣ�戝彂閫佺兢鑱婃秷鎭細鍐呴儴鏌� active 鎴愬憳 + 鎺ㄩ��
+ * <p>
+ * 璋冪敤鏂规壒閲忚皟鐢ㄤ細瑙﹀彂澶氭 active 鎴愬憳鏌ヨ锛涘鏋滆皟鐢ㄦ柟宸茬粡鎸佹湁鎴愬憳蹇収锛屼紭鍏堜娇鐢� {@link #sendGroupMessage(Long, Collection, ImGroupMessageSendDTO)} 鏂规硶锛岄伩鍏嶉噸澶嶆煡璇€��
+ *
+ * @param senderId 鍙戦�佷汉缂栧彿
+ * @param dto 娑堟伅 DTO
+ * @return 娑堟伅
+ */
+ ImGroupMessageDO sendGroupMessage(Long senderId, ImGroupMessageSendDTO dto);
+
+ /**
+ * 銆愮郴缁熻皟鐢ㄣ�戝彂閫佺兢鑱婃秷鎭細鏄惧紡鎸囧畾鎺ㄩ�佺洰鏍�
+ *
+ * @param senderId 鍙戦�佷汉缂栧彿
+ * @param targetUserIds 鎺ㄩ�佺洰鏍囩敤鎴风紪鍙烽泦鍚堬紙璋冪敤鏂瑰湪鍙樻洿鎴愬憳鐘舵�佸墠鎶撳彇鐨勫揩鐓э級
+ * @param dto 娑堟伅 DTO
+ * @return 鏋勯�犵殑娑堟伅 DO锛堟寔涔呭寲鏃� id 宸插洖濉級
+ */
+ ImGroupMessageDO sendGroupMessage(Long senderId, Collection<Long> targetUserIds, ImGroupMessageSendDTO dto);
+
+ /**
+ * 銆愮敤鎴疯皟鐢ㄣ�戞挙鍥炵兢鑱婃秷鎭�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param messageId 娑堟伅缂栧彿
+ * @return 鎾ゅ洖鍚庣殑鎻愮ず娑堟伅
+ */
+ ImGroupMessageDO recallGroupMessage(Long userId, Long messageId);
+
+ /**
+ * 鎷夊彇缇よ亰娑堟伅锛堝閲忥級
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param minId 鏈�灏忔秷鎭� id锛堜笉鍚級
+ * @param size 鎷夊彇鏁伴噺
+ * @return 娑堟伅鍒楄〃
+ */
+ List<ImGroupMessageDO> pullGroupMessageList(Long userId, Long minId, Integer size);
+
+ /**
+ * 鏍囪缇よ亰娑堟伅宸茶
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param groupId 缇ょ紪鍙�
+ * @param messageId 宸茶鍒扮殑娑堟伅缂栧彿
+ */
+ void readGroupMessages(Long userId, Long groupId, Long messageId);
+
+ /**
+ * 鑾峰彇缇ゆ秷鎭殑宸茶鐢ㄦ埛鍒楄〃
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param groupId 缇ょ紪鍙�
+ * @param messageId 娑堟伅缂栧彿
+ * @return 宸茶鐢ㄦ埛缂栧彿鍒楄〃
+ */
+ List<Long> getGroupReadUserIds(Long userId, Long groupId, Long messageId);
+
+ /**
+ * 鏌ヨ缇よ亰鍘嗗彶娑堟伅锛堟父鏍囨媺鍙栵級
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param reqVO 鎷夊彇璇锋眰
+ * @return 娑堟伅鍒楄〃锛堟寜 id 鍊掑簭锛�
+ */
+ List<ImGroupMessageDO> getGroupMessageList(Long userId, ImGroupMessageListReqVO reqVO);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝垎椤垫煡璇㈢兢鑱婃秷鎭�
+ */
+ PageResult<ImGroupMessageDO> getGroupMessagePage(ImGroupMessageManagerPageReqVO reqVO);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戣幏鍙栫兢鑱婃秷鎭鎯�
+ */
+ ImGroupMessageDO getGroupMessage(Long id);
+
+ /**
+ * 鎵归噺鎸夋秷鎭紪鍙锋煡璇㈢兢鑱婃秷鎭�
+ *
+ * @param ids 娑堟伅缂栧彿闆嗗悎
+ * @return 娑堟伅鍒楄〃
+ */
+ List<ImGroupMessageDO> getGroupMessageList(Collection<Long> ids);
+
+ /**
+ * 鎵归噺鎸夋秷鎭紪鍙锋煡璇㈢兢鑱婃秷鎭紝杩斿洖 messageId 鈫� DO 鏄犲皠
+ *
+ * @param ids 娑堟伅缂栧彿闆嗗悎
+ * @return 娑堟伅 Map锛坘ey = 娑堟伅缂栧彿锛�
+ */
+ Map<Long, ImGroupMessageDO> getGroupMessageMap(Collection<Long> ids);
+
+}
+
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImpl.java
new file mode 100644
index 0000000..12914fb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImpl.java
@@ -0,0 +1,548 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.group.ImGroupMessageManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageListReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.conversation.ImConversationReadService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.sensitiveword.ImSensitiveWordService;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImGroupMessageNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReadNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReceiptNotification;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.QuoteMessage;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.RecallMessage;
+import cn.iocoder.yudao.module.im.util.ImMessageUtils;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+
+/**
+ * IM 缇よ亰娑堟伅 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+@Slf4j
+public class ImGroupMessageServiceImpl implements ImGroupMessageService {
+
+ @Resource
+ private ImGroupMessageMapper groupMessageMapper;
+
+ @Resource
+ private ImGroupService groupService;
+ @Resource
+ private ImGroupMemberService groupMemberService;
+ @Resource
+ private ImSensitiveWordService sensitiveWordService;
+ @Resource
+ private ImConversationReadService conversationReadService;
+
+ @Resource
+ private ImWebSocketService imWebSocketService;
+
+ @Resource
+ private ImProperties imProperties;
+
+ @Override
+ public ImGroupMessageDO sendGroupMessage(Long senderId, ImGroupMessageSendReqVO reqVO) {
+ // 1.1 骞傜瓑鏍¢獙锛氭牴鎹� senderId + clientMessageId 鏌ラ噸
+ ImGroupMessageDO existing = groupMessageMapper.selectBySenderIdAndClientMessageId(
+ senderId, reqVO.getClientMessageId());
+ if (existing != null) {
+ log.info("[sendGroupMessage][骞傜瓑鍛戒腑 senderId({}) clientMessageId({}) 宸插瓨鍦ㄦ秷鎭�({})]",
+ senderId, reqVO.getClientMessageId(), existing.getId());
+ return existing;
+ }
+ // 1.2 娑堟伅鍐呭鏍¢獙
+ ImMessageUtils.validateUserMessageContent(reqVO.getType(), reqVO.getContent());
+ // 1.3 鏍¢獙缇ゅ瓨鍦ㄣ�佸彂閫佷汉浠嶅湪缇や腑
+ ImGroupDO group = groupService.validateGroupExists(reqVO.getGroupId());
+ ImGroupMemberDO senderMember = groupMemberService.validateMemberInGroup(reqVO.getGroupId(), senderId);
+ // 1.4 绂佽█鏍¢獙
+ validateMuteStatus(group, senderMember);
+ // 1.5 鏂囨湰娑堟伅鏁忔劅璇嶈繃婊�
+ if (ImContentTypeEnum.TEXT.getType().equals(reqVO.getType())) {
+ sensitiveWordService.validateText(reqVO.getContent());
+ }
+
+ // 2.1 鍥哄寲鍙戦�佸綋鏃跺彲瑙佹垚鍛樺揩鐓э細鐢ㄦ埛鍙戦�佸潎涓哄叏鍛樺箍鎾紱getReceiverUserIds 鍏滃簳绾冲叆鍙戦�佽�咃紝閽夋鍙戦�佽�呭繀鍙
+ List<Long> memberUserIds = groupMemberService.getActiveGroupMemberUserIdsByGroupId(reqVO.getGroupId());
+ Set<Long> receiverUserIds = getReceiverUserIds(null, senderId, memberUserIds);
+ // 2.2 寮曠敤 quote 娑堟伅瑙勮寖鍖栵紙鍚彲瑙佹�у瓙闆嗘牎楠岋紝闃叉瀹氬悜娑堟伅鍐呭琚箍鎾紩鐢ㄦ硠婕忥級
+ reqVO.setContent(normalizeQuoteContent(reqVO, senderMember, receiverUserIds));
+ // 2.3 鏋勫缓骞朵繚瀛樻秷鎭紱鍞竴閿啿绐佹椂鍥炴煡宸插瓨鍦ㄦ秷鎭繑鍥�
+ ImGroupMessageDO message = BeanUtils.toBean(reqVO, ImGroupMessageDO.class, m -> m
+ .setSenderId(senderId).setStatus(ImMessageStatusEnum.NORMAL.getStatus()).setSendTime(LocalDateTime.now())
+ .setReceiverUserIds(new ArrayList<>(receiverUserIds))
+ .setReceiptStatus(resolveReceiptStatus(reqVO.getReceipt())));
+ try {
+ groupMessageMapper.insert(message);
+ } catch (DuplicateKeyException e) {
+ log.warn("[sendGroupMessage][senderId({}) clientMessageId({}) 骞跺彂鎻掑叆鍐茬獊锛屽洖鏌ヨ繑鍥瀅",
+ senderId, reqVO.getClientMessageId());
+ return groupMessageMapper.selectBySenderIdAndClientMessageId(senderId, reqVO.getClientMessageId());
+ }
+
+ // 3. WebSocket 寮傛鎺ㄩ�侊紙蹇収鍐呭彲瑙佹垚鍛� + 鍙戦�佹柟澶氱鍚屾锛�
+ ImGroupMessageNotification notification = ImGroupMessageNotification.ofSend(message);
+ imWebSocketService.sendNotificationAsync(receiverUserIds, ImConversationTypeEnum.GROUP.getType(),
+ notification.getType(), notification);
+ return message;
+ }
+
+ @Override
+ public ImGroupMessageDO sendGroupMessage(Long senderId, ImGroupMessageSendDTO dto) {
+ List<Long> memberUserIds = groupMemberService.getActiveGroupMemberUserIdsByGroupId(dto.getGroupId());
+ Set<Long> receiverUserIds = getReceiverUserIds(dto.getReceiverUserIds(), senderId, memberUserIds);
+ return sendGroupMessage(senderId, receiverUserIds, dto);
+ }
+
+ @Override
+ public ImGroupMessageDO sendGroupMessage(Long senderId, Collection<Long> receiverUserIds, ImGroupMessageSendDTO dto) {
+ // 1.1 content 搴忓垪鍖栵細null / String 閫忎紶锛孭OJO 璧� JSON
+ Object payload = dto.getContent();
+ String contentString = payload == null || payload instanceof String
+ ? (String) payload
+ : JsonUtils.toJsonString(payload);
+ // 1.2 鏋勫缓骞朵繚瀛樻秷鎭�
+ ImGroupMessageDO message = new ImGroupMessageDO().setClientMessageId(IdUtil.fastSimpleUUID())
+ .setSenderId(senderId).setGroupId(dto.getGroupId())
+ .setType(dto.getType()).setContent(contentString)
+ .setStatus(ImMessageStatusEnum.NORMAL.getStatus()).setSendTime(LocalDateTime.now())
+ .setAtUserIds(dto.getAtUserIds()).setReceiverUserIds(new ArrayList<>(receiverUserIds))
+ .setReceiptStatus(resolveReceiptStatus(dto.getReceipt()));
+ // 1.3 鎸� type.persistent 鍐冲畾鏄惁鍏ュ簱
+ if (ImContentTypeEnum.validate(dto.getType()).isPersistent()) {
+ groupMessageMapper.insert(message);
+ }
+
+ // 2. WebSocket 寮傛鎺ㄩ��
+ ImGroupMessageNotification notification = ImGroupMessageNotification.ofSend(message);
+ imWebSocketService.sendNotificationAsync(receiverUserIds, ImConversationTypeEnum.GROUP.getType(),
+ notification.getType(), notification);
+ return message;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public ImGroupMessageDO recallGroupMessage(Long userId, Long messageId) {
+ // 1.1 鏍¢獙娑堟伅瀛樺湪
+ ImGroupMessageDO message = validateGroupMessageExists(messageId);
+ // 1.2 鏍¢獙鎾ゅ洖浜轰粛鍦ㄧ兢涓紝骞跺彇瑙掕壊鐢ㄤ簬鏉冮檺鍒ゆ柇
+ ImGroupMemberDO operator = groupMemberService.validateMemberInGroup(message.getGroupId(), userId);
+ boolean isOwnerOrAdmin = ImGroupMemberRoleEnum.isOwnerOrAdmin(operator.getRole());
+ // 1.3 鏅�氭垚鍛樺彧鑳芥挙鍥炶嚜宸卞彂鐨勬秷鎭紱缇や富 / 绠$悊鍛樺彲鎾ゅ洖浠栦汉杩濊娑堟伅
+ if (ObjUtil.notEqual(message.getSenderId(), userId) && !isOwnerOrAdmin) {
+ throw exception(MESSAGE_RECALL_DENIED);
+ }
+ // 1.4 涓嶈兘閲嶅鎾ゅ洖
+ if (ImMessageStatusEnum.RECALL.getStatus().equals(message.getStatus())) {
+ throw exception(MESSAGE_ALREADY_RECALLED);
+ }
+ // 1.5 鎾ゅ洖鏃堕棿绐椾粎绾︽潫鎾ゅ洖鑷繁鐨勬秷鎭紱缇や富 / 绠$悊鍛樻不鐞嗕粬浜鸿繚瑙勬秷鎭笉鍙楁椂闂撮檺鍒�
+ if (ObjUtil.equal(message.getSenderId(), userId)) {
+ int recallTimeoutMinutes = imProperties.getMessage().getRecallTimeoutMinutes();
+ if (message.getSendTime().plusMinutes(recallTimeoutMinutes).isBefore(LocalDateTime.now())) {
+ throw exception(MESSAGE_RECALL_TIMEOUT, recallTimeoutMinutes);
+ }
+ }
+
+ // 2. 鏇存柊鍘熸秷鎭姸鎬佷负鎾ゅ洖
+ groupMessageMapper.updateById(new ImGroupMessageDO().setId(messageId)
+ .setStatus(ImMessageStatusEnum.RECALL.getStatus()));
+
+ // 3. 鍙戦�佹挙鍥炰簨浠�
+ return sendGroupMessage(userId, new ImGroupMessageSendDTO().setGroupId(message.getGroupId())
+ .setType(ImContentTypeEnum.RECALL.getType())
+ .setReceiverUserIds(message.getReceiverUserIds())
+ .setContent(new RecallMessage().setMessageId(messageId)));
+ }
+
+ @Override
+ public List<ImGroupMessageDO> pullGroupMessageList(Long userId, Long minId, Integer size) {
+ int maxPullSize = imProperties.getMessage().getMaxPullSize();
+ if (size > maxPullSize) {
+ throw exception(MESSAGE_PULL_SIZE_EXCEEDED, maxPullSize);
+ }
+
+ // 0. 鎷夊彇鏃堕棿绐楋紱瓒呰繃绐楀彛鐨勮�佹秷鎭笉鍐嶉�氳繃绂荤嚎閫氶亾鎺ㄩ��
+ LocalDateTime minSendTime = LocalDateTime.now().minusDays(imProperties.getMessage().getGroupPullMaxDays());
+
+ // 1. 鍊欓�夌兢 = 鐢ㄦ埛鏇剧粡鍔犲叆鐨勬墍鏈夌兢锛堝惈閫�缇わ級锛涘彲瑙佹�т笌鏃堕棿绐楅兘浜ょ粰 SQL锛岄��缇ょ兢鏈�澶氳础鐚� 0 鏉�
+ Set<Long> groupIds = convertSet(groupMemberService.getGroupMemberListByUserId(userId),
+ ImGroupMemberDO::getGroupId);
+ if (CollUtil.isEmpty(groupIds)) {
+ return Collections.emptyList();
+ }
+
+ // 2. 鎸� receiver_user_ids 蹇収杩囨护鍙鎬э紝缁撴灉鎸� id 鍗囧簭
+ List<ImGroupMessageDO> messages = groupMessageMapper.selectListByMinId(userId, groupIds, minId, minSendTime, size);
+
+ // 3. 琛ラ綈鏈汉鍙戦�佺殑鍥炴墽娑堟伅鐨勫凡璇讳汉鏁�
+ appendMessageReceipt(userId, messages);
+ log.info("[pullGroupMessageList][userId({}) minId({}) size({}) result({})]", userId, minId, size, messages.size());
+ return messages;
+ }
+
+ /**
+ * 琛ュ叏鏈汉鍙戦�佹秷鎭殑鍥炴墽宸茶浜烘暟锛坮eadCount锛�
+ * <p>
+ * 浠呭鏈汉鍙戦�併�佷笖闇�瑕佸洖鎵э紙闈� NO_RECEIPT锛夌殑娑堟伅锛屾寜 receiver_user_ids 蹇収 鈭� 褰撳墠鏈夋晥鎴愬憳 - 鍙戦�佽�� 绠楀凡璇讳汉鏁�
+ */
+ @SuppressWarnings("DataFlowIssue")
+ private void appendMessageReceipt(Long userId, List<ImGroupMessageDO> messages) {
+ if (CollUtil.isEmpty(messages)) {
+ return;
+ }
+ // 缇ゅ凡璇诲叧闂細涓嶈ˉ readCount
+ if (BooleanUtil.isFalse(imProperties.getMessage().isGroupReadEnabled())) {
+ return;
+ }
+ Map<Long, Map<Long, Long>> readPositionsByGroup = new HashMap<>(); // 缇� 鈫� (鐢ㄦ埛 鈫� 宸茶浣嶇疆)
+ Map<Long, List<ImGroupMemberDO>> membersByGroup = new HashMap<>(); // 缇� 鈫� 鍏ㄩ儴鎴愬憳鍒楄〃
+ for (ImGroupMessageDO message : messages) {
+ // 浠呰ˉ鏈汉鍙戦�併�佷笖闇�瑕佸洖鎵э紙闈� NO_RECEIPT锛夌殑娑堟伅
+ if (ObjUtil.notEqual(message.getSenderId(), userId)
+ || ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus().equals(message.getReceiptStatus())) {
+ continue;
+ }
+ Long groupId = message.getGroupId();
+ Map<Long, Long> positions = readPositionsByGroup.computeIfAbsent(groupId,
+ gid -> conversationReadService.getUserReadMessageIdMap(ImConversationTypeEnum.GROUP.getType(), gid));
+ // 搴旇鍒嗘瘝鍙栧綋鍓嶆湁鏁堟垚鍛橈紙鍓旈櫎宸查��缇わ級锛屼笌寮傛鍥炴墽鍒锋柊銆佸墠绔凡璇诲脊灞傚彛寰勪竴鑷�
+ List<ImGroupMemberDO> activeMembers = membersByGroup.computeIfAbsent(groupId,
+ groupMemberService::getActiveGroupMemberListByGroupId);
+ Set<Long> receiverUserIds = getReceiverUserIds(message, activeMembers);
+ receiverUserIds.remove(message.getSenderId());
+ int readCount = getSumValue(receiverUserIds,
+ uid -> positions.getOrDefault(uid, -1L) >= message.getId() ? 1 : null,
+ Integer::sum, 0);
+ message.setReadCount(readCount);
+ }
+ }
+
+ @Override
+ public void readGroupMessages(Long userId, Long groupId, Long messageId) {
+ // 0. 鍏ㄥ眬寮�鍏虫牎楠�
+ if (BooleanUtil.isFalse(imProperties.getMessage().isGroupReadEnabled())) {
+ throw exception(MESSAGE_GROUP_READ_DISABLED);
+ }
+ Assert.notNull(messageId, "宸茶娑堟伅缂栧彿涓嶈兘涓虹┖");
+ // 1. 鏍¢獙娑堟伅灞炰簬褰撳墠缇わ紝涓斿褰撳墠鐢ㄦ埛鍙锛堟寜蹇収锛�
+ ImGroupMessageDO message = groupMessageMapper.selectById(messageId);
+ if (message == null
+ || ObjUtil.notEqual(message.getGroupId(), groupId)
+ || !isMessageReceived(message, userId)) {
+ throw exception(MESSAGE_NOT_IN_GROUP);
+ }
+
+ // 2. 鍙栨棫璇讳綅缃紙鐢ㄤ簬鍥炴墽鍒锋柊鍖洪棿锛夛紝鍐嶆洿鏂扮兢宸茶浣嶇疆锛涜浣嶇疆鏈墠杩涘垯涓嶆帹
+ Long prevMaxMessageId = conversationReadService.getConversationReadMessageId(
+ userId, ImConversationTypeEnum.GROUP.getType(), groupId);
+ boolean advanced = conversationReadService.updateConversationReadPosition(
+ userId, ImConversationTypeEnum.GROUP.getType(), groupId, messageId);
+ if (!advanced) {
+ return;
+ }
+
+ // 3. 寮傛鍙戦�� READ 浜嬩欢 + 鍒锋柊鑼冨洿鍐呯殑缇ゅ洖鎵�
+ getSelf().readGroupMessageEvent(userId, groupId, prevMaxMessageId, messageId);
+ }
+
+ @Override
+ public List<Long> getGroupReadUserIds(Long userId, Long groupId, Long messageId) {
+ // 0. 鍏ㄥ眬寮�鍏虫牎楠�
+ if (BooleanUtil.isFalse(imProperties.getMessage().isGroupReadEnabled())) {
+ throw exception(MESSAGE_GROUP_READ_DISABLED);
+ }
+ // 1.1 鏍¢獙鐢ㄦ埛鍦ㄧ兢涓紙鏉冮檺鏍¢獙锛�
+ groupMemberService.validateMemberInGroup(groupId, userId);
+ // 1.2 鑾峰彇娑堟伅锛涘苟鏍¢獙娑堟伅褰掑睘浜庤缇ゃ�佸璋冪敤鑰呭彲瑙併�佽皟鐢ㄨ�呮槸鍙戦�佹柟
+ ImGroupMessageDO message = groupMessageMapper.selectById(messageId);
+ if (message == null || ObjUtil.notEqual(message.getGroupId(), groupId)) {
+ return Collections.emptyList();
+ }
+ if (!isMessageReceived(message, userId)) {
+ return Collections.emptyList();
+ }
+ // 1.3 浠呮秷鎭彂閫佹柟鍏冲績宸茶浜烘暟锛涢潪鍙戦�佹柟鏌ヨ鐩存帴杩斿洖绌�
+ if (ObjUtil.notEqual(message.getSenderId(), userId)) {
+ return Collections.emptyList();
+ }
+
+ // 2. 鑾峰彇褰撳墠鏈夋晥鎴愬憳鍜屽凡璇讳綅缃紙鍓旈櫎宸查��缇わ紝涓庡洖鎵у垎姣嶅彛寰勪竴鑷达級
+ List<ImGroupMemberDO> activeMembers = groupMemberService.getActiveGroupMemberListByGroupId(groupId);
+ Map<Long, Long> allPositions = conversationReadService.getUserReadMessageIdMap(
+ ImConversationTypeEnum.GROUP.getType(), groupId);
+
+ // 3. 璁$畻璇ユ秷鎭殑鍙鎴愬憳闆嗗悎锛堟帓闄ゅ彂閫佽�呰嚜宸憋級
+ Set<Long> receiverUserIds = getReceiverUserIds(message, activeMembers);
+ receiverUserIds.remove(message.getSenderId());
+
+ // 4. 鍙繑鍥炲湪鍙鑼冨洿鍐呬笖宸茶浣嶇疆 >= messageId 鐨勭敤鎴�
+ List<Long> readUserIds = new ArrayList<>();
+ allPositions.forEach((uid, readMaxMessageId) -> {
+ if (receiverUserIds.contains(uid) && readMaxMessageId >= messageId) {
+ readUserIds.add(uid);
+ }
+ });
+ return readUserIds;
+ }
+
+ @Override
+ public List<ImGroupMessageDO> getGroupMessageList(Long userId, ImGroupMessageListReqVO reqVO) {
+ // 1. 鏍¢獙鐢ㄦ埛鏇剧粡鍦ㄧ兢锛堝綋鍓嶅湪缇ゆ垨宸查��缇わ級锛屼笌 pull 閫�缇ょ獥鍙e彛寰勪竴鑷达紱鍐呭浠嶇敱 receiver_user_ids 蹇収杩囨护
+ if (groupMemberService.getGroupMember(reqVO.getGroupId(), userId) == null) {
+ throw exception(GROUP_MEMBER_NOT_IN_GROUP);
+ }
+
+ // 2. 鏌ヨ鍘嗗彶娑堟伅锛歋QL 宸叉寜 receiver_user_ids 蹇収杩囨护褰撳墠鐢ㄦ埛鍙
+ return groupMessageMapper.selectHistoryListByUser(
+ userId, reqVO.getGroupId(), reqVO.getMaxId(), reqVO.getLimit());
+ }
+
+ // ========== 寮傛 WebSocket 鎺ㄩ�� ==========
+
+ /**
+ * 鍙戦�佸凡璇� + 鍒锋柊缇ゅ洖鎵� WebSocket 浜嬩欢
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param groupId 缇ょ紪鍙�
+ * @param prevMaxMessageId 涓婃宸茶浣嶇疆
+ * @param newMaxMessageId 鏈宸茶浣嶇疆
+ */
+ @Async
+ @SuppressWarnings("DataFlowIssue")
+ public void readGroupMessageEvent(Long userId, Long groupId, Long prevMaxMessageId, Long newMaxMessageId) {
+ // 1. 鍙戦�� READ 浜嬩欢缁欒嚜宸辩殑鍏朵粬缁堢锛堝绔悓姝ワ級
+ imWebSocketService.sendNotificationAsync(userId, ImConversationTypeEnum.GROUP.getType(),
+ ImContentTypeEnum.READ.getType(),
+ ImMessageReadNotification.ofGroup(userId, groupId, newMaxMessageId));
+
+ // 2. 鍒锋柊 (prevMaxMessageId, newMaxMessageId] 鍖洪棿鍐呯殑寰呭洖鎵ф秷鎭�
+ List<ImGroupMessageDO> pendingMessages = groupMessageMapper.selectListByGroupIdAndPendingReceipt(
+ groupId, prevMaxMessageId, newMaxMessageId);
+ if (CollUtil.isEmpty(pendingMessages)) {
+ return;
+ }
+ List<ImGroupMemberDO> activeMembers = groupMemberService.getActiveGroupMemberListByGroupId(groupId);
+ Map<Long, Long> allPositions = conversationReadService.getUserReadMessageIdMap(
+ ImConversationTypeEnum.GROUP.getType(), groupId);
+ for (ImGroupMessageDO message : pendingMessages) {
+ // 2.1.1 缁熻鍙鎴愬憳涓殑宸茶浜烘暟锛堝簲璇诲垎姣� = 蹇収 鈭� 褰撳墠鏈夋晥鎴愬憳 - sender锛�
+ Set<Long> receiverUserIds = getReceiverUserIds(message, activeMembers);
+ receiverUserIds.remove(message.getSenderId()); // 鍙戦�佽�呰嚜宸变笉绠楀凡璇�
+ if (CollUtil.isEmpty(receiverUserIds)) {
+ continue;
+ }
+ int readCount = getSumValue(receiverUserIds,
+ uid -> allPositions.getOrDefault(uid, -1L) >= message.getId() ? 1 : null,
+ Integer::sum, 0);
+ // 2.1.2 鍏ㄩ儴宸茶 鈫� 鏍囪鍥炴墽瀹屾垚
+ Integer newReceiptStatus = ImMessageReceiptStatusEnum.PENDING.getStatus();
+ if (readCount >= receiverUserIds.size()) {
+ newReceiptStatus = ImMessageReceiptStatusEnum.DONE.getStatus();
+ groupMessageMapper.updateById(new ImGroupMessageDO().setId(message.getId())
+ .setReceiptStatus(newReceiptStatus));
+ }
+
+ // 2.2 鍙戦�� RECEIPT 浜嬩欢缁欐秷鎭彂閫佹柟锛堝彧鏈� ta 鍏冲績宸茶杩涘害锛�
+ imWebSocketService.sendNotificationAsync(message.getSenderId(), ImConversationTypeEnum.GROUP.getType(),
+ ImContentTypeEnum.RECEIPT.getType(),
+ ImMessageReceiptNotification.ofGroup(message.getId(), groupId, readCount, newReceiptStatus));
+ }
+ }
+
+ // ========== 绉佹湁宸ュ叿鏂规硶 ==========
+
+ /**
+ * 缇よ亰寮曠敤娑堟伅瑙勮寖鍖�
+ *
+ * @param reqVO 鍙戦�佽姹�
+ * @param senderMember 鍙戦�佷汉鎴愬憳
+ * @param newAudience 鏂版秷鎭彲瑙佹垚鍛橀泦鍚堬紙鍙戦�佸綋鏃跺揩鐓э級
+ * @return 瑙勮寖鍖栧悗鐨� content
+ */
+ private String normalizeQuoteContent(ImGroupMessageSendReqVO reqVO, ImGroupMemberDO senderMember,
+ Set<Long> newAudience) {
+ // 瑙f瀽瀹㈡埛绔� content 閲岀殑 quote.messageId
+ Long quoteMessageId = ImMessageUtils.parseQuoteMessageId(reqVO.getContent());
+
+ // 鎯呭喌涓�锛氭病鏈� quoteMessageId锛岀洿鎺� remove 鎺� content 閲屽彲鑳戒吉閫犵殑 quote 瀛楁
+ if (quoteMessageId == null) {
+ return ImMessageUtils.removeQuote(reqVO.getContent());
+ }
+
+ // 鎯呭喌浜岋細鏈� quoteMessageId锛屽姞杞藉師娑堟伅骞舵牎楠�
+ ImGroupMessageDO original = groupMessageMapper.selectById(quoteMessageId);
+ if (original == null
+ || ImMessageStatusEnum.RECALL.getStatus().equals(original.getStatus())) {
+ throw exception(MESSAGE_QUOTE_INVALID);
+ }
+ // 鏍¢獙鏄悓缇�
+ if (ObjUtil.notEqual(original.getGroupId(), reqVO.getGroupId())) {
+ throw exception(MESSAGE_QUOTE_INVALID);
+ }
+ // 鏍¢獙瀵瑰彂閫佷汉鍙锛堟寜蹇収锛�
+ if (!isMessageReceived(original, senderMember.getUserId())) {
+ throw exception(MESSAGE_QUOTE_INVALID);
+ }
+ // 闃叉硠婕忥細鏂版秷鎭彲瑙侀泦鍚堝繀椤绘槸琚紩鐢ㄦ秷鎭彲瑙侀泦鍚堢殑瀛愰泦锛屽惁鍒欑姝㈠紩鐢紱
+ // 鍚﹀垯鍙閮ㄥ垎鎴愬憳鍙鐨勫畾鍚戞秷鎭唴瀹癸紝浼氶殢骞挎挱寮曠敤娉勬紡缁欏師鏈湅涓嶅埌鐨勬垚鍛�
+ if (!new HashSet<>(original.getReceiverUserIds()).containsAll(newAudience)) {
+ throw exception(MESSAGE_QUOTE_INVALID);
+ }
+ // 鏋勫缓 quote 瀵硅薄骞舵敞鍏� content
+ QuoteMessage quote = ImMessageUtils.buildQuote(original.getId(),
+ original.getSenderId(), original.getType(), original.getContent());
+ return ImMessageUtils.appendQuote(reqVO.getContent(), quote);
+ }
+
+ /**
+ * 鏍¢獙缇よ亰娑堟伅瀛樺湪
+ *
+ * @param messageId 娑堟伅缂栧彿
+ * @return 缇よ亰娑堟伅
+ */
+ private ImGroupMessageDO validateGroupMessageExists(Long messageId) {
+ ImGroupMessageDO message = groupMessageMapper.selectById(messageId);
+ if (message == null) {
+ throw exception(MESSAGE_NOT_EXISTS);
+ }
+ return message;
+ }
+
+ /**
+ * 鍒ゆ柇涓�鏉$兢娑堟伅鏄惁琚煇涓敤鎴锋帴鏀跺埌
+ * <p>
+ * 鎺ユ敹鑼冨洿浠ュ彂閫佸綋鏃跺浐鍖栫殑 receiver_user_ids 蹇収涓哄噯锛涘彂閫佽�呬篃鍦ㄥ揩鐓у唴銆�
+ *
+ * @param message 娑堟伅
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @return 鏄惁鎺ユ敹鍒�
+ */
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ private boolean isMessageReceived(ImGroupMessageDO message, Long userId) {
+ return CollUtil.contains(message.getReceiverUserIds(), userId);
+ }
+
+ /**
+ * 璁$畻涓�鏉$兢娑堟伅鐨勫彲瑙佹垚鍛橀泦鍚堬紙蹇収涓庝紶鍏ユ垚鍛樼殑浜ら泦锛屽惈鍙戦�佽�咃級
+ */
+ private Set<Long> getReceiverUserIds(ImGroupMessageDO message, List<ImGroupMemberDO> members) {
+ if (CollUtil.isEmpty(message.getReceiverUserIds())) {
+ return new HashSet<>();
+ }
+ Set<Long> snapshot = new HashSet<>(message.getReceiverUserIds());
+ return convertSet(members, ImGroupMemberDO::getUserId, member -> snapshot.contains(member.getUserId()));
+ }
+
+ /**
+ * 鍩轰簬缇ゆ垚鍛� userId 鍒楄〃锛岃绠椾竴鏉℃柊娑堟伅鐨勫彲瑙佹垚鍛樺揩鐓э紙鍚彂閫佽�咃級銆�
+ * <p>
+ * 浠呴�傜敤浜庛�屾柊娑堟伅銆嶅彂閫佸満鏅細鏃犲畾鍚戞帴鏀跺垪琛ㄥ垯鍏ㄥ憳鍙锛屽惁鍒欏彇瀹氬悜鐢ㄦ埛涓庡綋鍓嶆垚鍛樼殑浜ら泦锛�
+ * 鍙戦�佽�呭缁堢撼鍏ュ揩鐓э紝淇濊瘉 receiver_user_ids 闈炵┖涓斿彂閫佹柟鍙銆�
+ */
+ private Set<Long> getReceiverUserIds(List<Long> directedUserIds, Long senderId, Collection<Long> memberUserIds) {
+ // 鏃犲畾鍚戞帴鏀跺垪琛� 鈫� 鍏ㄥ憳鍙锛涘惁鍒欏彇瀹氬悜鐢ㄦ埛涓庡綋鍓嶆垚鍛樼殑浜ら泦
+ Set<Long> result = CollUtil.isEmpty(directedUserIds)
+ ? new HashSet<>(memberUserIds)
+ : new HashSet<>(CollUtil.intersection(memberUserIds, directedUserIds));
+ // 鍙戦�佽�呭缁堝彲瑙侊紙澶氱鍚屾锛夛紝鍗充究鎴愬憳缂撳瓨鏆傛湭鍖呭惈
+ if (senderId != null) {
+ result.add(senderId);
+ }
+ return result;
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImGroupMessageDO> getGroupMessagePage(ImGroupMessageManagerPageReqVO reqVO) {
+ return groupMessageMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public ImGroupMessageDO getGroupMessage(Long id) {
+ return groupMessageMapper.selectById(id);
+ }
+
+ @Override
+ public List<ImGroupMessageDO> getGroupMessageList(Collection<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return Collections.emptyList();
+ }
+ return groupMessageMapper.selectByIds(ids);
+ }
+
+ @Override
+ public Map<Long, ImGroupMessageDO> getGroupMessageMap(Collection<Long> ids) {
+ return convertMap(getGroupMessageList(ids), ImGroupMessageDO::getId);
+ }
+
+ private ImGroupMessageServiceImpl getSelf() {
+ return SpringUtil.getBean(getClass());
+ }
+
+ /**
+ * 璁$畻缇ゆ秷鎭洖鎵� status锛氱兢宸茶鍏抽棴鏃跺己鍒� NO_RECEIPT锛屽拷鐣ュ彂閫佹柟浼犲叆鐨� receipt锛坮eceipt 涓� null 绛変环 false锛�
+ */
+ private Integer resolveReceiptStatus(Boolean receipt) {
+ if (BooleanUtil.isFalse(imProperties.getMessage().isGroupReadEnabled())) {
+ return ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus();
+ }
+ return BooleanUtil.isTrue(receipt)
+ ? ImMessageReceiptStatusEnum.PENDING.getStatus()
+ : ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus();
+ }
+
+ /**
+ * 绂佽█鐘舵�佹牎楠岋細鍏ㄧ兢绂佽█ 鈫� 鎴愬憳绂佽█锛涚兢涓� / 绠$悊鍛樿眮鍏嶅叏缇ょ瑷�
+ */
+ private void validateMuteStatus(ImGroupDO group, ImGroupMemberDO senderMember) {
+ boolean isOwnerOrAdmin = ImGroupMemberRoleEnum.isOwnerOrAdmin(senderMember.getRole());
+ // 1. 鍏ㄧ兢绂佽█锛氱兢涓� / 绠$悊鍛樿眮鍏�
+ if (Boolean.TRUE.equals(group.getMutedAll()) && !isOwnerOrAdmin) {
+ throw exception(GROUP_MUTED_CANNOT_SEND);
+ }
+ // 2. 鎴愬憳绂佽█
+ if (senderMember.getMuteEndTime() != null && senderMember.getMuteEndTime().isAfter(LocalDateTime.now())) {
+ throw exception(GROUP_MEMBER_MUTED_CANNOT_SEND, senderMember.getMuteEndTime());
+ }
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageService.java
new file mode 100644
index 0000000..23ac9b3
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageService.java
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates.ImPrivateMessageManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageListReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO;
+
+import java.util.List;
+
+/**
+ * IM 绉佽亰娑堟伅 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImPrivateMessageService {
+
+ /**
+ * 銆愮敤鎴疯皟鐢ㄣ�戝彂閫佺鑱婃秷鎭�
+ * <p>
+ * 鐢ㄦ埛鍦� IM 瀹㈡埛绔彂閫� TEXT / IMAGE 绛夋秷鎭椂璋冪敤锛屽惈骞傜瓑銆佸ソ鍙嬫牎楠屻�佹晱鎰熻瘝銆乹uote 瑙f瀽绛変笟鍔℃牎楠屻��
+ * type 鏍¢獙鐢� VO 灞� {@code @InEnum} + {@code @AssertTrue} 瀹屾垚锛堜粎鍏佽 normal 绫诲瀷锛夈��
+ *
+ * @param senderId 鍙戦�佷汉缂栧彿
+ * @param reqVO 鍙戦�佽姹�
+ * @return 娑堟伅
+ */
+ ImPrivateMessageDO sendPrivateMessage(Long senderId, ImPrivateMessageSendReqVO reqVO);
+
+ /**
+ * 銆愮郴缁熻皟鐢ㄣ�戝彂閫佺鑱婃秷鎭�
+ *
+ * @param senderId 鍙戦�佷汉缂栧彿
+ * @param dto 娑堟伅 DTO
+ * @return 鏋勯�犵殑娑堟伅 DO锛堟寔涔呭寲鏃� id 宸插洖濉級
+ */
+ ImPrivateMessageDO sendPrivateMessage(Long senderId, ImPrivateMessageSendDTO dto);
+
+ /**
+ * 銆愮敤鎴疯皟鐢ㄣ�戞挙鍥炵鑱婃秷鎭�
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param messageId 娑堟伅缂栧彿
+ * @return 鎾ゅ洖鍚庣殑娑堟伅
+ */
+ ImPrivateMessageDO recallPrivateMessage(Long userId, Long messageId);
+
+ /**
+ * 鎷夊彇绉佽亰娑堟伅锛堝閲忥級
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param minId 鏈�灏忔秷鎭� id锛堜笉鍚級
+ * @param size 鎷夊彇鏁伴噺
+ * @return 娑堟伅鍒楄〃
+ */
+ List<ImPrivateMessageDO> pullPrivateMessageList(Long userId, Long minId, Integer size);
+
+ /**
+ * 鏍囪绉佽亰娑堟伅宸茶
+ * <p>
+ * 璇箟锛氭妸銆屽鏂瑰彂缁欏綋鍓嶇敤鎴枫�乮d <= messageId 鐨勫緟鍥炴墽娑堟伅銆嶄竴娆℃�ф洿鏂颁负宸插畬鎴愶紙DONE锛夊苟鍓嶈繘璇讳綅缃紝
+ * 涓庣兢鑱� readGroupMessages 瀵圭О锛岄伩鍏嶃�宻elect-then-update銆嶄袱姝ュ紡甯︽潵鐨勭珵鎬併��
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param receiverId 鎺ユ敹鏂圭敤鎴风紪鍙凤紙瀵规柟锛�
+ * @param messageId 宸茶浣嶇疆锛堝惈锛夛紝閫氬父鏄墠绔細璇濆唴鏈�澶ф秷鎭� id
+ */
+ void readPrivateMessages(Long userId, Long receiverId, Long messageId);
+
+ /**
+ * 鏌ヨ瀵规柟宸茶鍒版垜鍙戠殑鏈�澶ф秷鎭� id
+ * <p>
+ * 鐢ㄤ簬澶氱 / 绂荤嚎鍦烘櫙涓嬬殑宸茶浣嶇疆琛ラ綈锛氬鎴风杩涘叆浼氳瘽鎴栨柇绾块噸杩炲悗锛�
+ * 璋冪敤姝ゆ帴鍙f嬁鍒板鏂圭殑 maxReadId锛屽啀鎸� id <= maxReadId 鏇存柊鏈湴鑷彂娑堟伅鐨勫洖鎵х姸鎬侊紝寮ヨˉ绂荤嚎鏈熼棿閿欒繃鐨� RECEIPT 鎺ㄩ�佷簨浠躲��
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param peerId 瀵规柟鐢ㄦ埛缂栧彿
+ * @return 瀵规柟宸茶鍒扮殑鏈�澶ф秷鎭� id锛涘鏂逛竴鏉¢兘娌¤杩囨椂杩斿洖 null
+ */
+ Long getMaxReadMessageId(Long userId, Long peerId);
+
+ /**
+ * 鏌ヨ绉佽亰鍘嗗彶娑堟伅锛堟父鏍囨媺鍙栵級
+ *
+ * @param userId 褰撳墠鐢ㄦ埛缂栧彿
+ * @param reqVO 鎷夊彇璇锋眰
+ * @return 娑堟伅鍒楄〃锛堟寜 id 鍊掑簭锛�
+ */
+ List<ImPrivateMessageDO> getPrivateMessageList(Long userId, ImPrivateMessageListReqVO reqVO);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝垎椤垫煡璇㈢鑱婃秷鎭�
+ */
+ PageResult<ImPrivateMessageDO> getPrivateMessagePage(ImPrivateMessageManagerPageReqVO reqVO);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戣幏鍙栫鑱婃秷鎭鎯�
+ */
+ ImPrivateMessageDO getPrivateMessage(Long id);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImpl.java
new file mode 100644
index 0000000..de79f9e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImpl.java
@@ -0,0 +1,297 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.message.vo.privates.ImPrivateMessageManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageListReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImPrivateMessageMapper;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.conversation.ImConversationReadService;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.sensitiveword.ImSensitiveWordService;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReadNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReceiptNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImPrivateMessageNotification;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.QuoteMessage;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.RecallMessage;
+import cn.iocoder.yudao.module.im.util.ImMessageUtils;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+
+/**
+ * IM 绉佽亰娑堟伅 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+@Slf4j
+public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
+
+ @Resource
+ private ImPrivateMessageMapper privateMessageMapper;
+
+ @Resource
+ private ImFriendService friendService;
+ @Resource
+ private ImSensitiveWordService sensitiveWordService;
+ @Resource
+ private ImConversationReadService conversationReadService;
+
+ @Resource
+ private ImWebSocketService imWebSocketService;
+
+ @Resource
+ private ImProperties imProperties;
+
+ @Override
+ public ImPrivateMessageDO sendPrivateMessage(Long senderId, ImPrivateMessageSendReqVO reqVO) {
+ // 1.1 骞傜瓑鏍¢獙锛氭牴鎹� senderId + clientMessageId 鏌ラ噸
+ ImPrivateMessageDO existing = privateMessageMapper.selectBySenderIdAndClientMessageId(
+ senderId, reqVO.getClientMessageId());
+ if (existing != null) {
+ log.info("[sendPrivateMessage][骞傜瓑鍛戒腑 senderId({}) clientMessageId({}) 宸插瓨鍦ㄦ秷鎭�({})]",
+ senderId, reqVO.getClientMessageId(), existing.getId());
+ return existing;
+ }
+ // 1.2 娑堟伅鍐呭鏍¢獙
+ ImMessageUtils.validateUserMessageContent(reqVO.getType(), reqVO.getContent());
+ // 1.3 濂藉弸鏍¢獙
+ friendService.validateFriend(senderId, reqVO.getReceiverId());
+ // 1.4 鏂囨湰娑堟伅鏁忔劅璇嶈繃婊�
+ if (ImContentTypeEnum.TEXT.getType().equals(reqVO.getType())) {
+ sensitiveWordService.validateText(reqVO.getContent());
+ }
+
+ // 2.1 寮曠敤 quote 娑堟伅瑙勮寖鍖�
+ reqVO.setContent(normalizeQuoteContent(reqVO, senderId));
+ // 2.2 鏋勫缓骞朵繚瀛樻秷鎭紱鍞竴閿啿绐佹椂鍥炴煡宸插瓨鍦ㄦ秷鎭繑鍥�
+ // 鐢ㄦ埛绉佽亰娑堟伅榛樿闇�瑕佸洖鎵э紙receipt 涓嶄紶鎸� true锛夛紱绯荤粺閫氱煡璧� DTO 閫氶亾锛岄粯璁や笉鍥炴墽
+ Boolean receipt = reqVO.getReceipt() != null ? reqVO.getReceipt() : Boolean.TRUE;
+ ImPrivateMessageDO message = BeanUtils.toBean(reqVO, ImPrivateMessageDO.class, m -> m
+ .setSenderId(senderId).setStatus(ImMessageStatusEnum.NORMAL.getStatus())
+ .setReceiptStatus(resolveReceiptStatus(receipt)).setSendTime(LocalDateTime.now()));
+ try {
+ privateMessageMapper.insert(message);
+ } catch (DuplicateKeyException e) {
+ log.warn("[sendPrivateMessage][senderId({}) clientMessageId({}) 骞跺彂鎻掑叆鍐茬獊锛屽洖鏌ヨ繑鍥瀅",
+ senderId, reqVO.getClientMessageId());
+ return privateMessageMapper.selectBySenderIdAndClientMessageId(senderId, reqVO.getClientMessageId());
+ }
+
+ // 3. WebSocket 寮傛鎺ㄩ�侊細鎺ユ敹鏂� + 鍙戦�佹柟澶氱鍚屾
+ ImPrivateMessageNotification notification = ImPrivateMessageNotification.ofSend(message);
+ imWebSocketService.sendNotificationAsync(message.getReceiverId(), ImConversationTypeEnum.PRIVATE.getType(),
+ notification.getType(), notification);
+ imWebSocketService.sendNotificationAsync(senderId, ImConversationTypeEnum.PRIVATE.getType(),
+ notification.getType(), notification);
+ return message;
+ }
+
+ @Override
+ public ImPrivateMessageDO sendPrivateMessage(Long senderId, ImPrivateMessageSendDTO dto) {
+ // 1.1 content 搴忓垪鍖栵細null / String 閫忎紶锛孭OJO 璧� JSON
+ Object payload = dto.getContent();
+ String contentString = payload == null || payload instanceof String
+ ? (String) payload
+ : JsonUtils.toJsonString(payload);
+ // 1.2 鏋勫缓娑堟伅
+ ImPrivateMessageDO message = new ImPrivateMessageDO().setClientMessageId(IdUtil.fastSimpleUUID())
+ .setSenderId(senderId).setReceiverId(dto.getReceiverId())
+ .setType(dto.getType()).setContent(contentString)
+ .setStatus(ImMessageStatusEnum.NORMAL.getStatus())
+ .setReceiptStatus(resolveReceiptStatus(dto.getReceipt())).setSendTime(LocalDateTime.now());
+ // 1.3 鍐冲畾鏄惁鎸佷箙鍖栵細dto.persistent 浼樺厛锛涗负 null 鏃舵寜 type 榛樿
+ boolean persistent = dto.getPersistent() != null
+ ? dto.getPersistent()
+ : ImContentTypeEnum.validate(dto.getType()).isPersistent();
+ if (persistent) {
+ privateMessageMapper.insert(message);
+ }
+
+ // 2. WebSocket 寮傛鎺ㄩ�侊細鍙屽悜锛堥粯璁わ級锛涘崟杈硅涔夛紙persistent=false锛変笅浠呮帹 sender 澶氱锛屽鏂逛笉鎰熺煡
+ ImPrivateMessageNotification notification = ImPrivateMessageNotification.ofSend(message);
+ if (persistent) {
+ imWebSocketService.sendNotificationAsync(dto.getReceiverId(), ImConversationTypeEnum.PRIVATE.getType(),
+ notification.getType(), notification);
+ }
+ imWebSocketService.sendNotificationAsync(senderId, ImConversationTypeEnum.PRIVATE.getType(),
+ notification.getType(), notification);
+ return message;
+ }
+
+ /**
+ * 璁$畻绉佽亰娑堟伅鍥炴墽 status锛氱鑱婂凡璇诲叧闂椂寮哄埗 NO_RECEIPT锛屽拷鐣ュ彂閫佹柟浼犲叆鐨� receipt锛坮eceipt 涓� null 绛変环 false锛�
+ */
+ private Integer resolveReceiptStatus(Boolean receipt) {
+ if (BooleanUtil.isFalse(imProperties.getMessage().isPrivateReadEnabled())) {
+ return ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus();
+ }
+ return BooleanUtil.isTrue(receipt)
+ ? ImMessageReceiptStatusEnum.PENDING.getStatus()
+ : ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public ImPrivateMessageDO recallPrivateMessage(Long userId, Long messageId) {
+ // 1.1 鏍¢獙娑堟伅瀛樺湪
+ ImPrivateMessageDO message = privateMessageMapper.selectById(messageId);
+ if (message == null) {
+ throw exception(MESSAGE_NOT_EXISTS);
+ }
+ // 1.2 鍙兘鎾ゅ洖鑷繁鍙戦�佺殑娑堟伅
+ if (ObjUtil.notEqual(message.getSenderId(), userId)) {
+ throw exception(MESSAGE_RECALL_DENIED);
+ }
+ // 1.3 涓嶈兘閲嶅鎾ゅ洖
+ if (ImMessageStatusEnum.RECALL.getStatus().equals(message.getStatus())) {
+ throw exception(MESSAGE_ALREADY_RECALLED);
+ }
+ // 1.4 鍙厑璁告挙鍥為檺瀹氭椂闂村唴鐨勬秷鎭�
+ int recallTimeoutMinutes = imProperties.getMessage().getRecallTimeoutMinutes();
+ if (message.getSendTime().plusMinutes(recallTimeoutMinutes).isBefore(LocalDateTime.now())) {
+ throw exception(MESSAGE_RECALL_TIMEOUT, recallTimeoutMinutes);
+ }
+
+ // 2. 鏇存柊鍘熸秷鎭姸鎬佷负鎾ゅ洖
+ privateMessageMapper.updateById(new ImPrivateMessageDO().setId(messageId)
+ .setStatus(ImMessageStatusEnum.RECALL.getStatus()));
+
+ // 3. 鍙戦�佹挙鍥炰簨浠�
+ return sendPrivateMessage(userId, new ImPrivateMessageSendDTO().setReceiverId(message.getReceiverId())
+ .setType(ImContentTypeEnum.RECALL.getType()).setContent(new RecallMessage().setMessageId(messageId)));
+ }
+
+ /**
+ * 绉佽亰寮曠敤娑堟伅瑙勮寖鍖�
+ *
+ * @param reqVO 鍙戦�佽姹�
+ * @param senderId 鍙戦�佷汉缂栧彿
+ * @return 瑙勮寖鍖栧悗鐨� content
+ */
+ private String normalizeQuoteContent(ImPrivateMessageSendReqVO reqVO, Long senderId) {
+ // 瑙f瀽瀹㈡埛绔� content 閲岀殑 quote.messageId
+ Long quoteMessageId = ImMessageUtils.parseQuoteMessageId(reqVO.getContent());
+
+ // 鎯呭喌涓�锛氭病鏈� quoteMessageId锛岀洿鎺� remove 鎺� content 閲屽彲鑳戒吉閫犵殑 quote 瀛楁
+ if (quoteMessageId == null) {
+ return ImMessageUtils.removeQuote(reqVO.getContent());
+ }
+
+ // 鎯呭喌浜岋細鏈� quoteMessageId锛屽姞杞藉師娑堟伅骞舵牎楠�
+ ImPrivateMessageDO original = privateMessageMapper.selectById(quoteMessageId);
+ if (original == null
+ || ImMessageStatusEnum.RECALL.getStatus().equals(original.getStatus())) {
+ throw exception(MESSAGE_QUOTE_INVALID);
+ }
+ // 鏍¢獙鏄悓瀵硅瘽
+ boolean sameConversation = (ObjUtil.equal(original.getSenderId(), senderId) // 鍙戦�佷汉鏄綋鍓嶇敤鎴凤紝鎺ユ敹浜烘槸瀵规柟
+ && ObjUtil.equal(original.getReceiverId(), reqVO.getReceiverId()))
+ || (ObjUtil.equal(original.getSenderId(), reqVO.getReceiverId()) // 鍙戦�佷汉鏄鏂癸紝鎺ユ敹浜烘槸褰撳墠鐢ㄦ埛
+ && ObjUtil.equal(original.getReceiverId(), senderId));
+ if (!sameConversation) {
+ throw exception(MESSAGE_QUOTE_INVALID);
+ }
+ // 鏋勫缓 quote 瀵硅薄骞舵敞鍏� content
+ QuoteMessage quote = ImMessageUtils.buildQuote(original.getId(),
+ original.getSenderId(), original.getType(), original.getContent());
+ return ImMessageUtils.appendQuote(reqVO.getContent(), quote);
+ }
+
+ @Override
+ public List<ImPrivateMessageDO> pullPrivateMessageList(Long userId, Long minId, Integer size) {
+ int maxPullSize = imProperties.getMessage().getMaxPullSize();
+ if (size > maxPullSize) {
+ throw exception(MESSAGE_PULL_SIZE_EXCEEDED, maxPullSize);
+ }
+ // 0. 鎷夊彇鏃堕棿绐楋紱瓒呰繃绐楀彛鐨勮�佹秷鎭笉鍐嶉�氳繃绂荤嚎閫氶亾鎺ㄩ��
+ LocalDateTime minSendTime = LocalDateTime.now().minusDays(imProperties.getMessage().getPrivatePullMaxDays());
+
+ // 鏍规嵁 minId 鍜� minSendTime 鎷夊彇娑堟伅锛岄伩鍏� minId 鎭板ソ琚彂鍑哄悗鎵嶆媺鍙栵紝瀵艰嚧婕忔秷鎭�
+ List<ImPrivateMessageDO> messages = privateMessageMapper.selectListByMinId(userId, minId, minSendTime, size);
+ log.info("[pullPrivateMessageList][userId({}) minId({}) size({}) result({})]",
+ userId, minId, size, messages.size());
+ return messages;
+ }
+
+ @Override
+ public void readPrivateMessages(Long userId, Long receiverId, Long messageId) {
+ // 1. 鍏ㄥ眬寮�鍏虫牎楠�
+ if (BooleanUtil.isFalse(imProperties.getMessage().isPrivateReadEnabled())) {
+ throw exception(MESSAGE_PRIVATE_READ_DISABLED);
+ }
+ Assert.notNull(messageId, "宸茶娑堟伅缂栧彿涓嶈兘涓虹┖");
+
+ // 2. 鍥炴墽缃� DONE锛氭妸 (receiverId 鈫� userId) 涓� id <= messageId銆佸緟鍥炴墽(PENDING) 鐨勬秷鎭爣璁颁负宸插畬鎴�
+ // status 涓嶅啀琛ㄨ揪宸茶锛堜繚鎸� NORMAL锛夛紱鍙炕 PENDING 琛岋紝閬垮厤瑕嗙洊 NO_RECEIPT / 宸� DONE
+ privateMessageMapper.updateBySenderIdAndReceiverIdAndIdLeAndReceiptStatus(
+ receiverId, userId, messageId, ImMessageReceiptStatusEnum.PENDING.getStatus(),
+ new ImPrivateMessageDO().setReceiptStatus(ImMessageReceiptStatusEnum.DONE.getStatus()));
+
+ // 3. 鍚屾鍐� im_conversation_read锛堣浣嶇疆鍞竴鏉冨▉锛屽崟璋冮�掑锛夛紱璇讳綅缃墠杩涙墠涓嬪彂浜嬩欢
+ boolean advanced = conversationReadService.updateConversationReadPosition(
+ userId, ImConversationTypeEnum.PRIVATE.getType(), receiverId, messageId);
+ if (!advanced) {
+ return;
+ }
+
+ // 4. 寮傛鍙戦�� READ + RECEIPT 浜嬩欢锛堝凡璇讳綅缃互鍓嶇涓婃姤涓哄噯锛屼笌澶氱 / 瀵规柟 UI 鏄剧ず涓�鑷达級
+ imWebSocketService.sendNotificationAsync(userId, ImConversationTypeEnum.PRIVATE.getType(),
+ ImContentTypeEnum.READ.getType(), ImMessageReadNotification.ofPrivate(userId, receiverId, messageId));
+ imWebSocketService.sendNotificationAsync(receiverId, ImConversationTypeEnum.PRIVATE.getType(),
+ ImContentTypeEnum.RECEIPT.getType(),
+ ImMessageReceiptNotification.ofPrivate(userId, receiverId, messageId));
+ }
+
+ @Override
+ public Long getMaxReadMessageId(Long userId, Long peerId) {
+ if (BooleanUtil.isFalse(imProperties.getMessage().isPrivateReadEnabled())) {
+ throw exception(MESSAGE_PRIVATE_READ_DISABLED);
+ }
+ // 瀵圭 peer 鍦ㄣ�屼笌 userId 鐨勪細璇濄�嶉噷鐨勮浣嶇疆 = peer 鎶� userId 鍙戠殑娑堟伅璇诲埌鍝�
+ return conversationReadService.getConversationReadMessageId(
+ peerId, ImConversationTypeEnum.PRIVATE.getType(), userId);
+ }
+
+ @Override
+ public List<ImPrivateMessageDO> getPrivateMessageList(Long userId, ImPrivateMessageListReqVO reqVO) {
+ return privateMessageMapper.selectHistoryList(userId, reqVO.getReceiverId(), reqVO.getMaxId(), reqVO.getLimit());
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImPrivateMessageDO> getPrivateMessagePage(ImPrivateMessageManagerPageReqVO reqVO) {
+ return privateMessageMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public ImPrivateMessageDO getPrivateMessage(Long id) {
+ return privateMessageMapper.selectById(id);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/dto/ImGroupMessageSendDTO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/dto/ImGroupMessageSendDTO.java
new file mode 100644
index 0000000..87a7f88
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/dto/ImGroupMessageSendDTO.java
@@ -0,0 +1,235 @@
+package cn.iocoder.yudao.module.im.service.message.dto;
+
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.service.websocket.notification.group.*;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * IM 缇よ亰娑堟伅鍙戦�� DTO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class ImGroupMessageSendDTO {
+
+ /**
+ * 缇ょ紪鍙�
+ */
+ @NotNull(message = "缇ょ紪鍙蜂笉鑳戒负绌�")
+ private Long groupId;
+ /**
+ * 娑堟伅绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImContentTypeEnum}
+ */
+ @NotNull(message = "娑堟伅绫诲瀷涓嶈兘涓虹┖")
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭
+ * <p>
+ * 鏀寔 String / POJO锛涢潪 String 鏃剁敱 service 搴忓垪鍖栦负 JSON
+ */
+ private Object content;
+ /**
+ * @ 鐩爣鐢ㄦ埛缂栧彿鍒楄〃
+ */
+ private List<Long> atUserIds;
+ /**
+ * 瀹氬悜鎺ユ敹鐢ㄦ埛缂栧彿鍒楄〃
+ * <p>
+ * 涓虹┖琛ㄧず鍏ㄥ憳鍙
+ */
+ private List<Long> receiverUserIds;
+ /**
+ * 鏄惁闇�瑕佸洖鎵�
+ * <p>
+ * 缂虹渷瑙嗕负鏃犻渶鍥炴墽锛坒alse锛�
+ */
+ private Boolean receipt;
+
+ // ========== 缇ゅ箍鎾簨浠堕潤鎬佸伐鍘傦紙瀵瑰簲 ImContentTypeEnum 缇や簨浠讹級 ==========
+
+ public static ImGroupMessageSendDTO ofGroupCreate(Long groupId, Long operatorUserId, Collection<Long> memberUserIds) {
+ GroupCreateNotification notification = new GroupCreateNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMemberUserIds(new ArrayList<>(memberUserIds));
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_CREATE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupInfoUpdate(Long groupId, Long operatorUserId,
+ String oldAvatar, String newAvatar,
+ Boolean oldJoinApproval, Boolean newJoinApproval) {
+ GroupInfoUpdateNotification notification = new GroupInfoUpdateNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setOldAvatar(oldAvatar);
+ notification.setNewAvatar(newAvatar);
+ notification.setOldJoinApproval(oldJoinApproval);
+ notification.setNewJoinApproval(newJoinApproval);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_INFO_UPDATE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMemberQuit(Long groupId, Long operatorUserId) {
+ GroupMemberQuitNotification notification = new GroupMemberQuitNotification();
+ notification.setOperatorUserId(operatorUserId);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MEMBER_QUIT.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupOwnerTransfer(Long groupId, Long operatorUserId, Long newOwnerUserId) {
+ GroupOwnerTransferNotification notification = new GroupOwnerTransferNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setNewOwnerUserId(newOwnerUserId);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_OWNER_TRANSFER.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMemberKick(Long groupId, Long operatorUserId, Collection<Long> memberUserIds) {
+ GroupMemberKickNotification notification = new GroupMemberKickNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMemberUserIds(new ArrayList<>(memberUserIds));
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MEMBER_KICK.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMemberInvite(Long groupId, Long operatorUserId, Collection<Long> memberUserIds) {
+ GroupMemberInviteNotification notification = new GroupMemberInviteNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMemberUserIds(new ArrayList<>(memberUserIds));
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MEMBER_INVITE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMemberEnter(Long groupId, Long entrantUserId, Integer addSource) {
+ GroupMemberEnterNotification notification = new GroupMemberEnterNotification();
+ notification.setOperatorUserId(entrantUserId);
+ notification.setEntrantUserId(entrantUserId);
+ notification.setAddSource(addSource);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MEMBER_ENTER.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupDissolve(Long groupId, Long operatorUserId) {
+ GroupDissolveNotification notification = new GroupDissolveNotification();
+ notification.setOperatorUserId(operatorUserId);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_DISSOLVE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMemberNicknameUpdate(Long groupId, Long operatorUserId, String displayUserName) {
+ GroupMemberNicknameUpdateNotification notification = new GroupMemberNicknameUpdateNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setDisplayUserName(displayUserName);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MEMBER_NICKNAME_UPDATE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupAdminAdd(Long groupId, Long operatorUserId, Collection<Long> memberUserIds) {
+ GroupAdminAddNotification notification = new GroupAdminAddNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMemberUserIds(new ArrayList<>(memberUserIds));
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_ADMIN_ADD.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupAdminRemove(Long groupId, Long operatorUserId, Collection<Long> memberUserIds) {
+ GroupAdminRemoveNotification notification = new GroupAdminRemoveNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMemberUserIds(new ArrayList<>(memberUserIds));
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_ADMIN_REMOVE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupNoticeUpdate(Long groupId, Long operatorUserId, String oldNotice, String newNotice) {
+ GroupNoticeUpdateNotification notification = new GroupNoticeUpdateNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setOldNotice(oldNotice).setNewNotice(newNotice);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_NOTICE_UPDATE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupNameUpdate(Long groupId, Long operatorUserId, String oldName, String newName) {
+ GroupNameUpdateNotification notification = new GroupNameUpdateNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setOldName(oldName).setNewName(newName);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_NAME_UPDATE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMemberSettingUpdate(Long groupId, Long operatorUserId, Boolean silent, String groupRemark) {
+ GroupMemberSettingUpdateNotification notification = new GroupMemberSettingUpdateNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setSilent(silent).setGroupRemark(groupRemark);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MEMBER_SETTING_UPDATE.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMessagePin(Long groupId, Long operatorUserId, ImGroupMessageDO message) {
+ GroupMessagePinNotification notification = new GroupMessagePinNotification();
+ GroupMessagePinNotification.PinnedMessage pinnedMessage = new GroupMessagePinNotification.PinnedMessage()
+ .setId(message.getId()).setSenderId(message.getSenderId()).setGroupId(message.getGroupId())
+ .setType(message.getType()).setContent(message.getContent()).setSendTime(message.getSendTime())
+ .setAtUserIds(message.getAtUserIds()).setReceiverUserIds(message.getReceiverUserIds());
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMessageId(message.getId()).setMessage(pinnedMessage);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MESSAGE_PIN.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMessageUnpin(Long groupId, Long operatorUserId, Long messageId) {
+ GroupMessageUnpinNotification notification = new GroupMessageUnpinNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMessageId(messageId);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MESSAGE_UNPIN.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMemberMuted(Long groupId, Long operatorUserId,
+ Long mutedUserId,
+ java.time.LocalDateTime muteEndTime) {
+ GroupMemberMutedNotification notification = new GroupMemberMutedNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMutedUserId(mutedUserId);
+ notification.setMuteEndTime(muteEndTime);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MEMBER_MUTED.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMemberCancelMuted(Long groupId, Long operatorUserId, Long mutedUserId) {
+ GroupMemberCancelMutedNotification notification = new GroupMemberCancelMutedNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setMutedUserId(mutedUserId);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MEMBER_CANCEL_MUTED.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupMuted(Long groupId, Long operatorUserId) {
+ GroupMutedNotification notification = new GroupMutedNotification();
+ notification.setOperatorUserId(operatorUserId);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_MUTED.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupCancelMuted(Long groupId, Long operatorUserId) {
+ GroupCancelMutedNotification notification = new GroupCancelMutedNotification();
+ notification.setOperatorUserId(operatorUserId);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_CANCEL_MUTED.getType()).setContent(notification);
+ }
+
+ public static ImGroupMessageSendDTO ofGroupBanned(Long groupId, Long operatorUserId, boolean banned) {
+ GroupBannedNotification notification = new GroupBannedNotification();
+ notification.setOperatorUserId(operatorUserId);
+ notification.setBanned(banned);
+ return new ImGroupMessageSendDTO().setGroupId(groupId)
+ .setType(ImContentTypeEnum.GROUP_BANNED.getType()).setContent(notification);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/dto/ImPrivateMessageSendDTO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/dto/ImPrivateMessageSendDTO.java
new file mode 100644
index 0000000..5758c3b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/message/dto/ImPrivateMessageSendDTO.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.im.service.message.dto;
+
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import lombok.Data;
+
+/**
+ * IM 绉佽亰娑堟伅鍙戦�� DTO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class ImPrivateMessageSendDTO {
+
+ /**
+ * 鎺ユ敹浜虹紪鍙�
+ */
+ private Long receiverId;
+ /**
+ * 娑堟伅绫诲瀷
+ * <p>
+ * 鏋氫妇 {@link ImContentTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭
+ * <p>
+ * 鏀寔 String / POJO锛涢潪 String 鏃剁敱 service 搴忓垪鍖栦负 JSON
+ */
+ private Object content;
+ /**
+ * 鏄惁鎸佷箙鍖� + 鎺ㄩ�佺粰鎺ユ敹鏂癸紙鍗曡竟璇箟寮�鍏筹級
+ * <p>
+ * null锛氶粯璁ゆ寜 {@link ImContentTypeEnum#isPersistent()} 鍐冲畾鏄惁鍏ュ簱 + 鍙屽悜 WS 鎺ㄩ�侊紙淇濇寔鍘熻涓猴級<br>
+ * false锛氳鐩栦负鍗曡竟鈥斺�斾笉鍏ュ簱銆佷粎鎺� sender 澶氱锛屽鏂逛笉鎰熺煡锛堝銆屼綘宸插垹闄� XXX銆嶈繖绫讳粎鑷繁鍙鐨� TIP锛�<br>
+ * true锛氳鐩栦负鍙屽悜 + 鍏ュ簱
+ */
+ private Boolean persistent;
+ /**
+ * 鏄惁闇�瑕佸洖鎵э紱null 绛変环 false锛堢郴缁熸秷鎭粯璁や笉闇�瑕佸洖鎵э級
+ */
+ private Boolean receipt;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallService.java
new file mode 100644
index 0000000..5be2c7c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallService.java
@@ -0,0 +1,169 @@
+package cn.iocoder.yudao.module.im.service.rtc;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallCreateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallInviteReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcParticipantDO;
+
+import java.util.List;
+
+/**
+ * IM 瀹炴椂閫氳瘽 Service
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImRtcCallService {
+
+ /**
+ * 鍒涘缓鏂伴�氳瘽锛涘悓濂藉弸瀵� / 鍚岀兢宸叉湁杩涜涓�氳瘽鐩存帴鎶涢敊锛堢兢鍦烘櫙搴旀敼璧� {@link #inviteCall} 杩藉姞閭�璇凤紝鎴� {@link #joinCall} 鍔犲叆鏃佽锛�
+ *
+ * @param userId 鍙戣捣浜虹紪鍙凤紱閫氬父鏄綋鍓嶇櫥褰曠敤鎴�
+ * @param reqVO 璇锋眰鍙傛暟锛坰cene / mediaType / peerUserId 鎴� groupId + inviteeIds锛�
+ * @return 閫氳瘽涓昏〃
+ */
+ ImRtcCallDO createCall(Long userId, ImRtcCallCreateReqVO reqVO);
+
+ /**
+ * 閫氳瘽涓拷鍔犻個璇凤細浠呯兢閫氳瘽鍦烘櫙鍙敤锛涙湰浜哄繀椤绘槸鎴垮唴 JOINED 鍙備笌鑰咃紱缁欐柊閭�璇蜂汉鎺� RTC_CALL(INVITE)
+ *
+ * @param userId 鎿嶄綔浜虹紪鍙凤紱蹇呴』鏄綋鍓嶄細璇濆弬涓庤��
+ * @param reqVO room + 鏂伴個璇风殑鐢ㄦ埛缂栧彿闆嗗悎
+ */
+ void inviteCall(Long userId, ImRtcCallInviteReqVO reqVO);
+
+ /**
+ * 鍔犲叆宸叉湁缇ら�氳瘽锛氱敤浜庣兢鑳跺泭鏉°�屽姞鍏ャ�嶆寜閽紱鏃佽鑰呬綔涓� JOINER 鍔犲叆锛岄個璇锋睜鍐呮垚鍛樿浆 JOINED
+ *
+ * @param userId 鍔犲叆鑰呯敤鎴风紪鍙�
+ * @param room 涓氬姟閫氳瘽缂栧彿锛涗粠鑳跺泭鏉� activeCall 鎷�
+ * @return 閫氳瘽涓昏〃
+ */
+ ImRtcCallDO joinCall(Long userId, String room);
+
+ /**
+ * 鎺ュ惉閫氳瘽锛氬弬涓庤�� INVITING 鈫� JOINED锛涗富琛� CREATED 鈫� RUNNING锛堥娆℃湁闈炲彂璧蜂汉鎺ラ�氭椂锛�
+ *
+ * @param userId 鎺ュ惉鑰呯敤鎴风紪鍙�
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ * @return 閫氳瘽涓昏〃
+ */
+ ImRtcCallDO acceptCall(Long userId, String room);
+
+ /**
+ * 鎷掔粷閫氳瘽锛涗粎 INVITING 鐘舵�佸彲鎷掞紱缇ら�氳瘽鎷掔粷绛夊悓浜庝笉鍙備笌锛屾埧闂翠粛瀛樺湪
+ *
+ * @param userId 鎷掓帴鑰呯敤鎴风紪鍙�
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ */
+ void rejectCall(Long userId, String room);
+
+ /**
+ * 鍙栨秷閭�璇凤紱涓诲彨鍦� INVITING 鐘舵�佷富鍔ㄥ彇娑�
+ *
+ * @param userId 鍙栨秷鑰呯敤鎴风紪鍙凤紙蹇呴』鏄富鍙級
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ */
+ void cancelCall(Long userId, String room);
+
+ /**
+ * 绂诲紑閫氳瘽锛汻UNNING 鐘舵�佷笅绂诲紑锛涚鑱婁换涓�鏂圭寮� = 閫氳瘽缁撴潫锛涚兢閫氳瘽鏈�鍚庝竴浜虹寮�鎵嶇粨鏉�
+ *
+ * @param userId 绂诲紑鑰呯敤鎴风紪鍙�
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ */
+ void leaveCall(Long userId, String room);
+
+ /**
+ * 鏌ヨ褰撳墠姝e湪杩涜鐨勯�氳瘽锛涚洰鍓嶄粎缇よ亰鍦烘櫙锛堣兌鍥婃潯锛夛紝绉佽亰鏈潵鎵╁睍鍐嶈ˉ peerUserId 鍙傛暟
+ * <p>
+ * 閴存潈锛氫粎缇ゆ椿璺冩垚鍛樺彲鏌ワ紱闃叉浠绘剰鐢ㄦ埛鎺㈡祴缇ら�氳瘽鐘舵�� / 鎷垮埌 inviter / inviteeIds 绛夋晱鎰熶俊鎭�
+ *
+ * @param userId 鎿嶄綔浜虹紪鍙凤紱閫氬父鏄綋鍓嶇櫥褰曠敤鎴�
+ * @param groupId 缇ょ紪鍙�
+ * @return 閫氳瘽涓昏〃锛涗笉瀛樺湪杩斿洖 null
+ */
+ ImRtcCallDO getActiveCall(Long userId, Long groupId);
+
+ /**
+ * 鏌ヨ鏌愰�氳瘽鐨勫叏閮ㄥ弬涓庤�呮槑缁嗭紱浜ょ粰 Controller 鎷艰 inviteeIds / joinedUserIds
+ *
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ * @return 鍙備笌鑰呮槑缁嗗垪琛�
+ */
+ List<ImRtcParticipantDO> getCallParticipantList(String room);
+
+ /**
+ * 绛惧彂鎸囧畾鐢ㄦ埛杩涘叆璇ラ�氳瘽鐨� LiveKit Token锛涗緵 Controller 鎷兼帴鍒板搷搴� VO
+ *
+ * @param userId 杩涙埧鐢ㄦ埛缂栧彿锛泃oken 鍐� displayName 鍙栬鐢ㄦ埛鏄电О
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ * @return JWT 瀛楃涓�
+ */
+ String signCallToken(Long userId, String room);
+
+ /**
+ * 澶勭悊 LiveKit Webhook 浜嬩欢锛涚敤浜庡叧 tab / 寮烘潃 / 缃戠粶鏂紑绛夊紓甯搁��鍑哄満鏅殑鍏滃簳娓呯悊
+ * <p>
+ * 鍏抽敭浜嬩欢锛歱articipant_left锛堟垚鍛樼寮�锛� / room_finished锛堟埧闂寸粨鏉燂級銆�
+ * 鍓嶇姝e父 leave 鏃讹紝涔熶細瑙﹀彂鍚屾牱鐨� LiveKit 浜嬩欢锛涙澶勯渶鍋氬箓绛夊鐞嗭紝session 宸茶涓氬姟鎺ュ彛绉婚櫎鏃剁洿鎺ュ拷鐣ャ��
+ *
+ * @param event LiveKit Webhook 浜嬩欢
+ */
+ void handleLiveKitEvent(cn.iocoder.yudao.module.im.framework.rtc.core.LiveKitWebhookEventDTO event);
+
+ /**
+ * 銆愬畾鏃朵换鍔¤皟鐢ㄣ�戞竻鐞嗗兊灏搁�氳瘽
+ *
+ * @param thresholdMinutes 閫氳瘽鍒涘缓瓒呰繃姝ゅ垎閽熸暟鎵嶇撼鍏ユ壂鎻忥紱璋冪敤鏂逛繚璇� > 0
+ * @return 娓呯悊鏁伴噺
+ */
+ int cleanupZombieCalls(int thresholdMinutes);
+
+ /**
+ * 銆愬畾鏃朵换鍔¤皟鐢ㄣ�戣秴鏃舵湭鎺ラ�氱殑 INVITING 鍙備笌鑰咃細鍗曚汉绮掑害鏍� NO_ANSWER + 鎺� RTC_CALL(NO_ANSWER) 璁╁墠绔� banner 鏀舵暃锛�
+ * 鑻ュ鑷撮�氳瘽鍙墿涓诲彨锛岀敱 endSessionIfTerminal 绾ц仈鍏虫埧
+ *
+ * @param thresholdMinutes 閭�璇锋椂闂磋秴杩囨鍒嗛挓鏁版墠绾冲叆鎵弿锛涜皟鐢ㄦ柟淇濊瘉 > 0
+ * @return 瓒呮椂澶勭悊鏁伴噺
+ */
+ int timeoutInvitingParticipants(int thresholdMinutes);
+
+ /**
+ * 鍓嶇 RUNNING 绔� timer 鍏滃簳锛涚珛鍗虫壂鎻忔寚瀹� room 鍐呰秴鏃剁殑 INVITING 鍙備笌鑰咃紝绛夊悓 Job 浣嗛檺瀹氬崟 room锛�
+ * 瀹為檯瓒呮椂闃堝�肩敱鍚庣 {@link cn.iocoder.yudao.module.im.framework.config.ImProperties.Rtc#getInviteTimeoutMinutes()} 鍐冲畾锛�
+ * 閬垮厤鍓嶅悗绔厤缃笉涓�鑷达紱鎺ュ彛闈欓粯锛屾墍鏈夎竟鐣岋紙room 涓嶅瓨鍦� / 閴存潈澶辫触 / 鏃犺秴鏃跺�欓�夛級閮借繑鍥� false 涓嶆姏寮傚父
+ *
+ * @param userId 璋冪敤鑰呯敤鎴风紪鍙凤紱蹇呴』鏄 room 鐨勫弬涓庤��
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ */
+ void noAnswerCallCheck(Long userId, String room);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戣幏寰楅�氳瘽璁板綍鍒嗛〉
+ *
+ * @param reqVO 鍒嗛〉鏌ヨ鏉′欢
+ * @return 閫氳瘽璁板綍鍒嗛〉
+ */
+ PageResult<ImRtcCallDO> getCallPage(ImRtcCallManagerPageReqVO reqVO);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戣幏寰楅�氳瘽璁板綍
+ *
+ * @param id 閫氳瘽缂栧彿
+ * @return 閫氳瘽璁板綍
+ */
+ ImRtcCallDO getCall(Long id);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戞寜閫氳瘽缂栧彿鏌ヨ鍙備笌鑰呮槑缁�
+ *
+ * @param id 閫氳瘽缂栧彿
+ * @return 鍙備笌鑰呮槑缁嗗垪琛紱閫氳瘽涓嶅瓨鍦ㄦ椂杩斿洖绌洪泦鍚�
+ */
+ List<ImRtcParticipantDO> getCallParticipantListByCallId(Long id);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImpl.java
new file mode 100644
index 0000000..6aa4f56
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImpl.java
@@ -0,0 +1,1186 @@
+package cn.iocoder.yudao.module.im.service.rtc;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallCreateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallInviteReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcParticipantDO;
+import cn.iocoder.yudao.module.im.dal.mysql.rtc.ImRtcCallMapper;
+import cn.iocoder.yudao.module.im.dal.mysql.rtc.ImRtcParticipantMapper;
+import cn.iocoder.yudao.module.im.dal.redis.rtc.ImRtcCallLockRedisDAO;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallEndReasonEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallStatusEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantRoleEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantStatusEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.framework.rtc.core.LiveKitClient;
+import cn.iocoder.yudao.module.im.framework.rtc.core.LiveKitWebhookEventDTO;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import cn.iocoder.yudao.module.im.service.message.ImPrivateMessageService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.rtc.*;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import jakarta.annotation.Resource;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+
+/**
+ * IM 瀹炴椂閫氳瘽 Service 瀹炵幇
+ * <p>
+ * 瀛樺偍妯″瀷锛欴B 鍗曚竴瀛樺偍锛坕m_rtc_call 涓昏〃 + im_rtc_participant 鏄庣粏琛級
+ * <p>
+ * 骞跺彂骞傜瓑锛氬悓濂藉弸瀵� / 鍚岀兢娲昏穬鍞竴鎬ц蛋 {@link ImRtcCallLockRedisDAO} 鍒嗗竷寮忛攣 + 閿佸唴 SELECT 鍏滃簳锛泈ebhook 鍏滃簳璧版潯浠� UPDATE锛�
+ * <p>
+ * 鎺ㄩ�侀�氶亾鍒嗘祦锛�
+ * 1601 RTC_CALL锛圛NVITING / JOINED / REJECTED / NO_ANSWER / LEFT 瀛愮被鍨嬶級鈫� {@link ImWebSocketService#sendNotificationAsync} 浠呮帹鍙備笌鏂癸紱
+ * 1602 / 1603 PARTICIPANT_CONNECTED / DISCONNECTED 鈫� {@link ImWebSocketService} 鎺ㄥ弬涓庢柟 + 缇ら�氳瘽鍦烘櫙骞挎挱鍏ㄧ兢锛�
+ * 1610 RTC_CALL_START + 1611 RTC_CALL_END 鈫� {@link ImPrivateMessageService} / {@link ImGroupMessageService} 鍏ユ秷鎭祦褰撹亰澶� tip
+ * 锛圫TART 浠呯兢閫氳瘽锛涗袱鑰呭垎鍒湪 invite / cancel(leave) 浜嬪姟閲� INSERT锛岃嚜澧� id 鑷劧淇濊瘉椤哄簭锛�
+ * <p>
+ * 鑱岃矗杈圭晫锛氬獟浣撳崗鍟嗗畬鍏ㄤ氦缁� LiveKit锛涘悗绔彧鍋氫細璇濈姸鎬佹満銆乀oken 绛惧彂銆佹潵鐢典俊浠ゆ帹閫併�侀�氳瘽鍘嗗彶钀芥秷鎭祦锛涙埧鍐呭獟浣撴祦鍙樺寲浜ょ粰 LiveKit 瀹㈡埛绔簨浠讹紙TrackSubscribed 绛夛級锛屽悗绔笉閲嶅鎺�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+@Slf4j
+public class ImRtcCallServiceImpl implements ImRtcCallService {
+
+ @Resource
+ private ImRtcCallMapper rtcCallMapper;
+ @Resource
+ private ImRtcParticipantMapper rtcParticipantMapper;
+ @Resource
+ private ImRtcCallLockRedisDAO rtcCallLockRedisDAO;
+
+ @Resource
+ private ImGroupMemberService groupMemberService;
+ @Resource
+ private ImFriendService friendService;
+ @Resource
+ private ImWebSocketService webSocketService;
+ @Resource
+ private ImPrivateMessageService privateMessageService;
+ @Resource
+ private ImGroupMessageService groupMessageService;
+
+ @Resource
+ private LiveKitClient liveKitClient;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @Resource
+ private ImProperties imProperties;
+
+ // ========== 涓氬姟鎺ュ彛 ==========
+
+ @Override
+ @SneakyThrows
+ @Transactional(rollbackFor = Exception.class)
+ public ImRtcCallDO createCall(Long userId, ImRtcCallCreateReqVO reqVO) {
+ validateEnabled();
+ // 1. 鏍¢獙鍏ュ弬涓庡満鏅�
+ validateCreateCall(userId, reqVO);
+
+ // 2. 鍔犻攣鍚庤窇涓氬姟涓讳綋锛涘悓濂藉弸瀵� / 鍚岀兢涓茶锛岄伩鍏嶅苟鍙戝悇寮�涓�閫氱殑绔炴��
+ if (ImConversationTypeEnum.isGroup(reqVO.getConversationType())) {
+ return rtcCallLockRedisDAO.lockGroup(reqVO.getGroupId(), () -> createGroupCall(userId, reqVO));
+ }
+ Long peerUserId = CollUtil.getFirst(reqVO.getInviteeIds());
+ return rtcCallLockRedisDAO.lockPrivate(userId, peerUserId, () -> createPrivateCall(userId, reqVO, peerUserId));
+ }
+
+ /**
+ * 缇ら�氳瘽鍒涘缓閿佸唴涓讳綋锛氱兢鏈夋椿璺冮�氳瘽鐩存帴鎶涳紙寮曞璧� inviteCall / joinCall锛夛紱
+ * 鍚﹀垯璧板畬鏁寸敓鍛藉懆鏈燂紝鑻ュ彂璧蜂汉鑷韩蹇欑嚎绔嬪嵆 end(BUSY) 鐣欎笅閫氳瘽璁板綍
+ *
+ * @param userId 鍙戣捣浜虹紪鍙�
+ * @param reqVO 鍒涘缓璇锋眰
+ * @return 閫氳瘽涓昏〃锛堝彲鑳� status=ENDED 琛ㄧず鑷韩蹇欑嚎锛�
+ */
+ private ImRtcCallDO createGroupCall(Long userId, ImRtcCallCreateReqVO reqVO) {
+ // 1.1 鍚岀兢鏈夋椿璺冮�氳瘽 鈫� 鐩存帴鎶涘紓甯革紙UI 搴斿凡鎷︽埅锛夛紝寮曞鐢ㄦ埛璧� inviteCall / joinCall锛涢伩鍏嶉噸澶嶅紑閫�
+ ImRtcCallDO active = rtcCallMapper.selectLastOneByGroupIdAndStatusIn(
+ reqVO.getGroupId(), ImRtcCallStatusEnum.ACTIVE_STATUSES);
+ if (active != null) {
+ throw exception(RTC_GROUP_CALL_ACTIVE);
+ }
+ // 1.2 鍏堟娴嬪彂璧蜂汉蹇欑嚎鐘舵�侊紱涓嶆姏锛岀暀缁欎笅鏂� end 鍐冲畾
+ boolean selfBusy = rtcParticipantMapper.selectLastOneByUserIdAndStatus(
+ userId, ImRtcParticipantStatusEnum.ACTIVE_STATUSES) != null;
+
+ // 2. 瀹屾暣鐢熷懡鍛ㄦ湡锛欼NSERT + INVITE 脳 N + START 鍏ㄦ帹
+ ImRtcCallDO call = createCall0(userId, reqVO);
+
+ // 3. 鑷韩蹇欑嚎绔嬪嵆 end(BUSY)锛汦ND 鎺ㄩ�佺粰缇わ紝缇ゆ垚鍛樼湅鍒板畬鏁� START + END
+ if (selfBusy) {
+ endSession(call, userId, ImRtcCallEndReasonEnum.BUSY);
+ }
+ return call;
+ }
+
+ /**
+ * 绉佽亰鍒涘缓閿佸唴涓讳綋锛氬弻鏂瑰繖绾挎椂浠嶈蛋瀹屾暣鐢熷懡鍛ㄦ湡锛坈reate + 绔嬪嵆 end(BUSY)锛夛紝
+ * 鍚屼竴瀵规鍦ㄩ�氳瘽瑙嗕綔鏁版嵁寮傚父鐩存帴鎶�
+ *
+ * @param userId 鍙戣捣浜虹紪鍙�
+ * @param reqVO 鍒涘缓璇锋眰
+ * @param peerUserId 瀵圭缂栧彿锛涙潵鑷� reqVO.inviteeIds 鐨勫敮涓�鍏冪礌
+ * @return 閫氳瘽涓昏〃锛堝彲鑳� status=ENDED 琛ㄧず蹇欑嚎锛�
+ */
+ private ImRtcCallDO createPrivateCall(Long userId, ImRtcCallCreateReqVO reqVO, Long peerUserId) {
+ // 1.1 鍙屾柟宸插湪鍚屼竴閫氳瘽 鈫� 鏁版嵁寮傚父锛圲I 搴斿凡鎷︽埅锛夛紝鐩存帴鎶�
+ if (getActivePrivateCallByPair(userId, peerUserId) != null) {
+ throw exception(RTC_SELF_BUSY);
+ }
+ // 1.2 蹇欑嚎妫�娴嬶細self 浼樺厛锛堟洿鍙墽琛岀殑鎻愮ず锛夛紱涓嶆姏锛岀暀缁欎笅鏂� end 鍐冲畾
+ boolean selfBusy = rtcParticipantMapper.selectLastOneByUserIdAndStatus(
+ userId, ImRtcParticipantStatusEnum.ACTIVE_STATUSES) != null;
+ boolean peerBusy = !selfBusy && rtcParticipantMapper.selectLastOneByUserIdAndStatus(
+ peerUserId, ImRtcParticipantStatusEnum.ACTIVE_STATUSES) != null;
+
+ // 2. 瀹屾暣鐢熷懡鍛ㄦ湡锛欼NSERT + INVITE 鍏ㄦ帹
+ ImRtcCallDO call = createCall0(userId, reqVO);
+
+ // 3. 蹇欑嚎绔嬪嵆 end(BUSY)锛沷perator 鍐冲畾涓ょ鐪嬪埌鐨勬枃妗堬紙self busy 鈫� operator=鑷繁锛沺eer busy 鈫� operator=瀵圭锛�
+ if (selfBusy) {
+ endSession(call, userId, ImRtcCallEndReasonEnum.BUSY);
+ } else if (peerBusy) {
+ endSession(call, peerUserId, ImRtcCallEndReasonEnum.BUSY);
+ }
+ return call;
+ }
+
+ @Override
+ @SneakyThrows
+ @Transactional(rollbackFor = Exception.class)
+ public void inviteCall(Long userId, ImRtcCallInviteReqVO reqVO) {
+ validateEnabled();
+ // 1.1 鏍¢獙閫氳瘽瀛樺湪涓旀椿璺�
+ ImRtcCallDO call = validateCallActive(reqVO.getRoom());
+ // 1.2 浠呯兢閫氳瘽鏀寔杩藉姞閭�璇�
+ if (!ImConversationTypeEnum.isGroup(call.getConversationType())) {
+ throw exception(RTC_GROUP_REQUIRED);
+ }
+ // 1.3 鎿嶄綔鑰呭繀椤绘槸鎴垮唴 JOINED 鍙備笌鑰�
+ ImRtcParticipantDO operator = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
+ if (operator == null || !ImRtcParticipantStatusEnum.isJoined(operator.getStatus())) {
+ throw exception(RTC_NOT_PARTICIPANT);
+ }
+ // 2. 鍔犵兢閿佸悗鎵ц杩藉姞閭�璇凤紱閬垮厤涓庢柊寤� / 閲嶅杩藉姞鐨勭珵鎬�
+ rtcCallLockRedisDAO.lockGroup(call.getGroupId(), () -> {
+ addInvitees(call, userId, reqVO.getInviteeIds());
+ return null;
+ });
+ }
+
+ /**
+ * 鏂板缓閫氳瘽瀹炰綋锛汭NSERT 涓昏〃 + 鍙備笌琛� + 鎺ㄩ�� INVITE / START
+ *
+ * @param inviterId 鍙戣捣浜虹紪鍙�
+ * @param reqVO 鍒涘缓璇锋眰
+ * @return 閫氳瘽涓昏〃
+ */
+ private ImRtcCallDO createCall0(Long inviterId, ImRtcCallCreateReqVO reqVO) {
+ // 1. 鏋勯�犲弬鏁帮細room 鐢� UUID锛涜В鏋愯閭�璇锋睜
+ String room = IdUtil.fastSimpleUUID();
+ LocalDateTime now = LocalDateTime.now();
+ Set<Long> invitees = resolveInvitees(reqVO, inviterId);
+
+ // 2.1 INSERT 涓昏〃锛涚兢鑱婂彂璧蜂汉鍗虫椂 JOINED 浣嗛�氳瘽浠嶅 CREATED锛岀瓑棣栦釜闈炲彂璧蜂汉鎺ラ�氭墠鍒� RUNNING
+ ImRtcCallDO call = new ImRtcCallDO().setRoom(room)
+ .setConversationType(reqVO.getConversationType()).setMediaType(reqVO.getMediaType())
+ .setInviterUserId(inviterId).setGroupId(reqVO.getGroupId())
+ .setStatus(ImRtcCallStatusEnum.CREATED.getStatus()).setStartTime(now);
+ rtcCallMapper.insert(call);
+ // 2.2 鎵归噺 INSERT 鍙備笌琛細鍙戣捣浜哄嵆鏃� JOINED锛岃閭�璇蜂汉 INVITING 绛夋帴閫�
+ List<ImRtcParticipantDO> participants = new ArrayList<>(invitees.size() + 1);
+ participants.add(new ImRtcParticipantDO().setCallId(call.getId()).setRoom(room).setUserId(inviterId)
+ .setRole(ImRtcParticipantRoleEnum.INVITER.getRole())
+ .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus())
+ .setInviteTime(now).setAcceptTime(now));
+ for (Long inviteeId : invitees) {
+ participants.add(new ImRtcParticipantDO()
+ .setCallId(call.getId()).setRoom(room).setUserId(inviteeId)
+ .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole())
+ .setStatus(ImRtcParticipantStatusEnum.INVITING.getStatus())
+ .setInviteTime(now));
+ }
+ rtcParticipantMapper.insertBatch(participants);
+
+ // 3.1 鎺ㄩ�侀�氱煡锛歊TC_CALL(INVITE) 缁欐瘡涓閭�璇蜂汉
+ AdminUserRespDTO inviterUser = adminUserApi.getUser(inviterId);
+ Map<Long, AdminUserRespDTO> inviteeMap = adminUserApi.getUserMap(invitees);
+ for (Long inviteeId : invitees) {
+ pushCallInviteNotification(call, inviterUser, inviteeId, inviteeMap.get(inviteeId), invitees);
+ }
+ // 3.2 鍚戞秷鎭祦鍐欏叆 RTC_CALL_START锛涚兢鑱婂叏缇ゅ箍鎾紝绉佽亰瀹氬悜缁欒鍙紝浣滀负浼氳瘽鍒楄〃棰勮鐨勪緷鎹�
+ pushCallStartNotification(call, inviterUser, invitees);
+ return call;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public ImRtcCallDO joinCall(Long userId, String room) {
+ validateEnabled();
+ // 1.1 鏍¢獙閫氳瘽瀛樺湪涓旀椿璺�
+ ImRtcCallDO call = validateCallActive(room);
+ // 1.2 浠呯兢閫氳瘽鏀寔銆屾梺瑙傝�呭姞鍏ャ��
+ if (!ImConversationTypeEnum.isGroup(call.getConversationType())) {
+ throw exception(RTC_GROUP_REQUIRED);
+ }
+ // 1.3 鏍¢獙褰撳墠鐢ㄦ埛鏄缇ゆ湁鏁堟垚鍛橈紱闃叉浠呭嚟 room 灏辨嬁鍒� LiveKit token 瓒婃潈鍏ヤ細
+ groupMemberService.validateMemberInGroup(call.getGroupId(), userId);
+ // 1.4 鏍¢獙褰撳墠鐢ㄦ埛娌℃湁鍏跺畠娲昏穬閫氳瘽
+ validateUserNotInOtherCall(userId, call.getRoom());
+
+ // 2. 鍏ュ弬涓庤〃锛氬凡鏈夎褰曞垏鍥� JOINED锛涗笉鍦ㄨ褰曞垯浠� JOINER 瑙掕壊 INSERT
+ LocalDateTime now = LocalDateTime.now();
+ joinParticipant(call, userId, now);
+
+ // 3. 涓昏〃 CREATED 鈫� RUNNING锛堥娆℃湁闈炲彂璧蜂汉鍔犲叆锛�
+ maybeMarkOngoing(call, userId, now);
+ return call;
+ }
+
+ /**
+ * 缁欏凡瀛樺湪鐨勬椿璺冪兢閫氳瘽杩藉姞閭�璇凤紱鎵归噺鏍¢獙缇ゆ垚鍛� + 鍘婚噸宸插湪閫氳瘽姹� + 鎺ㄩ�� INVITE
+ *
+ * @param call 娲昏穬閫氳瘽涓昏〃
+ * @param inviterId 鏈杩藉姞閭�璇风殑鍙戣捣浜猴紱宸叉槸鎴垮唴 JOINED 鍙備笌鑰�
+ * @param inviteeIds 鏈杩藉姞鐨勮閭�璇蜂汉缂栧彿
+ */
+ private void addInvitees(ImRtcCallDO call, Long inviterId, Collection<Long> inviteeIds) {
+ // 1.1 鏍¢獙琚個璇蜂汉閮芥槸缇ゆ椿璺冩垚鍛�
+ groupMemberService.validateMembersInGroup(call.getGroupId(), inviteeIds);
+ // 1.2 鎺掗櫎宸插湪閫氳瘽姹犵殑锛涘墿浣欏嵆鏈鏂伴個璇�
+ List<ImRtcParticipantDO> existingParticipants = rtcParticipantMapper.selectListByRoom(call.getRoom());
+ Set<Long> existingUserIds = CollectionUtils.convertSet(existingParticipants, ImRtcParticipantDO::getUserId);
+ Set<Long> incomingUserIds = new LinkedHashSet<>(inviteeIds);
+ incomingUserIds.removeAll(existingUserIds);
+ if (CollUtil.isEmpty(incomingUserIds)) {
+ return;
+ }
+ long activeCount = existingParticipants.stream()
+ .filter(participant -> ImRtcParticipantStatusEnum.ACTIVE_STATUSES.contains(participant.getStatus()))
+ .count();
+ if (activeCount + incomingUserIds.size() > imProperties.getRtc().getGroupMaxParticipants()) {
+ throw exception(RTC_GROUP_INVITEE_OVER_LIMIT);
+ }
+
+ // 2. 鎵归噺 INSERT 鏂伴個璇蜂汉
+ LocalDateTime now = LocalDateTime.now();
+ List<ImRtcParticipantDO> participants = CollectionUtils.convertList(incomingUserIds, inviteeId ->
+ new ImRtcParticipantDO().setCallId(call.getId()).setRoom(call.getRoom()).setUserId(inviteeId)
+ .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole())
+ .setStatus(ImRtcParticipantStatusEnum.INVITING.getStatus()).setInviteTime(now));
+ rtcParticipantMapper.insertBatch(participants);
+
+ // 3. 鎺ㄩ�侀�氱煡锛歊TC_CALL(INVITE) 缁欐瘡涓柊閭�璇蜂汉
+ AdminUserRespDTO inviter = adminUserApi.getUser(inviterId);
+ Map<Long, AdminUserRespDTO> inviteeMap = adminUserApi.getUserMap(incomingUserIds);
+ for (Long inviteeId : incomingUserIds) {
+ pushCallInviteNotification(call, inviter, inviteeId, inviteeMap.get(inviteeId), incomingUserIds);
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public ImRtcCallDO acceptCall(Long userId, String room) {
+ validateEnabled();
+ // 1.1 鏍¢獙閫氳瘽瀛樺湪涓旀椿璺�
+ ImRtcCallDO call = validateCallActive(room);
+ // 1.2 鏍¢獙鏈汉鏄閫氳瘽鐨勫弬涓庤��
+ ImRtcParticipantDO participant = validateParticipant(call, userId);
+
+ // 2.1 宸� JOINED 鐩存帴骞傜瓑杩斿洖
+ if (ImRtcParticipantStatusEnum.isJoined(participant.getStatus())) {
+ return call;
+ }
+ validateUserNotInOtherCall(userId, call.getRoom());
+ // 2.2 浠� INVITING 鈫� JOINED锛涘叾瀹冪姸鎬佹嫆
+ if (!ImRtcParticipantStatusEnum.isInviting(participant.getStatus())) {
+ throw exception(RTC_SESSION_NOT_EXISTS);
+ }
+ LocalDateTime now = LocalDateTime.now();
+ int updated = rtcParticipantMapper.updateByIdAndStatus(participant.getId(), ImRtcParticipantStatusEnum.INVITING.getStatus(),
+ new ImRtcParticipantDO().setId(participant.getId()).setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus()).setAcceptTime(now));
+ if (updated == 0) {
+ throw exception(RTC_SESSION_NOT_EXISTS);
+ }
+
+ // 3. 涓昏〃 CREATED 鈫� RUNNING锛堥娆℃湁闈炲彂璧蜂汉鎺ラ�氾級
+ maybeMarkOngoing(call, userId, now);
+ return call;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void rejectCall(Long userId, String room) {
+ validateEnabled();
+ // 1.1 鏍¢獙閫氳瘽瀛樺湪涓旀椿璺�
+ ImRtcCallDO call = validateCallActive(room);
+ // 1.2 鏍¢獙鏈汉鏄閫氳瘽鐨勫弬涓庤��
+ ImRtcParticipantDO participant = validateParticipant(call, userId);
+ // 1.3 浠� INVITING 鐘舵�佸彲鎷�
+ if (!ImRtcParticipantStatusEnum.isInviting(participant.getStatus())) {
+ throw exception(RTC_SESSION_NOT_EXISTS);
+ }
+
+ // 2. INVITING 鈫� REJECTED锛涘苟鍙戝凡鍙樻洿鍒欏拷鐣�
+ int updated = rtcParticipantMapper.updateByIdAndStatus(participant.getId(), ImRtcParticipantStatusEnum.INVITING.getStatus(),
+ new ImRtcParticipantDO().setId(participant.getId()).setStatus(ImRtcParticipantStatusEnum.REJECTED.getStatus()).setLeaveTime(LocalDateTime.now()));
+ if (updated == 0) {
+ return;
+ }
+
+ // 3.1 缇ら�氳瘽鎷掔粷锛氭帹 RTC_CALL(REJECT) 缁欎富鍙紝鍐嶅垽瀹氭槸鍚﹁鍏虫埧锛堝叏鍛樻嫆鎺� / 鍙墿涓诲彨涓�浜烘椂鏀舵暃锛�
+ if (ImConversationTypeEnum.isGroup(call.getConversationType())) {
+ pushCallRejectNotification(call, userId);
+ endSessionIfTerminal(call, userId);
+ return;
+ }
+ // 3.2 绉佽亰鎷掔粷锛氳蛋 endSession锛堟帹 RTC_CALL_END(reason=REJECT)锛�
+ endSession(call, userId, ImRtcCallEndReasonEnum.REJECT);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void cancelCall(Long userId, String room) {
+ validateEnabled();
+ // 1.1 鏍¢獙閫氳瘽瀛樺湪涓旀椿璺�
+ ImRtcCallDO call = validateCallActive(room);
+ // 1.2 浠呬富鍙彲鍙栨秷
+ if (ObjUtil.notEqual(call.getInviterUserId(), userId)) {
+ throw exception(RTC_NOT_PARTICIPANT);
+ }
+ // 1.3 浠� CREATED 鐘舵�佸彲鍙栨秷锛圧UNNING 搴旇蛋 leave锛�
+ if (!ImRtcCallStatusEnum.isCreated(call.getStatus())) {
+ throw exception(RTC_SESSION_NOT_EXISTS);
+ }
+
+ // 2. 鍏充細璇濆苟鎺� RTC_CALL_END(reason=CANCEL)
+ endSession(call, userId, ImRtcCallEndReasonEnum.CANCEL);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void leaveCall(Long userId, String room) {
+ validateEnabled();
+ // 1.1 鏍¢獙閫氳瘽瀛樺湪涓旀椿璺�
+ ImRtcCallDO call = validateCallActive(room);
+ // 1.2 鏍¢獙鏈汉鏄閫氳瘽鐨勫弬涓庤��
+ ImRtcParticipantDO participant = validateParticipant(call, userId);
+
+ // 2. 褰撳墠鐘舵�� 鈫� LEFT锛涙潯浠� UPDATE 闃插苟鍙戝弽澶嶆敼
+ LocalDateTime now = LocalDateTime.now();
+ int updated = rtcParticipantMapper.updateByIdAndStatus(participant.getId(), participant.getStatus(),
+ new ImRtcParticipantDO().setId(participant.getId()).setStatus(ImRtcParticipantStatusEnum.LEFT.getStatus()).setLeaveTime(now));
+ if (updated == 0) {
+ return;
+ }
+
+ // 3. 缇ら�氳瘽宸插叆浼氬弬涓庤�呯寮�鏃舵帹閫佺绾块�氱煡
+ if (ImConversationTypeEnum.isGroup(call.getConversationType())
+ && ImRtcParticipantStatusEnum.isJoined(participant.getStatus())) {
+ pushParticipantDisconnectedNotification(call, userId);
+ }
+
+ // 4. 瑙﹀彂鍏虫埧鍒ゅ畾锛氱鑱婁换涓�鏂圭寮�蹇呭叧锛涚兢閫氳瘽浠呭湪銆屾棤浜哄湪鎴� + 鏃犱汉鍝嶉搩銆嶆椂鍏�
+ endSessionIfTerminal(call, userId);
+ }
+
+ /**
+ * 缇ら�氳瘽鏄惁搴旇鍏抽棴
+ * <p>
+ * 涓ょ缁堟�侊細
+ * 1. JOINED 鏁� = 0锛堟埧鍐呭凡娌′汉锛�
+ * 2. JOINED 鏁� = 1 涓� INVITING 鏁� = 0锛堝彧鍓� 1 浜虹嫭瀹堬紝鏃犲悗缁彲鍔犲叆鑰咃級
+ * <p>
+ * 鍏虫埧鍚� endSession 浼氭妸娈嬬暀 INVITING 鎵归噺鏀� NO_ANSWER 骞舵帹 RTC_CALL_END锛屽搷閾冪 UI 鑷姩鏀舵暃
+ *
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ * @return true 琛ㄧず鏃犳硶缁х画閫氳瘽锛屽簲鍏虫埧
+ */
+ private boolean shouldCloseGroupRoom(String room) {
+ int joined = 0;
+ int inviting = 0;
+ for (ImRtcParticipantDO p : rtcParticipantMapper.selectListByRoom(room)) {
+ if (ImRtcParticipantStatusEnum.isJoined(p.getStatus())) {
+ joined++;
+ } else if (ImRtcParticipantStatusEnum.isInviting(p.getStatus())) {
+ inviting++;
+ }
+ }
+ return joined == 0 || (joined == 1 && inviting == 0);
+ }
+
+ /**
+ * 鏌ヨ涓や汉鍏卞悓鎵�鍦ㄧ殑娲昏穬绉佽亰閫氳瘽
+ * <p>
+ * 鎷嗘垚 3 娈电畝鍗曟煡璇細鎷� A 鐨勬椿璺� participant 鈫� 鎷夸富琛ㄥ垽绉佽亰鏈粨鏉� 鈫� 鐪� B 鏄惁鍦ㄥ悓 call 娲昏穬
+ *
+ * @param userIdA 鐢ㄦ埛 A 缂栧彿
+ * @param userIdB 鐢ㄦ埛 B 缂栧彿
+ * @return 娲昏穬绉佽亰閫氳瘽锛涗笉瀛樺湪杩斿洖 null
+ */
+ private ImRtcCallDO getActivePrivateCallByPair(Long userIdA, Long userIdB) {
+ ImRtcParticipantDO participantA = rtcParticipantMapper.selectLastOneByUserIdAndStatus(userIdA, ImRtcParticipantStatusEnum.ACTIVE_STATUSES);
+ if (participantA == null) {
+ return null;
+ }
+ ImRtcCallDO call = rtcCallMapper.selectByRoom(participantA.getRoom());
+ if (call == null
+ || !ImConversationTypeEnum.isPrivate(call.getConversationType())
+ || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
+ return null;
+ }
+ ImRtcParticipantDO participantB = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userIdB);
+ if (participantB == null
+ || !ImRtcParticipantStatusEnum.ACTIVE_STATUSES.contains(participantB.getStatus())) {
+ return null;
+ }
+ return call;
+ }
+
+ @Override
+ public ImRtcCallDO getActiveCall(Long userId, Long groupId) {
+ validateEnabled();
+ // 1. 閴存潈锛氫粎缇ゆ椿璺冩垚鍛樿兘鏌ワ紙璧板崟琛� SQL锛屼笉渚濊禆鎴愬憳鍒楄〃缂撳瓨锛�
+ groupMemberService.validateMemberInGroup(groupId, userId);
+ // 2. 鏌ヨ娲昏穬閫氳瘽
+ return rtcCallMapper.selectLastOneByGroupIdAndStatusIn(groupId, ImRtcCallStatusEnum.ACTIVE_STATUSES);
+ }
+
+ @Override
+ public List<ImRtcParticipantDO> getCallParticipantList(String room) {
+ return rtcParticipantMapper.selectListByRoom(room);
+ }
+
+ @Override
+ public String signCallToken(Long userId, String room) {
+ validateEnabled();
+ ImRtcCallDO call = validateCallActive(room);
+ ImRtcParticipantDO participant = validateParticipant(call, userId);
+ if (!ImRtcParticipantStatusEnum.isJoined(participant.getStatus())) {
+ throw exception(RTC_NOT_PARTICIPANT);
+ }
+ return signToken(userId, resolveDisplayName(adminUserApi.getUser(userId), userId), room);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void handleLiveKitEvent(LiveKitWebhookEventDTO event) {
+ if (event == null || event.getEvent() == null) {
+ return;
+ }
+ switch (event.getEvent()) {
+ case LiveKitWebhookEventDTO.EVENT_PARTICIPANT_JOINED:
+ handleParticipantJoined(event);
+ break;
+ case LiveKitWebhookEventDTO.EVENT_PARTICIPANT_LEFT:
+ handleParticipantLeft(event);
+ break;
+ case LiveKitWebhookEventDTO.EVENT_ROOM_FINISHED:
+ handleRoomFinished(event);
+ break;
+ default:
+ // 鍏跺畠浜嬩欢蹇界暐锛泃rack_published 绛変笟鍔℃�佺敱 LiveKit 鑷韩鍒嗗彂椹卞姩
+ }
+ }
+
+ /**
+ * 澶勭悊 LiveKit 銆屾垚鍛樺姞鍏ャ�嶄簨浠讹細DB 鎺ラ�氭�佺敱 {@link #acceptCall(Long, String)} 鎺ュ彛鍐欏叆锛屾澶勪粎鍋� 1602 杞帹
+ *
+ * @param event 浜嬩欢
+ */
+ private void handleParticipantJoined(LiveKitWebhookEventDTO event) {
+ if (ObjUtil.hasNull(event.getRoom(), event.getParticipant())) {
+ return;
+ }
+ // 1. 鍓嶇疆妫�鏌ワ細閫氳瘽瀛樺湪涓旀椿璺�
+ String room = event.getRoom().getName();
+ ImRtcCallDO call = rtcCallMapper.selectByRoom(room);
+ if (call == null || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
+ return;
+ }
+ Long userId = liveKitClient.parseUserId(event.getParticipant().getIdentity());
+ if (userId == null) {
+ return;
+ }
+
+ // 2. 鎺� 1602 閫氱煡鍙備笌鏂� / 鍏ㄧ兢鍙備笌鏂�
+ pushParticipantConnectedNotification(call, userId);
+ }
+
+ /**
+ * 澶勭悊 LiveKit 銆屾垚鍛樼寮�銆嶄簨浠讹細姝e父 {@link #leaveCall(Long, String)} 鎺ュ彛宸茬粡娓呯悊杩囩殑璇濓紝鏉′欢 UPDATE 鑷姩骞傜瓑
+ *
+ * @param event 浜嬩欢
+ */
+ private void handleParticipantLeft(LiveKitWebhookEventDTO event) {
+ if (ObjUtil.hasNull(event.getRoom(), event.getParticipant())) {
+ return;
+ }
+ // 1. 鍓嶇疆妫�鏌ワ細閫氳瘽瀛樺湪涓旀椿璺� + 鍙備笌鑰呬粛鍦� JOINED
+ String room = event.getRoom().getName();
+ ImRtcCallDO call = rtcCallMapper.selectByRoom(room);
+ if (call == null || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
+ return;
+ }
+ Long userId = liveKitClient.parseUserId(event.getParticipant().getIdentity());
+ if (userId == null) {
+ return;
+ }
+ ImRtcParticipantDO participant = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
+ if (participant == null || !ImRtcParticipantStatusEnum.isJoined(participant.getStatus())) {
+ return;
+ }
+
+ // 2. JOINED 鈫� LEFT锛涙甯� leave 鎺ュ彛宸叉敼杩囧垯 update 褰卞搷 0 琛岀洿鎺ラ��鍑�
+ int updated = rtcParticipantMapper.updateByIdAndStatus(participant.getId(), ImRtcParticipantStatusEnum.JOINED.getStatus(),
+ new ImRtcParticipantDO().setId(participant.getId()).setStatus(ImRtcParticipantStatusEnum.LEFT.getStatus()).setLeaveTime(LocalDateTime.now()));
+ if (updated == 0) {
+ return;
+ }
+ log.info("[handleParticipantLeft][room={} userId={} 鐢� LiveKit Webhook 鍏滃簳]", room, userId);
+
+ // 3. 鎺� 1603 閫氱煡鍙備笌鏂� / 鍏ㄧ兢鍙備笌鏂�
+ pushParticipantDisconnectedNotification(call, userId);
+ // 4. 瑙﹀彂鍏虫埧鍒ゅ畾锛氱鑱婁换涓�鏂圭寮�蹇呭叧锛涚兢閫氳瘽浠呭湪銆屾棤浜哄湪鎴� + 鏃犱汉鍝嶉搩銆嶆椂鍏�
+ endSessionIfTerminal(call, userId);
+ }
+
+ /**
+ * 澶勭悊 LiveKit 銆屾埧闂寸粨鏉熴�嶄簨浠讹細鍏滃簳鎶� call 鎺ㄥ埌 ENDED
+ *
+ * @param event 浜嬩欢
+ */
+ private void handleRoomFinished(LiveKitWebhookEventDTO event) {
+ if (event.getRoom() == null) {
+ return;
+ }
+ // 1. 鍓嶇疆妫�鏌ワ細閫氳瘽瀛樺湪涓旀椿璺�
+ String room = event.getRoom().getName();
+ ImRtcCallDO call = rtcCallMapper.selectByRoom(room);
+ if (call == null || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
+ return;
+ }
+ // 2. 鍏充細璇�
+ log.info("[handleRoomFinished][room={} 鐢� LiveKit Webhook 鍏滃簳]", room);
+ endSession(call, null, ImRtcCallEndReasonEnum.HANGUP);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int cleanupZombieCalls(int thresholdMinutes) {
+ // 闃堝�肩敱璋冪敤鏂癸紙Job锛変繚璇� > 0锛涗綆浜� 1 鍒嗛挓浼氳鏉�鍒氬彂璧风殑鍚堢悊闆朵汉鎬�
+ LocalDateTime threshold = LocalDateTime.now().minusMinutes(thresholdMinutes);
+ List<ImRtcCallDO> candidates = rtcCallMapper.selectListByStatusInAndStartTimeBefore(
+ ImRtcCallStatusEnum.ACTIVE_STATUSES, threshold);
+ if (CollUtil.isEmpty(candidates)) {
+ return 0;
+ }
+
+ // 2. 閫愪釜鏌� LiveKit 鎴块棿鐪熷疄 participant 鏁�
+ int cleaned = 0;
+ for (ImRtcCallDO call : candidates) {
+ int count;
+ try {
+ count = liveKitClient.listParticipants(call.getRoom());
+ } catch (Exception e) {
+ log.warn("[cleanupZombieCalls][鏌ヨ LiveKit 澶辫触 room={}]", call.getRoom(), e);
+ continue;
+ }
+ if (count != 0) {
+ continue;
+ }
+ log.info("[cleanupZombieCalls][娓呯悊鍍靛案閫氳瘽 room={}]", call.getRoom());
+ endSession(call, null, ImRtcCallEndReasonEnum.HANGUP);
+ cleaned++;
+ }
+ return cleaned;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int timeoutInvitingParticipants(int thresholdMinutes) {
+ // 闃堝�肩敱璋冪敤鏂癸紙Job锛変繚璇� > 0锛涗綆浜� 1 鍒嗛挓鍙兘璇潃鍒氬彂璧疯繕鍦ㄥ搷閾冪殑鍚堢悊 INVITING 鎬�
+ LocalDateTime threshold = LocalDateTime.now().minusMinutes(thresholdMinutes);
+ return noAnswerCallCheck0(rtcParticipantMapper.selectListByStatusAndInviteTimeBefore(
+ ImRtcParticipantStatusEnum.INVITING.getStatus(), threshold));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void noAnswerCallCheck(Long userId, String room) {
+ // 閴存潈锛氫粎璇� room 鍙備笌鑰呭彲瑙﹀彂锛涘け璐ラ潤榛橈紝涓嶆毚闇查敊璇�
+ ImRtcParticipantDO operator = rtcParticipantMapper.selectByRoomAndUserId(room, userId);
+ if (operator == null) {
+ return;
+ }
+ // 闃堝�煎彇鍚庣閰嶇疆锛岄伩鍏嶅墠鍚庣閰嶇疆涓嶄竴鑷达紱鍓嶇 timer 浠呮槸瑙﹀彂鏃舵満
+ LocalDateTime threshold = LocalDateTime.now()
+ .minusMinutes(imProperties.getRtc().getInviteTimeoutMinutes());
+ List<ImRtcParticipantDO> candidates = rtcParticipantMapper.selectListByRoomAndStatusAndInviteTimeBefore(
+ room, ImRtcParticipantStatusEnum.INVITING.getStatus(), threshold);
+ noAnswerCallCheck0(candidates);
+ }
+
+ /**
+ * 鎵归噺瓒呮椂澶勭悊锛氬惊鐜崟鍙備笌鑰咃紱鍚� room 澶嶇敤 call銆佹壒閲忛鏌� user 閬垮厤 N+1锛涜繑鍥炴垚鍔熷鐞嗘暟
+ *
+ * @param candidates 宸茶繃婊ょ殑瓒呮椂 INVITING 鍊欓��
+ * @return 鎴愬姛澶勭悊锛圕AS 鎶㈠崰锛夌殑鏁伴噺
+ */
+ private int noAnswerCallCheck0(List<ImRtcParticipantDO> candidates) {
+ if (CollUtil.isEmpty(candidates)) {
+ return 0;
+ }
+ Map<String, ImRtcCallDO> callCache = new HashMap<>();
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
+ CollectionUtils.convertSet(candidates, ImRtcParticipantDO::getUserId));
+ int timedOut = 0;
+ for (ImRtcParticipantDO participant : candidates) {
+ if (timeoutInvitingParticipant(participant, callCache, userMap)) {
+ timedOut++;
+ }
+ }
+ return timedOut;
+ }
+
+ /**
+ * 鍗曞弬涓庤�呮尟閾冭秴鏃讹細CAS 鎶� INVITING 鍒囧埌 NO_ANSWER锛岀兢閫氳瘽鎺� RTC_CALL(NO_ANSWER) + 绾ц仈鍏虫埧鍒ゅ畾锛�
+ * 绉佽亰鍦烘櫙琚彨瓒呮椂鍗虫暣閫氳瘽缁撴潫锛岃蛋 endSession(NO_ANSWER) 鎺� RTC_CALL_END
+ *
+ * @param participant INVITING 鐘舵�佺殑瓒呮椂鍊欓��
+ * @param callCache 鎸� room 缂撳瓨 call 瀵硅薄锛岄伩鍏嶅悓鎵规澶氫汉閲嶅鏌ヨ
+ * @param userMap 鍊欓�夌敤鎴烽鏌� map锛涢伩鍏嶉�愪釜 adminUserApi.getUser 璧� N+1
+ * @return 鏄惁鎴愬姛澶勭悊锛圕AS 澶辫触 / 閫氳瘽涓昏〃缂哄け绛夊満鏅繑鍥� false锛�
+ */
+ private boolean timeoutInvitingParticipant(ImRtcParticipantDO participant,
+ Map<String, ImRtcCallDO> callCache,
+ Map<Long, AdminUserRespDTO> userMap) {
+ // 1. CAS锛欼NVITING 鈫� NO_ANSWER锛涘苟鍙戝凡鍙橈紙鐢ㄦ埛鍒氭帴 / 鎷掞紝鎴� endSession 鏁翠綋鏀癸級璺宠繃
+ int updated = rtcParticipantMapper.updateByIdAndStatus(participant.getId(),
+ ImRtcParticipantStatusEnum.INVITING.getStatus(),
+ new ImRtcParticipantDO().setId(participant.getId())
+ .setStatus(ImRtcParticipantStatusEnum.NO_ANSWER.getStatus())
+ .setLeaveTime(LocalDateTime.now()));
+ if (updated == 0) {
+ return false;
+ }
+ Long userId = participant.getUserId();
+ log.info("[timeoutInvitingParticipant][鍙備笌鑰呮尟閾冭秴鏃� room={} userId={}]", participant.getRoom(), userId);
+
+ // 2. 鏌ヨ閫氳瘽涓昏〃锛涘悓 room 澶嶇敤 callCache锛岄伩鍏嶅悓鎵规澶氫汉閲嶅鏌ヨ
+ ImRtcCallDO call = callCache.computeIfAbsent(participant.getRoom(), rtcCallMapper::selectByRoom);
+ if (call == null) {
+ log.warn("[timeoutInvitingParticipant][閫氳瘽涓昏〃缂哄け room={} userId={}]", participant.getRoom(), userId);
+ return false;
+ }
+
+ // 3.1 缇ら�氳瘽锛氭帹 RTC_CALL(NO_ANSWER) 璁╁墠绔� banner 绉婚櫎璇ヤ汉 + 绾ц仈鍏虫埧鍒ゅ畾
+ if (ImConversationTypeEnum.isGroup(call.getConversationType())) {
+ pushCallNoAnswerNotification(call, userId, userMap.get(userId));
+ endSessionIfTerminal(call, userId);
+ return true;
+ }
+ // 3.2 绉佽亰锛氳鍙秴鏃� = 鏁撮�氳瘽鏃犱汉鎺ュ惉锛岃蛋 endSession 鎺� RTC_CALL_END(NO_ANSWER)
+ endSession(call, userId, ImRtcCallEndReasonEnum.NO_ANSWER);
+ return true;
+ }
+
+ // ========== 鍐呴儴杈呭姪 ==========
+
+ private void validateEnabled() {
+ if (!imProperties.getRtc().isEnabled()) {
+ throw exception(RTC_NOT_ENABLED);
+ }
+ }
+
+ /**
+ * 鏍¢獙閫氳瘽瀛樺湪涓旀椿璺冿細涓嶅瓨鍦� / 宸� ENDED 鐩存帴鎶�
+ *
+ * @param room 涓氬姟閫氳瘽缂栧彿
+ * @return 閫氳瘽涓昏〃
+ */
+ private ImRtcCallDO validateCallActive(String room) {
+ ImRtcCallDO call = rtcCallMapper.selectByRoom(room);
+ if (call == null || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
+ throw exception(RTC_SESSION_NOT_EXISTS);
+ }
+ return call;
+ }
+
+ /**
+ * 鏍¢獙鏈汉鏄閫氳瘽鐨勫弬涓庤�咃細accept / reject / leave / refreshToken 鐨勫叡鐢ㄥ墠缃�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @return 鍙備笌鑰呰褰�
+ */
+ private ImRtcParticipantDO validateParticipant(ImRtcCallDO call, Long userId) {
+ ImRtcParticipantDO participant = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
+ if (participant == null) {
+ throw exception(RTC_NOT_PARTICIPANT);
+ }
+ return participant;
+ }
+
+ /**
+ * 鏍¢獙鐢ㄦ埛涓嶅湪鍏跺畠娲昏穬閫氳瘽涓�
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param room 褰撳墠鎴块棿鏍囪瘑
+ */
+ private void validateUserNotInOtherCall(Long userId, String room) {
+ // 鏌ヨ褰撳墠鎴块棿澶栫殑娲昏穬鍙備笌璁板綍
+ ImRtcParticipantDO participant = rtcParticipantMapper.selectLastOneByUserIdAndStatusInAndRoomNot(
+ userId, ImRtcParticipantStatusEnum.ACTIVE_STATUSES, room);
+ // 瀛樺湪娲昏穬鍙備笌璁板綍锛屽垯褰撳墠鐢ㄦ埛蹇欑嚎
+ if (participant != null) {
+ throw exception(RTC_SELF_BUSY);
+ }
+ }
+
+ /**
+ * 鍔犲叆缇ら�氳瘽鍙備笌鑰呭垪琛�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param now 褰撳墠鏃堕棿
+ */
+ private void joinParticipant(ImRtcCallDO call, Long userId, LocalDateTime now) {
+ // 1. 宸叉湁鍙備笌璁板綍锛氬垏鍥� JOINED
+ ImRtcParticipantDO existing = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
+ if (existing != null) {
+ updateParticipantJoined(existing, now);
+ return;
+ }
+
+ // 2. 鏃犲弬涓庤褰曪細浠ヤ富鍔ㄥ姞鍏ヨ�呰韩浠芥柊澧�
+ try {
+ rtcParticipantMapper.insert(new ImRtcParticipantDO()
+ .setCallId(call.getId()).setRoom(call.getRoom())
+ .setUserId(userId).setRole(ImRtcParticipantRoleEnum.JOINER.getRole())
+ .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus()).setInviteTime(now).setAcceptTime(now));
+ } catch (DuplicateKeyException ex) {
+ // 3. 鍞竴閿啿绐侊細鍥炴煡骞跺鐢ㄥ苟鍙戝啓鍏ョ殑璁板綍
+ existing = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
+ if (existing == null) {
+ throw ex;
+ }
+ updateParticipantJoined(existing, now);
+ }
+ }
+
+ /**
+ * 灏嗗弬涓庤�呮洿鏂颁负宸插姞鍏�
+ *
+ * @param participant 鍙備笌鑰呰褰�
+ * @param now 褰撳墠鏃堕棿
+ */
+ private void updateParticipantJoined(ImRtcParticipantDO participant, LocalDateTime now) {
+ // 宸叉槸 JOINED 鐩存帴杩斿洖
+ if (ImRtcParticipantStatusEnum.isJoined(participant.getStatus())) {
+ return;
+ }
+ // 鏇存柊鐘舵�佸拰鎺ュ惉鏃堕棿
+ rtcParticipantMapper.updateById(new ImRtcParticipantDO().setId(participant.getId())
+ .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus()).setAcceptTime(now));
+ }
+
+ /**
+ * 鍏虫埧鍒ゅ畾鏀跺彛锛氱鑱婁换涓�鏂圭寮�蹇呭叧锛涚兢閫氳瘽浠呭湪銆屾棤浜哄湪鎴� + 鏃犱汉鍝嶉搩銆嶆椂鍏�
+ * <p>
+ * end reason 鎸� call.status 鑷姩鎺細CREATED锛堟病浜烘帴閫氳繃锛�= CANCEL锛汻UNNING锛堟湁浜烘帴閫氳繃锛�= HANGUP
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param operatorId 鎿嶄綔鑰呯敤鎴风紪鍙凤紱webhook 鍏滃簳鍦烘櫙鍙┖
+ */
+ private void endSessionIfTerminal(ImRtcCallDO call, Long operatorId) {
+ if (!ImConversationTypeEnum.isPrivate(call.getConversationType())
+ && !shouldCloseGroupRoom(call.getRoom())) {
+ return;
+ }
+ ImRtcCallEndReasonEnum reason = ImRtcCallStatusEnum.isCreated(call.getStatus())
+ ? ImRtcCallEndReasonEnum.CANCEL : ImRtcCallEndReasonEnum.HANGUP;
+ endSession(call, operatorId, reason);
+ }
+
+ /**
+ * 鏍¢獙鍒涘缓閫氳瘽鍏ュ弬锛涙寜鍦烘櫙鍖哄垎蹇呭~瀛楁锛岀鑱婅ˉ濂藉弸鏍¢獙锛岀兢鑱婅ˉ缇ゆ垚鍛樻牎楠�
+ *
+ * @param userId 鍙戣捣浜虹紪鍙�
+ * @param reqVO 鍒涘缓璇锋眰
+ */
+ private void validateCreateCall(Long userId, ImRtcCallCreateReqVO reqVO) {
+ Integer conversationType = reqVO.getConversationType();
+ if (ImConversationTypeEnum.isPrivate(conversationType)) {
+ // 绉佽亰蹇呴』 1 涓绔�
+ if (CollUtil.size(reqVO.getInviteeIds()) != 1) {
+ throw exception(RTC_PRIVATE_INVITEE_REQUIRED);
+ }
+ Long peerUserId = CollUtil.getFirst(reqVO.getInviteeIds());
+ if (ObjUtil.equal(userId, peerUserId)) {
+ throw exception(RTC_INVITE_SELF);
+ }
+ friendService.validateFriend(userId, peerUserId);
+ return;
+ }
+ if (ImConversationTypeEnum.isGroup(conversationType)) {
+ if (reqVO.getGroupId() == null) {
+ throw exception(RTC_GROUP_REQUIRED);
+ }
+ // 缇ら�氳瘽蹇呴』鍓嶇閫変腑琚個璇蜂汉锛堝榻愬井淇★級锛涚┖闆嗗悎鐩存帴鎷�
+ if (CollUtil.isEmpty(reqVO.getInviteeIds())) {
+ throw exception(RTC_GROUP_INVITEE_REQUIRED);
+ }
+ groupMemberService.validateMemberInGroup(reqVO.getGroupId(), userId);
+ return;
+ }
+ throw new IllegalArgumentException("闈炴硶鐨� conversationType: " + conversationType);
+ }
+
+ /**
+ * 瑙f瀽琚個璇锋睜锛氱鑱婁负 peerUserId 鍗曞厓绱狅紱缇よ亰涓哄墠绔�変腑瀛愰泦锛堣秴閲忔姏閿欙級
+ *
+ * @param reqVO 鍒涘缓璇锋眰
+ * @param inviterId 鍙戣捣浜虹紪鍙凤紱鑷繁涓嶈繘琚個璇锋睜
+ * @return 琚個璇蜂汉 userId 闆嗗悎
+ */
+ private Set<Long> resolveInvitees(ImRtcCallCreateReqVO reqVO, Long inviterId) {
+ // 1. 绉佽亰锛歩nviteeIds 宸插湪 validateCreateCall 鏍¢獙浠� 1 涓绔紝鐩存帴澶嶇敤
+ if (ImConversationTypeEnum.isPrivate(reqVO.getConversationType())) {
+ return new LinkedHashSet<>(reqVO.getInviteeIds());
+ }
+
+ // 2. 缇よ亰鏍¢獙锛氳閭�璇蜂汉蹇呴』鏄缇ゆ椿璺冩垚鍛橈紝闃叉鎭舵剰瀹㈡埛绔浠绘剰 userId
+ groupMemberService.validateMembersInGroup(reqVO.getGroupId(), reqVO.getInviteeIds());
+ Set<Long> initial = new LinkedHashSet<>(reqVO.getInviteeIds());
+ // 鍙戣捣浜烘湰浜轰笉杩涜閭�璇锋睜
+ initial.remove(inviterId);
+ if (CollUtil.isEmpty(initial)) {
+ throw exception(RTC_GROUP_INVITEE_REQUIRED);
+ }
+ int max = imProperties.getRtc().getGroupMaxParticipants();
+ if (initial.size() + 1 > max) {
+ throw exception(RTC_GROUP_INVITEE_OVER_LIMIT);
+ }
+ return initial;
+ }
+
+ /**
+ * 涓昏〃 CREATED 鈫� RUNNING锛涗粎褰撻涓潪鍙戣捣浜哄姞鍏ユ椂鎺ㄨ繘锛涙潯浠� UPDATE 淇濆箓绛�
+ *
+ * @param call 閫氳瘽涓昏〃锛涙帹杩涙垚鍔熷悗浼氬悓姝ュ唴瀛樺瓧娈�
+ * @param acceptorId 鍔犲叆鑰呯敤鎴风紪鍙凤紱鍙戣捣浜哄姞鍏ヤ笉绠椼�岄娆℃帴閫氥��
+ * @param now 褰撳墠鏃堕棿
+ */
+ private void maybeMarkOngoing(ImRtcCallDO call, Long acceptorId, LocalDateTime now) {
+ // 1. 宸� RUNNING / ENDED 鐩存帴閫�鍑猴紱鍙戣捣浜哄姞鍏ヤ笉绠椼�岄娆℃湁浜烘帴閫氥��
+ if (!ImRtcCallStatusEnum.isCreated(call.getStatus())) {
+ return;
+ }
+ if (ObjUtil.equal(call.getInviterUserId(), acceptorId)) {
+ return;
+ }
+
+ // 2. CREATED 鈫� RUNNING 鏉′欢 UPDATE锛涘浜哄苟鍙戝彧鏈変竴浜烘垚鍔�
+ int updated = rtcCallMapper.updateByIdAndStatus(call.getId(), ImRtcCallStatusEnum.CREATED.getStatus(),
+ new ImRtcCallDO().setStatus(ImRtcCallStatusEnum.RUNNING.getStatus()).setAcceptTime(now));
+ if (updated == 0) {
+ // 3. 绔炰簤澶辫触锛歳eload 鐪嬬湡瀹炵粓鎬侊紱宸� ENDED 鎶涢敊锛屽惁鍒欏悓姝ュ唴瀛�
+ ImRtcCallDO latest = rtcCallMapper.selectById(call.getId());
+ if (latest == null || ImRtcCallStatusEnum.isEnded(latest.getStatus())) {
+ throw exception(RTC_SESSION_NOT_EXISTS);
+ }
+ call.setStatus(latest.getStatus()).setAcceptTime(latest.getAcceptTime());
+ return;
+ }
+ // 4. 鎺ㄨ繘鎴愬姛锛氬悓姝ュ唴瀛樼粰鍚庣画鍒ゆ柇
+ call.setStatus(ImRtcCallStatusEnum.RUNNING.getStatus()).setAcceptTime(now);
+ }
+
+ /**
+ * 鍏抽棴浼氳瘽锛氫富琛ㄦ潯浠� UPDATE 鎺ㄥ埌 ENDED 鈫� 娈嬬暀 INVITING 鎵归噺鏀� NO_ANSWER 鈫� 鎺� RTC_CALL_END
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param operatorId 鎿嶄綔鑰呯敤鎴风紪鍙凤紱webhook 鍏滃簳 / Job 娓呯悊鍦烘櫙鍙┖
+ * @param reason 缁撴潫鍘熷洜
+ */
+ private void endSession(ImRtcCallDO call, Long operatorId, ImRtcCallEndReasonEnum reason) {
+ // 1.1 鏇存柊閫氳瘽涓昏〃涓哄凡缁撴潫锛涙潯浠� UPDATE 浠呭湪 status 杩樻椿璺冩椂鐢熸晥
+ LocalDateTime now = LocalDateTime.now();
+ int updated = rtcCallMapper.updateByIdAndStatusIn(call.getId(), ImRtcCallStatusEnum.ACTIVE_STATUSES,
+ new ImRtcCallDO().setStatus(ImRtcCallStatusEnum.ENDED.getStatus())
+ .setEndReason(reason.getReason()).setEndTime(now));
+ if (updated == 0) {
+ log.info("[endSession][宸茶鍙︿竴璺緞缁堢粨锛岃烦杩� room={} operator={} reason={}]",
+ call.getRoom(), operatorId, reason);
+ return;
+ }
+ // 銆愮壒娈娿�戝悓姝ュ唴瀛� call锛氳 createCall 杩欑被璋冪敤鏂规嬁鍒扮殑 DO 绔嬪嵆鍙嶆槧 ENDED 缁堟�侊紝Controller 鎷� RespVO 鑳界洿鎺ョ敤
+ call.setStatus(ImRtcCallStatusEnum.ENDED.getStatus()).setEndReason(reason.getReason()).setEndTime(now);
+ // 1.2 鏇存柊鍙備笌琛ㄤ负宸茬粨鏉燂細娈嬬暀 INVITING 鏀� NO_ANSWER锛涙畫鐣� JOINED 鏀� LEFT 骞跺啓 leaveTime
+ rtcParticipantMapper.updateByRoomAndStatus(call.getRoom(), ImRtcParticipantStatusEnum.INVITING.getStatus(),
+ new ImRtcParticipantDO().setStatus(ImRtcParticipantStatusEnum.NO_ANSWER.getStatus()));
+ rtcParticipantMapper.updateByRoomAndStatus(call.getRoom(), ImRtcParticipantStatusEnum.JOINED.getStatus(),
+ new ImRtcParticipantDO().setStatus(ImRtcParticipantStatusEnum.LEFT.getStatus()).setLeaveTime(now));
+
+ // 2. 鎺� RTC_CALL_END锛涘厛浜� deleteRoom 寮傛鍙戝嚭锛岃鍓嶇鎸変笟鍔¤涔� reset锛圢O_ANSWER / CANCEL 绛夛級锛�
+ // 閬垮厤闅忓悗 LiveKit Disconnected 浜嬩欢鎶㈠厛瑙﹀彂鍓嶇 "閫氳瘽宸叉柇寮�" 鍏滃簳 toast
+ Long durationSeconds = call.getAcceptTime() != null ?
+ Duration.between(call.getAcceptTime(), now).getSeconds() : null;
+ pushCallEndNotification(call, operatorId, reason, durationSeconds);
+
+ // 3. 鍏滃簳鍒犻櫎 LiveKit 鎴块棿锛屽己鍒舵柇寮�寮傚父娈嬬暀瀹㈡埛绔紱澶辫触浠呰鏃ュ織锛屼笉闃绘柇涓氬姟
+ try {
+ liveKitClient.deleteRoom(call.getRoom());
+ } catch (Exception e) {
+ log.warn("[endSession][鍒犻櫎 LiveKit 鎴块棿澶辫触 room={} operator={} reason={}]",
+ call.getRoom(), operatorId, reason, e);
+ }
+ log.info("[endSession][room={} operator={} reason={}]", call.getRoom(), operatorId, reason);
+ }
+
+ /**
+ * 閫氳瘽浜嬩欢鐨勬敹浠朵汉姹狅細1锛夌鑱婁负鍙屾柟鍙備笌鑰咃紱2锛夌兢鑱婁负缇ゆ椿璺冩垚鍛�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @return 鏀朵欢浜� userId 闆嗗悎
+ */
+ private Collection<Long> getCallAudienceUserIdList(ImRtcCallDO call) {
+ if (ImConversationTypeEnum.isGroup(call.getConversationType())) {
+ return groupMemberService.getActiveGroupMemberUserIdsByGroupId(call.getGroupId());
+ }
+ return CollectionUtils.convertSet(
+ rtcParticipantMapper.selectListByRoom(call.getRoom()), ImRtcParticipantDO::getUserId);
+ }
+
+ // ========== 閫氱煡鎺ㄩ�� ==========
+
+ /**
+ * RTC_CALL(INVITE)锛氳蛋 webSocketService 鐩存帹鍒拌閭�璇蜂汉锛沺ersistent=false 涓嶅叆娑堟伅娴�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param inviter 鍙戣捣浜猴紱鍙┖锛岀己澶辨椂 payload 鐨� inviterNickname / Avatar 鐣欑┖
+ * @param inviteeId 琚個璇蜂汉鐢ㄦ埛缂栧彿
+ * @param invitee 琚個璇蜂汉锛涘彲绌猴紝缂哄け鏃� token 鍐� displayName 闄嶇骇涓� userId
+ * @param inviteeIds 鏈琚個璇蜂汉鍒楄〃锛涘墠绔潵鐢电晫闈㈠睍绀恒�岄個璇风殑鍏朵粬浜恒�嶇敤锛屽寘鍚� inviteeId 鑷韩
+ */
+ private void pushCallInviteNotification(ImRtcCallDO call, AdminUserRespDTO inviter,
+ Long inviteeId, AdminUserRespDTO invitee,
+ Collection<Long> inviteeIds) {
+ String token = signToken(inviteeId, resolveDisplayName(invitee, inviteeId), call.getRoom());
+ ImRtcCallNotification payload = ImRtcCallNotification.ofInvite(
+ call, inviter, imProperties.getRtc().getLivekitUrl(), token, inviteeIds);
+ webSocketService.sendNotificationAsync(inviteeId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.RTC_CALL.getType(), payload);
+ }
+
+ /**
+ * RTC_CALL(REJECT)锛氫粎缇ら�氳瘽鍦烘櫙锛涜蛋 webSocketService 鎺ㄧ粰缇ら�氳瘽鍙椾紬
+ * <p>
+ * 绉佽亰鎷掔粷璧� endSession 鈫� RTC_CALL_END(reason=REJECT) 鍏ユ秷鎭祦锛屼笉鍦ㄦ鎺�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param operatorUserId 鎷掓帴鑰呯敤鎴风紪鍙�
+ */
+ private void pushCallRejectNotification(ImRtcCallDO call, Long operatorUserId) {
+ AdminUserRespDTO operator = operatorUserId != null ? adminUserApi.getUser(operatorUserId) : null;
+ ImRtcCallNotification payload = ImRtcCallNotification.ofReject(call, operatorUserId, operator);
+ for (Long receiverUserId : getCallAudienceUserIdList(call)) {
+ webSocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.RTC_CALL.getType(), payload);
+ }
+ }
+
+ /**
+ * RTC_CALL(NO_ANSWER)锛氫粎缇ら�氳瘽鍦烘櫙锛涙尟閾冭秴鏃剁敱 Job 瑙﹀彂锛涜蛋 webSocketService 鎺ㄧ粰缇ら�氳瘽鍙椾紬
+ * <p>
+ * 绉佽亰鏈帴鍚蛋 endSession 鈫� RTC_CALL_END(reason=NO_ANSWER) 鍏ユ秷鎭祦锛屼笉鍦ㄦ鎺�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param operatorUserId 鏈帴鍚�呯敤鎴风紪鍙�
+ * @param operator 鏈帴鍚�呴鏌ョ粨鏋滐紱璋冪敤鏂规壒閲忔煡閬垮厤 N+1锛屽彲绌�
+ */
+ private void pushCallNoAnswerNotification(ImRtcCallDO call, Long operatorUserId, AdminUserRespDTO operator) {
+ ImRtcCallNotification payload = ImRtcCallNotification.ofNoAnswer(call, operatorUserId, operator);
+ for (Long receiverUserId : getCallAudienceUserIdList(call)) {
+ webSocketService.sendNotificationAsync(receiverUserId, ImConversationTypeEnum.NONE.getType(),
+ ImContentTypeEnum.RTC_CALL.getType(), payload);
+ }
+ }
+
+ /**
+ * 閫氳瘽鍙備笌鑰呭姞鍏ワ細LiveKit webhook participant_joined 瑙﹀彂锛涚鑱婃帹鍙屾柟澶氱銆佺兢鑱婃帹鍏ㄧ兢鎴愬憳锛堣兌鍥婃潯 + 1锛�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param userId 鍔犲叆鐨勫弬涓庤�呯敤鎴风紪鍙�
+ */
+ private void pushParticipantConnectedNotification(ImRtcCallDO call, Long userId) {
+ pushParticipantNotification(call, ImContentTypeEnum.RTC_PARTICIPANT_CONNECTED.getType(), userId,
+ ImRtcParticipantConnectedNotification.of(call, userId));
+ }
+
+ /**
+ * 閫氳瘽鍙備笌鑰呯寮�锛歀iveKit webhook participant_left 瑙﹀彂锛涙帹閫佽寖鍥村悓 {@link #pushParticipantConnectedNotification}
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param userId 绂诲紑鐨勫弬涓庤�呯敤鎴风紪鍙�
+ */
+ private void pushParticipantDisconnectedNotification(ImRtcCallDO call, Long userId) {
+ pushParticipantNotification(call, ImContentTypeEnum.RTC_PARTICIPANT_DISCONNECTED.getType(), userId,
+ ImRtcParticipantDisconnectedNotification.of(call, userId));
+ }
+
+ /**
+ * 鎺ㄩ�佸弬涓庤�呬簨浠剁殑鍏叡楠ㄦ灦锛涙寜浼氳瘽绫诲瀷鍐冲畾鏀朵欢浜猴紝鍗曟 batch 鎺ㄩ�佹墖鍑�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param type 娑堟伅绫诲瀷锛�1602 / 1603
+ * @param actorUserId 瑙﹀彂鏈浜嬩欢鐨勭敤鎴风紪鍙�
+ * @param payload 涓氬姟 payload
+ */
+ private void pushParticipantNotification(ImRtcCallDO call, Integer type, Long actorUserId, Object payload) {
+ Collection<Long> receivers = getCallAudienceUserIdList(call);
+ if (CollUtil.isEmpty(receivers)) {
+ return;
+ }
+ webSocketService.sendNotificationAsync(receivers, ImConversationTypeEnum.NONE.getType(), type, payload);
+ }
+
+ /**
+ * RTC_CALL_START锛氱兢鑱婅蛋 imGroupMessageService.send 鍏ㄧ兢骞挎挱锛涚鑱婅蛋 imPrivateMessageService.send 瀹氬悜缁欒鍙�
+ * <p>
+ * 绉佽亰 peer 鐩存帴澶嶇敤 createCall 瑙f瀽濂界殑 invitees锛岄伩鍏嶅啀鏌ュ弬涓庤〃锛涚敤浜庝細璇濆垪琛ㄩ瑙堝睍绀恒�孾璇煶閫氳瘽]銆�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param inviter 鍙戣捣浜猴紱鍙┖
+ * @param invitees 鏈閭�璇锋睜锛涚鑱婂満鏅彇棣栦釜浣滀负 peer
+ */
+ private void pushCallStartNotification(ImRtcCallDO call, AdminUserRespDTO inviter, Set<Long> invitees) {
+ ImRtcCallStartNotification payload = ImRtcCallStartNotification.of(call, inviter);
+ Long peerUserId = ImConversationTypeEnum.isGroup(call.getConversationType()) ? null : CollUtil.getFirst(invitees);
+ pushCallChatMessage(call, ImContentTypeEnum.RTC_CALL_START, payload, peerUserId);
+ }
+
+ /**
+ * RTC_CALL_END锛氱鑱婅蛋 imPrivateMessageService.send锛涚兢閫氳瘽璧� imGroupMessageService.send
+ * <p>
+ * senderId 濮嬬粓鐢ㄩ�氳瘽鍙戣捣浜猴紝璁╁墠绔寜銆岃皝鍙戣捣閫氳瘽銆嶅喅瀹氭皵娉″乏鍙筹紱鎿嶄綔鑰呬粠 payload.operatorUserId 鎷�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param operatorId 鎿嶄綔鑰呯敤鎴风紪鍙凤紱webhook 鍏滃簳 / Job 娓呯悊鍦烘櫙鍙┖
+ * @param reason 缁撴潫鍘熷洜
+ * @param durationSeconds 閫氳瘽鏃堕暱锛堢锛夛紱鏈帴閫氭椂涓� null
+ */
+ private void pushCallEndNotification(ImRtcCallDO call, Long operatorId, ImRtcCallEndReasonEnum reason,
+ Long durationSeconds) {
+ AdminUserRespDTO operator = operatorId != null ? adminUserApi.getUser(operatorId) : null;
+ ImRtcCallEndNotification payload = ImRtcCallEndNotification.of(call, reason, durationSeconds, operatorId, operator);
+ Long peerUserId = null;
+ if (!ImConversationTypeEnum.isGroup(call.getConversationType())) {
+ ImRtcParticipantDO peer = CollUtil.findOne(
+ rtcParticipantMapper.selectListByRoom(call.getRoom()),
+ p -> ObjUtil.notEqual(p.getUserId(), call.getInviterUserId()));
+ peerUserId = peer != null ? peer.getUserId() : null;
+ }
+ pushCallChatMessage(call, ImContentTypeEnum.RTC_CALL_END, payload, peerUserId);
+ }
+
+ /**
+ * RTC 閫氳瘽浜嬩欢鍏ユ秷鎭祦锛氱兢鑱婅蛋 groupMessageService 鍏ㄧ兢骞挎挱锛岀鑱婅蛋 privateMessageService 瀹氬悜缁� peer
+ * <p>
+ * senderId 鍥哄畾鍙� inviterUserId锛岃鍓嶇鎸夈�岃皝鍙戣捣銆嶅喅瀹氭皵娉″乏鍙筹紱绉佽亰 peer 缂哄け鏃堕檷绾т负鍙戠粰鑷繁浣滃厹搴�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param type 娑堟伅绫诲瀷锛汻TC_CALL_START / RTC_CALL_END
+ * @param payload 鎺ㄩ�� payload
+ * @param peerUserId 绉佽亰瀵圭鐢ㄦ埛缂栧彿锛涚兢鑱婂拷鐣ワ紝绉佽亰缂哄け鏃跺洖閫�涓� senderId
+ */
+ private void pushCallChatMessage(ImRtcCallDO call, ImContentTypeEnum type, Object payload, Long peerUserId) {
+ Long senderId = call.getInviterUserId();
+ if (ImConversationTypeEnum.isGroup(call.getConversationType())) {
+ ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO().setGroupId(call.getGroupId())
+ .setType(type.getType()).setContent(payload);
+ groupMessageService.sendGroupMessage(senderId, dto);
+ return;
+ }
+ Long receiverId = peerUserId != null ? peerUserId : senderId;
+ ImPrivateMessageSendDTO dto = new ImPrivateMessageSendDTO().setReceiverId(receiverId)
+ .setType(type.getType()).setContent(payload);
+ privateMessageService.sendPrivateMessage(senderId, dto);
+ }
+
+ // ========== Token / VO ==========
+
+ /**
+ * 绛� LiveKit Token
+ *
+ * @param userId 鐢ㄦ埛缂栧彿锛泃oken 鍐� identity 鐢辨娲剧敓
+ * @param displayName 鎴垮唴鏄剧ず鍚�
+ * @param room LiveKit 鎴块棿鍚�
+ * @return JWT 瀛楃涓�
+ */
+ private String signToken(Long userId, String displayName, String room) {
+ return liveKitClient.signJoinToken(liveKitClient.buildIdentity(userId), displayName, room);
+ }
+
+ /**
+ * 瑙f瀽鎴垮唴鏄剧ず鍚嶏細浼樺厛鍙� user.nickname锛岀己澶辨椂闄嶇骇涓� userId 瀛楃涓诧紙LiveKit displayName 涓嶅彲绌猴級
+ *
+ * @param user 鐢ㄦ埛淇℃伅锛涘彲绌�
+ * @param userId 鐢ㄦ埛缂栧彿锛沝isplayName 鍏滃簳
+ * @return 鎴垮唴鏄剧ず鍚�
+ */
+ private static String resolveDisplayName(AdminUserRespDTO user, Long userId) {
+ return StrUtil.blankToDefault(
+ user == null ? null : user.getNickname(), String.valueOf(userId));
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImRtcCallDO> getCallPage(ImRtcCallManagerPageReqVO reqVO) {
+ return rtcCallMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public ImRtcCallDO getCall(Long id) {
+ return rtcCallMapper.selectById(id);
+ }
+
+ @Override
+ public List<ImRtcParticipantDO> getCallParticipantListByCallId(Long id) {
+ return rtcParticipantMapper.selectListByCallId(id);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordService.java
new file mode 100644
index 0000000..1a5c3aa
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordService.java
@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.im.service.sensitiveword;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.sensitiveword.ImSensitiveWordDO;
+import jakarta.validation.Valid;
+
+import java.util.List;
+
+/**
+ * IM 鏁忔劅璇� Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImSensitiveWordService {
+
+ /**
+ * 鏍¢獙鏂囨湰鏄惁鍖呭惈鏁忔劅璇�
+ *
+ * @param text 寰呮牎楠屾枃鏈�
+ */
+ void validateText(String text);
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝垎椤垫煡璇㈡晱鎰熻瘝
+ */
+ PageResult<ImSensitiveWordDO> getSensitiveWordPage(ImSensitiveWordPageReqVO reqVO);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戣幏鍙栨晱鎰熻瘝璇︽儏
+ */
+ ImSensitiveWordDO getSensitiveWord(Long id);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戞柊澧炴晱鎰熻瘝锛岃繑鍥炴柊澧� id
+ */
+ Long createSensitiveWord(@Valid ImSensitiveWordSaveReqVO reqVO);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戜慨鏀规晱鎰熻瘝
+ */
+ void updateSensitiveWord(@Valid ImSensitiveWordSaveReqVO reqVO);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戝垹闄ゆ晱鎰熻瘝
+ */
+ void deleteSensitiveWord(Long id);
+
+ /**
+ * 銆愮鐞嗗悗鍙般�戞壒閲忓垹闄ゆ晱鎰熻瘝
+ */
+ void deleteSensitiveWordList(List<Long> ids);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImpl.java
new file mode 100644
index 0000000..57ed857
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImpl.java
@@ -0,0 +1,228 @@
+package cn.iocoder.yudao.module.im.service.sensitiveword;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+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.cache.CacheUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
+import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordPageReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.sensitiveword.ImSensitiveWordDO;
+import cn.iocoder.yudao.module.im.dal.mysql.sensitiveword.ImSensitiveWordMapper;
+import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import jakarta.annotation.Resource;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_SENSITIVE_WORD_BLOCKED;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.SENSITIVE_WORD_DUPLICATED;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.SENSITIVE_WORD_NOT_EXISTS;
+
+/**
+ * IM 鏁忔劅璇� Service 瀹炵幇绫�
+ * <p>
+ * 璇嶅簱鍖归厤浜ょ粰 houbb sensitive-word 搴擄紙trie 鏍� + 鍏�/鍗婅 / 澶у皬鍐� / 绻佺畝浣� / 鏁板瓧椋庢牸瑙勮寖鍖栵級
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+@Slf4j
+public class ImSensitiveWordServiceImpl implements ImSensitiveWordService {
+
+ @Resource
+ private ImSensitiveWordMapper sensitiveWordMapper;
+
+ /**
+ * 缂撳瓨鏉$洰
+ */
+ @Data
+ @AllArgsConstructor
+ private static class SensitiveWordBsCache {
+
+ /**
+ * 鏁忔劅璇嶆娴嬪櫒
+ */
+ private SensitiveWordBs bs;
+ /**
+ * 鏋勫缓鏈疄渚嬫椂鏁版嵁搴撻噷鐨� max(update_time)锛屼綔涓轰笅娆″埛鏂版瘮瀵圭殑鍩虹嚎
+ */
+ private LocalDateTime maxUpdateTime;
+
+ }
+
+ /**
+ * 绉熸埛 鈫� SensitiveWordBs 瀹炰緥鐨勬湰鍦扮紦瀛�
+ * <p>
+ * 姣忓垎閽熻Е鍙戜竴娆″紓姝� reload锛屽厛璇� max(update_time)锛屾病鍙樺氨澶嶇敤鏃у疄渚嬶紙閬垮厤 trie 閲嶅缓锛夛紝鍙樹簡鎵嶉噸鏂拌璇嶅簱 + 閲嶅缓銆�
+ * 鍗曞疄渚� CRUD 鍚庡彟澶栭�氳繃 {@link #invalidateSensitiveWordBsCaches()} 绔嬪嵆璁╂湰鏈哄け鏁堬紝澶氬疄渚嬮潬瀹氭椂鍒锋柊鏈�闀� 1 鍒嗛挓鍐呮敹鏁涖��
+ */
+ @SuppressWarnings({"Convert2Diamond", "NullableProblems"})
+ private final LoadingCache<Long, SensitiveWordBsCache> sensitiveWordBsCaches = CacheUtils.buildAsyncReloadingCache(
+ Duration.ofMinutes(1L), // 1 鍒嗛挓杩囨湡
+ new CacheLoader<Long, SensitiveWordBsCache>() {
+
+ @Override
+ public SensitiveWordBsCache load(Long tenantId) {
+ return loadFresh(tenantId);
+ }
+
+ @Override
+ public ListenableFuture<SensitiveWordBsCache> reload(Long tenantId, SensitiveWordBsCache oldValue) {
+ // 寮傛鍒锋柊绾跨▼鐙珛浜庝笟鍔$嚎绋嬶紝娌℃湁绉熸埛涓婁笅鏂囷紱蹇呴』鏄惧紡 TenantUtils.execute 璁剧疆锛屽惁鍒欑鎴锋嫤鎴櫒浼氭寜褰撳墠绾跨▼鐨勭┖涓婁笅鏂囨嫾 SQL
+ return Futures.immediateFuture(TenantUtils.execute(tenantId, () -> {
+ LocalDateTime currentMax = sensitiveWordMapper.selectMaxUpdateTime(tenantId);
+ // 娌″彉 鈫� 澶嶇敤鏃у疄渚嬶紝閬垮厤鏃犺皳鍦伴噸寤� trie
+ if (Objects.equals(oldValue.getMaxUpdateTime(), currentMax)) {
+ return oldValue;
+ }
+ // 鍙樹簡 鈫� 閲嶆柊璇昏瘝搴撳苟閲嶅缓 trie
+ return loadFresh(tenantId);
+ }));
+ }
+
+ });
+
+ private SensitiveWordBsCache loadFresh(Long tenantId) {
+ return TenantUtils.execute(tenantId, () -> {
+ // 鍏堝彇鍩虹嚎鏃堕棿鍐嶈璇嶅簱锛氬弽杩囨潵鍦ㄤ袱娆℃煡璇箣闂村嚭鐜扮殑鏂版彃鍏ヤ細琚紡鎰熺煡
+ LocalDateTime maxUpdateTime = sensitiveWordMapper.selectMaxUpdateTime(tenantId);
+ List<ImSensitiveWordDO> words = sensitiveWordMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ // 鏋勫缓鏁忔劅璇嶆娴嬪櫒
+ SensitiveWordBs bs = SensitiveWordBs.newInstance()
+ .wordDeny(() -> convertList(words, ImSensitiveWordDO::getWord))
+ .ignoreCase(true)
+ .ignoreWidth(true) // 蹇界暐鍏�/鍗婅
+ .ignoreNumStyle(true) // 蹇界暐鏁板瓧椋庢牸锛堜腑鏂�/闃挎媺浼級
+ .ignoreChineseStyle(true) // 蹇界暐绻佺畝浣�
+ .enableWordCheck(true)
+ .init();
+ return new SensitiveWordBsCache(bs, maxUpdateTime);
+ });
+ }
+
+ /**
+ * 寮哄埗璁╂晱鎰熻瘝缂撳瓨澶辨晥锛屼笅娆¤闂寜鏈�鏂� DB 閲嶅缓
+ * <p>
+ * 鏈夌鎴蜂笂涓嬫枃锛氫粎澶辨晥璇ョ鎴枫�傛棤绉熸埛涓婁笅鏂囷紙濡傜郴缁熺骇 / 璺ㄧ鎴锋竻鐞嗭級锛氬厹搴曞け鏁堟墍鏈夌鎴枫��
+ */
+ private void invalidateSensitiveWordBsCaches() {
+ Long tenantId = TenantContextHolder.getTenantId();
+ if (tenantId != null) {
+ sensitiveWordBsCaches.invalidate(tenantId);
+ return;
+ }
+ sensitiveWordBsCaches.invalidateAll();
+ }
+
+ @Override
+ public void validateText(String text) {
+ if (StrUtil.isBlank(text)) {
+ return;
+ }
+ SensitiveWordBs bs = sensitiveWordBsCaches.getUnchecked(TenantContextHolder.getRequiredTenantId()).getBs();
+ if (bs.contains(text)) {
+ throw exception(MESSAGE_SENSITIVE_WORD_BLOCKED);
+ }
+ }
+
+ // ==================== 绠$悊鍚庡彴 ====================
+
+ @Override
+ public PageResult<ImSensitiveWordDO> getSensitiveWordPage(ImSensitiveWordPageReqVO reqVO) {
+ return sensitiveWordMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public ImSensitiveWordDO getSensitiveWord(Long id) {
+ return sensitiveWordMapper.selectById(id);
+ }
+
+ @Override
+ public Long createSensitiveWord(ImSensitiveWordSaveReqVO reqVO) {
+ // 1. 鏍¢獙鍞竴
+ validateWordUnique(null, reqVO.getWord());
+
+ // 2.1 鍏ュ簱
+ ImSensitiveWordDO word = BeanUtils.toBean(reqVO, ImSensitiveWordDO.class);
+ sensitiveWordMapper.insert(word);
+ // 2.2 寮哄埗澶辨晥鏈満缂撳瓨锛堝瀹炰緥闈犲畾鏃跺埛鏂版敹鏁涳級
+ invalidateSensitiveWordBsCaches();
+ return word.getId();
+ }
+
+ @Override
+ public void updateSensitiveWord(ImSensitiveWordSaveReqVO reqVO) {
+ // 1.1 鏍¢獙瀛樺湪
+ validateSensitiveWordExists(reqVO.getId());
+ // 1.2 鏍¢獙鍞竴锛堟帓闄よ嚜韬級
+ validateWordUnique(reqVO.getId(), reqVO.getWord());
+
+ // 2.1 鏇存柊
+ ImSensitiveWordDO updateObj = BeanUtils.toBean(reqVO, ImSensitiveWordDO.class);
+ sensitiveWordMapper.updateById(updateObj);
+ // 2.2 寮哄埗澶辨晥鏈満缂撳瓨
+ invalidateSensitiveWordBsCaches();
+ }
+
+ @Override
+ public void deleteSensitiveWord(Long id) {
+ // 1. 鏍¢獙瀛樺湪
+ validateSensitiveWordExists(id);
+
+ // 2.1 鍒犻櫎
+ sensitiveWordMapper.deleteById(id);
+ // 2.2 寮哄埗澶辨晥鏈満缂撳瓨
+ invalidateSensitiveWordBsCaches();
+ }
+
+
+ @Override
+ public void deleteSensitiveWordList(List<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return;
+ }
+ // 1. 鍒犻櫎
+ sensitiveWordMapper.deleteByIds(ids);
+ // 2. 寮哄埗澶辨晥鏈満缂撳瓨
+ invalidateSensitiveWordBsCaches();
+ }
+
+ private void validateSensitiveWordExists(Long id) {
+ if (sensitiveWordMapper.selectById(id) == null) {
+ throw exception(SENSITIVE_WORD_NOT_EXISTS);
+ }
+ }
+
+ /**
+ * 鏍¢獙鏁忔劅璇嶅敮涓�锛堜慨鏀规椂鎺掗櫎鑷韩锛�
+ */
+ private void validateWordUnique(Long id, String word) {
+ ImSensitiveWordDO exist = sensitiveWordMapper.selectByWord(word);
+ if (exist == null) {
+ return;
+ }
+ if (id == null || ObjUtil.notEqual(exist.getId(), id)) {
+ throw exception(SENSITIVE_WORD_DUPLICATED, word);
+ }
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerService.java
new file mode 100644
index 0000000..a21fc03
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerService.java
@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.im.service.statistics;
+
+import java.time.LocalDateTime;
+import java.util.Map;
+
+/**
+ * IM 鏁版嵁鐪嬫澘 Service 鎺ュ彛
+ * <p>
+ * 浠呮湇鍔′簬 manager 鍚庡彴缁熻椤碉紝鐙珛浜庝笟鍔� Service锛岄伩鍏嶆薄鏌撱��
+ * 杩斿洖鐨勫潎涓鸿仛鍚堝悗鐨勭畝鍗曠粨鏋勶紝鐢� Controller 璐熻矗 VO 瑁呴厤涓庢樀绉板洖濉��
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImStatisticsManagerService {
+
+ // ==================== 鐢ㄦ埛 ====================
+
+ /**
+ * 鑾峰彇鐢ㄦ埛鎬绘暟
+ */
+ Long getTotalUserCount();
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呮柊澧炵敤鎴锋暟
+ */
+ Long getNewUserCount(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呮椿璺冪敤鎴锋暟锛堢鑱�+缇よ亰鍘婚噸锛�
+ */
+ Long getActiveUserCount(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呮瘡鏃ユ柊澧炵敤鎴锋暟 Map锛坘ey 涓� yyyy-MM-dd 鏃ユ湡锛�
+ */
+ Map<LocalDateTime, Long> getNewUserDailyCountMap(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呮瘡鏃ユ椿璺冪敤鎴锋暟 Map
+ */
+ Map<LocalDateTime, Long> getActiveUserDailyCountMap(LocalDateTime beginTime, LocalDateTime endTime);
+
+ // ==================== 缇� ====================
+
+ /**
+ * 鑾峰彇缇ゆ�绘暟
+ */
+ Long getTotalGroupCount();
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呮柊寤虹兢鏁�
+ */
+ Long getNewGroupCount(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇缇よ妯″垎甯� Map锛坘ey 涓哄垎妗跺悕锛�
+ */
+ Map<String, Long> getGroupSizeCountMap();
+
+ // ==================== 娑堟伅 ====================
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呯鑱婃秷鎭暟
+ */
+ Long getPrivateMessageCount(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呯兢鑱婃秷鎭暟
+ */
+ Long getGroupMessageCount(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呮瘡鏃ョ鑱婃秷鎭暟 Map
+ */
+ Map<LocalDateTime, Long> getPrivateMessageDailyCountMap(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呮瘡鏃ョ兢鑱婃秷鎭暟 Map
+ */
+ Map<LocalDateTime, Long> getGroupMessageDailyCountMap(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇鍖洪棿鍐呭唴瀹圭被鍨嬪垎甯� Map锛坘ey 涓烘秷鎭被鍨嬶級
+ */
+ Map<Integer, Long> getMessageTypeCountMap(LocalDateTime beginTime, LocalDateTime endTime);
+
+ /**
+ * 鑾峰彇鍖洪棿鍐� TOP 鍙戦�佽�� Map锛坘ey 涓� userId锛寁alue 涓烘秷鎭暟锛涙寜娑堟伅鏁板�掑簭锛�
+ */
+ Map<Long, Long> getTopSenderCountMap(LocalDateTime beginTime, LocalDateTime endTime, int limit);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImpl.java
new file mode 100644
index 0000000..5251641
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImpl.java
@@ -0,0 +1,126 @@
+package cn.iocoder.yudao.module.im.service.statistics;
+
+import cn.hutool.core.convert.Convert;
+import cn.iocoder.yudao.module.im.dal.mysql.statistics.ImStatisticsManagerMapper;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+
+/**
+ * IM 鏁版嵁鐪嬫澘 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class ImStatisticsManagerServiceImpl implements ImStatisticsManagerService {
+
+ @Resource
+ private ImStatisticsManagerMapper statisticsMapper;
+
+ // ==================== 鐢ㄦ埛 ====================
+
+ @Override
+ public Long getTotalUserCount() {
+ return statisticsMapper.selectTotalUserCount();
+ }
+
+ @Override
+ public Long getNewUserCount(LocalDateTime beginTime, LocalDateTime endTime) {
+ return statisticsMapper.selectNewUserCount(beginTime, endTime);
+ }
+
+ @Override
+ public Long getActiveUserCount(LocalDateTime beginTime, LocalDateTime endTime) {
+ return statisticsMapper.selectActiveUserCount(beginTime, endTime);
+ }
+
+ @Override
+ public Map<LocalDateTime, Long> getNewUserDailyCountMap(LocalDateTime beginTime, LocalDateTime endTime) {
+ List<Map<String, Object>> rows = statisticsMapper.selectNewUserDailyCount(beginTime, endTime);
+ return toDailyCountMap(rows);
+ }
+
+ @Override
+ public Map<LocalDateTime, Long> getActiveUserDailyCountMap(LocalDateTime beginTime, LocalDateTime endTime) {
+ List<Map<String, Object>> rows = statisticsMapper.selectActiveUserDailyCount(beginTime, endTime);
+ return toDailyCountMap(rows);
+ }
+
+ // ==================== 缇� ====================
+
+ @Override
+ public Long getTotalGroupCount() {
+ return statisticsMapper.selectTotalGroupCount();
+ }
+
+ @Override
+ public Long getNewGroupCount(LocalDateTime beginTime, LocalDateTime endTime) {
+ return statisticsMapper.selectNewGroupCount(beginTime, endTime);
+ }
+
+ @Override
+ public Map<String, Long> getGroupSizeCountMap() {
+ List<Map<String, Object>> rows = statisticsMapper.selectGroupSizeDistribution();
+ return convertMap(rows,
+ row -> (String) row.get("range"),
+ row -> Convert.toLong(row.get("count")));
+ }
+
+ // ==================== 娑堟伅 ====================
+
+ @Override
+ public Long getPrivateMessageCount(LocalDateTime beginTime, LocalDateTime endTime) {
+ return statisticsMapper.selectPrivateMessageCount(beginTime, endTime);
+ }
+
+ @Override
+ public Long getGroupMessageCount(LocalDateTime beginTime, LocalDateTime endTime) {
+ return statisticsMapper.selectGroupMessageCount(beginTime, endTime);
+ }
+
+ @Override
+ public Map<LocalDateTime, Long> getPrivateMessageDailyCountMap(LocalDateTime beginTime, LocalDateTime endTime) {
+ List<Map<String, Object>> rows = statisticsMapper.selectPrivateMessageDailyCount(beginTime, endTime);
+ return toDailyCountMap(rows);
+ }
+
+ @Override
+ public Map<LocalDateTime, Long> getGroupMessageDailyCountMap(LocalDateTime beginTime, LocalDateTime endTime) {
+ List<Map<String, Object>> rows = statisticsMapper.selectGroupMessageDailyCount(beginTime, endTime);
+ return toDailyCountMap(rows);
+ }
+
+ @Override
+ public Map<Integer, Long> getMessageTypeCountMap(LocalDateTime beginTime, LocalDateTime endTime) {
+ List<Map<String, Object>> rows = statisticsMapper.selectMessageTypeDistribution(beginTime, endTime);
+ return convertMap(rows,
+ row -> Convert.toInt(row.get("type")),
+ row -> Convert.toLong(row.get("count")));
+ }
+
+ @Override
+ public Map<Long, Long> getTopSenderCountMap(LocalDateTime beginTime, LocalDateTime endTime, int limit) {
+ List<Map<String, Object>> rows = statisticsMapper.selectTopSenders(beginTime, endTime, limit);
+ return convertMap(rows,
+ row -> Convert.toLong(row.get("userId")),
+ row -> Convert.toLong(row.get("messageCount")));
+ }
+
+ /**
+ * 鎶� [{date, count}] 琛屾槧灏勪负 {LocalDateTime -> Long}锛�
+ */
+ private static Map<LocalDateTime, Long> toDailyCountMap(List<Map<String, Object>> rows) {
+ return convertMap(rows,
+ row -> Convert.convert(LocalDate.class, row.get("date")).atStartOfDay(),
+ row -> Convert.toLong(row.get("count")));
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketService.java
new file mode 100644
index 0000000..2e7404c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketService.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.im.service.websocket;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * IM WebSocket 鎺ㄩ�� Service 鎺ュ彛
+ * <p>
+ * 缁熶竴灏佽 WebSocket 閫氱煡鎺ㄩ�侊紝浜嬪姟鍐呰皟鐢ㄦ椂鎻愪氦鍚庡紓姝ユ墽琛屻��
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface ImWebSocketService {
+
+ /**
+ * 寮傛鎺ㄩ�� WebSocket 閫氱煡缁欐寚瀹氱敤鎴�
+ *
+ * @param userId 鐩爣鐢ㄦ埛缂栧彿
+ * @param conversationType 浼氳瘽绫诲瀷锛屽弬瑙� ImConversationTypeEnum 鏋氫妇绫�
+ * @param contentType 鍐呭绫诲瀷锛屽弬瑙� ImContentTypeEnum 鏋氫妇绫�
+ * @param payload 閫氱煡 payload
+ */
+ default void sendNotificationAsync(Long userId, Integer conversationType, Integer contentType, Object payload) {
+ sendNotificationAsync(Collections.singleton(userId), conversationType, contentType, payload);
+ }
+
+ /**
+ * 寮傛鎵归噺鎺ㄩ�� WebSocket 閫氱煡缁欏涓敤鎴�
+ *
+ * @param userIds 鐩爣鐢ㄦ埛缂栧彿鍒楄〃
+ * @param conversationType 浼氳瘽绫诲瀷锛屽弬瑙� ImConversationTypeEnum 鏋氫妇绫�
+ * @param contentType 鍐呭绫诲瀷锛屽弬瑙� ImContentTypeEnum 鏋氫妇绫�
+ * @param payload 閫氱煡 payload
+ */
+ void sendNotificationAsync(Collection<Long> userIds, Integer conversationType, Integer contentType, Object payload);
+
+ /**
+ * 寮傛骞挎挱 WebSocket 閫氱煡缁欏綋鍓嶆墍鏈夊湪绾跨鐞嗙鐢ㄦ埛
+ *
+ * @param conversationType 浼氳瘽绫诲瀷锛屽弬瑙� ImConversationTypeEnum 鏋氫妇绫�
+ * @param contentType 鍐呭绫诲瀷锛屽弬瑙� ImContentTypeEnum 鏋氫妇绫�
+ * @param payload 閫氱煡 payload
+ */
+ void broadcastNotificationAsync(Integer conversationType, Integer contentType, Object payload);
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImpl.java
new file mode 100644
index 0000000..a3a1078
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImpl.java
@@ -0,0 +1,116 @@
+package cn.iocoder.yudao.module.im.service.websocket;
+
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.module.im.service.websocket.notification.ImNotificationWebSocketDTO;
+import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Collection;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertLinkedSet;
+
+/**
+ * IM WebSocket 鎺ㄩ�� Service 瀹炵幇绫�
+ * <p>
+ * 褰撹皟鐢ㄦ柟澶勪簬浜嬪姟涓椂锛屾帹閫佷細寤惰繜鍒颁簨鍔℃彁浜ゅ悗鍐嶅紓姝ユ墽琛岋紝
+ * 閬垮厤瀹㈡埛绔敹鍒� WebSocket 娑堟伅鏃舵暟鎹簱鍙樻洿灏氭湭鍙銆�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+@Slf4j
+public class ImWebSocketServiceImpl implements ImWebSocketService {
+
+ @Resource
+ private WebSocketSenderApi webSocketSenderApi;
+
+ @Override
+ public void sendNotificationAsync(Collection<Long> userIds, Integer conversationType, Integer contentType,
+ Object payload) {
+ ImNotificationWebSocketDTO notification = buildNotification(conversationType, contentType, payload);
+ executeAfterTransaction(() -> getSelf().doSendNotification(userIds, notification));
+ }
+
+ @Override
+ public void broadcastNotificationAsync(Integer conversationType, Integer contentType, Object payload) {
+ ImNotificationWebSocketDTO notification = buildNotification(conversationType, contentType, payload);
+ executeAfterTransaction(() -> getSelf().doBroadcastNotification(notification));
+ }
+
+ private static ImNotificationWebSocketDTO buildNotification(Integer conversationType, Integer contentType,
+ Object payload) {
+ return new ImNotificationWebSocketDTO()
+ .setConversationType(conversationType)
+ .setContentType(contentType)
+ .setPayload(payload);
+ }
+
+ /**
+ * 寮傛鍙戦�� WebSocket 閫氱煡
+ */
+ @Async
+ public void doSendNotification(Collection<Long> userIds, ImNotificationWebSocketDTO notification) {
+ for (Long userId : getDistinctUserIds(userIds)) {
+ try {
+ webSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(), userId,
+ ImNotificationWebSocketDTO.TYPE, notification);
+ } catch (Exception e) {
+ log.error("[doSendNotification][userId({}) notification({}) 鍙戦�佸け璐", userId, notification, e);
+ }
+ }
+ }
+
+ /**
+ * 寮傛骞挎挱 WebSocket 閫氱煡
+ */
+ @Async
+ public void doBroadcastNotification(ImNotificationWebSocketDTO notification) {
+ try {
+ webSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(),
+ ImNotificationWebSocketDTO.TYPE, notification);
+ } catch (Exception e) {
+ log.error("[doBroadcastNotification][notification({}) 骞挎挱澶辫触]", notification, e);
+ }
+ }
+
+ private static Set<Long> getDistinctUserIds(Collection<Long> userIds) {
+ return convertLinkedSet(userIds, userId -> userId);
+ }
+
+ /**
+ * 浜嬪姟鎰熺煡鐨勪换鍔¤皟搴�
+ *
+ * @param task 寰呮墽琛岀殑鎺ㄩ�佷换鍔�
+ */
+ private void executeAfterTransaction(Runnable task) {
+ if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+ task.run();
+ return;
+ }
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
+
+ @Override
+ public void afterCommit() {
+ task.run();
+ }
+
+ });
+ }
+
+ /**
+ * 鑾峰緱鑷韩鐨勪唬鐞嗗璞★紝瑙e喅 @Async AOP 浠g悊闂
+ */
+ private ImWebSocketServiceImpl getSelf() {
+ return SpringUtil.getBean(getClass());
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/ImNotificationWebSocketDTO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/ImNotificationWebSocketDTO.java
new file mode 100644
index 0000000..38a6d04
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/ImNotificationWebSocketDTO.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * IM WebSocket 鍦ㄧ嚎閫氱煡澶栧3
+ * <p>
+ * conversationType 瀹氫綅浼氳瘽缁村害锛沜ontentType 瀹氫綅涓氬姟鍐呭锛沺ayload 鎵胯浇瀵瑰簲閫氱煡瀵硅薄銆�
+ * 浼氳繘鍏ヨ亰澶╂祦鐨勭鑱娿�佺兢鑱娿�侀閬撲簨浠惰蛋 message 瀛愬寘锛涗笉杩涘叆鑱婂ぉ娴佺殑濂藉弸銆佸姞缇ょ敵璇枫�侀�氳瘽淇′护璧� NONE 浼氳瘽銆�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+@Accessors(chain = true)
+public class ImNotificationWebSocketDTO {
+
+ public static final String TYPE = "im-notification";
+
+ /**
+ * 浼氳瘽绫诲瀷锛屽弬瑙� ImConversationTypeEnum 鏋氫妇绫�
+ */
+ private Integer conversationType;
+ /**
+ * 鍐呭绫诲瀷锛屽弬瑙� ImContentTypeEnum 鏋氫妇绫�
+ */
+ private Integer contentType;
+ /**
+ * 璐熻浇鏁版嵁
+ */
+ private Object payload;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/BaseFriendNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/BaseFriendNotification.java
new file mode 100644
index 0000000..d2d3a22
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/BaseFriendNotification.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 濂藉弸浜嬩欢閫氱煡鍩虹被
+ * <p>
+ * 鎵�鏈夊ソ鍙嬩簨浠� payload 鍏变韩锛�
+ * - operatorUserId 鏍囪瘑"璋佽Е鍙戠殑"锛岀敤浜庡绔悓姝ユ椂鏈璇嗗埆"鏄垜鑷繁瑙﹀彂鐨�"杩樻槸"瀵规柟瑙﹀彂鐨�"
+ * - friendUserId 鏍囪瘑"濂藉弸鏄皝"锛屽墠绔寜瀹冨畾浣� / 鏇存柊鏈湴 friend 缂撳瓨
+ */
+@Data
+public abstract class BaseFriendNotification {
+
+ /**
+ * 鎿嶄綔浜虹敤鎴风紪鍙�
+ */
+ private Long operatorUserId;
+ /**
+ * 濂藉弸鐢ㄦ埛缂栧彿
+ */
+ private Long friendUserId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendAddNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendAddNotification.java
new file mode 100644
index 0000000..781c94c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendAddNotification.java
@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 鏂板濂藉弸閫氱煡
+ * <p>
+ * 鍙屽悜寤虹珛濂藉弸鍏崇郴鍚庯紝鎺ㄩ�佺粰 A銆丅 鍙屾柟澶氱锛涘墠绔媺鍙栧ソ鍙嬩俊鎭叆搴�
+ */
+@Data
+public class FriendAddNotification extends BaseFriendNotification {
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendBlockNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendBlockNotification.java
new file mode 100644
index 0000000..abc0913
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendBlockNotification.java
@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 鍔犲叆榛戝悕鍗曢�氱煡
+ * <p>
+ * A 鎷夐粦 B 鍚庝粎鎺� A 澶氱锛汢 绔笉鎰熺煡锛圔 閭h竟 blocked=0 涓嶅彉锛�
+ */
+@Data
+public class FriendBlockNotification extends BaseFriendNotification {
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendDeleteNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendDeleteNotification.java
new file mode 100644
index 0000000..814c4eb
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendDeleteNotification.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 濂藉弸鍒犻櫎閫氱煡
+ * <p>
+ * 浠呮帹閫佺粰鎿嶄綔浜哄绔仛鍚屾锛堝绔笉鎰熺煡锛屼笌鍗曡竟鍒犻櫎璇箟瀵归綈锛夛紱鍓嶇娓呴櫎鏈湴濂藉弸 + 鎸� clear 鍐冲畾绾ц仈娓呯悊
+ */
+@Data
+public class FriendDeleteNotification extends BaseFriendNotification {
+
+ /**
+ * 鏄惁绾ц仈娓呯悊鏈鐩稿叧鏁版嵁锛堝綋鍓嶅寘鍚鑱婁細璇濓紱鏈潵鍙兘鎵╁睍鏇村 clear 椤癸級
+ */
+ private Boolean clear;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendInfoUpdatedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendInfoUpdatedNotification.java
new file mode 100644
index 0000000..60890b0
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendInfoUpdatedNotification.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 濂藉弸璧勬枡鍙樻洿閫氱煡锛堝绔敼浜嗘樀绉� / 澶村儚锛�
+ * <p>
+ * 鐢� AdminUserProfileUpdateConsumer 鐩戝惉 system 妯″潡鐨� AdminUserProfileUpdateMessage 鍚庯紝鎵归噺鎺ㄩ�佺粰璧勬枡琚敼鐨勪汉鐨勬墍鏈夊ソ鍙嬶紱
+ * 鍓嶇 dispatcher 鏀跺埌鍚庤皟 loadFriendInfo 閲嶆媺璧勬枡
+ * <p>
+ * 姝ゅ friendUserId 琛ㄧず銆岃祫鏂欒鏇存柊鐨勯偅涓汉銆嶏紙鍗冲绔級锛屼笌 operatorUserId 涓�鑷�
+ */
+@Data
+public class FriendInfoUpdatedNotification extends BaseFriendNotification {
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestApprovedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestApprovedNotification.java
new file mode 100644
index 0000000..5cb748c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestApprovedNotification.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 濂藉弸鐢宠琚悓鎰忛�氱煡
+ * <p>
+ * 鎺ㄩ�佺粰鍘熺敵璇峰彂璧锋柟澶氱锛涘墠绔寜 requestId 鎶婂搴旂敵璇疯褰� handleResult 鏇存柊涓恒�屽凡鍚屾剰銆�
+ */
+@Data
+public class FriendRequestApprovedNotification extends BaseFriendNotification {
+
+ /**
+ * 宸插鐞嗙殑鐢宠璁板綍缂栧彿
+ */
+ private Long requestId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestNotification.java
new file mode 100644
index 0000000..5d82e0e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestNotification.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 鏀跺埌鏂扮殑濂藉弸鐢宠閫氱煡
+ * <p>
+ * 鎺ㄩ�佺粰鐢宠鐨勬帴鏀舵柟澶氱锛沺ayload 宸叉惡甯� fromUser 鑱氬悎瀛楁锛屽墠绔寜 requestId 鐩存帴 push 杩涘垪琛紝鏃犻渶鍥炴媺
+ */
+@Data
+public class FriendRequestNotification extends BaseFriendNotification {
+
+ /**
+ * 鐢宠璁板綍缂栧彿
+ */
+ private Long requestId;
+ /**
+ * 鐢宠鐞嗙敱
+ */
+ private String applyContent;
+ /**
+ * 娣诲姞鏉ユ簮
+ */
+ private Integer addSource;
+
+ // ========== 鑱氬悎鑷� AdminUser锛岄伩鍏嶅墠绔啀璋� system 鎺ュ彛 ==========
+
+ /**
+ * 鐢宠鏂规樀绉�
+ */
+ private String fromNickname;
+ /**
+ * 鐢宠鏂瑰ご鍍�
+ */
+ private String fromAvatar;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestRejectedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestRejectedNotification.java
new file mode 100644
index 0000000..716ba4a
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendRequestRejectedNotification.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 濂藉弸鐢宠琚嫆缁濋�氱煡
+ * <p>
+ * 鎺ㄩ�佺粰鍘熺敵璇峰彂璧锋柟澶氱锛涘墠绔寜 requestId 鎶婂搴旂敵璇疯褰� handleResult 鏇存柊涓恒�屽凡鎷掔粷銆�
+ */
+@Data
+public class FriendRequestRejectedNotification extends BaseFriendNotification {
+
+ /**
+ * 宸插鐞嗙殑鐢宠璁板綍缂栧彿
+ */
+ private Long requestId;
+ /**
+ * 鎷掔粷鐞嗙敱锛堝彲閫夛級
+ */
+ private String handleContent;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendUnblockNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendUnblockNotification.java
new file mode 100644
index 0000000..00c246e
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendUnblockNotification.java
@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 绉诲嚭榛戝悕鍗曢�氱煡
+ * <p>
+ * A 鎶� B 绉诲嚭榛戝悕鍗曞悗浠呮帹 A 澶氱
+ */
+@Data
+public class FriendUnblockNotification extends BaseFriendNotification {
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendUpdateNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendUpdateNotification.java
new file mode 100644
index 0000000..2f3df5b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/friend/FriendUpdateNotification.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.friend;
+
+import lombok.Data;
+
+/**
+ * 濂藉弸淇℃伅鎵归噺鏇存柊閫氱煡锛堝娉� / 鍏嶆墦鎵� / 鑱旂郴浜虹疆椤剁瓑鍗曡竟灞炴�э級
+ * <p>
+ * A 鏀逛簡瀵� B 鐨勫娉� / 鍏嶆墦鎵� / 缃《绛夊崟杈瑰睘鎬у悗浠呮帹 A 澶氱鍋氬悓姝ワ紱
+ * 涓�娆� update 娑夊強澶氫釜瀛楁鏃跺悎骞朵负鍗曟潯閫氱煡锛岄伩鍏嶅閫氱煡椤哄簭绔炰簤銆�
+ */
+@Data
+public class FriendUpdateNotification extends BaseFriendNotification {
+
+ /**
+ * 澶囨敞锛涗笉涓虹┖鍒欐洿鏂帮紙绌轰覆琛ㄧず娓呯┖锛�
+ */
+ private String displayName;
+ /**
+ * 鍏嶆墦鎵帮紱涓嶄负绌哄垯鏇存柊
+ */
+ private Boolean silent;
+ /**
+ * 鑱旂郴浜虹疆椤讹紱涓嶄负绌哄垯鏇存柊
+ */
+ private Boolean pinned;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/BaseGroupNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/BaseGroupNotification.java
new file mode 100644
index 0000000..cd97756
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/BaseGroupNotification.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 缇や簨浠堕�氱煡鍩虹被锛氭墍鏈夌兢浜嬩欢 payload 鍏变韩 operatorUserId
+ */
+@Data
+public abstract class BaseGroupNotification {
+
+ /**
+ * 鎿嶄綔浜虹敤鎴风紪鍙�
+ */
+ private Long operatorUserId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupAdminAddNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupAdminAddNotification.java
new file mode 100644
index 0000000..42dfa34
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupAdminAddNotification.java
@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+/**
+ * 娣诲姞绠$悊鍛樹簨浠堕�氱煡锛坢emberUserIds 涓鸿璁剧鐞嗗憳鐨勬垚鍛橈級
+ */
+public class GroupAdminAddNotification extends GroupMemberListNotification {
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupAdminRemoveNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupAdminRemoveNotification.java
new file mode 100644
index 0000000..39b67dc
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupAdminRemoveNotification.java
@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+/**
+ * 鎾ら攢绠$悊鍛樹簨浠堕�氱煡锛坢emberUserIds 涓鸿鎾ら攢绠$悊鍛樼殑鎴愬憳锛�
+ */
+public class GroupAdminRemoveNotification extends GroupMemberListNotification {
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupBannedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupBannedNotification.java
new file mode 100644
index 0000000..f72a79b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupBannedNotification.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 缇ゅ皝绂� / 瑙e皝閫氱煡
+ */
+@Data
+public class GroupBannedNotification extends BaseGroupNotification {
+
+ /**
+ * 鏄惁灏佺
+ */
+ private Boolean banned;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupCancelMutedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupCancelMutedNotification.java
new file mode 100644
index 0000000..0dbc4b6
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupCancelMutedNotification.java
@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鍏ㄧ兢鍙栨秷绂佽█閫氱煡
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GroupCancelMutedNotification extends BaseGroupNotification {
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupCreateNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupCreateNotification.java
new file mode 100644
index 0000000..2d10bab
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupCreateNotification.java
@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+/**
+ * 缇ゅ垱寤轰簨浠堕�氱煡锛坢emberUserIds 鍚垱寤鸿�� + 鍒濆閭�璇锋垚鍛橈級
+ */
+public class GroupCreateNotification extends GroupMemberListNotification {
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupDissolveNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupDissolveNotification.java
new file mode 100644
index 0000000..acff6b0
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupDissolveNotification.java
@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+/**
+ * 缇よВ鏁d簨浠堕�氱煡
+ */
+public class GroupDissolveNotification extends BaseGroupNotification {
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupInfoUpdateNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupInfoUpdateNotification.java
new file mode 100644
index 0000000..7dbe87c
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupInfoUpdateNotification.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 缇や俊鎭彉鏇翠簨浠堕�氱煡锛圢AME / NOTICE 璧扮嫭绔嬩簨浠讹級
+ */
+@Data
+public class GroupInfoUpdateNotification extends BaseGroupNotification {
+
+ /**
+ * 鏃х兢澶村儚
+ */
+ private String oldAvatar;
+ /**
+ * 鏂扮兢澶村儚
+ */
+ private String newAvatar;
+ /**
+ * 鏃ц繘缇ゅ鎵瑰紑鍏�
+ */
+ private Boolean oldJoinApproval;
+ /**
+ * 鏂拌繘缇ゅ鎵瑰紑鍏�
+ */
+ private Boolean newJoinApproval;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberCancelMutedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberCancelMutedNotification.java
new file mode 100644
index 0000000..70719ef
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberCancelMutedNotification.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鍙栨秷鎴愬憳绂佽█閫氱煡
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GroupMemberCancelMutedNotification extends BaseGroupNotification {
+
+ /**
+ * 琚彇娑堢瑷�鐨勭敤鎴风紪鍙�
+ */
+ private Long mutedUserId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberEnterNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberEnterNotification.java
new file mode 100644
index 0000000..337c744
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberEnterNotification.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鑷敱杩涚兢浜嬩欢閫氱煡
+ * <p>
+ * 鐢ㄦ埛缁忔悳绱� / 浜岀淮鐮� / 鍒嗕韩閾炬帴鑷敱杩涚兢锛團REE 妯″紡鎴栧鎵归�氳繃鍚庯級锛屽叏鍛樺箍鎾紱
+ * 杩涚兢鑰呭墠绔寜 entrantUserId === self 鑷垽锛屽垵娆℃媺鍙� fetchGroupInfo + fetchGroupMembers锛涘叾浣欐垚鍛樺眬閮ㄦ彃鍏ユ柊鎴愬憳
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupMemberEnterNotification extends BaseGroupNotification {
+
+ /**
+ * 杩涚兢鑰呯敤鎴风紪鍙�
+ */
+ private Long entrantUserId;
+ /**
+ * 鍔犲叆鏉ユ簮
+ */
+ private Integer addSource;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberInviteNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberInviteNotification.java
new file mode 100644
index 0000000..7455845
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberInviteNotification.java
@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+/**
+ * 鎴愬憳鍔犲叆浜嬩欢閫氱煡锛坢emberUserIds 涓鸿閭�璇蜂汉锛�
+ */
+public class GroupMemberInviteNotification extends GroupMemberListNotification {
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberKickNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberKickNotification.java
new file mode 100644
index 0000000..24ff486
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberKickNotification.java
@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+/**
+ * 鎴愬憳琚Щ鍑轰簨浠堕�氱煡锛坢emberUserIds 涓鸿绉诲嚭鎴愬憳锛�
+ */
+public class GroupMemberKickNotification extends GroupMemberListNotification {
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberListNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberListNotification.java
new file mode 100644
index 0000000..5a57254
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberListNotification.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 缇や簨浠舵垚鍛樺垪琛ㄩ�氱煡鍩虹被
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public abstract class GroupMemberListNotification extends BaseGroupNotification {
+
+ /**
+ * 鍙楀奖鍝嶇殑鎴愬憳鐢ㄦ埛缂栧彿鍒楄〃
+ */
+ private List<Long> memberUserIds;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberMutedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberMutedNotification.java
new file mode 100644
index 0000000..a636249
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberMutedNotification.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+/**
+ * 鎴愬憳绂佽█閫氱煡
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GroupMemberMutedNotification extends BaseGroupNotification {
+
+ /**
+ * 琚瑷�鐨勭敤鎴风紪鍙�
+ */
+ private Long mutedUserId;
+ /**
+ * 绂佽█鍒版湡鏃堕棿
+ */
+ private LocalDateTime muteEndTime;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberNicknameUpdateNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberNicknameUpdateNotification.java
new file mode 100644
index 0000000..869fc2b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberNicknameUpdateNotification.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 鎴愬憳缁勫唴鏄电О鍙樻洿浜嬩欢閫氱煡
+ */
+@Data
+public class GroupMemberNicknameUpdateNotification extends BaseGroupNotification {
+
+ /**
+ * 缇ゅ唴鏄电О
+ */
+ private String displayUserName;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberQuitNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberQuitNotification.java
new file mode 100644
index 0000000..663f104
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberQuitNotification.java
@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+/**
+ * 鎴愬憳閫�缇や簨浠堕�氱煡
+ */
+public class GroupMemberQuitNotification extends BaseGroupNotification {
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberSettingUpdateNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberSettingUpdateNotification.java
new file mode 100644
index 0000000..05f0215
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMemberSettingUpdateNotification.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 缇ゆ垚鍛樹釜浜鸿缃彉鏇翠簨浠堕�氱煡锛堜釜浜哄绔悓姝ワ級
+ * <p>
+ * silent / groupRemark 瀛楁 null 琛ㄧず鏈鏈彉鏇达紝鍓嶇鎸夐潪 null 灞�閮ㄦ洿鏂�
+ */
+@Data
+public class GroupMemberSettingUpdateNotification extends BaseGroupNotification {
+
+ /**
+ * 缇ゅ厤鎵撴壈
+ */
+ private Boolean silent;
+ /**
+ * 缇ゅ娉�
+ */
+ private String groupRemark;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMessagePinNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMessagePinNotification.java
new file mode 100644
index 0000000..1717b1b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMessagePinNotification.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 缇ゆ秷鎭疆椤朵簨浠堕�氱煡
+ */
+@Data
+public class GroupMessagePinNotification extends BaseGroupNotification {
+
+ /**
+ * 琚疆椤剁殑娑堟伅缂栧彿
+ */
+ private Long messageId;
+ /**
+ * 琚疆椤剁殑娑堟伅灞曠ず鏁版嵁
+ */
+ private PinnedMessage message;
+
+ /**
+ * 琚疆椤剁殑娑堟伅灞曠ず鏁版嵁
+ */
+ @Data
+ public static class PinnedMessage {
+
+ /**
+ * 娑堟伅缂栧彿
+ */
+ private Long id;
+ /**
+ * 鍙戦�佷汉缂栧彿
+ */
+ private Long senderId;
+ /**
+ * 缇ょ紪鍙�
+ */
+ private Long groupId;
+ /**
+ * 娑堟伅绫诲瀷
+ */
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭
+ */
+ private String content;
+ /**
+ * 鍙戦�佹椂闂�
+ */
+ private LocalDateTime sendTime;
+ /**
+ * @ 鐩爣鐢ㄦ埛缂栧彿鍒楄〃
+ */
+ private List<Long> atUserIds;
+ /**
+ * 瀹氬悜鎺ユ敹鐢ㄦ埛缂栧彿鍒楄〃
+ */
+ private List<Long> receiverUserIds;
+
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMessageUnpinNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMessageUnpinNotification.java
new file mode 100644
index 0000000..8051967
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMessageUnpinNotification.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 缇ゆ秷鎭彇娑堢疆椤朵簨浠堕�氱煡
+ */
+@Data
+public class GroupMessageUnpinNotification extends BaseGroupNotification {
+
+ /**
+ * 琚彇娑堢疆椤剁殑娑堟伅缂栧彿
+ */
+ private Long messageId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMutedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMutedNotification.java
new file mode 100644
index 0000000..dc49a29
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupMutedNotification.java
@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 鍏ㄧ兢绂佽█閫氱煡
+ */
+@Data
+public class GroupMutedNotification extends BaseGroupNotification {
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupNameUpdateNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupNameUpdateNotification.java
new file mode 100644
index 0000000..00fcc74
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupNameUpdateNotification.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 缇ゅ悕鍙樻洿浜嬩欢閫氱煡
+ */
+@Data
+public class GroupNameUpdateNotification extends BaseGroupNotification {
+
+ /**
+ * 鏃х兢鍚�
+ */
+ private String oldName;
+ /**
+ * 鏂扮兢鍚�
+ */
+ private String newName;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupNoticeUpdateNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupNoticeUpdateNotification.java
new file mode 100644
index 0000000..ecd3e34
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupNoticeUpdateNotification.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 缇ゅ叕鍛婂彉鏇翠簨浠堕�氱煡
+ */
+@Data
+public class GroupNoticeUpdateNotification extends BaseGroupNotification {
+
+ /**
+ * 鏃х兢鍏憡
+ */
+ private String oldNotice;
+ /**
+ * 鏂扮兢鍏憡
+ */
+ private String newNotice;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupOwnerTransferNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupOwnerTransferNotification.java
new file mode 100644
index 0000000..b4e8564
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupOwnerTransferNotification.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+
+/**
+ * 缇や富杞浜嬩欢閫氱煡
+ */
+@Data
+public class GroupOwnerTransferNotification extends BaseGroupNotification {
+
+ /**
+ * 鏂扮兢涓荤敤鎴风紪鍙�
+ */
+ private Long newOwnerUserId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestApprovedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestApprovedNotification.java
new file mode 100644
index 0000000..2e083f2
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestApprovedNotification.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鍏ョ兢鐢宠琚悓鎰忛�氱煡
+ * <p>
+ * 瀹氬悜鎺ㄩ�佺粰鐢宠浜� + 缇や富 + 鍏ㄩ儴绠$悊鍛橈紱admin 渚ф嵁姝ゆ妸 unhandledCount 鍑� 1 骞朵粠鏈鐞嗗垪琛ㄧЩ闄�
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupRequestApprovedNotification extends BaseGroupNotification {
+
+ /**
+ * 宸插鐞嗙殑鐢宠璁板綍缂栧彿
+ */
+ private Long requestId;
+ /**
+ * 缇ょ紪鍙�
+ */
+ private Long groupId;
+ /**
+ * 鐢宠浜� / 琚個璇蜂汉鐢ㄦ埛缂栧彿
+ */
+ private Long userId;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestReceivedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestReceivedNotification.java
new file mode 100644
index 0000000..29b5aa3
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestReceivedNotification.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鏀跺埌鏂扮殑鍏ョ兢鐢宠閫氱煡
+ * <p>
+ * 瀹氬悜鎺ㄩ�佺粰缇や富 + 鍏ㄩ儴绠$悊鍛橈紙澶氱鍚屾锛夛紱payload 宸叉惡甯︾敵璇锋柟鏄电О / 澶村儚锛屽墠绔寜 requestId 鐩存帴 push 杩涘垪琛�
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupRequestReceivedNotification extends BaseGroupNotification {
+
+ /**
+ * 鐢宠璁板綍缂栧彿
+ */
+ private Long requestId;
+ /**
+ * 缇ょ紪鍙�
+ */
+ private Long groupId;
+ /**
+ * 鐢宠浜� / 琚個璇蜂汉鐢ㄦ埛缂栧彿
+ */
+ private Long userId;
+ /**
+ * 閭�璇蜂汉鐢ㄦ埛缂栧彿锛汵ULL 琛ㄧず鐢ㄦ埛涓诲姩鐢宠
+ */
+ private Long inviterUserId;
+ /**
+ * 鐢宠鐞嗙敱
+ */
+ private String applyContent;
+ /**
+ * 鍔犲叆鏉ユ簮
+ */
+ private Integer addSource;
+
+ // ========== 鑱氬悎鑷� AdminUser锛岄伩鍏嶅墠绔啀璋� system 鎺ュ彛 ==========
+
+ /**
+ * 鐢宠鏂� / 琚個璇蜂汉鏄电О
+ */
+ private String userNickname;
+ /**
+ * 鐢宠鏂� / 琚個璇蜂汉澶村儚
+ */
+ private String userAvatar;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestRejectedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestRejectedNotification.java
new file mode 100644
index 0000000..dd6e153
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/group/GroupRequestRejectedNotification.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.group;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鍏ョ兢鐢宠琚嫆缁濋�氱煡
+ * <p>
+ * 瀹氬悜鎺ㄩ�佺粰鐢宠浜� + 缇や富 + 鍏ㄩ儴绠$悊鍛橈紱admin 渚ф嵁姝ゆ妸 unhandledCount 鍑� 1 骞朵粠鏈鐞嗗垪琛ㄧЩ闄�
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupRequestRejectedNotification extends BaseGroupNotification {
+
+ /**
+ * 宸插鐞嗙殑鐢宠璁板綍缂栧彿
+ */
+ private Long requestId;
+ /**
+ * 缇ょ紪鍙�
+ */
+ private Long groupId;
+ /**
+ * 鐢宠浜� / 琚個璇蜂汉鐢ㄦ埛缂栧彿
+ */
+ private Long userId;
+ /**
+ * 鎷掔粷鐞嗙敱锛堝彲閫夛級
+ */
+ private String handleContent;
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImChannelMessageNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImChannelMessageNotification.java
new file mode 100644
index 0000000..af7e4c2
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImChannelMessageNotification.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.message;
+
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 棰戦亾娑堟伅 WebSocket 鎺ㄩ�侀�氱煡
+ * <p>
+ * 鍗曞悜锛氭湇鍔$杩愯惀鎺ㄩ�� 鈫� C 绔敤鎴凤紱C 绔笉鑳藉悜棰戦亾鍙戞秷鎭��
+ * 瀛楁鍒嗗眰锛氶《灞傛槸娑堟伅鍏冩暟鎹� + 妫�绱㈢淮搴︼紝content 鏄� MaterialMessage payload 鐨� JSON 涓层��
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+@Accessors(chain = true)
+public class ImChannelMessageNotification {
+
+ /**
+ * 娑堟伅缂栧彿
+ */
+ private Long id;
+ /**
+ * 棰戦亾缂栧彿
+ */
+ private Long channelId;
+ /**
+ * 鍏宠仈绱犳潗缂栧彿
+ */
+ private Long materialId;
+ /**
+ * 娑堟伅绫诲瀷
+ */
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭锛沺ayload JSON 涓�
+ */
+ private String content;
+ /**
+ * 鍙戦�佹椂闂�
+ */
+ private LocalDateTime sendTime;
+
+ /**
+ * 鐢遍閬撴秷鎭� DO 鏋勫缓鎺ㄩ�侀�氱煡
+ */
+ public static ImChannelMessageNotification ofSend(ImChannelMessageDO message) {
+ return BeanUtils.toBean(message, ImChannelMessageNotification.class);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImGroupMessageNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImGroupMessageNotification.java
new file mode 100644
index 0000000..cbefa05
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImGroupMessageNotification.java
@@ -0,0 +1,77 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.message;
+
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * IM 缇よ亰娑堟伅 WebSocket 缁熶竴鎺ㄩ�侀�氱煡
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class ImGroupMessageNotification {
+
+ /**
+ * 娑堟伅缂栧彿
+ */
+ private Long id;
+ /**
+ * 瀹㈡埛绔秷鎭紪鍙�
+ */
+ private String clientMessageId;
+ /**
+ * 鍙戦�佷汉缂栧彿
+ */
+ private Long senderId;
+ /**
+ * 缇ょ紪鍙�
+ */
+ private Long groupId;
+ /**
+ * 娑堟伅绫诲瀷
+ */
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭
+ */
+ private String content;
+ /**
+ * 娑堟伅鐘舵��
+ */
+ private Integer status;
+ /**
+ * 鍥炴墽鐘舵��
+ */
+ private Integer receiptStatus;
+ /**
+ * 宸茶浜烘暟
+ */
+ private Integer readCount;
+ /**
+ * 鍙戦�佹椂闂�
+ */
+ private LocalDateTime sendTime;
+ /**
+ * @ 鐩爣鐢ㄦ埛缂栧彿鍒楄〃
+ */
+ private List<Long> atUserIds;
+ /**
+ * 瀹氬悜鎺ユ敹鐢ㄦ埛缂栧彿鍒楄〃
+ */
+ private List<Long> receiverUserIds;
+ /**
+ * 鏋勫缓鍙戦�佹秷鎭�氱煡
+ *
+ * @param message 缇よ亰娑堟伅 DO
+ * @return 缇よ亰閫氱煡
+ */
+ public static ImGroupMessageNotification ofSend(ImGroupMessageDO message) {
+ return BeanUtils.toBean(message, ImGroupMessageNotification.class)
+ .setReadCount(message.getReadCount() != null ? message.getReadCount() : 0);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImMessageReadNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImMessageReadNotification.java
new file mode 100644
index 0000000..c066fa0
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImMessageReadNotification.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.message;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * IM 娑堟伅宸茶鍚屾閫氱煡
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+@Accessors(chain = true)
+public class ImMessageReadNotification {
+
+ /**
+ * 宸茶浣嶇疆锛堟渶澶у凡璇绘秷鎭紪鍙凤級
+ */
+ private Long id;
+ /**
+ * 鍙戦�佷汉缂栧彿
+ */
+ private Long senderId;
+ /**
+ * 绉佽亰鎺ユ敹浜虹紪鍙�
+ */
+ private Long receiverId;
+ /**
+ * 缇ょ紪鍙�
+ */
+ private Long groupId;
+ /**
+ * 棰戦亾缂栧彿
+ */
+ private Long channelId;
+ /**
+ * 宸茶浣嶇疆锛堟渶澶у凡璇绘秷鎭紪鍙凤級
+ */
+ private Long readId;
+
+ public static ImMessageReadNotification ofPrivate(Long senderId, Long receiverId, Long readId) {
+ return new ImMessageReadNotification()
+ .setId(readId).setReadId(readId)
+ .setSenderId(senderId).setReceiverId(receiverId);
+ }
+
+ public static ImMessageReadNotification ofGroup(Long senderId, Long groupId, Long readId) {
+ return new ImMessageReadNotification()
+ .setId(readId).setReadId(readId)
+ .setSenderId(senderId).setGroupId(groupId);
+ }
+
+ public static ImMessageReadNotification ofChannel(Long channelId, Long readId) {
+ return new ImMessageReadNotification()
+ .setId(readId).setReadId(readId)
+ .setChannelId(channelId);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImMessageReceiptNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImMessageReceiptNotification.java
new file mode 100644
index 0000000..f82df9f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImMessageReceiptNotification.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.message;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * IM 娑堟伅鍥炴墽閫氱煡
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+@Accessors(chain = true)
+public class ImMessageReceiptNotification {
+
+ /**
+ * 娑堟伅缂栧彿
+ */
+ private Long id;
+ /**
+ * 宸茶鏂圭殑鐢ㄦ埛缂栧彿
+ */
+ private Long senderId;
+ /**
+ * 绉佽亰鎺ユ敹浜虹紪鍙�
+ */
+ private Long receiverId;
+ /**
+ * 缇ょ紪鍙�
+ */
+ private Long groupId;
+ /**
+ * 宸茶浜烘暟
+ */
+ private Integer readCount;
+ /**
+ * 鍥炴墽鐘舵��
+ */
+ private Integer receiptStatus;
+
+ public static ImMessageReceiptNotification ofPrivate(Long senderId, Long receiverId, Long readId) {
+ return new ImMessageReceiptNotification()
+ .setId(readId).setSenderId(senderId).setReceiverId(receiverId);
+ }
+
+ public static ImMessageReceiptNotification ofGroup(Long messageId, Long groupId,
+ Integer readCount, Integer receiptStatus) {
+ return new ImMessageReceiptNotification()
+ .setId(messageId).setGroupId(groupId)
+ .setReadCount(readCount).setReceiptStatus(receiptStatus);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImPrivateMessageNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImPrivateMessageNotification.java
new file mode 100644
index 0000000..0a88591
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/message/ImPrivateMessageNotification.java
@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.message;
+
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.time.LocalDateTime;
+
+/**
+ * IM 绉佽亰娑堟伅 WebSocket 缁熶竴鎺ㄩ�侀�氱煡
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+@Accessors(chain = true)
+public class ImPrivateMessageNotification {
+
+ /**
+ * 娑堟伅缂栧彿
+ */
+ private Long id;
+ /**
+ * 瀹㈡埛绔秷鎭紪鍙�
+ */
+ private String clientMessageId;
+ /**
+ * 鍙戦�佷汉缂栧彿
+ */
+ private Long senderId;
+ /**
+ * 鎺ユ敹浜虹紪鍙�
+ */
+ private Long receiverId;
+ /**
+ * 娑堟伅绫诲瀷
+ */
+ private Integer type;
+ /**
+ * 娑堟伅鍐呭
+ */
+ private String content;
+ /**
+ * 娑堟伅鐘舵��
+ */
+ private Integer status;
+ /**
+ * 鍥炴墽鐘舵��
+ */
+ private Integer receiptStatus;
+ /**
+ * 鍙戦�佹椂闂�
+ */
+ private LocalDateTime sendTime;
+
+ // ========== 闈欐�佸伐鍘傛柟娉� ==========
+
+ /**
+ * 鏋勫缓鍙戦�佹秷鎭�氱煡
+ *
+ * @param message 绉佽亰娑堟伅 DO
+ * @return 绉佽亰閫氱煡
+ */
+ public static ImPrivateMessageNotification ofSend(ImPrivateMessageDO message) {
+ return BeanUtils.toBean(message, ImPrivateMessageNotification.class);
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/package-info.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/package-info.java
new file mode 100644
index 0000000..7c2c251
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/package-info.java
@@ -0,0 +1,14 @@
+/**
+ * IM WebSocket 鍦ㄧ嚎閫氱煡瀵硅薄銆�
+ *
+ * <p>
+ * 鏈寘鍙斁 WebSocket 澶栧眰閫氱煡瀵硅薄锛屽浐瀹氫娇鐢� im-notification 浣滀负鎺ㄩ�� type銆�
+ * 鍏蜂綋涓氬姟 payload 鏀惧湪瀛愬寘涓細
+ * <ul>
+ * <li>{@code message}锛氱鑱娿�佺兢鑱娿�侀閬撴秷鎭�氱煡锛屼互鍙婃秷鎭唴瀹圭粨鏋勶紱</li>
+ * <li>{@code friend}锛氬ソ鍙嬪叧绯诲拰濂藉弸鐢宠閫氱煡锛�</li>
+ * <li>{@code group}锛氱兢璧勬枡銆佺兢鎴愬憳銆佸姞缇ょ敵璇烽�氱煡锛�</li>
+ * <li>{@code rtc}锛氬疄鏃堕�氳瘽閫氱煡銆�</li>
+ * </ul>
+ */
+package cn.iocoder.yudao.module.im.service.websocket.notification;
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallEndNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallEndNotification.java
new file mode 100644
index 0000000..8c616db
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallEndNotification.java
@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.rtc;
+
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallEndReasonEnum;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import lombok.Data;
+
+/**
+ * RTC_CALL_END 閫氳瘽缁撴潫閫氱煡
+ * <p>
+ * 鍏� im_private_message / im_group_message锛涙帴鏀舵柟鍏抽棴閫氳瘽绐� + 娓叉煋鑱婂ぉ tip
+ * <p>
+ * 鏂囨鍒嗗満鏅細
+ * 缇よ亰锛氥�岃闊抽�氳瘽宸茬粡缁撴潫銆嶏紱鍙戣捣浜轰俊鎭蛋閰嶅鐨� {@link ImRtcCallStartNotification}
+ * 绉佽亰锛氫豢寰俊鍑嗘皵娉★紝鎸� endReason 脳 selfSend 瑙嗚杞崲鏂囨锛圚ANGUP / CANCEL / REJECT / BUSY / ERROR锛�
+ * <p>
+ * 涓� {@link ImRtcCallStartNotification} 涓ゆ寮忛厤瀵癸細START 鍦� invite 浜嬪姟閲� INSERT锛孍ND 鍦� cancel / leave 浜嬪姟閲� INSERT锛�
+ * 涓ゆ浣嶄簬涓嶅悓璇锋眰 / 浜嬪姟锛岃嚜澧� id 淇濊瘉鑱婂ぉ娴侀『搴�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class ImRtcCallEndNotification {
+
+ /**
+ * 涓氬姟閫氳瘽缂栧彿
+ */
+ private String room;
+ /**
+ * 浼氳瘽绫诲瀷
+ */
+ private Integer conversationType;
+ /**
+ * 濯掍綋绫诲瀷
+ */
+ private Integer mediaType;
+ /**
+ * 缁撴潫鍘熷洜
+ */
+ private Integer endReason;
+ /**
+ * 閫氳瘽鏃堕暱锛堢锛夛細鎺ラ�氳繃涓� endTime - acceptTime锛涙湭鎺ラ�氫负 null
+ */
+ private Long durationSeconds;
+ /**
+ * 鎿嶄綔鑰呯敤鎴风紪鍙凤細HANGUP / CANCEL / REJECT 鏄Е鍙戠粨鏉熺殑浜猴紱HANGUP webhook 鍏滃簳涓� null
+ * <p>
+ * 鐢ㄤ簬鍓嶇銆岃鏌愭煇鎸傛柇銆嶇被鏂囨锛涙櫘閫氭枃妗堜笉渚濊禆姝ゅ瓧娈�
+ */
+ private Long operatorUserId;
+ /**
+ * 鎿嶄綔鑰呮樀绉帮細鍓嶇鎸夐渶灞曠ず锛堣鏌愭煇鎸傛柇 / 澶村儚 tip锛夛紱鎿嶄綔鑰呬负绌烘椂闅忎箣涓虹┖
+ */
+ private String operatorNickname;
+ /**
+ * 鎿嶄綔鑰呭ご鍍忥細鍓嶇鎸夐渶灞曠ず锛涙搷浣滆�呬负绌烘椂闅忎箣涓虹┖
+ */
+ private String operatorAvatar;
+
+ public static ImRtcCallEndNotification of(ImRtcCallDO call, ImRtcCallEndReasonEnum reason, Long durationSeconds,
+ Long operatorId, AdminUserRespDTO operator) {
+ ImRtcCallEndNotification notification = new ImRtcCallEndNotification();
+ notification.room = call.getRoom();
+ notification.conversationType = call.getConversationType();
+ notification.mediaType = call.getMediaType();
+ notification.endReason = reason.getReason();
+ notification.durationSeconds = durationSeconds;
+ notification.operatorUserId = operatorId;
+ if (operator != null) {
+ notification.operatorNickname = operator.getNickname();
+ notification.operatorAvatar = operator.getAvatar();
+ }
+ return notification;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallNotification.java
new file mode 100644
index 0000000..e25f389
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallNotification.java
@@ -0,0 +1,165 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.rtc;
+
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantStatusEnum;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import lombok.Data;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * RTC_CALL 閫氳瘽淇′护閫氱煡锛堥�氳瘽淇′护缁熶竴鍏ュ彛锛�
+ * <p>
+ * 涓嶅叆搴擄紱璧� imWebSocketService 浠呮帹鍙備笌鏂�
+ * <p>
+ * status 瀛楁澶嶇敤 {@link ImRtcParticipantStatusEnum}锛岃〃杈俱�屾湰娆′俊浠ゅ搴旂殑鍙備笌鑰呯姸鎬佸彉杩併��
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class ImRtcCallNotification {
+
+ /**
+ * 淇′护瀵瑰簲鐨勫弬涓庤�呯姸鎬�
+ *
+ * 鍙栧�煎弬瑙� {@link ImRtcParticipantStatusEnum}
+ */
+ private Integer status;
+
+ /**
+ * 涓氬姟閫氳瘽缂栧彿
+ */
+ private String room;
+ /**
+ * 浼氳瘽绫诲瀷
+ */
+ private Integer conversationType;
+ /**
+ * 濯掍綋绫诲瀷
+ */
+ private Integer mediaType;
+ /**
+ * 缇ょ紪鍙凤細缇ら�氳瘽鍦烘櫙蹇呭~
+ */
+ private Long groupId;
+
+ // ========== INVITE 涓撳睘瀛楁 ==========
+
+ /**
+ * LiveKit Server WebSocket 鍦板潃锛汭NVITE 涓撳睘
+ */
+ private String livekitUrl;
+ /**
+ * 璇ヨ鍙笓灞炵殑 LiveKit 鎺ュ惉 Token锛涙帴閫氬悗鐩存帴 connect 鐢紱INVITE 涓撳睘
+ */
+ private String token;
+ /**
+ * 鍙戣捣浜虹敤鎴风紪鍙凤紱INVITE 涓撳睘
+ */
+ private Long inviterUserId;
+ /**
+ * 鍙戣捣浜烘樀绉帮紱INVITE 涓撳睘锛屽墠绔潵鐢电晫闈㈠睍绀�
+ */
+ private String inviterNickname;
+ /**
+ * 鍙戣捣浜哄ご鍍忥紱INVITE 涓撳睘锛屽墠绔潵鐢电晫闈㈠睍绀�
+ */
+ private String inviterAvatar;
+ /**
+ * 鏈琚個璇蜂汉鍒楄〃锛汭NVITE 涓撳睘锛屽墠绔潵鐢电晫闈㈠睍绀恒�岄個璇风殑鍏朵粬浜恒��
+ *
+ * 娉ㄦ剰锛氬寘鍚敹浠朵汉鑷韩锛屽墠绔寜闇�杩囨护
+ */
+ private List<Long> inviteeIds;
+
+ // ========== REJECT 涓撳睘瀛楁 ==========
+
+ /**
+ * 鎿嶄綔鑰呯敤鎴风紪鍙凤紱REJECT 瑙﹀彂鏈鐘舵�佸彉杩佺殑浜�
+ */
+ private Long operatorUserId;
+ /**
+ * 鎿嶄綔鑰呮樀绉帮紱鍓嶇鎸夐渶灞曠ず锛堣鏌愭煇鎷掓帴锛夛紱鏅�氭枃妗堜笉渚濊禆
+ */
+ private String operatorNickname;
+ /**
+ * 鎿嶄綔鑰呭ご鍍忥紱鍓嶇鎸夐渶灞曠ず锛涙櫘閫氭枃妗堜笉渚濊禆
+ */
+ private String operatorAvatar;
+
+ /**
+ * 鏋勯�� INVITE 淇′护锛涙帹琚個璇蜂汉锛宨nvitee 鐘舵�佸彉涓� INVITING
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param inviter 鍙戣捣浜猴紱鍙┖锛岀己澶辨椂 inviterNickname / inviterAvatar 鐣欑┖
+ * @param livekitUrl LiveKit Server WebSocket 鍦板潃
+ * @param token 琚彨鐨勬帴鍚� Token锛涙寜鏀朵欢浜哄崟鐙鍙�
+ * @param inviteeIds 鏈琚個璇蜂汉鍒楄〃锛涘墠绔潵鐢电晫闈㈠睍绀恒�岄個璇风殑鍏朵粬浜恒�嶇敤
+ * @return INVITE 淇′护
+ */
+ public static ImRtcCallNotification ofInvite(ImRtcCallDO call, AdminUserRespDTO inviter,
+ String livekitUrl, String token,
+ Collection<Long> inviteeIds) {
+ ImRtcCallNotification notification = baseOf(call, ImRtcParticipantStatusEnum.INVITING.getStatus());
+ notification.livekitUrl = livekitUrl;
+ notification.token = token;
+ notification.inviterUserId = call.getInviterUserId();
+ if (inviter != null) {
+ notification.inviterNickname = inviter.getNickname();
+ notification.inviterAvatar = inviter.getAvatar();
+ }
+ notification.inviteeIds = inviteeIds != null ? new java.util.ArrayList<>(inviteeIds) : null;
+ return notification;
+ }
+
+ /**
+ * 鏋勯�� REJECT 淇′护锛涗粎缇ら�氳瘽鍦烘櫙锛涙帹涓诲彨
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param operatorUserId 鎷掓帴鑰呯敤鎴风紪鍙�
+ * @param operator 鎷掓帴鑰咃紱鍙┖锛岀己澶辨椂 operatorNickname / operatorAvatar 鐣欑┖
+ * @return REJECT 淇′护
+ */
+ public static ImRtcCallNotification ofReject(ImRtcCallDO call, Long operatorUserId, AdminUserRespDTO operator) {
+ ImRtcCallNotification notification = baseOf(call, ImRtcParticipantStatusEnum.REJECTED.getStatus());
+ notification.operatorUserId = operatorUserId;
+ if (operator != null) {
+ notification.operatorNickname = operator.getNickname();
+ notification.operatorAvatar = operator.getAvatar();
+ }
+ return notification;
+ }
+
+ /**
+ * 鏋勯�� NO_ANSWER 淇′护锛涗粎缇ら�氳瘽鍦烘櫙锛涙帹涓诲彨锛涜秴鏃舵湭鎺ュ惉璇箟鐙珛浜� REJECT
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param operatorUserId 鏈帴鍚�呯敤鎴风紪鍙�
+ * @param operator 鏈帴鍚�咃紱鍙┖锛岀己澶辨椂 operatorNickname / operatorAvatar 鐣欑┖
+ * @return NO_ANSWER 淇′护
+ */
+ public static ImRtcCallNotification ofNoAnswer(ImRtcCallDO call, Long operatorUserId, AdminUserRespDTO operator) {
+ ImRtcCallNotification notification = baseOf(call, ImRtcParticipantStatusEnum.NO_ANSWER.getStatus());
+ notification.operatorUserId = operatorUserId;
+ if (operator != null) {
+ notification.operatorNickname = operator.getNickname();
+ notification.operatorAvatar = operator.getAvatar();
+ }
+ return notification;
+ }
+
+ /**
+ * 鍏叡楠ㄦ灦锛涘~鍏� call 涓婁笅鏂� + status
+ */
+ private static ImRtcCallNotification baseOf(ImRtcCallDO call, Integer status) {
+ ImRtcCallNotification notification = new ImRtcCallNotification();
+ notification.status = status;
+ notification.room = call.getRoom();
+ notification.conversationType = call.getConversationType();
+ notification.mediaType = call.getMediaType();
+ notification.groupId = call.getGroupId();
+ return notification;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallStartNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallStartNotification.java
new file mode 100644
index 0000000..a7a8596
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcCallStartNotification.java
@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.rtc;
+
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import lombok.Data;
+
+/**
+ * RTC_CALL_START 閫氳瘽寮�濮嬮�氱煡
+ * <p>
+ * 缇よ亰鍏� im_group_message 鍏ㄧ兢骞挎挱锛涘墠绔覆鏌撹亰澶� tip銆寋inviterNickname} 鍙戣捣浜嗚闊抽�氳瘽銆�
+ * <p>
+ * 绉佽亰鍏� im_private_message 瀹氬悜缁欒鍙紱鍓嶇涓嶆覆鏌撹亰澶� tip锛屼粎鐢ㄤ簬浼氳瘽鍒楄〃棰勮灞曠ず銆孾璇煶閫氳瘽]銆嶏紙鍒锋柊鍚庝粛鍙锛�
+ * <p>
+ * 涓� {@link ImRtcCallEndNotification} 涓ゆ寮忛厤瀵癸細
+ * START 鍦� invite 鎺ュ彛浜嬪姟閲� INSERT锛孍ND 鍦� cancel / leave 鎺ュ彛浜嬪姟閲� INSERT锛�
+ * 涓ゆ浣嶄簬涓嶅悓璇锋眰 / 浜嬪姟锛岃嚜澧� id 淇濊瘉鑱婂ぉ娴侀『搴忥紱鍚庣画濡傛灉鍚堝苟鍒板悓涓�浜嬪姟閲� push锛岄渶瑕侀澶栦繚璇� START 鍏堜簬 END
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class ImRtcCallStartNotification {
+
+ /**
+ * 涓氬姟閫氳瘽缂栧彿
+ */
+ private String room;
+ /**
+ * 浼氳瘽绫诲瀷锛氬綋鍓嶅浐瀹� GROUP锛堢鑱婃棤 START锛�
+ */
+ private Integer conversationType;
+ /**
+ * 濯掍綋绫诲瀷
+ */
+ private Integer mediaType;
+ /**
+ * 鍙戣捣浜虹敤鎴风紪鍙�
+ */
+ private Long inviterUserId;
+ /**
+ * 鍙戣捣浜烘樀绉帮細鐢ㄤ簬鑱婂ぉ tip 鏂囨锛屽彲绌鸿蛋鍓嶇 fallback
+ */
+ private String inviterNickname;
+ /**
+ * 鍙戣捣浜哄ご鍍忥細鍙┖锛岄鐣欑粰鐐瑰嚮 tip 灞曠ず鍙戣捣浜哄崱鐗�
+ */
+ private String inviterAvatar;
+
+ public static ImRtcCallStartNotification of(ImRtcCallDO call, AdminUserRespDTO inviter) {
+ ImRtcCallStartNotification notification = new ImRtcCallStartNotification();
+ notification.room = call.getRoom();
+ notification.conversationType = call.getConversationType();
+ notification.mediaType = call.getMediaType();
+ notification.inviterUserId = call.getInviterUserId();
+ if (inviter != null) {
+ notification.inviterNickname = inviter.getNickname();
+ notification.inviterAvatar = inviter.getAvatar();
+ }
+ return notification;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcParticipantConnectedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcParticipantConnectedNotification.java
new file mode 100644
index 0000000..dee51c9
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcParticipantConnectedNotification.java
@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.rtc;
+
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import lombok.Data;
+
+/**
+ * RTC_PARTICIPANT_CONNECTED 閫氳瘽鍙備笌鑰呭姞鍏ラ�氱煡
+ * <p>
+ * 涓嶅叆搴擄紱LiveKit webhook participant_joined 瑙﹀彂锛涚鑱婃帹 peer 澶氱 + inviter 澶氱锛岀兢鑱婂叏缇ゅ箍鎾�
+ * <p>
+ * 鍓嶇 callStore 鎶� userId 杩藉姞杩� joinedUserIds锛涜兌鍥婃潯浜烘暟 +1锛涚兢鑱婂満鏅鏉� 1602 鎼哄甫閫氳瘽鍏冧俊鎭互渚� 棣栨濉厖鑳跺泭鏉�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class ImRtcParticipantConnectedNotification {
+
+ /**
+ * 涓氬姟閫氳瘽缂栧彿
+ */
+ private String room;
+ /**
+ * 鍔犲叆鐨勫弬涓庤�呯敤鎴风紪鍙�
+ */
+ private Long userId;
+ /**
+ * 浼氳瘽绫诲瀷
+ */
+ private Integer conversationType;
+ /**
+ * 缇ょ紪鍙凤紱缇ら�氳瘽鍦烘櫙蹇呭~
+ */
+ private Long groupId;
+ /**
+ * 濯掍綋绫诲瀷锛涚兢鑱婂満鏅殑闈為個璇锋垚鍛橀潬杩欎釜瀛楁 棣栨濉厖鑳跺泭鏉�
+ */
+ private Integer mediaType;
+ /**
+ * 鍙戣捣浜虹敤鎴风紪鍙凤紱缇よ亰鍦烘櫙鐨勯潪閭�璇锋垚鍛橀潬杩欎釜瀛楁 棣栨濉厖鑳跺泭鏉�
+ */
+ private Long inviterUserId;
+
+ /**
+ * 鏋勯�犲弬涓庤�呭姞鍏ラ�氱煡锛涙寜 {@link ImRtcCallDO} 鎶介�氳瘽涓婁笅鏂囷紝浠� userId 鏄彉閲�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param userId 鍔犲叆鐨勫弬涓庤�呯敤鎴风紪鍙�
+ * @return 閫氱煡杞借嵎
+ */
+ public static ImRtcParticipantConnectedNotification of(ImRtcCallDO call, Long userId) {
+ ImRtcParticipantConnectedNotification notification = new ImRtcParticipantConnectedNotification();
+ notification.room = call.getRoom();
+ notification.userId = userId;
+ notification.conversationType = call.getConversationType();
+ notification.groupId = call.getGroupId();
+ notification.mediaType = call.getMediaType();
+ notification.inviterUserId = call.getInviterUserId();
+ return notification;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcParticipantDisconnectedNotification.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcParticipantDisconnectedNotification.java
new file mode 100644
index 0000000..4aec61b
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/notification/rtc/ImRtcParticipantDisconnectedNotification.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.im.service.websocket.notification.rtc;
+
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import lombok.Data;
+
+/**
+ * RTC_PARTICIPANT_DISCONNECTED 閫氳瘽鍙備笌鑰呯寮�閫氱煡
+ * <p>
+ * 涓嶅叆搴擄紱LiveKit webhook participant_left 瑙﹀彂锛涙帹閫佽寖鍥村悓 {@link ImRtcParticipantConnectedNotification}
+ * <p>
+ * 鍓嶇 callStore 鎶� userId 浠� joinedUserIds 绉婚櫎锛涜兌鍥婃潯浜烘暟 -1
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class ImRtcParticipantDisconnectedNotification {
+
+ /**
+ * 涓氬姟閫氳瘽缂栧彿
+ */
+ private String room;
+ /**
+ * 绂诲紑鐨勫弬涓庤�呯敤鎴风紪鍙�
+ */
+ private Long userId;
+ /**
+ * 浼氳瘽绫诲瀷
+ */
+ private Integer conversationType;
+ /**
+ * 缇ょ紪鍙凤紱缇ら�氳瘽鍦烘櫙蹇呭~
+ */
+ private Long groupId;
+
+ /**
+ * 鏋勯�犲弬涓庤�呯寮�閫氱煡锛涙寜 {@link ImRtcCallDO} 鎶介�氳瘽涓婁笅鏂囷紝浠� userId 鏄彉閲�
+ *
+ * @param call 閫氳瘽涓昏〃
+ * @param userId 绂诲紑鐨勫弬涓庤�呯敤鎴风紪鍙�
+ * @return 閫氱煡杞借嵎
+ */
+ public static ImRtcParticipantDisconnectedNotification of(ImRtcCallDO call, Long userId) {
+ ImRtcParticipantDisconnectedNotification notification = new ImRtcParticipantDisconnectedNotification();
+ notification.room = call.getRoom();
+ notification.userId = userId;
+ notification.conversationType = call.getConversationType();
+ notification.groupId = call.getGroupId();
+ return notification;
+ }
+
+}
diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/util/ImMessageUtils.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/util/ImMessageUtils.java
new file mode 100644
index 0000000..bdfa83f
--- /dev/null
+++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/util/ImMessageUtils.java
@@ -0,0 +1,218 @@
+package cn.iocoder.yudao.module.im.util;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.QuoteMessage;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_CONTENT_INVALID;
+
+/**
+ * IM 娑堟伅鍐呭鐩稿叧宸ュ叿绫�
+ */
+public class ImMessageUtils {
+
+ /**
+ * 鏂囨湰娑堟伅鏈�澶ч暱搴�
+ */
+ private static final int TEXT_MAX_LENGTH = 4096;
+ /**
+ * URL 鏈�澶ч暱搴�
+ */
+ private static final int URL_MAX_LENGTH = 2048;
+ /**
+ * 鍚堝苟娑堟伅鏈�澶ф潯鏁�
+ */
+ private static final int MERGE_MESSAGE_MAX_COUNT = 100;
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鍙戦�佺殑娑堟伅鍐呭
+ *
+ * @param type 娑堟伅绫诲瀷
+ * @param content 娑堟伅鍐呭
+ */
+ public static void validateUserMessageContent(Integer type, String content) {
+ ImContentTypeEnum messageType;
+ try {
+ messageType = ImContentTypeEnum.validate(type);
+ } catch (IllegalArgumentException e) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ if (!messageType.isNormal()) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ Map<String, Object> map = JsonUtils.parseMap(content);
+ if (map == null) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ if (ImContentTypeEnum.TEXT == messageType) {
+ validateTextContent(map);
+ } else if (ImContentTypeEnum.IMAGE == messageType || ImContentTypeEnum.FACE == messageType) {
+ validateUrl(getString(map, "url"));
+ } else if (ImContentTypeEnum.VOICE == messageType) {
+ validateUrl(getString(map, "url"));
+ validatePositiveNumber(map.get("duration"));
+ } else if (ImContentTypeEnum.VIDEO == messageType) {
+ validateUrl(getString(map, "url"));
+ } else if (ImContentTypeEnum.FILE == messageType) {
+ validateUrl(getString(map, "url"));
+ validateNotBlank(getString(map, "name"));
+ } else if (ImContentTypeEnum.CARD == messageType) {
+ validateCardContent(map);
+ } else if (ImContentTypeEnum.MERGE == messageType) {
+ validateMergeContent(map);
+ } else if (ImContentTypeEnum.MATERIAL == messageType) {
+ validateMaterialContent(map);
+ }
+ }
+
+ private static void validateTextContent(Map<String, Object> map) {
+ String text = getString(map, "content");
+ validateNotBlank(text);
+ if (text.length() > TEXT_MAX_LENGTH) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ }
+
+ private static void validateCardContent(Map<String, Object> map) {
+ validateNumber(map.get("targetType"));
+ validateNumber(map.get("targetId"));
+ validateNotBlank(getString(map, "name"));
+ }
+
+ @SuppressWarnings("PatternVariableCanBeUsed")
+ private static void validateMergeContent(Map<String, Object> map) {
+ validateNotBlank(getString(map, "title"));
+ Object messages = map.get("messages");
+ if (!(messages instanceof Collection)) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ Collection<?> messageList = (Collection<?>) messages;
+ if (CollUtil.isEmpty(messageList) || messageList.size() > MERGE_MESSAGE_MAX_COUNT) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ }
+
+ private static void validateMaterialContent(Map<String, Object> map) {
+ if (map.get("materialId") == null && StrUtil.isBlank(getString(map, "title"))) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ validateUrlIfPresent(getString(map, "url"));
+ validateUrlIfPresent(getString(map, "coverUrl"));
+ }
+
+ private static String getString(Map<String, Object> map, String field) {
+ return Convert.toStr(map.get(field), null);
+ }
+
+ private static void validateNotBlank(String value) {
+ if (StrUtil.isBlank(value)) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ }
+
+ private static void validateNumber(Object value) {
+ if (Convert.toLong(value, null) == null) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ }
+
+ private static void validatePositiveNumber(Object value) {
+ Integer number = Convert.toInt(value, null);
+ if (number == null || number < 0) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ }
+
+ private static void validateUrlIfPresent(String url) {
+ if (StrUtil.isBlank(url)) {
+ return;
+ }
+ validateUrl(url);
+ }
+
+ private static void validateUrl(String url) {
+ validateNotBlank(url);
+ if (url.length() > URL_MAX_LENGTH) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ String lowerUrl = StrUtil.trim(url).toLowerCase();
+ if (StrUtil.startWithAny(lowerUrl, "javascript:", "data:", "vbscript:", "file:")) {
+ throw exception(MESSAGE_CONTENT_INVALID);
+ }
+ }
+
+ /**
+ * 浠� content 瑙f瀽瀹㈡埛绔啓鍏ョ殑 quote.messageId
+ *
+ * @param content 鍘� content(JSON)
+ * @return messageId锛屼笉瀛樺湪 / 闈炴硶杩斿洖 null
+ */
+ public static Long parseQuoteMessageId(String content) {
+ Map<String, Object> map = JsonUtils.parseMap(content);
+ if (map == null) {
+ return null;
+ }
+ Object quoteRaw = map.get(QuoteMessage.FIELD_NAME);
+ if (!(quoteRaw instanceof Map)) {
+ return null;
+ }
+ return Convert.toLong(((Map<?, ?>) quoteRaw).get(QuoteMessage.FIELD_MESSAGE_ID));
+ }
+
+ /**
+ * 鎶� quote 鍐欏叆 content 鐨� quote 瀛楁
+ *
+ * @param content 鍘� content(JSON)
+ * @param quote QuoteMessage 瀵硅薄
+ * @return 娉ㄥ叆 quote 鍚庣殑 content(JSON)
+ */
+ public static String appendQuote(String content, QuoteMessage quote) {
+ Map<String, Object> map = JsonUtils.parseMap(content);
+ if (map == null) {
+ map = new LinkedHashMap<>();
+ }
+ map.put(QuoteMessage.FIELD_NAME, quote);
+ return JsonUtils.toJsonString(map);
+ }
+
+ /**
+ * 绉婚櫎 content 閲岀殑 quote 瀛楁
+ *
+ * @param content 鍘� content(JSON)
+ * @return remove quote 鍚庣殑 content(JSON)
+ */
+ public static String removeQuote(String content) {
+ if (StrUtil.isBlank(content) || !StrUtil.contains(content, "\"" + QuoteMessage.FIELD_NAME + "\"")) {
+ return content;
+ }
+ Map<String, Object> map = JsonUtils.parseMap(content);
+ if (map == null) {
+ return content;
+ }
+ map.remove(QuoteMessage.FIELD_NAME);
+ return JsonUtils.toJsonString(map);
+ }
+
+ /**
+ * 鏋勫缓 QuoteMessage 瀵硅薄
+ *
+ * @param messageId 琚紩鐢ㄦ秷鎭紪鍙�
+ * @param senderId 琚紩鐢ㄦ秷鎭彂閫佷汉缂栧彿
+ * @param type 琚紩鐢ㄦ秷鎭被鍨�
+ * @param originalContent 琚紩鐢ㄦ秷鎭師 content(JSON)锛屾湇鍔$浼� removeQuote 闃叉宓屽
+ * @return QuoteMessage 瀵硅薄
+ */
+ public static QuoteMessage buildQuote(Long messageId, Long senderId, Integer type, String originalContent) {
+ return new QuoteMessage().setMessageId(messageId).setSenderId(senderId).setType(type)
+ .setContent(removeQuote(originalContent));
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationReadMapperTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationReadMapperTest.java
new file mode 100644
index 0000000..b56845f
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationReadMapperTest.java
@@ -0,0 +1,105 @@
+package cn.iocoder.yudao.module.im.dal.mysql.conversation;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationReadDO;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link ImConversationReadMapper} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImConversationReadMapperTest extends BaseDbUnitTest {
+
+ @Resource
+ private ImConversationReadMapper mapper;
+
+ @Test
+ public void testUpdateReadMessageIdToLarger_onlyAdvancesWhenLarger() {
+ // 鍑嗗锛氱敤鎴� 1 鍦ㄧ兢 10 鐨勮浣嶇疆 = 50
+ ImConversationReadDO read = buildRead(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 50L);
+ mapper.insert(read);
+
+ // 1. 鏂颁綅缃洿澶� 鈫� 鍓嶈繘
+ int advanced = mapper.updateReadMessageIdToLarger(read.getId(), 100L, LocalDateTime.now());
+ assertEquals(1, advanced);
+ assertEquals(100L, mapper.selectById(read.getId()).getMessageId());
+
+ // 2. 鏂颁綅缃浉绛� 鈫� 涓嶆洿鏂�
+ int equalUpdate = mapper.updateReadMessageIdToLarger(read.getId(), 100L, LocalDateTime.now());
+ assertEquals(0, equalUpdate);
+
+ // 3. 鏂颁綅缃洿灏忥紙涔卞簭涓婃姤锛夆啋 涓嶅洖閫�
+ int smaller = mapper.updateReadMessageIdToLarger(read.getId(), 80L, LocalDateTime.now());
+ assertEquals(0, smaller);
+ assertEquals(100L, mapper.selectById(read.getId()).getMessageId());
+ }
+
+ @Test
+ public void testSelectByUserIdAndConversation() {
+ ImConversationReadDO read = buildRead(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 50L);
+ mapper.insert(read);
+ // 鍚岀敤鎴蜂笉鍚屼細璇濈被鍨嬶紝涓嶅簲鍛戒腑
+ mapper.insert(buildRead(1L, ImConversationTypeEnum.PRIVATE.getType(), 10L, 99L));
+
+ ImConversationReadDO result = mapper.selectByUserIdAndConversation(
+ 1L, ImConversationTypeEnum.GROUP.getType(), 10L);
+
+ assertNotNull(result);
+ assertEquals(50L, result.getMessageId());
+ }
+
+ @Test
+ public void testSelectListByConversation_aggregatesAllUsers() {
+ // 缇� 10 鍐呬笁涓敤鎴风殑璇讳綅缃紝鐢ㄤ簬缇ゅ洖鎵т汉鏁拌仛鍚�
+ mapper.insert(buildRead(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L));
+ mapper.insert(buildRead(2L, ImConversationTypeEnum.GROUP.getType(), 10L, 80L));
+ mapper.insert(buildRead(3L, ImConversationTypeEnum.GROUP.getType(), 10L, 50L));
+ // 鍒殑缇わ紝涓嶅簲娣峰叆
+ mapper.insert(buildRead(1L, ImConversationTypeEnum.GROUP.getType(), 20L, 999L));
+
+ List<ImConversationReadDO> list = mapper.selectListByConversation(
+ ImConversationTypeEnum.GROUP.getType(), 10L);
+ Map<Long, Long> positions = convertMap(list,
+ ImConversationReadDO::getUserId, ImConversationReadDO::getMessageId);
+
+ assertEquals(3, positions.size());
+ assertEquals(100L, positions.get(1L));
+ assertEquals(80L, positions.get(2L));
+ assertEquals(50L, positions.get(3L));
+ }
+
+ @Test
+ public void testSelectListByUserIdAndConversations_batch() {
+ // 鐢ㄦ埛 1 鍦ㄩ閬� 10 / 20 / 30 鐨勮浣嶇疆
+ mapper.insert(buildRead(1L, ImConversationTypeEnum.CHANNEL.getType(), 10L, 5L));
+ mapper.insert(buildRead(1L, ImConversationTypeEnum.CHANNEL.getType(), 20L, 8L));
+ mapper.insert(buildRead(1L, ImConversationTypeEnum.CHANNEL.getType(), 30L, 3L));
+
+ List<ImConversationReadDO> list = mapper.selectListByUserIdAndConversations(
+ 1L, ImConversationTypeEnum.CHANNEL.getType(), List.of(10L, 20L));
+
+ assertEquals(2, list.size());
+ }
+
+ private ImConversationReadDO buildRead(Long userId, Integer conversationType, Long conversationId,
+ Long readMessageId) {
+ return ImConversationReadDO.builder()
+ .userId(userId)
+ .conversationType(conversationType)
+ .targetId(conversationId)
+ .messageId(readMessageId)
+ .readTime(LocalDateTime.now())
+ .build();
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapperTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapperTest.java
new file mode 100644
index 0000000..ef7fb54
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapperTest.java
@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.module.im.dal.mysql.friend;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendRequestHandleResultEnum;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link ImFriendRequestMapper} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImFriendRequestMapperTest extends BaseDbUnitTest {
+
+ @Resource
+ private ImFriendRequestMapper mapper;
+
+ // ========== selectMyList ==========
+
+ @Test
+ public void testSelectMyList_bidirectional() {
+ // 鍑嗗锛�1 鏃綔涓� from 鍙堜綔涓� to锛�3 鏄棤鍏崇敤鎴�
+ mapper.insert(buildRequest(1L, 2L));
+ mapper.insert(buildRequest(2L, 1L));
+ mapper.insert(buildRequest(3L, 4L));
+
+ // 璋冪敤锛歝ursor 涓虹┖锛屾媺棣栭〉
+ List<ImFriendRequestDO> list = mapper.selectMyList(1L, null, null, 10);
+
+ // 鏂█锛氬弻鍚� OR 鍛戒腑涓ゆ潯锛屾棤鍏崇敤鎴疯鎺掗櫎
+ assertEquals(2, list.size());
+ list.forEach(r -> assertTrue(r.getFromUserId().equals(1L) || r.getToUserId().equals(1L)));
+ }
+
+ @Test
+ public void testSelectMyList_cursorPaging() {
+ // 鍑嗗锛氫笁鏉� 1 鐩稿叧鐨勭敵璇�
+ ImFriendRequestDO r1 = buildRequest(1L, 2L);
+ ImFriendRequestDO r2 = buildRequest(1L, 3L);
+ ImFriendRequestDO r3 = buildRequest(1L, 4L);
+ mapper.insert(r1);
+ mapper.insert(r2);
+ mapper.insert(r3);
+
+ // 璋冪敤锛歝ursor = r3锛屾媺姣� r3 鏇存棭鐨勪笅涓�椤�
+ ImFriendRequestDO cursor = mapper.selectById(r3.getId());
+ List<ImFriendRequestDO> next = mapper.selectMyList(1L, cursor.getUpdateTime(), cursor.getId(), 10);
+
+ // 鏂█锛氫粎鍚� r1 / r2锛屾寜 id 鍊掑簭
+ assertEquals(2, next.size());
+ assertEquals(r2.getId(), next.get(0).getId());
+ assertEquals(r1.getId(), next.get(1).getId());
+ }
+
+ @Test
+ public void testSelectMyList_limit() {
+ // 鍑嗗锛氭彃鍏� 3 鏉�
+ for (int i = 0; i < 3; i++) {
+ mapper.insert(buildRequest(1L, (long) (10 + i)));
+ }
+
+ // 璋冪敤锛歭imit = 2
+ List<ImFriendRequestDO> list = mapper.selectMyList(1L, null, null, 2);
+
+ // 鏂█锛氭墜鍐� LIMIT 鐪熺敓鏁�
+ assertEquals(2, list.size());
+ }
+
+ private static ImFriendRequestDO buildRequest(Long fromUserId, Long toUserId) {
+ return new ImFriendRequestDO()
+ .setFromUserId(fromUserId).setToUserId(toUserId)
+ .setHandleResult(ImFriendRequestHandleResultEnum.UNHANDLED.getResult());
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImGroupMessageMapperTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImGroupMessageMapperTest.java
new file mode 100644
index 0000000..5dcee93
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImGroupMessageMapperTest.java
@@ -0,0 +1,195 @@
+package cn.iocoder.yudao.module.im.dal.mysql.message;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link ImGroupMessageMapper} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImGroupMessageMapperTest extends BaseDbUnitTest {
+
+ @Resource
+ private ImGroupMessageMapper mapper;
+
+ private static final LocalDateTime FAR_PAST = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
+
+ // ========== selectListByMinId ==========
+
+ @Test
+ public void testSelectListByMinId_filterByReceiverSnapshot() {
+ // 鍑嗗锛氱兢 10 涓夋潯娑堟伅锛屽揩鐓у垎鍒懡涓� / 涓嶅懡涓敤鎴� 1
+ ImGroupMessageDO visible = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L, 2L));
+ mapper.insert(visible);
+ ImGroupMessageDO invisible = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(2L, 3L));
+ mapper.insert(invisible);
+ ImGroupMessageDO selfSend = buildMessage(10L, 1L, ImMessageStatusEnum.NORMAL, List.of(1L, 2L));
+ mapper.insert(selfSend);
+
+ // 璋冪敤锛氱敤鎴� 1 鎷夊彇缇� 10
+ List<ImGroupMessageDO> result = mapper.selectListByMinId(1L, List.of(10L), 0L, FAR_PAST, 100);
+
+ // 鏂█锛氫粎杩斿洖蹇収鍖呭惈鐢ㄦ埛 1 鐨勬秷鎭�
+ assertEquals(2, result.size());
+ assertEquals(visible.getId(), result.get(0).getId());
+ assertEquals(selfSend.getId(), result.get(1).getId());
+ }
+
+ @Test
+ public void testSelectListByMinId_excludeNullAndEmptySnapshot() {
+ // 鍑嗗锛氬揩鐓т负 null / 绌哄瓧绗︿覆鐨勮�佹暟鎹紝涓嶅簲琚换浣曠敤鎴锋媺鍒�
+ ImGroupMessageDO nullSnapshot = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, null);
+ mapper.insert(nullSnapshot);
+ ImGroupMessageDO emptySnapshot = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of());
+ mapper.insert(emptySnapshot);
+
+ List<ImGroupMessageDO> result = mapper.selectListByMinId(1L, List.of(10L), 0L, FAR_PAST, 100);
+
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testSelectListByMinId_onlyReturnsGroupsInIdList() {
+ // 鍑嗗锛氱兢 10 + 缇� 20 鍚勪竴鏉★紝鐢ㄦ埛 1 閮藉湪蹇収鍐�
+ ImGroupMessageDO msg10 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L, 2L));
+ mapper.insert(msg10);
+ ImGroupMessageDO msg20 = buildMessage(20L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L, 2L));
+ mapper.insert(msg20);
+
+ // 璋冪敤锛氬�欓�夌兢鍙惈缇� 10
+ List<ImGroupMessageDO> result = mapper.selectListByMinId(1L, List.of(10L), 0L, FAR_PAST, 100);
+
+ assertEquals(1, result.size());
+ assertEquals(msg10.getId(), result.get(0).getId());
+ }
+
+ @Test
+ public void testSelectListByMinId_includesRecall() {
+ // 鍑嗗锛氭挙鍥炴秷鎭篃瑕佽繑鍥烇紝鐢卞鎴风鎸� status 娓叉煋銆屾娑堟伅宸叉挙鍥炪�嶅崰浣�
+ ImGroupMessageDO normal = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(normal);
+ ImGroupMessageDO recalled = buildMessage(10L, 2L, ImMessageStatusEnum.RECALL, List.of(1L));
+ mapper.insert(recalled);
+
+ List<ImGroupMessageDO> result = mapper.selectListByMinId(1L, List.of(10L), 0L, FAR_PAST, 100);
+
+ assertEquals(2, result.size());
+ }
+
+ @Test
+ public void testSelectListByMinId_sendTimeWindow() {
+ // 鍑嗗锛氫竴鏉″湪绐楀彛鍐咃紝涓�鏉″湪绐楀彛澶�
+ ImGroupMessageDO inWindow = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ inWindow.setSendTime(LocalDateTime.now().minusDays(1));
+ mapper.insert(inWindow);
+ ImGroupMessageDO outWindow = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ outWindow.setSendTime(LocalDateTime.now().minusDays(40));
+ mapper.insert(outWindow);
+
+ List<ImGroupMessageDO> result = mapper.selectListByMinId(1L, List.of(10L), 0L,
+ LocalDateTime.now().minusDays(30), 100);
+
+ assertEquals(1, result.size());
+ assertEquals(inWindow.getId(), result.get(0).getId());
+ }
+
+ @Test
+ public void testSelectListByMinId_sortAscLimit() {
+ // 鍑嗗锛氭彃鍏� 3 鏉″彲瑙佹秷鎭�
+ ImGroupMessageDO m1 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(m1);
+ ImGroupMessageDO m2 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(m2);
+ ImGroupMessageDO m3 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(m3);
+
+ // 璋冪敤锛歴ize=2锛岃繑鍥� id 鏈�灏忕殑 2 鏉�
+ List<ImGroupMessageDO> result = mapper.selectListByMinId(1L, List.of(10L), 0L, FAR_PAST, 2);
+
+ assertEquals(2, result.size());
+ assertTrue(result.get(0).getId() < result.get(1).getId());
+ assertEquals(m1.getId(), result.get(0).getId());
+ assertEquals(m2.getId(), result.get(1).getId());
+ }
+
+ @Test
+ public void testSelectListByMinId_minIdExclusive() {
+ // 鍑嗗锛氭父鏍囦箣鍓嶇殑娑堟伅涓嶈繑鍥�
+ ImGroupMessageDO m1 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(m1);
+ ImGroupMessageDO m2 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(m2);
+
+ List<ImGroupMessageDO> result = mapper.selectListByMinId(1L, List.of(10L), m1.getId(), FAR_PAST, 100);
+
+ assertEquals(1, result.size());
+ assertEquals(m2.getId(), result.get(0).getId());
+ }
+
+ // ========== selectHistoryListByUser ==========
+
+ @Test
+ public void testSelectHistoryListByUser_filterByReceiverSnapshot() {
+ // 鍑嗗锛氱兢 10 涓夋潯锛岀敤鎴� 1 鍦ㄥ墠涓ゆ潯蹇収鍐呫�佺涓夋潯瀹氬悜缁欏埆浜�
+ ImGroupMessageDO m1 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L, 2L));
+ mapper.insert(m1);
+ ImGroupMessageDO m2 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L, 2L));
+ mapper.insert(m2);
+ ImGroupMessageDO directedOther = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(2L, 3L));
+ mapper.insert(directedOther);
+ // 鍒殑缇�
+ ImGroupMessageDO other = buildMessage(20L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(other);
+
+ List<ImGroupMessageDO> result = mapper.selectHistoryListByUser(1L, 10L, null, 100);
+
+ // 鏂█锛氬彧杩斿洖缇� 10 涓敤鎴� 1 鍙鐨勶紝鎸� id 鍊掑簭
+ assertEquals(2, result.size());
+ assertEquals(m2.getId(), result.get(0).getId());
+ assertEquals(m1.getId(), result.get(1).getId());
+ }
+
+ @Test
+ public void testSelectHistoryListByUser_maxIdCursor() {
+ ImGroupMessageDO m1 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(m1);
+ ImGroupMessageDO m2 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(m2);
+ ImGroupMessageDO m3 = buildMessage(10L, 2L, ImMessageStatusEnum.NORMAL, List.of(1L));
+ mapper.insert(m3);
+
+ List<ImGroupMessageDO> result = mapper.selectHistoryListByUser(1L, 10L, m3.getId(), 100);
+
+ // 鏂█锛氬彧杩斿洖 id < m3.id 鐨� m1銆乵2
+ assertEquals(2, result.size());
+ assertTrue(result.stream().allMatch(m -> m.getId() < m3.getId()));
+ }
+
+ // ========== 宸ュ叿鏂规硶 ==========
+
+ private ImGroupMessageDO buildMessage(Long groupId, Long senderId, ImMessageStatusEnum status,
+ List<Long> receiverUserIds) {
+ return ImGroupMessageDO.builder()
+ .clientMessageId("uuid-" + System.nanoTime())
+ .senderId(senderId)
+ .groupId(groupId)
+ .type(0)
+ .content("{\"content\":\"test\"}")
+ .status(status.getStatus())
+ .sendTime(LocalDateTime.now())
+ .receiverUserIds(receiverUserIds)
+ .receiptStatus(ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus())
+ .build();
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapperTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapperTest.java
new file mode 100644
index 0000000..f3b5ee3
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapperTest.java
@@ -0,0 +1,196 @@
+package cn.iocoder.yudao.module.im.dal.mysql.message;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link ImPrivateMessageMapper} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImPrivateMessageMapperTest extends BaseDbUnitTest {
+
+ @Resource
+ private ImPrivateMessageMapper mapper;
+
+ private static final LocalDateTime FAR_PAST = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
+
+ // ========== selectListByMinId ==========
+
+ @Test
+ public void testSelectListByMinId() {
+ // 鍑嗗锛氱敤鎴� 1 鍙戠粰鐢ㄦ埛 2
+ ImPrivateMessageDO msg1 = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg1);
+ // 鐢ㄦ埛 2 鍙戠粰鐢ㄦ埛 1
+ ImPrivateMessageDO msg2 = buildMessage(2L, 1L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg2);
+ // 鐢ㄦ埛 3 鍙戠粰鐢ㄦ埛 4锛堜笉鐩稿叧锛�
+ ImPrivateMessageDO msg3 = buildMessage(3L, 4L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg3);
+
+ // 璋冪敤锛氱敤鎴� 1 浠� id=0 鎷夊彇
+ List<ImPrivateMessageDO> result = mapper.selectListByMinId(1L, 0L, FAR_PAST, 100);
+
+ // 鏂█锛氬彧鍖呭惈涓庣敤鎴� 1 鐩稿叧鐨� 2 鏉�
+ assertEquals(2, result.size());
+ assertTrue(result.stream().allMatch(m ->
+ m.getSenderId().equals(1L) || m.getReceiverId().equals(1L)));
+ }
+
+ @Test
+ public void testSelectListByMinId_withMinId() {
+ // 鍑嗗
+ ImPrivateMessageDO msg1 = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg1);
+ ImPrivateMessageDO msg2 = buildMessage(2L, 1L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg2);
+
+ // 璋冪敤锛氫粠 msg1.id 涔嬪悗鎷夊彇
+ List<ImPrivateMessageDO> result = mapper.selectListByMinId(1L, msg1.getId(), FAR_PAST, 100);
+
+ // 鏂█锛氬彧鏈� msg2
+ assertEquals(1, result.size());
+ assertEquals(msg2.getId(), result.get(0).getId());
+ }
+
+ @Test
+ public void testSelectListByMinId_limitSize() {
+ // 鍑嗗锛氭彃鍏� 3 鏉�
+ mapper.insert(buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL));
+ mapper.insert(buildMessage(2L, 1L, ImMessageStatusEnum.NORMAL));
+ mapper.insert(buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL));
+
+ // 璋冪敤锛歭imit 2
+ List<ImPrivateMessageDO> result = mapper.selectListByMinId(1L, 0L, FAR_PAST, 2);
+
+ // 鏂█
+ assertEquals(2, result.size());
+ }
+
+ @Test
+ public void testSelectListByMinId_sendTimeFilter() {
+ // 鍑嗗锛氫竴鏉¤惤鍦ㄧ獥鍙e唴锛屼竴鏉¤惤鍦ㄧ獥鍙e
+ ImPrivateMessageDO newMsg = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ newMsg.setSendTime(LocalDateTime.now().minusDays(1));
+ mapper.insert(newMsg);
+ ImPrivateMessageDO oldMsg = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ oldMsg.setSendTime(LocalDateTime.now().minusDays(40));
+ mapper.insert(oldMsg);
+
+ // 璋冪敤锛氱獥鍙h捣鐐� = 30 澶╁墠
+ List<ImPrivateMessageDO> result = mapper.selectListByMinId(1L, 0L,
+ LocalDateTime.now().minusDays(30), 100);
+
+ // 鏂█锛氬彧杩斿洖绐楀彛鍐呯殑娑堟伅
+ assertEquals(1, result.size());
+ assertEquals(newMsg.getId(), result.get(0).getId());
+ }
+
+ // ========== selectHistoryList ==========
+
+ @Test
+ public void testSelectHistoryList_basic() {
+ // 鍑嗗锛氱敤鎴� 1 <-> 鐢ㄦ埛 2 鐨勬秷鎭�
+ ImPrivateMessageDO msg1 = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg1);
+ ImPrivateMessageDO msg2 = buildMessage(2L, 1L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg2);
+ // 鐢ㄦ埛 1 <-> 鐢ㄦ埛 3 鐨勬秷鎭紙涓嶇浉鍏筹級
+ ImPrivateMessageDO msg3 = buildMessage(1L, 3L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg3);
+
+ // 璋冪敤
+ List<ImPrivateMessageDO> result = mapper.selectHistoryList(1L, 2L, null, 100);
+
+ // 鏂█锛氬彧鏈変笌鐢ㄦ埛 2 瀵硅瘽鐨� 2 鏉★紝鎸� id 鍊掑簭
+ assertEquals(2, result.size());
+ assertTrue(result.get(0).getId() > result.get(1).getId());
+ }
+
+ @Test
+ public void testSelectHistoryList_includeRecall() {
+ // 鍑嗗
+ ImPrivateMessageDO msg1 = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg1);
+ ImPrivateMessageDO msg2 = buildMessage(1L, 2L, ImMessageStatusEnum.RECALL);
+ mapper.insert(msg2);
+
+ // 璋冪敤
+ List<ImPrivateMessageDO> result = mapper.selectHistoryList(1L, 2L, null, 100);
+
+ // 鏂█锛氭挙鍥炴秷鎭竴骞惰繑鍥�
+ assertEquals(2, result.size());
+ assertEquals(msg2.getId(), result.get(0).getId());
+ assertEquals(msg1.getId(), result.get(1).getId());
+ }
+
+ @Test
+ public void testSelectHistoryList_withMaxId() {
+ // 鍑嗗
+ ImPrivateMessageDO msg1 = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg1);
+ ImPrivateMessageDO msg2 = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg2);
+ ImPrivateMessageDO msg3 = buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL);
+ mapper.insert(msg3);
+
+ // 璋冪敤锛氫粠 msg3 寰�鍓嶆媺
+ List<ImPrivateMessageDO> result = mapper.selectHistoryList(1L, 2L, msg3.getId(), 100);
+
+ // 鏂█锛氬彧鏈� msg1 鍜� msg2
+ assertEquals(2, result.size());
+ assertTrue(result.stream().allMatch(m -> m.getId() < msg3.getId()));
+ }
+
+ @Test
+ public void testSelectHistoryList_limit() {
+ // 鍑嗗
+ mapper.insert(buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL));
+ mapper.insert(buildMessage(2L, 1L, ImMessageStatusEnum.NORMAL));
+ mapper.insert(buildMessage(1L, 2L, ImMessageStatusEnum.NORMAL));
+
+ // 璋冪敤锛歭imit 2
+ List<ImPrivateMessageDO> result = mapper.selectHistoryList(1L, 2L, null, 2);
+
+ // 鏂█
+ assertEquals(2, result.size());
+ }
+
+ @Test
+ public void testSelectHistoryList_bidirectional() {
+ // 鍑嗗锛氶獙璇佸弻鍚戞煡璇�
+ ImPrivateMessageDO msg1 = buildMessage(2L, 1L, ImMessageStatusEnum.NORMAL); // 瀵规柟鍙戠殑
+ mapper.insert(msg1);
+
+ // 璋冪敤锛氫互鐢ㄦ埛 1 鐨勮瑙掓煡
+ List<ImPrivateMessageDO> result = mapper.selectHistoryList(1L, 2L, null, 100);
+
+ // 鏂█锛氳兘鏌ュ埌瀵规柟鍙戞潵鐨勬秷鎭�
+ assertEquals(1, result.size());
+ assertEquals(2L, result.get(0).getSenderId());
+ }
+
+ // ========== 宸ュ叿鏂规硶 ==========
+
+ private ImPrivateMessageDO buildMessage(Long senderId, Long receiverId, ImMessageStatusEnum status) {
+ return ImPrivateMessageDO.builder()
+ .clientMessageId("uuid-" + System.nanoTime())
+ .senderId(senderId)
+ .receiverId(receiverId)
+ .type(0)
+ .content("{\"content\":\"test\"}")
+ .status(status.getStatus())
+ .sendTime(LocalDateTime.now())
+ .build();
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapperTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapperTest.java
new file mode 100644
index 0000000..7c50033
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/dal/mysql/statistics/ImStatisticsManagerMapperTest.java
@@ -0,0 +1,278 @@
+package cn.iocoder.yudao.module.im.dal.mysql.statistics;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMapper;
+import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMemberMapper;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImPrivateMessageMapper;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.sql.DataSource;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link ImStatisticsManagerMapper} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImStatisticsManagerMapperTest extends BaseDbUnitTest {
+
+ private static final LocalDateTime WINDOW_BEGIN = LocalDateTime.of(2026, 1, 1, 0, 0);
+ private static final LocalDateTime WINDOW_END = LocalDateTime.of(2026, 2, 1, 0, 0);
+
+ @Resource
+ private ImStatisticsManagerMapper mapper;
+
+ @Resource
+ private ImPrivateMessageMapper privateMessageMapper;
+ @Resource
+ private ImGroupMessageMapper groupMessageMapper;
+ @Resource
+ private ImGroupMapper groupMapper;
+ @Resource
+ private ImGroupMemberMapper groupMemberMapper;
+ @Resource
+ private DataSource dataSource;
+
+ private JdbcTemplate jdbcTemplate;
+
+ @BeforeEach
+ public void initJdbcTemplate() {
+ jdbcTemplate = new JdbcTemplate(dataSource);
+ }
+
+ // ========== 鐢ㄦ埛 ==========
+
+ @Test
+ public void testSelectTotalUserCount() {
+ // 鍑嗗锛�3 涓湭鍒犻櫎鐢ㄦ埛
+ insertUser(1L, LocalDateTime.now());
+ insertUser(2L, LocalDateTime.now());
+ insertUser(3L, LocalDateTime.now());
+
+ // 璋冪敤 + 鏂█
+ assertEquals(3L, mapper.selectTotalUserCount());
+ }
+
+ @Test
+ public void testSelectNewUserCount_windowFilter() {
+ // 鍑嗗锛�1 涓湪绐楀彛鍐� + 2 涓湪绐楀彛澶�
+ insertUser(1L, WINDOW_BEGIN.plusDays(3));
+ insertUser(2L, WINDOW_BEGIN.minusDays(1));
+ insertUser(3L, WINDOW_END.plusDays(1));
+
+ // 璋冪敤 + 鏂█锛氬彧鍛戒腑绐楀彛鍐�
+ assertEquals(1L, mapper.selectNewUserCount(WINDOW_BEGIN, WINDOW_END));
+ }
+
+ @Test
+ public void testSelectActiveUserCount_distinctAcrossPrivateAndGroup() {
+ // 鍑嗗锛�1 绉佽亰锛�2 缇よ亰锛�3 鍦ㄧ獥鍙e锛�1 鏃㈠彂绉佽亰鍙堝彂缇よ亰锛堝幓閲嶏級
+ privateMessageMapper.insert(buildPrivate(1L, 2L, WINDOW_BEGIN.plusDays(1)));
+ privateMessageMapper.insert(buildPrivate(1L, 2L, WINDOW_BEGIN.plusDays(2)));
+ groupMessageMapper.insert(buildGroupMessage(2L, 100L, WINDOW_BEGIN.plusDays(3)));
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.plusDays(4))); // 鐢ㄦ埛 1 宸茶涓�娆�
+ privateMessageMapper.insert(buildPrivate(3L, 4L, WINDOW_BEGIN.minusDays(1))); // 绐楀彛澶�
+
+ // 璋冪敤 + 鏂█锛氬幓閲嶅悗 = 2
+ assertEquals(2L, mapper.selectActiveUserCount(WINDOW_BEGIN, WINDOW_END));
+ }
+
+ @Test
+ public void testSelectNewUserDailyCount_groupByDay() {
+ // 鍑嗗锛氱 1 澶� 2 涓紱绗� 2 澶� 1 涓紱绐楀彛澶� 1 涓�
+ insertUser(1L, WINDOW_BEGIN.plusDays(1));
+ insertUser(2L, WINDOW_BEGIN.plusDays(1));
+ insertUser(3L, WINDOW_BEGIN.plusDays(2));
+ insertUser(4L, WINDOW_BEGIN.minusDays(1));
+
+ // 璋冪敤
+ List<Map<String, Object>> list = mapper.selectNewUserDailyCount(WINDOW_BEGIN, WINDOW_END);
+
+ // 鏂█锛氳繑鍥炰袱涓垎缁勩�佹�绘暟 = 3
+ assertEquals(2, list.size());
+ long sum = list.stream().mapToLong(m -> ((Number) m.get("count")).longValue()).sum();
+ assertEquals(3L, sum);
+ }
+
+ @Test
+ public void testSelectActiveUserDailyCount_distinctPerDay() {
+ // 鍑嗗锛氬悓涓�澶╅噷鐢ㄦ埛 1 鍦ㄧ鑱婁笌缇よ亰閮藉彂浜嗭紱绗簩澶╃敤鎴� 2 鍙戜簡
+ privateMessageMapper.insert(buildPrivate(1L, 9L, WINDOW_BEGIN.plusDays(1)));
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.plusDays(1)));
+ groupMessageMapper.insert(buildGroupMessage(2L, 100L, WINDOW_BEGIN.plusDays(2)));
+
+ // 璋冪敤
+ List<Map<String, Object>> list = mapper.selectActiveUserDailyCount(WINDOW_BEGIN, WINDOW_END);
+
+ // 鏂█锛氫袱澶╁悎璁� 2 鍚嶆椿璺冪敤鎴凤紙鍚屼竴澶� user 1 鍘婚噸 + 绗簩澶� user 2锛�
+ assertEquals(2, list.size());
+ long sum = list.stream().mapToLong(m -> ((Number) m.get("count")).longValue()).sum();
+ assertEquals(2L, sum);
+ }
+
+ // ========== 缇� ==========
+
+ @Test
+ public void testSelectTotalGroupCount_onlyEnabled() {
+ // 鍑嗗锛�2 涓甯� + 1 涓凡瑙f暎
+ groupMapper.insert(buildGroup(CommonStatusEnum.ENABLE));
+ groupMapper.insert(buildGroup(CommonStatusEnum.ENABLE));
+ groupMapper.insert(buildGroup(CommonStatusEnum.DISABLE));
+
+ // 璋冪敤 + 鏂█
+ assertEquals(2L, mapper.selectTotalGroupCount());
+ }
+
+ @Test
+ public void testSelectNewGroupCount_windowFilter() {
+ // 鍑嗗锛�1 涓獥鍙e唴 + 1 涓獥鍙e
+ groupMapper.insert(buildGroup(CommonStatusEnum.ENABLE));
+ groupMapper.insert(buildGroup(CommonStatusEnum.ENABLE));
+ // 绐楀彛绐勫埌鍙鐩� 1 绉�
+ LocalDateTime narrowBegin = LocalDateTime.now().plusYears(10);
+ LocalDateTime narrowEnd = narrowBegin.plusSeconds(1);
+
+ // 璋冪敤 + 鏂█锛氭瀬绐勭獥鍙d笉鍛戒腑浠讳綍缇�
+ assertEquals(0L, mapper.selectNewGroupCount(narrowBegin, narrowEnd));
+ }
+
+ @Test
+ public void testSelectGroupSizeDistribution_bucketing() {
+ // 鍑嗗锛氫竴涓� 5 浜虹兢銆佷竴涓� 15 浜虹兢
+ Long groupSmall = insertGroupAndMembers(5);
+ Long groupMid = insertGroupAndMembers(15);
+ assertNotNull(groupSmall);
+ assertNotNull(groupMid);
+
+ // 璋冪敤
+ List<Map<String, Object>> dist = mapper.selectGroupSizeDistribution();
+
+ // 鏂█锛氬垎妗跺寘鍚��1-9 浜恒�嶅拰銆�10-49 浜恒��
+ Map<Object, Long> byRange = dist.stream().collect(java.util.stream.Collectors.toMap(
+ m -> m.get("range"), m -> ((Number) m.get("count")).longValue()));
+ assertEquals(1L, byRange.get("1-9 浜�"));
+ assertEquals(1L, byRange.get("10-49 浜�"));
+ }
+
+ // ========== 娑堟伅 ==========
+
+ @Test
+ public void testSelectPrivateMessageCount_windowFilter() {
+ // 鍑嗗锛�1 鍦ㄧ獥鍙e唴 + 1 鍦ㄧ獥鍙e
+ privateMessageMapper.insert(buildPrivate(1L, 2L, WINDOW_BEGIN.plusDays(1)));
+ privateMessageMapper.insert(buildPrivate(1L, 2L, WINDOW_BEGIN.minusDays(1)));
+
+ // 璋冪敤 + 鏂█
+ assertEquals(1L, mapper.selectPrivateMessageCount(WINDOW_BEGIN, WINDOW_END));
+ }
+
+ @Test
+ public void testSelectGroupMessageCount_windowFilter() {
+ // 鍑嗗锛�1 鍦ㄧ獥鍙e唴 + 1 鍦ㄧ獥鍙e
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.plusDays(1)));
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.minusDays(1)));
+
+ // 璋冪敤 + 鏂█
+ assertEquals(1L, mapper.selectGroupMessageCount(WINDOW_BEGIN, WINDOW_END));
+ }
+
+ @Test
+ public void testSelectMessageTypeDistribution_mergePrivateAndGroup() {
+ // 鍑嗗锛氱鑱� type=0 脳1锛岀兢鑱� type=0 脳2銆乼ype=1 脳1
+ privateMessageMapper.insert(buildPrivate(1L, 2L, WINDOW_BEGIN.plusDays(1)).setType(ImContentTypeEnum.TEXT.getType()));
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.plusDays(1)).setType(ImContentTypeEnum.TEXT.getType()));
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.plusDays(1)).setType(ImContentTypeEnum.TEXT.getType()));
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.plusDays(1)).setType(ImContentTypeEnum.IMAGE.getType()));
+
+ // 璋冪敤
+ List<Map<String, Object>> dist = mapper.selectMessageTypeDistribution(WINDOW_BEGIN, WINDOW_END);
+
+ // 鏂█锛歵ype=TEXT(0) 鈫� 3锛泃ype=IMAGE(1) 鈫� 1
+ Map<Object, Long> byType = dist.stream().collect(java.util.stream.Collectors.toMap(
+ m -> ((Number) m.get("type")).intValue(), m -> ((Number) m.get("count")).longValue()));
+ assertEquals(3L, byType.get(ImContentTypeEnum.TEXT.getType()));
+ assertEquals(1L, byType.get(ImContentTypeEnum.IMAGE.getType()));
+ }
+
+ @Test
+ public void testSelectTopSenders_orderByCountDescAndLimit() {
+ // 鍑嗗锛歶ser 1 鍏� 3 鏉★紱user 2 鍏� 2 鏉★紱user 3 鍏� 1 鏉�
+ privateMessageMapper.insert(buildPrivate(1L, 9L, WINDOW_BEGIN.plusDays(1)));
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.plusDays(1)));
+ groupMessageMapper.insert(buildGroupMessage(1L, 100L, WINDOW_BEGIN.plusDays(1)));
+ privateMessageMapper.insert(buildPrivate(2L, 9L, WINDOW_BEGIN.plusDays(1)));
+ groupMessageMapper.insert(buildGroupMessage(2L, 100L, WINDOW_BEGIN.plusDays(1)));
+ privateMessageMapper.insert(buildPrivate(3L, 9L, WINDOW_BEGIN.plusDays(1)));
+
+ // 璋冪敤锛氬彇 TOP 2
+ List<Map<String, Object>> tops = mapper.selectTopSenders(WINDOW_BEGIN, WINDOW_END, 2);
+
+ // 鏂█锛氳繑鍥� 2 鏉★紝鎸夋秷鎭暟鍊掑簭锛寀ser1 > user2
+ assertEquals(2, tops.size());
+ assertEquals(1L, ((Number) tops.get(0).get("userId")).longValue());
+ assertEquals(3L, ((Number) tops.get(0).get("messageCount")).longValue());
+ assertEquals(2L, ((Number) tops.get(1).get("userId")).longValue());
+ assertEquals(2L, ((Number) tops.get(1).get("messageCount")).longValue());
+ }
+
+ // ========== 宸ュ叿鏂规硶 ==========
+
+ private void insertUser(Long id, LocalDateTime createTime) {
+ jdbcTemplate.update(
+ "INSERT INTO system_users (id, username, password, nickname, status, create_time, update_time, deleted, tenant_id) " +
+ "VALUES (?, ?, '', ?, 0, ?, ?, FALSE, 0)",
+ id, "u" + id, "n" + id, createTime, createTime);
+ }
+
+ private static ImPrivateMessageDO buildPrivate(Long senderId, Long receiverId, LocalDateTime sendTime) {
+ return ImPrivateMessageDO.builder()
+ .clientMessageId("uuid-" + System.nanoTime())
+ .senderId(senderId).receiverId(receiverId)
+ .type(ImContentTypeEnum.TEXT.getType())
+ .content("{}")
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(sendTime).build();
+ }
+
+ private static ImGroupMessageDO buildGroupMessage(Long senderId, Long groupId, LocalDateTime sendTime) {
+ return new ImGroupMessageDO()
+ .setClientMessageId("uuid-" + System.nanoTime())
+ .setSenderId(senderId).setGroupId(groupId)
+ .setType(ImContentTypeEnum.TEXT.getType())
+ .setContent("{}")
+ .setStatus(ImMessageStatusEnum.NORMAL.getStatus())
+ .setSendTime(sendTime);
+ }
+
+ private static ImGroupDO buildGroup(CommonStatusEnum status) {
+ return ImGroupDO.builder().name("g" + System.nanoTime()).ownerUserId(1L)
+ .status(status.getStatus()).build();
+ }
+
+ private Long insertGroupAndMembers(int memberCount) {
+ ImGroupDO group = buildGroup(CommonStatusEnum.ENABLE);
+ groupMapper.insert(group);
+ for (int i = 0; i < memberCount; i++) {
+ groupMemberMapper.insert(new ImGroupMemberDO()
+ .setGroupId(group.getId()).setUserId((long) (1000 + i))
+ .setStatus(CommonStatusEnum.ENABLE.getStatus()).setRole(3));
+ }
+ return group.getId();
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImplTest.java
new file mode 100644
index 0000000..b14f4ea
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImplTest.java
@@ -0,0 +1,177 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.item.ImFacePackItemSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO;
+import cn.iocoder.yudao.module.im.dal.mysql.face.ImFacePackItemMapper;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_ITEM_NOT_EXISTS;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_NOT_EXISTS;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link ImFacePackItemServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImFacePackItemServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImFacePackItemServiceImpl service;
+
+ @Mock
+ private ImFacePackItemMapper facePackItemMapper;
+ @Mock
+ private ImFacePackService facePackService;
+
+ // ========== getEnabledItemListByPackIds ==========
+
+ @Test
+ public void testGetEnabledItemListByPackIds_emptyShortReturn() {
+ // 璋冪敤 + 鏂█锛氱┖鍏ュ弬鐩存帴杩斿洖绌哄垪琛紝涓嶆煡 DB
+ assertTrue(service.getEnabledItemListByPackIds(Collections.emptyList()).isEmpty());
+ verify(facePackItemMapper, never()).selectListByPackIdsAndStatus(any(), any());
+ }
+
+ @Test
+ public void testGetEnabledItemListByPackIds_passesEnableStatus() {
+ // 鍑嗗
+ List<Long> packIds = Arrays.asList(1L, 2L);
+ ImFacePackItemDO item = new ImFacePackItemDO();
+ when(facePackItemMapper.selectListByPackIdsAndStatus(packIds, CommonStatusEnum.ENABLE.getStatus()))
+ .thenReturn(Collections.singletonList(item));
+
+ // 璋冪敤 + 鏂█
+ assertEquals(1, service.getEnabledItemListByPackIds(packIds).size());
+ }
+
+ // ========== createFacePackItem ==========
+
+ @Test
+ public void testCreateFacePackItem_success() {
+ // 鍑嗗
+ ImFacePackItemSaveReqVO reqVO = new ImFacePackItemSaveReqVO();
+ reqVO.setPackId(10L).setUrl("a.png").setName("dog").setWidth(100).setHeight(100)
+ .setSort(0).setStatus(CommonStatusEnum.ENABLE.getStatus());
+ when(facePackService.validateFacePackExists(10L)).thenReturn(new ImFacePackDO());
+
+ // 璋冪敤
+ service.createFacePackItem(reqVO);
+
+ // 鏂█
+ ArgumentCaptor<ImFacePackItemDO> captor = ArgumentCaptor.forClass(ImFacePackItemDO.class);
+ verify(facePackItemMapper).insert(captor.capture());
+ assertEquals(10L, captor.getValue().getPackId());
+ assertEquals("a.png", captor.getValue().getUrl());
+ }
+
+ @Test
+ public void testCreateFacePackItem_packNotExists() {
+ // 鍑嗗锛氭墍灞炶〃鎯呭寘涓嶅瓨鍦�
+ ImFacePackItemSaveReqVO reqVO = new ImFacePackItemSaveReqVO();
+ reqVO.setPackId(99L).setUrl("a.png").setWidth(100).setHeight(100).setSort(0)
+ .setStatus(CommonStatusEnum.ENABLE.getStatus());
+ when(facePackService.validateFacePackExists(99L))
+ .thenThrow(new ServiceException(FACE_PACK_NOT_EXISTS.getCode(), FACE_PACK_NOT_EXISTS.getMsg()));
+
+ // 璋冪敤 + 鏂█锛氫笉钀藉簱
+ assertThrows(ServiceException.class, () -> service.createFacePackItem(reqVO));
+ verify(facePackItemMapper, never()).insert(any(ImFacePackItemDO.class));
+ }
+
+ // ========== updateFacePackItem ==========
+
+ @Test
+ public void testUpdateFacePackItem_success() {
+ // 鍑嗗
+ ImFacePackItemSaveReqVO reqVO = new ImFacePackItemSaveReqVO();
+ reqVO.setId(1L).setPackId(10L).setUrl("a.png").setWidth(100).setHeight(100)
+ .setSort(0).setStatus(CommonStatusEnum.ENABLE.getStatus());
+ when(facePackItemMapper.selectById(1L)).thenReturn(new ImFacePackItemDO());
+ when(facePackService.validateFacePackExists(10L)).thenReturn(new ImFacePackDO());
+
+ // 璋冪敤
+ service.updateFacePackItem(reqVO);
+
+ // 鏂█
+ verify(facePackItemMapper).updateById(any(ImFacePackItemDO.class));
+ }
+
+ @Test
+ public void testUpdateFacePackItem_itemNotExists() {
+ ImFacePackItemSaveReqVO reqVO = new ImFacePackItemSaveReqVO();
+ reqVO.setId(99L).setPackId(10L).setUrl("a.png").setWidth(100).setHeight(100).setSort(0)
+ .setStatus(CommonStatusEnum.ENABLE.getStatus());
+ when(facePackItemMapper.selectById(99L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.updateFacePackItem(reqVO));
+ assertEquals(FACE_PACK_ITEM_NOT_EXISTS.getCode(), exception.getCode());
+ verify(facePackItemMapper, never()).updateById(any(ImFacePackItemDO.class));
+ }
+
+ // ========== deleteFacePackItem ==========
+
+ @Test
+ public void testDeleteFacePackItem_success() {
+ when(facePackItemMapper.selectById(1L)).thenReturn(new ImFacePackItemDO());
+
+ service.deleteFacePackItem(1L);
+
+ verify(facePackItemMapper).deleteById(1L);
+ }
+
+ @Test
+ public void testDeleteFacePackItem_notExists() {
+ when(facePackItemMapper.selectById(99L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.deleteFacePackItem(99L));
+ assertEquals(FACE_PACK_ITEM_NOT_EXISTS.getCode(), exception.getCode());
+ verify(facePackItemMapper, never()).deleteById(anyLong());
+ }
+
+ @Test
+ public void testDeleteFacePackItemList_emptySkip() {
+ service.deleteFacePackItemList(Collections.emptyList());
+
+ verify(facePackItemMapper, never()).deleteByIds(any());
+ }
+
+ @Test
+ public void testDeleteFacePackItemList_success() {
+ List<Long> ids = Arrays.asList(1L, 2L);
+ when(facePackItemMapper.deleteByIds(ids)).thenReturn(2);
+
+ service.deleteFacePackItemList(ids);
+
+ verify(facePackItemMapper).deleteByIds(ids);
+ }
+
+ @Test
+ public void testDeleteFacePackItemList_ignoreMissingIds() {
+ List<Long> ids = Arrays.asList(1L, 2L);
+ when(facePackItemMapper.deleteByIds(ids)).thenReturn(1);
+
+ service.deleteFacePackItemList(ids);
+
+ verify(facePackItemMapper).deleteByIds(ids);
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImplTest.java
new file mode 100644
index 0000000..1b7c8ab
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImplTest.java
@@ -0,0 +1,177 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.pack.ImFacePackSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO;
+import cn.iocoder.yudao.module.im.dal.mysql.face.ImFacePackMapper;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_HAS_ITEMS;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_NOT_EXISTS;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link ImFacePackServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImFacePackServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImFacePackServiceImpl service;
+
+ @Mock
+ private ImFacePackMapper facePackMapper;
+ @Mock
+ private ImFacePackItemService facePackItemService;
+
+ // ========== validateFacePackExists ==========
+
+ @Test
+ public void testValidateFacePackExists_notFound() {
+ when(facePackMapper.selectById(1L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.validateFacePackExists(1L));
+ assertEquals(FACE_PACK_NOT_EXISTS.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testValidateFacePackExists_returnsDo() {
+ ImFacePackDO pack = ImFacePackDO.builder().id(1L).name("鐚富瀛�").build();
+ when(facePackMapper.selectById(1L)).thenReturn(pack);
+
+ assertEquals(pack, service.validateFacePackExists(1L));
+ }
+
+ // ========== createFacePack ==========
+
+ @Test
+ public void testCreateFacePack_insert() {
+ // 鍑嗗
+ ImFacePackSaveReqVO reqVO = new ImFacePackSaveReqVO();
+ reqVO.setName("鐚富瀛�").setIcon("icon.png").setSort(0).setStatus(CommonStatusEnum.ENABLE.getStatus());
+
+ // 璋冪敤
+ service.createFacePack(reqVO);
+
+ // 鏂█锛歮apper.insert 琚皟鐢ㄤ竴娆�
+ ArgumentCaptor<ImFacePackDO> captor = ArgumentCaptor.forClass(ImFacePackDO.class);
+ verify(facePackMapper).insert(captor.capture());
+ assertEquals("鐚富瀛�", captor.getValue().getName());
+ assertEquals(CommonStatusEnum.ENABLE.getStatus(), captor.getValue().getStatus());
+ }
+
+ // ========== updateFacePack ==========
+
+ @Test
+ public void testUpdateFacePack_success() {
+ // 鍑嗗锛氬瓨鍦�
+ ImFacePackSaveReqVO reqVO = new ImFacePackSaveReqVO();
+ reqVO.setId(1L).setName("鏂板悕").setSort(1).setStatus(CommonStatusEnum.ENABLE.getStatus());
+ when(facePackMapper.selectById(1L)).thenReturn(ImFacePackDO.builder().id(1L).build());
+
+ // 璋冪敤
+ service.updateFacePack(reqVO);
+
+ // 鏂█
+ ArgumentCaptor<ImFacePackDO> captor = ArgumentCaptor.forClass(ImFacePackDO.class);
+ verify(facePackMapper).updateById(captor.capture());
+ assertEquals(1L, captor.getValue().getId());
+ assertEquals("鏂板悕", captor.getValue().getName());
+ }
+
+ @Test
+ public void testUpdateFacePack_notExists() {
+ // 鍑嗗
+ ImFacePackSaveReqVO reqVO = new ImFacePackSaveReqVO();
+ reqVO.setId(99L).setName("x").setSort(0).setStatus(CommonStatusEnum.ENABLE.getStatus());
+ when(facePackMapper.selectById(99L)).thenReturn(null);
+
+ // 璋冪敤 + 鏂█
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.updateFacePack(reqVO));
+ assertEquals(FACE_PACK_NOT_EXISTS.getCode(), exception.getCode());
+ verify(facePackMapper, never()).updateById(any(ImFacePackDO.class));
+ }
+
+ // ========== deleteFacePack ==========
+
+ @Test
+ public void testDeleteFacePack_success() {
+ when(facePackMapper.selectById(1L)).thenReturn(ImFacePackDO.builder().id(1L).build());
+ when(facePackItemService.getFacePackItemCount(1L)).thenReturn(0L);
+
+ service.deleteFacePack(1L);
+
+ verify(facePackMapper).deleteById(1L);
+ }
+
+ @Test
+ public void testDeleteFacePack_hasItems() {
+ // 鍑嗗锛氬寘涓嬩粛鏈夎〃鎯�
+ when(facePackMapper.selectById(1L)).thenReturn(ImFacePackDO.builder().id(1L).build());
+ when(facePackItemService.getFacePackItemCount(1L)).thenReturn(3L);
+
+ ServiceException exception = assertThrows(ServiceException.class, () -> service.deleteFacePack(1L));
+ assertEquals(FACE_PACK_HAS_ITEMS.getCode(), exception.getCode());
+ verify(facePackMapper, never()).deleteById(anyLong());
+ }
+
+ @Test
+ public void testDeleteFacePack_notExists() {
+ when(facePackMapper.selectById(99L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class, () -> service.deleteFacePack(99L));
+ assertEquals(FACE_PACK_NOT_EXISTS.getCode(), exception.getCode());
+ }
+
+ // ========== deleteFacePackList ==========
+
+ @Test
+ public void testDeleteFacePackList_emptySkip() {
+ // 璋冪敤锛氱┖ ids 鍒楄〃鐩存帴杩斿洖锛屼笉鏌ヨ銆佷笉鍒犻櫎
+ service.deleteFacePackList(Collections.emptyList());
+
+ verify(facePackItemService, never()).getFacePackItemCount(any(java.util.Collection.class));
+ verify(facePackMapper, never()).deleteByIds(any());
+ }
+
+ @Test
+ public void testDeleteFacePackList_anyHasItemsRejectAll() {
+ // 鍑嗗锛氭壒閲忎腑瀛樺湪琛ㄦ儏
+ when(facePackItemService.getFacePackItemCount(Arrays.asList(1L, 2L))).thenReturn(1L);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.deleteFacePackList(Arrays.asList(1L, 2L)));
+ assertEquals(FACE_PACK_HAS_ITEMS.getCode(), exception.getCode());
+ verify(facePackMapper, never()).deleteByIds(any());
+ }
+
+ @Test
+ public void testDeleteFacePackList_success() {
+ // 鍑嗗
+ when(facePackItemService.getFacePackItemCount(Arrays.asList(1L, 2L))).thenReturn(0L);
+
+ // 璋冪敤
+ service.deleteFacePackList(Arrays.asList(1L, 2L));
+
+ // 鏂█
+ verify(facePackMapper).deleteByIds(Arrays.asList(1L, 2L));
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImplTest.java
new file mode 100644
index 0000000..94ca142
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImplTest.java
@@ -0,0 +1,164 @@
+package cn.iocoder.yudao.module.im.service.face;
+
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO;
+import cn.iocoder.yudao.module.im.dal.mysql.face.ImFaceUserItemMapper;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.springframework.dao.DuplicateKeyException;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_DUPLICATED;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_MAX_LIMIT;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_NOT_EXISTS;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_NOT_OWN;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link ImFaceUserItemServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImFaceUserItemServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImFaceUserItemServiceImpl service;
+
+ @Mock
+ private ImFaceUserItemMapper faceUserItemMapper;
+ @Spy
+ private ImProperties imProperties = new ImProperties();
+
+ // ========== createFaceUserItem ==========
+
+ @Test
+ public void testCreateFaceUserItem_success() {
+ // 鍑嗗
+ ImFaceUserItemSaveReqVO reqVO = new ImFaceUserItemSaveReqVO();
+ reqVO.setUrl("a.png").setName("doge").setWidth(100).setHeight(100);
+ when(faceUserItemMapper.selectByUserIdAndUrl(1L, "a.png")).thenReturn(null);
+ when(faceUserItemMapper.selectCountByUserId(1L)).thenReturn(10L);
+
+ // 璋冪敤
+ service.createFaceUserItem(1L, reqVO);
+
+ // 鏂█锛氬啓鍏ョ敤鎴风紪鍙�
+ ArgumentCaptor<ImFaceUserItemDO> captor = ArgumentCaptor.forClass(ImFaceUserItemDO.class);
+ verify(faceUserItemMapper).insert(captor.capture());
+ assertEquals(1L, captor.getValue().getUserId());
+ assertEquals("a.png", captor.getValue().getUrl());
+ }
+
+ @Test
+ public void testCreateFaceUserItem_duplicateUrl() {
+ // 鍑嗗锛氱浉鍚� (userId, url) 宸插瓨鍦�
+ ImFaceUserItemSaveReqVO reqVO = new ImFaceUserItemSaveReqVO();
+ reqVO.setUrl("a.png").setWidth(100).setHeight(100);
+ when(faceUserItemMapper.selectByUserIdAndUrl(1L, "a.png"))
+ .thenReturn(new ImFaceUserItemDO().setUserId(1L));
+
+ // 璋冪敤 + 鏂█锛氭姏閲嶅寮傚父锛屼笉钀藉簱
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.createFaceUserItem(1L, reqVO));
+ assertEquals(FACE_USER_ITEM_DUPLICATED.getCode(), exception.getCode());
+ verify(faceUserItemMapper, never()).insert(any(ImFaceUserItemDO.class));
+ }
+
+ @Test
+ public void testCreateFaceUserItem_maxLimit() {
+ // 鍑嗗锛氫釜浜鸿〃鎯呭凡杈句笂闄�
+ ImFaceUserItemSaveReqVO reqVO = new ImFaceUserItemSaveReqVO();
+ reqVO.setUrl("a.png").setWidth(100).setHeight(100);
+ imProperties.getFace().setUserItemMaxCount(20);
+ when(faceUserItemMapper.selectByUserIdAndUrl(1L, "a.png")).thenReturn(null);
+ when(faceUserItemMapper.selectCountByUserId(1L)).thenReturn(20L);
+
+ // 璋冪敤 + 鏂█锛氭姏涓婇檺寮傚父锛屼笉钀藉簱
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.createFaceUserItem(1L, reqVO));
+ assertEquals(FACE_USER_ITEM_MAX_LIMIT.getCode(), exception.getCode());
+ verify(faceUserItemMapper, never()).insert(any(ImFaceUserItemDO.class));
+ }
+
+ @Test
+ public void testCreateFaceUserItem_duplicateKey() {
+ // 鍑嗗锛氬苟鍙戞彃鍏ヨЕ鍙戝敮涓�绾︽潫
+ ImFaceUserItemSaveReqVO reqVO = new ImFaceUserItemSaveReqVO();
+ reqVO.setUrl("a.png").setWidth(100).setHeight(100);
+ when(faceUserItemMapper.selectByUserIdAndUrl(1L, "a.png")).thenReturn(null);
+ when(faceUserItemMapper.selectCountByUserId(1L)).thenReturn(10L);
+ when(faceUserItemMapper.insert(any(ImFaceUserItemDO.class))).thenThrow(new DuplicateKeyException("duplicate"));
+
+ // 璋冪敤 + 鏂█锛氭暟鎹簱鍞竴绾︽潫鍐茬獊杞笟鍔¢噸澶嶅紓甯�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.createFaceUserItem(1L, reqVO));
+ assertEquals(FACE_USER_ITEM_DUPLICATED.getCode(), exception.getCode());
+ }
+
+ // ========== deleteFaceUserItem锛堢敤鎴风锛� ==========
+
+ @Test
+ public void testDeleteFaceUserItem_userOwn_success() {
+ // 鍑嗗锛氬綊灞炲綋鍓嶇敤鎴�
+ when(faceUserItemMapper.selectById(10L)).thenReturn(new ImFaceUserItemDO().setUserId(1L));
+
+ // 璋冪敤
+ service.deleteFaceUserItem(1L, 10L);
+
+ // 鏂█
+ verify(faceUserItemMapper).deleteById(10L);
+ }
+
+ @Test
+ public void testDeleteFaceUserItem_notExists() {
+ when(faceUserItemMapper.selectById(99L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.deleteFaceUserItem(1L, 99L));
+ assertEquals(FACE_USER_ITEM_NOT_EXISTS.getCode(), exception.getCode());
+ verify(faceUserItemMapper, never()).deleteById(anyLong());
+ }
+
+ @Test
+ public void testDeleteFaceUserItem_notOwn() {
+ // 鍑嗗锛氳〃鎯呭綊灞� user 2锛屼絾 user 1 鏉ュ垹
+ when(faceUserItemMapper.selectById(10L)).thenReturn(new ImFaceUserItemDO().setUserId(2L));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.deleteFaceUserItem(1L, 10L));
+ assertEquals(FACE_USER_ITEM_NOT_OWN.getCode(), exception.getCode());
+ verify(faceUserItemMapper, never()).deleteById(anyLong());
+ }
+
+ // ========== deleteFaceUserItem锛堢鐞嗗悗鍙帮級 ==========
+
+ @Test
+ public void testDeleteFaceUserItemAdmin_success() {
+ when(faceUserItemMapper.selectById(10L)).thenReturn(new ImFaceUserItemDO().setUserId(2L));
+
+ service.deleteFaceUserItem(10L);
+
+ verify(faceUserItemMapper).deleteById(10L);
+ }
+
+ @Test
+ public void testDeleteFaceUserItemAdmin_notExists() {
+ when(faceUserItemMapper.selectById(99L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> service.deleteFaceUserItem(99L));
+ assertEquals(FACE_USER_ITEM_NOT_EXISTS.getCode(), exception.getCode());
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImplTest.java
new file mode 100644
index 0000000..2697e58
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImplTest.java
@@ -0,0 +1,355 @@
+package cn.iocoder.yudao.module.im.service.friend;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.request.ImFriendRequestApplyReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendRequestDO;
+import cn.iocoder.yudao.module.im.dal.mysql.friend.ImFriendRequestMapper;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendRequestHandleResultEnum;
+import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.dao.DuplicateKeyException;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link ImFriendRequestServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImFriendRequestServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImFriendRequestServiceImpl friendRequestService;
+
+ @Mock
+ private ImFriendRequestMapper friendRequestMapper;
+ @Mock
+ private ImFriendService friendService;
+ @Mock
+ private ImWebSocketService websocketService;
+ @Mock
+ private ImProperties imProperties;
+ @Mock
+ private AdminUserApi adminUserApi;
+
+ // ========== applyFriend ==========
+
+ @Test
+ public void testApplyFriend_addSelf() {
+ // 鍑嗗锛氬彂璧蜂汉 = 鎺ユ敹浜�
+ ImFriendRequestApplyReqVO reqVO = new ImFriendRequestApplyReqVO();
+ reqVO.setToUserId(1L);
+
+ // 璋冪敤 + 鏂█
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.applyFriend(1L, reqVO));
+ assertEquals(FRIEND_ADD_SELF.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testApplyFriend_alreadyFriend() {
+ // 鍑嗗
+ ImFriendRequestApplyReqVO reqVO = new ImFriendRequestApplyReqVO();
+ reqVO.setToUserId(2L);
+ when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.FRIEND.getState());
+
+ // 璋冪敤 + 鏂█
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.applyFriend(1L, reqVO));
+ assertEquals(FRIEND_REQUEST_ALREADY_FRIEND.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testApplyFriend_blockedByPeer() {
+ // 鍑嗗
+ ImFriendRequestApplyReqVO reqVO = new ImFriendRequestApplyReqVO();
+ reqVO.setToUserId(2L);
+ when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.BLOCKED.getState());
+
+ // 璋冪敤 + 鏂█
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.applyFriend(1L, reqVO));
+ assertEquals(FRIEND_REQUEST_BLOCKED_BY_PEER.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testApplyFriend_silentReAdd() {
+ // 鍑嗗锛氬崟鍚戝ソ鍙� 鈥� 鎴戝凡鍒犻櫎锛屼絾瀵规柟浠嶆妸鎴戝綋濂藉弸
+ ImFriendRequestApplyReqVO reqVO = new ImFriendRequestApplyReqVO();
+ reqVO.setToUserId(2L).setDisplayName("鑰佸紶").setAddSource(1);
+ when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.NONE.getState());
+ ImFriendDO peerFriend = ImFriendDO.builder().userId(2L).friendUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(friendService.getFriend(2L, 1L)).thenReturn(peerFriend);
+
+ // 璋冪敤
+ ImFriendRequestDO result = friendRequestService.applyFriend(1L, reqVO);
+
+ // 鏂█锛氳蛋闈欓粯閲嶆柊鍔犲ソ鍙嬶紝涓嶈惤鐢宠璁板綍
+ assertNull(result);
+ verify(friendService).silentReAddFriend(eq(1L), eq(2L), eq("鑰佸紶"), eq(1));
+ verify(friendRequestMapper, never()).insert(any(ImFriendRequestDO.class));
+ verify(websocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testApplyFriend_blockedByPeerWhenMyselfDeleted() {
+ // 鍑嗗锛氭垜渚у凡鍒犻櫎锛坓etFriendState=NONE锛夛紝瀵规柟浠嶆妸鎴戝綋濂藉弸浣嗗凡鎷夐粦
+ ImFriendRequestApplyReqVO reqVO = new ImFriendRequestApplyReqVO();
+ reqVO.setToUserId(2L).setDisplayName("鑰佸紶").setAddSource(1);
+ when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.NONE.getState());
+ ImFriendDO peerFriend = ImFriendDO.builder().userId(2L).friendUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).blocked(true).build();
+ when(friendService.getFriend(2L, 1L)).thenReturn(peerFriend);
+
+ // 璋冪敤 + 鏂█锛氬繀椤绘嫆鎺夛紝涓嶈兘璧� silentReAddFriend 缁曡繃鎷夐粦
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.applyFriend(1L, reqVO));
+ assertEquals(FRIEND_REQUEST_BLOCKED_BY_PEER.getCode(), exception.getCode());
+ verify(friendService, never()).silentReAddFriend(anyLong(), anyLong(), anyString(), anyInt());
+ verify(friendRequestMapper, never()).insert(any(ImFriendRequestDO.class));
+ }
+
+ @Test
+ public void testApplyFriend_insertNew() {
+ // 鍑嗗锛氬弻鏂归兘鏃犲叧绯伙紝涓旀棤鍘嗗彶鐢宠
+ ImFriendRequestApplyReqVO reqVO = new ImFriendRequestApplyReqVO();
+ reqVO.setToUserId(2L).setApplyContent("鍔犱釜濂藉弸").setDisplayName("鑰佸紶").setAddSource(1);
+ when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.NONE.getState());
+ when(friendService.getFriend(2L, 1L)).thenReturn(null);
+ when(friendRequestMapper.selectByFromUserIdAndToUserId(1L, 2L)).thenReturn(null);
+ when(adminUserApi.getUser(1L)).thenReturn(new AdminUserRespDTO().setNickname("寮犱笁").setAvatar("a.png"));
+ when(imProperties.getFriend()).thenReturn(new ImProperties.Friend());
+
+ // 璋冪敤
+ ImFriendRequestDO result = friendRequestService.applyFriend(1L, reqVO);
+
+ // 鏂█锛氳惤鏂扮敵璇疯褰�
+ ArgumentCaptor<ImFriendRequestDO> captor = ArgumentCaptor.forClass(ImFriendRequestDO.class);
+ verify(friendRequestMapper).insert(captor.capture());
+ ImFriendRequestDO saved = captor.getValue();
+ assertEquals(1L, saved.getFromUserId());
+ assertEquals(2L, saved.getToUserId());
+ assertEquals("鍔犱釜濂藉弸", saved.getApplyContent());
+ assertEquals(ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), saved.getHandleResult());
+ assertSame(saved, result);
+ // 鏂█锛氭帹閫佺粰鎺ユ敹鏂�
+ verify(websocketService).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testApplyFriend_reuseOldRequest() {
+ // 鍑嗗锛氬弻鏂归兘鏃犲叧绯伙紝浣嗗瓨鍦ㄥ巻鍙茬敵璇� 鈥� 璧� reset 澶嶇敤
+ ImFriendRequestApplyReqVO reqVO = new ImFriendRequestApplyReqVO();
+ reqVO.setToUserId(2L).setApplyContent("鍐嶆潵涓�娆�").setDisplayName("鑰佸紶").setAddSource(2);
+ when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.NONE.getState());
+ when(friendService.getFriend(2L, 1L)).thenReturn(null);
+ ImFriendRequestDO old = new ImFriendRequestDO().setId(100L).setFromUserId(1L).setToUserId(2L)
+ .setHandleResult(ImFriendRequestHandleResultEnum.REFUSED.getResult())
+ .setHandleContent("鏃ф嫆缁�").setApplyContent("鏃у唴瀹�");
+ when(friendRequestMapper.selectByFromUserIdAndToUserId(1L, 2L)).thenReturn(old);
+ when(adminUserApi.getUser(1L)).thenReturn(null);
+ when(imProperties.getFriend()).thenReturn(new ImProperties.Friend());
+
+ // 璋冪敤
+ ImFriendRequestDO result = friendRequestService.applyFriend(1L, reqVO);
+
+ // 鏂█锛氬鐢ㄦ棫璁板綍锛屾湭瑙﹀彂 insert
+ verify(friendRequestMapper).updateByIdReset(eq(100L), eq("鍐嶆潵涓�娆�"), eq("鑰佸紶"), eq(2),
+ any(java.time.LocalDateTime.class));
+ verify(friendRequestMapper, never()).insert(any(ImFriendRequestDO.class));
+ assertEquals(100L, result.getId());
+ assertEquals("鍐嶆潵涓�娆�", result.getApplyContent());
+ assertEquals(ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), result.getHandleResult());
+ assertNull(result.getHandleContent());
+ assertNull(result.getHandleTime());
+ }
+
+ @Test
+ public void testApplyFriend_insertDuplicateKey_reuseOldRequest() {
+ // 鍑嗗锛氶娆℃煡璇笉瀛樺湪锛屾彃鍏ユ椂鍛戒腑鍞竴閿紝鍥炴煡鍒板苟鍙戝啓鍏ョ殑鏃х敵璇�
+ ImFriendRequestApplyReqVO reqVO = new ImFriendRequestApplyReqVO();
+ reqVO.setToUserId(2L).setApplyContent("骞跺彂鐢宠").setDisplayName("鑰佸紶").setAddSource(2);
+ when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.NONE.getState());
+ when(friendService.getFriend(2L, 1L)).thenReturn(null);
+ ImFriendRequestDO old = new ImFriendRequestDO().setId(100L).setFromUserId(1L).setToUserId(2L)
+ .setHandleResult(ImFriendRequestHandleResultEnum.REFUSED.getResult());
+ when(friendRequestMapper.selectByFromUserIdAndToUserId(1L, 2L)).thenReturn(null, old);
+ when(friendRequestMapper.insert(any(ImFriendRequestDO.class))).thenThrow(new DuplicateKeyException("dup"));
+ when(adminUserApi.getUser(1L)).thenReturn(null);
+ when(imProperties.getFriend()).thenReturn(new ImProperties.Friend());
+
+ // 璋冪敤
+ ImFriendRequestDO result = friendRequestService.applyFriend(1L, reqVO);
+
+ // 鏂█锛氬鐢ㄥ苟閲嶇疆鏃х敵璇凤紝涓嶅悜涓婃姏鏁版嵁搴撳紓甯�
+ verify(friendRequestMapper).updateByIdReset(eq(100L), eq("骞跺彂鐢宠"), eq("鑰佸紶"), eq(2),
+ any(LocalDateTime.class));
+ assertEquals(100L, result.getId());
+ assertEquals(ImFriendRequestHandleResultEnum.UNHANDLED.getResult(), result.getHandleResult());
+ verify(websocketService).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any());
+ }
+
+ // ========== agreeFriendRequest ==========
+
+ @Test
+ public void testAgreeFriendRequest_success() {
+ // 鍑嗗
+ ImFriendRequestDO request = new ImFriendRequestDO().setId(100L).setFromUserId(1L).setToUserId(2L)
+ .setHandleResult(ImFriendRequestHandleResultEnum.UNHANDLED.getResult());
+ when(friendRequestMapper.selectById(100L)).thenReturn(request);
+ when(friendRequestMapper.updateByIdAndHandleResult(eq(100L),
+ eq(ImFriendRequestHandleResultEnum.UNHANDLED.getResult()), any(ImFriendRequestDO.class))).thenReturn(1);
+
+ // 璋冪敤
+ friendRequestService.agreeFriendRequest(2L, 100L);
+
+ // 鏂█锛氬弻鍚戝缓绔嬪ソ鍙� + 鎺� APPROVED 缁欏彂璧锋柟
+ verify(adminUserApi, never()).validateUserList(any());
+ verify(friendService).becomeFriends(request);
+ verify(websocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testAgreeFriendRequest_notExists() {
+ // 鍑嗗锛氱敵璇蜂笉瀛樺湪
+ when(friendRequestMapper.selectById(100L)).thenReturn(null);
+
+ // 璋冪敤 + 鏂█
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.agreeFriendRequest(2L, 100L));
+ assertEquals(FRIEND_REQUEST_NOT_EXISTS.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testAgreeFriendRequest_notToMe() {
+ // 鍑嗗锛氭搷浣滀汉涓嶆槸鎺ユ敹鏂�
+ ImFriendRequestDO request = new ImFriendRequestDO().setId(100L).setFromUserId(1L).setToUserId(2L)
+ .setHandleResult(ImFriendRequestHandleResultEnum.UNHANDLED.getResult());
+ when(friendRequestMapper.selectById(100L)).thenReturn(request);
+
+ // 璋冪敤 + 鏂█锛�3L 涓嶆槸鎺ユ敹鏂� 2L
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.agreeFriendRequest(3L, 100L));
+ assertEquals(FRIEND_REQUEST_NOT_TO_ME.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testAgreeFriendRequest_alreadyHandled() {
+ // 鍑嗗锛氱敵璇峰凡琚鐞�
+ ImFriendRequestDO request = new ImFriendRequestDO().setId(100L).setFromUserId(1L).setToUserId(2L)
+ .setHandleResult(ImFriendRequestHandleResultEnum.AGREED.getResult());
+ when(friendRequestMapper.selectById(100L)).thenReturn(request);
+
+ // 璋冪敤 + 鏂█
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.agreeFriendRequest(2L, 100L));
+ assertEquals(FRIEND_REQUEST_HANDLED.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testAgreeFriendRequest_concurrentCasFail() {
+ // 鍑嗗锛歠ail-fast 鏍¢獙閫氳繃锛屼絾涔愯閿� CAS 琚苟鍙戞姠鍏�
+ ImFriendRequestDO request = new ImFriendRequestDO().setId(100L).setFromUserId(1L).setToUserId(2L)
+ .setHandleResult(ImFriendRequestHandleResultEnum.UNHANDLED.getResult());
+ when(friendRequestMapper.selectById(100L)).thenReturn(request);
+ when(friendRequestMapper.updateByIdAndHandleResult(anyLong(), anyInt(), any(ImFriendRequestDO.class))).thenReturn(0);
+
+ // 璋冪敤 + 鏂█锛氳繑鍥� FRIEND_REQUEST_HANDLED
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.agreeFriendRequest(2L, 100L));
+ assertEquals(FRIEND_REQUEST_HANDLED.getCode(), exception.getCode());
+ verify(friendService, never()).becomeFriends(any(ImFriendRequestDO.class));
+ }
+
+ // ========== refuseFriendRequest ==========
+
+ @Test
+ public void testRefuseFriendRequest_success() {
+ // 鍑嗗
+ ImFriendRequestDO request = new ImFriendRequestDO().setId(100L).setFromUserId(1L).setToUserId(2L)
+ .setHandleResult(ImFriendRequestHandleResultEnum.UNHANDLED.getResult());
+ when(friendRequestMapper.selectById(100L)).thenReturn(request);
+ when(friendRequestMapper.updateByIdAndHandleResult(eq(100L),
+ eq(ImFriendRequestHandleResultEnum.UNHANDLED.getResult()), any(ImFriendRequestDO.class))).thenReturn(1);
+
+ // 璋冪敤
+ friendRequestService.refuseFriendRequest(2L, 100L, "涓嶈璇�");
+
+ // 鏂█锛歨andleResult / handleContent 鍐欏叆锛涙帹 REJECTED 缁欏彂璧锋柟
+ ArgumentCaptor<ImFriendRequestDO> captor = ArgumentCaptor.forClass(ImFriendRequestDO.class);
+ verify(friendRequestMapper).updateByIdAndHandleResult(eq(100L),
+ eq(ImFriendRequestHandleResultEnum.UNHANDLED.getResult()), captor.capture());
+ assertEquals(ImFriendRequestHandleResultEnum.REFUSED.getResult(), captor.getValue().getHandleResult());
+ assertEquals("涓嶈璇�", captor.getValue().getHandleContent());
+ verify(websocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testRefuseFriendRequest_concurrentCasFail() {
+ // 鍑嗗锛欳AS 澶辫触
+ ImFriendRequestDO request = new ImFriendRequestDO().setId(100L).setFromUserId(1L).setToUserId(2L)
+ .setHandleResult(ImFriendRequestHandleResultEnum.UNHANDLED.getResult());
+ when(friendRequestMapper.selectById(100L)).thenReturn(request);
+ when(friendRequestMapper.updateByIdAndHandleResult(anyLong(), anyInt(), any(ImFriendRequestDO.class))).thenReturn(0);
+
+ // 璋冪敤 + 鏂█锛氭姏 HANDLED锛屼笖涓嶆帹 REJECTED
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendRequestService.refuseFriendRequest(2L, 100L, "x"));
+ assertEquals(FRIEND_REQUEST_HANDLED.getCode(), exception.getCode());
+ verify(websocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ // ========== getMyFriendRequestList ==========
+
+ @Test
+ public void testGetMyFriendRequestList_delegate() {
+ // 鍑嗗锛歮apper 杩斿洖 mock 鏁版嵁
+ LocalDateTime updateTime = LocalDateTime.now();
+ ImFriendRequestDO cursor = new ImFriendRequestDO();
+ cursor.setId(99L);
+ cursor.setUpdateTime(updateTime);
+ ImFriendRequestDO one = new ImFriendRequestDO();
+ one.setId(1L);
+ when(friendRequestMapper.selectById(99L)).thenReturn(cursor);
+ when(friendRequestMapper.selectMyList(1L, updateTime, 99L, 20))
+ .thenReturn(java.util.Collections.singletonList(one));
+
+ // 璋冪敤 + 鏂█锛歝ursor 鐢� Service 鏌ヨ鍚庝紶缁� Mapper
+ assertEquals(1, friendRequestService.getMyFriendRequestList(1L, 99L, 20).size());
+ verify(friendRequestMapper).selectMyList(1L, updateTime, 99L, 20);
+ }
+
+ @Test
+ public void testGetMyFriendRequestList_cursorNotExists() {
+ // 鍑嗗锛歝ursor 涓嶅瓨鍦�
+ when(friendRequestMapper.selectById(99L)).thenReturn(null);
+
+ // 璋冪敤 + 鏂█锛氳繑鍥炵┖鍒楄〃
+ assertTrue(friendRequestService.getMyFriendRequestList(1L, 99L, 20).isEmpty());
+ verify(friendRequestMapper, never()).selectMyList(anyLong(), any(), anyLong(), anyInt());
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImplTest.java
new file mode 100644
index 0000000..b0d4d18
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImplTest.java
@@ -0,0 +1,291 @@
+package cn.iocoder.yudao.module.im.service.friend;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.friend.vo.ImFriendUpdateReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.dal.mysql.friend.ImFriendMapper;
+import cn.iocoder.yudao.module.im.service.message.ImPrivateMessageService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.dao.DuplicateKeyException;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_NOT_FRIEND;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link ImFriendServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImFriendServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImFriendServiceImpl friendService;
+
+ @Mock
+ private ImFriendMapper imFriendMapper;
+ @Mock
+ private AdminUserApi adminUserApi;
+ @Mock
+ private ImWebSocketService imWebSocketService;
+ @Mock
+ private ImPrivateMessageService privateMessageService;
+
+ // ========== updateFriend ==========
+
+ @Test
+ public void testUpdateFriend_success() {
+ // 鍑嗗
+ ImFriendUpdateReqVO reqVO = new ImFriendUpdateReqVO();
+ reqVO.setFriendUserId(2L);
+ reqVO.setSilent(true);
+ ImFriendDO friend = ImFriendDO.builder().id(100L).userId(1L).friendUserId(2L)
+ .silent(false).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(friend);
+
+ // 璋冪敤
+ friendService.updateFriend(1L, reqVO);
+
+ // 鏂█锛氭洿鏂颁簡 silent 瀛楁
+ ArgumentCaptor<ImFriendDO> captor = ArgumentCaptor.forClass(ImFriendDO.class);
+ verify(imFriendMapper).updateById(captor.capture());
+ assertEquals(100L, captor.getValue().getId());
+ assertTrue(captor.getValue().getSilent());
+ // 鏂█锛氭帹閫佷簡濂藉弸鏇存柊閫氱煡
+ verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateFriend_notFriend() {
+ // 鍑嗗
+ ImFriendUpdateReqVO reqVO = new ImFriendUpdateReqVO();
+ reqVO.setFriendUserId(2L);
+ reqVO.setSilent(true);
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(null);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendService.updateFriend(1L, reqVO));
+ assertEquals(FRIEND_NOT_FRIEND.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testUpdateFriend_disabledFriend() {
+ // 鍑嗗
+ ImFriendUpdateReqVO reqVO = new ImFriendUpdateReqVO();
+ reqVO.setFriendUserId(2L);
+ reqVO.setSilent(true);
+ ImFriendDO friend = ImFriendDO.builder().id(100L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(friend);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> friendService.updateFriend(1L, reqVO));
+ assertEquals(FRIEND_NOT_FRIEND.getCode(), exception.getCode());
+ verify(imFriendMapper, never()).updateById(any(ImFriendDO.class));
+ verify(imWebSocketService, never()).sendNotificationAsync(any(Long.class), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateFriend_displayNameOnly() {
+ // 鍑嗗锛氬彧浼犲娉ㄣ�佷笉浼� silent 鈥斺�� 璧板樊閲忔洿鏂�
+ ImFriendUpdateReqVO reqVO = new ImFriendUpdateReqVO();
+ reqVO.setFriendUserId(2L);
+ reqVO.setDisplayName("鑰佸紶");
+ ImFriendDO friend = ImFriendDO.builder().id(100L).userId(1L).friendUserId(2L)
+ .silent(false).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(friend);
+
+ // 璋冪敤
+ friendService.updateFriend(1L, reqVO);
+
+ // 鏂█锛歶pdateById 鏀跺埌 displayName 浣嗘病鏈� silent锛圡yBatis-Plus 闈� NOT_NULL 璺宠繃锛�
+ ArgumentCaptor<ImFriendDO> captor = ArgumentCaptor.forClass(ImFriendDO.class);
+ verify(imFriendMapper).updateById(captor.capture());
+ assertEquals(100L, captor.getValue().getId());
+ assertEquals("鑰佸紶", captor.getValue().getDisplayName());
+ assertNull(captor.getValue().getSilent());
+ // 鏂█锛氭帹閫佸ソ鍙嬫洿鏂伴�氱煡
+ verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testUpdateFriend_emptyRequest() {
+ // 鍑嗗锛歴ilent / displayName / pinned 閮戒笉浼� 鈥斺�� 杩涘叆鏂规硶绔嬪埢杩斿洖锛屼笉鏌� mapper 涔熶笉鍙戞帹閫�
+ ImFriendUpdateReqVO reqVO = new ImFriendUpdateReqVO();
+ reqVO.setFriendUserId(2L);
+
+ // 璋冪敤
+ friendService.updateFriend(1L, reqVO);
+
+ // 鏂█锛氭病鏌ヨ褰曘�佹病瑙﹀彂 SQL 鏇存柊 / 娌″彂 WebSocket 鎺ㄩ��
+ verify(imFriendMapper, never()).selectByUserIdAndFriendUserId(anyLong(), anyLong());
+ verify(imFriendMapper, never()).updateById(any(ImFriendDO.class));
+ verify(imWebSocketService, never()).sendNotificationAsync(any(Long.class), anyInt(), anyInt(), any());
+ }
+
+ // ========== 寤虹珛濂藉弸 ==========
+
+ @Test
+ public void testAddFriend0_existingEnabledSkip() {
+ // 鍑嗗锛氬凡瀛樺湪涓斿惎鐢�
+ ImFriendDO exists = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).silent(true).pinned(true).blocked(true).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists);
+
+ // 璋冪敤
+ friendService.addFriend0(1L, 2L, null, null);
+
+ // 鏂█锛氫笉鎻掑叆涔熶笉鏇存柊
+ verify(imFriendMapper, never()).insert(any(ImFriendDO.class));
+ verify(imFriendMapper, never()).updateById(any(ImFriendDO.class));
+ verify(imFriendMapper, never()).updateReAddFields(anyLong(), anyInt(), any(LocalDateTime.class),
+ any(LocalDateTime.class), anyBoolean(), anyBoolean(), anyBoolean(), any(), any());
+ }
+
+ @Test
+ public void testAddFriend0_existingDisabledRecovers() {
+ // 鍑嗗锛氬凡瀛樺湪涓� DISABLE锛屽簲褰撴仮澶嶇姸鎬�
+ ImFriendDO exists = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists);
+
+ // 璋冪敤
+ friendService.addFriend0(1L, 2L, null, null);
+
+ // 鏂█锛氭仮澶� ENABLE锛屽苟娓呯┖ deleteTime
+ verify(imFriendMapper).updateReAddFields(eq(10L), eq(CommonStatusEnum.ENABLE.getStatus()),
+ any(LocalDateTime.class), any(LocalDateTime.class), eq(false), eq(false), eq(false), isNull(), isNull());
+ verify(imFriendMapper, never()).insert(any(ImFriendDO.class));
+ }
+
+ @Test
+ public void testAddFriend0_duplicateKeyPropagates() {
+ // 鍑嗗锛歮apper 鎶涘苟鍙戝啿绐侊紱鏋佺骞跺彂涓嬭寮傚父鍚戝鎶涳紝鐢卞灞備簨鍔″洖婊�
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(null);
+ when(imFriendMapper.insert(any(ImFriendDO.class)))
+ .thenThrow(new DuplicateKeyException("concurrent insert"));
+
+ // 璋冪敤 + 鏂█锛氬紓甯稿悜澶栨姏
+ assertThrows(DuplicateKeyException.class, () -> friendService.addFriend0(1L, 2L, null, null));
+ verify(imFriendMapper).insert(any(ImFriendDO.class));
+ }
+
+ // ========== deleteFriend ==========
+
+ @Test
+ public void testDeleteFriend0_alreadyDisabled() {
+ // 鍑嗗锛氬凡缁忔槸 DISABLE锛屼笉鍐嶆洿鏂�
+ ImFriendDO exists = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists);
+
+ boolean result = friendService.deleteFriend0(1L, 2L);
+
+ assertFalse(result);
+ verify(imFriendMapper, never()).updateById(any(ImFriendDO.class));
+ }
+
+ @Test
+ public void testDeleteFriend0_enabledGetsDisabled() {
+ ImFriendDO exists = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists);
+
+ boolean result = friendService.deleteFriend0(1L, 2L);
+
+ assertTrue(result);
+ ArgumentCaptor<ImFriendDO> captor = ArgumentCaptor.forClass(ImFriendDO.class);
+ verify(imFriendMapper).updateById(captor.capture());
+ assertEquals(CommonStatusEnum.DISABLE.getStatus(), captor.getValue().getStatus());
+ assertNotNull(captor.getValue().getDeleteTime());
+ }
+
+ @Test
+ public void testDeleteFriend_alreadyDisabledSkipNotification() {
+ // 鍑嗗锛氬凡缁忔槸 DISABLE锛屼笉鍐嶆帹鏈鍒犻櫎閫氱煡
+ ImFriendDO exists = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists);
+
+ friendService.deleteFriend(1L, 2L, true);
+
+ verify(imFriendMapper, never()).updateById(any(ImFriendDO.class));
+ verify(privateMessageService, never()).sendPrivateMessage(anyLong(), any(ImPrivateMessageSendDTO.class));
+ }
+
+ @Test
+ public void testDeleteFriend_enabledSendNotification() {
+ // 鍑嗗
+ ImFriendDO exists = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists);
+
+ friendService.deleteFriend(1L, 2L, true);
+
+ verify(imFriendMapper).updateById(any(ImFriendDO.class));
+ verify(privateMessageService).sendPrivateMessage(eq(1L), any(ImPrivateMessageSendDTO.class));
+ }
+
+ // ========== 鍏跺畠璇绘柟娉� ==========
+
+ @Test
+ public void testGetFriendList() {
+ List<ImFriendDO> list = ListUtil.of(
+ ImFriendDO.builder().id(1L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImFriendDO.builder().id(2L).userId(1L).friendUserId(3L)
+ .status(CommonStatusEnum.DISABLE.getStatus())
+ .deleteTime(LocalDateTime.now()).build()
+ );
+ when(imFriendMapper.selectListByUserId(1L)).thenReturn(list);
+
+ List<ImFriendDO> result = friendService.getFriendList(1L);
+ assertEquals(2, result.size());
+ }
+
+ @Test
+ public void testGetActiveFriendList_emptySkip() {
+ List<ImFriendDO> result = friendService.getActiveFriendList(1L, Collections.emptyList());
+
+ assertTrue(result.isEmpty());
+ verify(imFriendMapper, never()).selectListByUserIdAndFriendUserIdsAndStatus(anyLong(), anyCollection(), anyInt());
+ }
+
+ @Test
+ public void testGetMutualEnableFriendList_filterSingleSideDeleted() {
+ ImFriendDO friend2 = ImFriendDO.builder().id(1L).userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ ImFriendDO friend3 = ImFriendDO.builder().id(2L).userId(1L).friendUserId(3L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(imFriendMapper.selectListByUserIdAndStatus(1L, CommonStatusEnum.ENABLE.getStatus()))
+ .thenReturn(ListUtil.of(friend2, friend3));
+ when(imFriendMapper.selectListByUserIdsAndFriendUserIdAndStatus(anyCollection(), eq(1L),
+ eq(CommonStatusEnum.ENABLE.getStatus()))).thenReturn(ListUtil.of(
+ ImFriendDO.builder().userId(2L).friendUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ List<ImFriendDO> result = friendService.getMutualEnableFriendList(1L);
+
+ assertEquals(1, result.size());
+ assertEquals(2L, result.get(0).getFriendUserId());
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImplTest.java
new file mode 100644
index 0000000..ba4e0a8
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupMemberServiceImplTest.java
@@ -0,0 +1,349 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberUpdateReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMemberMapper;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImGroupMessageNotification;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.dao.DuplicateKeyException;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.GROUP_MEMBER_NOT_IN_GROUP;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImGroupMemberServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImGroupMemberServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImGroupMemberServiceImpl groupMemberService;
+
+ @Mock
+ private ImGroupMemberMapper groupMemberMapper;
+ @Mock
+ private ImWebSocketService webSocketService;
+ @Mock
+ private cn.iocoder.yudao.module.im.service.message.ImGroupMessageService groupMessageService;
+
+ // ========== addGroupMember ==========
+
+ @Test
+ public void testAddGroupMember_newInsert() {
+ // 鍑嗗锛氭垚鍛樿褰曚笉瀛樺湪
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(null);
+
+ // 璋冪敤
+ ImGroupMemberDO result = groupMemberService.addGroupMember(10L, 1L);
+
+ // 鏂█锛氭墽琛屼簡 insert锛岃繑鍥炶褰曠殑 status 涓� ENABLE
+ assertNotNull(result);
+ assertEquals(10L, result.getGroupId());
+ assertEquals(1L, result.getUserId());
+ assertEquals(CommonStatusEnum.ENABLE.getStatus(), result.getStatus());
+ assertNotNull(result.getJoinTime());
+ verify(groupMemberMapper).insert(any(ImGroupMemberDO.class));
+ }
+
+ @Test
+ public void testAddGroupMember_existingEnabledReturns() {
+ // 鍑嗗锛氬凡瀛樺湪涓� ENABLE锛屽彧杩斿洖宸叉湁璁板綍锛屼笉鍋氬叾瀹冩搷浣�
+ ImGroupMemberDO exists = ImGroupMemberDO.builder().id(50L).groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(exists);
+
+ ImGroupMemberDO result = groupMemberService.addGroupMember(10L, 1L);
+
+ assertEquals(50L, result.getId());
+ verify(groupMemberMapper, never()).insert(any(ImGroupMemberDO.class));
+ verify(groupMemberMapper, never()).updateById(any(ImGroupMemberDO.class));
+ }
+
+ @Test
+ public void testAddGroupMember_existingDisabledRecovers() {
+ // 鍑嗗锛氬凡瀛樺湪涓� DISABLE锛屽簲閲嶇疆涓� ENABLE 骞堕噸缃� role 涓� MEMBER
+ ImGroupMemberDO exists = ImGroupMemberDO.builder().id(50L).groupId(10L).userId(1L)
+ .status(CommonStatusEnum.DISABLE.getStatus())
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole()).build();
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(exists);
+
+ ImGroupMemberDO result = groupMemberService.addGroupMember(10L, 1L);
+
+ verify(groupMemberMapper).updateRejoinFields(eq(50L), eq(CommonStatusEnum.ENABLE.getStatus()),
+ any(), eq(ImGroupMemberRoleEnum.NORMAL.getRole()), isNull(), isNull());
+ assertEquals(CommonStatusEnum.ENABLE.getStatus(), result.getStatus());
+ assertEquals(ImGroupMemberRoleEnum.NORMAL.getRole(), result.getRole());
+ assertNull(result.getQuitTime());
+ assertNull(result.getMuteEndTime());
+ }
+
+ @Test
+ public void testAddGroupMember_duplicateKeyFallsBackToSelect() {
+ // 鍑嗗锛氱涓�娆� select 杩斿洖 null锛宨nsert 鎶� DuplicateKey锛屽啀娆� select 杩斿洖宸叉彃鍏ヨ褰�
+ ImGroupMemberDO inserted = ImGroupMemberDO.builder().id(80L).groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(null).thenReturn(inserted);
+ when(groupMemberMapper.insert(any(ImGroupMemberDO.class)))
+ .thenThrow(new DuplicateKeyException("concurrent insert"));
+
+ // 璋冪敤锛氬啿绐佸悗闄嶇骇 select
+ ImGroupMemberDO result = groupMemberService.addGroupMember(10L, 1L);
+
+ assertNotNull(result);
+ assertEquals(80L, result.getId());
+ }
+
+ // ========== addGroupMembers ==========
+
+ @Test
+ public void testAddGroupMembers_mixedInsertAndUpdate() {
+ // 鍑嗗锛氱敤鎴� 2 涓嶅瓨鍦紙鏂板锛夛紝鐢ㄦ埛 3 宸插瓨鍦ㄤ笖 DISABLE锛堟仮澶嶏級锛岀敤鎴� 4 宸插瓨鍦ㄤ笖 ENABLE锛堣烦杩囷級
+ ImGroupMemberDO exist3 = ImGroupMemberDO.builder().id(30L).groupId(10L).userId(3L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build();
+ ImGroupMemberDO exist4 = ImGroupMemberDO.builder().id(40L).groupId(10L).userId(4L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberMapper.selectListByGroupIdAndUserIds(eq(10L), anyCollection()))
+ .thenReturn(ListUtil.of(exist3, exist4));
+
+ // 璋冪敤
+ groupMemberService.addGroupMembers(10L, ListUtil.of(2L, 3L, 4L));
+
+ // 鏂█锛歶pdates 鍙湁鐢ㄦ埛 3锛沬nserts 鍙湁鐢ㄦ埛 2
+ verify(groupMemberMapper).updateRejoinFields(eq(30L), eq(CommonStatusEnum.ENABLE.getStatus()),
+ any(), eq(ImGroupMemberRoleEnum.NORMAL.getRole()), isNull(), isNull());
+ verify(groupMemberMapper).insertBatch(argThat((List<ImGroupMemberDO> list) ->
+ list.size() == 1 && list.get(0).getUserId().equals(2L)));
+ }
+
+ @Test
+ public void testAddGroupMembers_allExisting_onlyUpdates() {
+ // 鍑嗗锛氫紶鍏ョ殑 3 涓敤鎴烽兘宸叉湁璁板綍锛堝叏閮� DISABLE锛� 鈫� 鍙仛 update锛屼笉鍋� insert
+ List<ImGroupMemberDO> existing = ListUtil.of(
+ ImGroupMemberDO.builder().id(1L).groupId(10L).userId(2L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().id(2L).groupId(10L).userId(3L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build()
+ );
+ when(groupMemberMapper.selectListByGroupIdAndUserIds(eq(10L), anyCollection()))
+ .thenReturn(existing);
+
+ groupMemberService.addGroupMembers(10L, ListUtil.of(2L, 3L));
+
+ verify(groupMemberMapper, times(2)).updateRejoinFields(anyLong(), eq(CommonStatusEnum.ENABLE.getStatus()),
+ any(), eq(ImGroupMemberRoleEnum.NORMAL.getRole()), isNull(), isNull());
+ verify(groupMemberMapper, never()).insertBatch(anyList());
+ }
+
+ @Test
+ public void testAddGroupMembers_allNew_onlyInserts() {
+ // 鍑嗗锛氶兘涓嶅瓨鍦� 鈫� 鍙仛 insert
+ when(groupMemberMapper.selectListByGroupIdAndUserIds(eq(10L), anyCollection()))
+ .thenReturn(ListUtil.of());
+
+ groupMemberService.addGroupMembers(10L, ListUtil.of(2L, 3L));
+
+ verify(groupMemberMapper, never()).updateRejoinFields(anyLong(), anyInt(), any(), anyInt(), any(), any());
+ verify(groupMemberMapper).insertBatch(anyList());
+ }
+
+ @Test
+ public void testAddGroupMembers_allExistingEnabled_nothingHappens() {
+ // 鍑嗗锛氶兘宸插瓨鍦ㄤ笖 ENABLE 鈫� 鏃笉 update 涔熶笉 insert
+ List<ImGroupMemberDO> existing = ListUtil.of(
+ ImGroupMemberDO.builder().id(1L).groupId(10L).userId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ );
+ when(groupMemberMapper.selectListByGroupIdAndUserIds(eq(10L), anyCollection()))
+ .thenReturn(existing);
+
+ groupMemberService.addGroupMembers(10L, ListUtil.of(2L));
+
+ verify(groupMemberMapper, never()).updateRejoinFields(anyLong(), anyInt(), any(), anyInt(), any(), any());
+ verify(groupMemberMapper, never()).insertBatch(anyList());
+ }
+
+ @Test
+ public void testAddGroupMembers_batchInsertDuplicateFallback() {
+ // 鍑嗗锛氫袱涓柊澧炴垚鍛橈紝鎵归噺鎻掑叆澶辫触鏃堕檷绾т负閫愪釜 addGroupMember
+ when(groupMemberMapper.selectListByGroupIdAndUserIds(eq(10L), anyCollection()))
+ .thenReturn(ListUtil.of());
+ doThrow(new DuplicateKeyException("concurrent batch insert"))
+ .when(groupMemberMapper).insertBatch(anyList());
+ // addGroupMember 鍗曟潯鍏滃簳閫昏緫
+ when(groupMemberMapper.selectByGroupIdAndUserId(eq(10L), anyLong())).thenReturn(null);
+
+ // 璋冪敤
+ groupMemberService.addGroupMembers(10L, ListUtil.of(2L, 3L));
+
+ // 鏂█锛氶檷绾т负閫愭潯璋冪敤 insert
+ verify(groupMemberMapper, times(2)).insert(any(ImGroupMemberDO.class));
+ }
+
+ // ========== validateMemberInGroup ==========
+
+ @Test
+ public void testValidateMemberInGroup_notInGroup() {
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMemberService.validateMemberInGroup(10L, 1L));
+ assertEquals(GROUP_MEMBER_NOT_IN_GROUP.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testValidateMemberInGroup_disabledEqualsNotInGroup() {
+ ImGroupMemberDO member = ImGroupMemberDO.builder().id(50L).groupId(10L).userId(1L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build();
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(member);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMemberService.validateMemberInGroup(10L, 1L));
+ assertEquals(GROUP_MEMBER_NOT_IN_GROUP.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testValidateMemberInGroup_success() {
+ ImGroupMemberDO member = ImGroupMemberDO.builder().id(50L).groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(member);
+
+ ImGroupMemberDO result = groupMemberService.validateMemberInGroup(10L, 1L);
+ assertEquals(50L, result.getId());
+ }
+
+ // ========== updateGroupMember ==========
+
+ @Test
+ public void testUpdateGroupMember_success() {
+ ImGroupMemberDO member = ImGroupMemberDO.builder().id(50L).groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(member);
+
+ ImGroupMemberUpdateReqVO reqVO = new ImGroupMemberUpdateReqVO()
+ .setGroupId(10L).setSilent(true).setDisplayUserName("鏄电О");
+
+ groupMemberService.updateGroupMember(1L, reqVO);
+
+ ArgumentCaptor<ImGroupMemberDO> captor = ArgumentCaptor.forClass(ImGroupMemberDO.class);
+ verify(groupMemberMapper).updateById(captor.capture());
+ assertEquals(50L, captor.getValue().getId());
+ assertTrue(captor.getValue().getSilent());
+ // 鍏紑瀛楁鏄电О鍙樺寲 鈫� 鍏ㄥ憳鍦ㄧ嚎鍚屾 GROUP_MEMBER_NICKNAME_UPDATE
+ verify(groupMessageService).sendGroupMessage(eq(1L), any(cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO.class));
+ // 涓汉瀛楁 silent 鍙樺寲 鈫� 浠呰嚜宸卞绔悓姝� GROUP_MEMBER_SETTING_UPDATE
+ verify(groupMessageService).sendGroupMessage(eq(1L), eq(ListUtil.of(1L)),
+ any(cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO.class));
+ }
+
+ // ========== removeGroupMember ==========
+
+ @Test
+ public void testRemoveGroupMember_success() {
+ ImGroupMemberDO member = ImGroupMemberDO.builder().id(50L).groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(member);
+
+ groupMemberService.removeGroupMember(10L, 1L);
+
+ ArgumentCaptor<ImGroupMemberDO> captor = ArgumentCaptor.forClass(ImGroupMemberDO.class);
+ verify(groupMemberMapper).updateById(captor.capture());
+ assertEquals(50L, captor.getValue().getId());
+ assertEquals(CommonStatusEnum.DISABLE.getStatus(), captor.getValue().getStatus());
+ assertNotNull(captor.getValue().getQuitTime());
+ }
+
+ @Test
+ public void testRemoveGroupMember_notInGroup() {
+ when(groupMemberMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMemberService.removeGroupMember(10L, 1L));
+ assertEquals(GROUP_MEMBER_NOT_IN_GROUP.getCode(), exception.getCode());
+ }
+
+ // ========== removeGroupMembers ==========
+
+ @Test
+ public void testRemoveGroupMembers_batch() {
+ groupMemberService.removeGroupMembers(10L, ListUtil.of(2L, 3L));
+
+ ArgumentCaptor<ImGroupMemberDO> captor = ArgumentCaptor.forClass(ImGroupMemberDO.class);
+ verify(groupMemberMapper).updateByGroupIdAndUserIdsAndStatus(eq(10L), anyCollection(),
+ eq(CommonStatusEnum.ENABLE.getStatus()), captor.capture());
+ assertEquals(CommonStatusEnum.DISABLE.getStatus(), captor.getValue().getStatus());
+ assertNotNull(captor.getValue().getQuitTime());
+ }
+
+ @Test
+ public void testRemoveGroupMembersByGroupId() {
+ groupMemberService.removeGroupMembersByGroupId(10L);
+
+ ArgumentCaptor<ImGroupMemberDO> captor = ArgumentCaptor.forClass(ImGroupMemberDO.class);
+ verify(groupMemberMapper).updateByGroupIdAndStatus(eq(10L),
+ eq(CommonStatusEnum.ENABLE.getStatus()), captor.capture());
+ assertEquals(CommonStatusEnum.DISABLE.getStatus(), captor.getValue().getStatus());
+ assertNotNull(captor.getValue().getQuitTime());
+ }
+
+ // ========== getActiveGroupMemberUserIdsByGroupId ==========
+
+ @Test
+ public void testGetActiveGroupMemberUserIdsByGroupId_extractsUserIds() {
+ // 鍑嗗锛�3 涓� ENABLE 鎴愬憳
+ List<ImGroupMemberDO> members = ListUtil.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(3L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ );
+ when(groupMemberMapper.selectListByGroupIdAndStatus(
+ 10L, CommonStatusEnum.ENABLE.getStatus())).thenReturn(members);
+
+ // 璋冪敤
+ List<Long> userIds = groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L);
+
+ // 鏂█锛氬彧杩斿洖 userId銆侀『搴忎繚鐣�
+ assertEquals(ListUtil.of(1L, 2L, 3L), userIds);
+ }
+
+ @Test
+ public void testGetActiveGroupMemberUserIdsByGroupId_emptyList() {
+ when(groupMemberMapper.selectListByGroupIdAndStatus(
+ 10L, CommonStatusEnum.ENABLE.getStatus())).thenReturn(ListUtil.of());
+
+ List<Long> userIds = groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L);
+
+ assertTrue(userIds.isEmpty());
+ }
+
+ @Test
+ public void testGetGroupMemberListByOwnerAndAdmin_passesRoles() {
+ List<Integer> roles = ListUtil.of(ImGroupMemberRoleEnum.OWNER.getRole(), ImGroupMemberRoleEnum.ADMIN.getRole());
+ List<ImGroupMemberDO> members = ListUtil.of(ImGroupMemberDO.builder().groupId(10L).userId(1L).build());
+ when(groupMemberMapper.selectListByGroupIdAndStatusAndRoles(10L, CommonStatusEnum.ENABLE.getStatus(), roles))
+ .thenReturn(members);
+
+ List<ImGroupMemberDO> result = groupMemberService.getGroupMemberListByOwnerAndAdmin(10L);
+
+ assertEquals(members, result);
+ verify(groupMemberMapper).selectListByGroupIdAndStatusAndRoles(
+ 10L, CommonStatusEnum.ENABLE.getStatus(), roles);
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImplTest.java
new file mode 100644
index 0000000..0d05e10
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupRequestServiceImplTest.java
@@ -0,0 +1,350 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.request.ImGroupRequestApplyReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupRequestDO;
+import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupRequestMapper;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupRequestHandleResultEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.dao.DuplicateKeyException;
+
+import java.util.Collection;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImGroupRequestServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImGroupRequestServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImGroupRequestServiceImpl groupRequestService;
+
+ @Mock
+ private ImGroupRequestMapper groupRequestMapper;
+ @Mock
+ private ImGroupService groupService;
+ @Mock
+ private ImGroupMemberService groupMemberService;
+ @Mock
+ private ImGroupMessageService groupMessageService;
+ @Mock
+ private ImWebSocketService websocketService;
+ @Mock
+ private AdminUserApi adminUserApi;
+
+ // ==================== applyJoinGroup ====================
+
+ @Test
+ public void testApplyJoinGroup_freeMode_directJoin() {
+ // 鍑嗗锛氱兢鏄� FREE 妯″紡
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .joinApproval(false)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+
+ ImGroupRequestApplyReqVO reqVO = new ImGroupRequestApplyReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setAddSource(ImGroupAddSourceEnum.SEARCH.getSource());
+
+ // 璋冪敤
+ ImGroupRequestDO result = groupRequestService.applyJoinGroup(1L, reqVO);
+
+ // 鏂█锛欶REE 璺緞鐩存帴鍏ョ兢锛屼笉钀界敵璇疯褰�
+ assertNull(result);
+ verify(groupService).validateMemberCountLimit(10L, 1);
+ verify(groupMemberService).addGroupMember(eq(10L), eq(1L),
+ eq(ImGroupMemberRoleEnum.NORMAL.getRole()),
+ eq(ImGroupAddSourceEnum.SEARCH.getSource()), isNull());
+ verify(groupRequestMapper, never()).insert(any(ImGroupRequestDO.class));
+ // 鎺� 1510 鑷敱杩涚兢
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_MEMBER_ENTER.getType(), dtoCaptor.getValue().getType());
+ }
+
+ @Test
+ public void testApplyJoinGroup_approvalMode_createsRequest() {
+ // 鍑嗗锛氱兢鏄� APPLY 妯″紡
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .joinApproval(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ // 缇ら噷鏈� owner + 涓�涓� admin锛屼綔涓� 1503 鎺ㄩ�佺洰鏍�
+ when(groupMemberService.getGroupMemberListByOwnerAndAdmin(10L)).thenReturn(ListUtil.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(99L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(98L)
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+ when(adminUserApi.getUser(1L)).thenReturn(buildUser(1L, "鐢宠浜�"));
+
+ ImGroupRequestApplyReqVO reqVO = new ImGroupRequestApplyReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setApplyContent("鎴戞兂杩涚兢");
+ reqVO.setAddSource(ImGroupAddSourceEnum.SEARCH.getSource());
+
+ // 璋冪敤
+ ImGroupRequestDO result = groupRequestService.applyJoinGroup(1L, reqVO);
+
+ // 鏂█锛氱敵璇疯褰曞凡钀藉簱 + 涓嶇洿杩涚兢
+ assertNotNull(result);
+ verify(groupMemberService, never()).addGroupMember(anyLong(), anyLong(), anyInt(), anyInt(), anyLong());
+ verify(groupRequestMapper).insert(any(ImGroupRequestDO.class));
+ // 1503 鎺ㄩ�佺粰 owner(99) + admin(98)锛屽幓閲嶅悗涓ゆ潯
+ verify(websocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testApplyJoinGroup_insertDuplicateKey_reuseOldRequest() {
+ // 鍑嗗锛氱兢鏄� APPLY 妯″紡锛岄娆℃煡璇笉瀛樺湪锛屾彃鍏ユ椂鍛戒腑鍞竴閿�
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .joinApproval(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ when(groupMemberService.getGroupMemberListByOwnerAndAdmin(10L)).thenReturn(ListUtil.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(99L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+ when(adminUserApi.getUser(1L)).thenReturn(buildUser(1L, "鐢宠浜�"));
+ ImGroupRequestDO old = new ImGroupRequestDO().setId(50L).setGroupId(10L).setUserId(1L)
+ .setHandleResult(ImGroupRequestHandleResultEnum.REFUSED.getResult());
+ when(groupRequestMapper.selectByGroupIdAndUserId(10L, 1L)).thenReturn(null, old);
+ when(groupRequestMapper.insert(any(ImGroupRequestDO.class))).thenThrow(new DuplicateKeyException("dup"));
+
+ ImGroupRequestApplyReqVO reqVO = new ImGroupRequestApplyReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setApplyContent("鎴戞兂杩涚兢");
+ reqVO.setAddSource(ImGroupAddSourceEnum.SEARCH.getSource());
+
+ // 璋冪敤
+ ImGroupRequestDO result = groupRequestService.applyJoinGroup(1L, reqVO);
+
+ // 鏂█锛氬鐢ㄥ苟閲嶇疆鏃х敵璇�
+ verify(groupRequestMapper).updateApplyByIdReset(eq(50L), eq("鎴戞兂杩涚兢"),
+ eq(ImGroupAddSourceEnum.SEARCH.getSource()), any());
+ assertEquals(50L, result.getId());
+ assertEquals(ImGroupRequestHandleResultEnum.UNHANDLED.getResult(), result.getHandleResult());
+ verify(websocketService).sendNotificationAsync(eq(99L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testApplyJoinGroup_alreadyMember_throws() {
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .joinApproval(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ when(groupMemberService.getGroupMember(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+
+ ImGroupRequestApplyReqVO reqVO = new ImGroupRequestApplyReqVO();
+ reqVO.setGroupId(10L);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupRequestService.applyJoinGroup(1L, reqVO));
+ assertEquals(GROUP_REQUEST_ALREADY_MEMBER.getCode(), exception.getCode());
+ }
+
+ // ==================== agreeGroupRequest ====================
+
+ @Test
+ public void testAgreeGroupRequest_success_activeApply() {
+ // 鍑嗗锛氫富鍔ㄧ敵璇锋湭澶勭悊锛屾搷浣滀汉鏄� admin
+ ImGroupRequestDO request = new ImGroupRequestDO()
+ .setGroupId(10L).setUserId(2L).setInviterUserId(null)
+ .setAddSource(ImGroupAddSourceEnum.SEARCH.getSource())
+ .setHandleResult(ImGroupRequestHandleResultEnum.UNHANDLED.getResult());
+ request.setId(50L);
+ when(groupRequestMapper.selectById(50L)).thenReturn(request);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ when(groupRequestMapper.updateByIdAndHandleResult(eq(50L),
+ eq(ImGroupRequestHandleResultEnum.UNHANDLED.getResult()), any())).thenReturn(1);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupService.getGroup(10L)).thenReturn(group);
+ when(groupMemberService.getGroupMemberListByOwnerAndAdmin(10L)).thenReturn(ListUtil.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(99L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ // 璋冪敤
+ groupRequestService.agreeGroupRequest(1L, 50L);
+
+ // 鏂█锛氫汉鏁版牎楠� + 鍐欑兢鎴愬憳 + 鎺� 1505 + 鎺� 1510锛堜富鍔ㄧ敵璇凤級
+ verify(groupService).validateMemberCountLimit(10L, 1);
+ verify(groupMemberService).addGroupMember(eq(10L), eq(2L),
+ eq(ImGroupMemberRoleEnum.NORMAL.getRole()),
+ eq(ImGroupAddSourceEnum.SEARCH.getSource()), isNull());
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_MEMBER_ENTER.getType(), dtoCaptor.getValue().getType());
+ // 1505 鎺ㄩ�佺粰鐢宠浜� + owner锛屽幓閲嶅悗涓ゆ潯
+ verify(websocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testAgreeGroupRequest_concurrent_secondCallFails() {
+ // 鍑嗗锛氱敵璇峰瓨鍦ㄤ絾涔愯閿佹洿鏂拌繑鍥� 0锛堣骞跺彂澶勭悊杩囷級
+ ImGroupRequestDO request = new ImGroupRequestDO()
+ .setGroupId(10L).setUserId(2L)
+ .setHandleResult(ImGroupRequestHandleResultEnum.UNHANDLED.getResult());
+ request.setId(50L);
+ when(groupRequestMapper.selectById(50L)).thenReturn(request);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ when(groupRequestMapper.updateByIdAndHandleResult(eq(50L),
+ eq(ImGroupRequestHandleResultEnum.UNHANDLED.getResult()), any())).thenReturn(0);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupRequestService.agreeGroupRequest(1L, 50L));
+ assertEquals(GROUP_REQUEST_HANDLED.getCode(), exception.getCode());
+ // 涓嶅啓缇ゆ垚鍛�
+ verify(groupMemberService, never()).addGroupMember(anyLong(), anyLong(), anyInt(), any(), any());
+ }
+
+ @Test
+ public void testAgreeGroupRequest_notOwnerOrAdmin_throws() {
+ ImGroupRequestDO request = new ImGroupRequestDO()
+ .setGroupId(10L).setUserId(2L)
+ .setHandleResult(ImGroupRequestHandleResultEnum.UNHANDLED.getResult());
+ request.setId(50L);
+ when(groupRequestMapper.selectById(50L)).thenReturn(request);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupRequestService.agreeGroupRequest(1L, 50L));
+ assertEquals(GROUP_REQUEST_NOT_TO_ME.getCode(), exception.getCode());
+ }
+
+ // ==================== refuseGroupRequest ====================
+
+ @Test
+ public void testRefuseGroupRequest_success() {
+ ImGroupRequestDO request = new ImGroupRequestDO()
+ .setGroupId(10L).setUserId(2L)
+ .setHandleResult(ImGroupRequestHandleResultEnum.UNHANDLED.getResult());
+ request.setId(50L);
+ when(groupRequestMapper.selectById(50L)).thenReturn(request);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ when(groupRequestMapper.updateByIdAndHandleResult(eq(50L),
+ eq(ImGroupRequestHandleResultEnum.UNHANDLED.getResult()), any())).thenReturn(1);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupService.getGroup(10L)).thenReturn(group);
+ when(groupMemberService.getGroupMemberListByOwnerAndAdmin(10L)).thenReturn(ListUtil.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ groupRequestService.refuseGroupRequest(1L, 50L, "鏆備笉閫氳繃");
+
+ // 涓嶅啓缇ゆ垚鍛橈紱鎺� 1506 缁欑敵璇蜂汉 + 缇や富锛堝悓涓�浜� 1L 鏃跺幓閲嶄负 1 + 鐢宠浜� 2L = 2 鏉★級
+ verify(groupMemberService, never()).addGroupMember(anyLong(), anyLong(), anyInt(), any(), any());
+ verify(websocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ // ==================== createInviteRequestList ====================
+
+ @Test
+ public void testCreateInviteRequestList_success() {
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .joinApproval(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ when(groupRequestMapper.selectByGroupIdAndUserId(eq(10L), anyLong())).thenReturn(null);
+ when(groupMemberService.getGroupMemberListByOwnerAndAdmin(10L)).thenReturn(ListUtil.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(99L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+ when(adminUserApi.getUserMap(anyCollection())).thenReturn(MapUtil.<Long, AdminUserRespDTO>builder()
+ .put(2L, buildUser(2L, "鐢ㄦ埛A"))
+ .put(3L, buildUser(3L, "鐢ㄦ埛B"))
+ .build());
+
+ // 璋冪敤锛氶個璇蜂汉 1L 閭�璇� 2L銆�3L锛堥兘娌℃湁鏃ц褰曪級
+ groupRequestService.createInviteRequestList(10L, 1L, ListUtil.of(2L, 3L));
+
+ // 鏂█锛氭彃鍏� 2 鏉� + 鎺� 1503 缁� owner锛堟瘡鏉� 1 甯э級鍏� 2 甯�
+ ArgumentCaptor<ImGroupRequestDO> captor = ArgumentCaptor.forClass(ImGroupRequestDO.class);
+ verify(groupRequestMapper, times(2)).insert(captor.capture());
+ verify(websocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ // 鏂█锛氭瘡鏉¤褰� inviterUserId=1 + addSource=INVITE锛岄伩鍏嶅鎵归�氳繃鍚庡洖鍐欑兢鎴愬憳鐣欑棔鐨勬潵婧愪负绌� / 鑴忓甫鏃у��
+ Collection<ImGroupRequestDO> inserted = captor.getAllValues();
+ assertEquals(2, inserted.size());
+ inserted.forEach(insert -> {
+ assertEquals(1L, insert.getInviterUserId());
+ assertEquals(ImGroupAddSourceEnum.INVITE.getSource(), insert.getAddSource());
+ });
+ }
+
+ @Test
+ public void testCreateInviteRequestList_insertDuplicateKey_reuseOldRequest() {
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .joinApproval(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ ImGroupRequestDO old = new ImGroupRequestDO().setId(50L).setGroupId(10L).setUserId(2L)
+ .setHandleResult(ImGroupRequestHandleResultEnum.REFUSED.getResult());
+ when(groupRequestMapper.selectByGroupIdAndUserId(10L, 2L)).thenReturn(null, old);
+ when(groupRequestMapper.insert(any(ImGroupRequestDO.class))).thenThrow(new DuplicateKeyException("dup"));
+ when(groupMemberService.getGroupMemberListByOwnerAndAdmin(10L)).thenReturn(ListUtil.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(99L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+ when(adminUserApi.getUserMap(anyCollection())).thenReturn(MapUtil.of(2L, buildUser(2L, "鐢ㄦ埛A")));
+
+ // 璋冪敤
+ groupRequestService.createInviteRequestList(10L, 1L, ListUtil.of(2L));
+
+ // 鏂█锛氬鐢ㄥ苟閲嶇疆鏃ч個璇风敵璇�
+ verify(groupRequestMapper).updateInviteByIdReset(eq(50L), eq(1L),
+ eq(ImGroupAddSourceEnum.INVITE.getSource()), any());
+ verify(websocketService).sendNotificationAsync(eq(99L), anyInt(), anyInt(), any());
+ }
+
+ private AdminUserRespDTO buildUser(Long id, String nickname) {
+ AdminUserRespDTO user = new AdminUserRespDTO();
+ user.setId(id);
+ user.setNickname(nickname);
+ return user;
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImplTest.java
new file mode 100644
index 0000000..d75e363
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImplTest.java
@@ -0,0 +1,1184 @@
+package cn.iocoder.yudao.module.im.service.group;
+
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminAddReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupAdminRemoveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupCreateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupMuteMemberReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupTransferOwnerReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.ImGroupUpdateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberInviteReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.group.vo.member.ImGroupMemberRemoveReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.manager.group.vo.ImGroupManagerBanReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMapper;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupAddSourceEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
+import cn.iocoder.yudao.module.im.service.message.ImGroupMessageService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImGroupMessageNotification;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Spy;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImGroupServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImGroupServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImGroupServiceImpl groupService;
+
+ @Mock
+ private ImGroupMapper groupMapper;
+ @Mock
+ private ImGroupMemberService groupMemberService;
+ @Mock
+ private ImGroupMessageService groupMessageService;
+ @Mock
+ private ImWebSocketService webSocketService;
+ @Mock
+ private ImFriendService friendService;
+ @Mock
+ private ImGroupRequestService groupRequestService;
+ @Mock
+ private AdminUserApi adminUserApi;
+ @Spy
+ private ImProperties imProperties = new ImProperties();
+
+ // ========== createGroup ==========
+
+ @Test
+ public void testCreateGroup_success() {
+ // 鍑嗗锛氫粎鍒涘缓鑰咃紝鏃犲垵濮嬫垚鍛�
+ ImGroupCreateReqVO reqVO = new ImGroupCreateReqVO();
+ reqVO.setName("娴嬭瘯缇�");
+ when(groupMapper.insert(any(ImGroupDO.class))).thenAnswer(invocation -> {
+ ImGroupDO group = invocation.getArgument(0);
+ group.setId(100L);
+ return 1;
+ });
+
+ // 璋冪敤
+ ImGroupDO result = groupService.createGroup(reqVO, 1L);
+
+ // 鏂█锛氱兢涓� + 鐘舵��
+ assertEquals(100L, result.getId());
+ assertEquals(1L, result.getOwnerUserId());
+ assertEquals(CommonStatusEnum.ENABLE.getStatus(), result.getStatus());
+ // 楠岃瘉锛氱兢涓诲姞鍏ョ兢锛堝甫 OWNER role锛�+ 涓嶈皟鎵归噺鍔犳垚鍛橈紙鏃犲垵濮嬫垚鍛橈級
+ verify(groupMemberService).addGroupMember(100L, 1L, ImGroupMemberRoleEnum.OWNER.getRole());
+ verify(groupMemberService, never()).addGroupMembers(anyLong(), anyCollection());
+ // 楠岃瘉锛氭帹閫� GROUP_CREATE 閫氱煡锛坧ayload memberUserIds 鍚垱寤鸿�呰嚜宸憋級
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), anyCollection(), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_CREATE.getType(), dtoCaptor.getValue().getType());
+ }
+
+ @Test
+ public void testCreateGroup_withInitialMembers() {
+ // 鍑嗗锛氬垱寤鸿�� + 2 涓垵濮嬫垚鍛橈紝閮芥槸濂藉弸
+ ImGroupCreateReqVO reqVO = new ImGroupCreateReqVO();
+ reqVO.setName("娴嬭瘯缇�");
+ reqVO.setMemberUserIds(new ArrayList<>(List.of(2L, 3L)));
+ when(groupMapper.insert(any(ImGroupDO.class))).thenAnswer(invocation -> {
+ ImGroupDO group = invocation.getArgument(0);
+ group.setId(100L);
+ return 1;
+ });
+ when(friendService.getActiveFriendList(eq(1L), anyCollection())).thenReturn(List.of(
+ ImFriendDO.builder().userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImFriendDO.builder().userId(1L).friendUserId(3L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ ));
+
+ // 璋冪敤
+ ImGroupDO result = groupService.createGroup(reqVO, 1L);
+
+ // 鏂█锛氱兢鍒涘缓鎴愬姛 + 鍒涘缓鑰� + 鍒濆鎴愬憳閮藉姞鍏�
+ assertEquals(100L, result.getId());
+ verify(groupMemberService).addGroupMember(100L, 1L, ImGroupMemberRoleEnum.OWNER.getRole());
+ verify(groupMemberService).addGroupMembers(eq(100L), anyCollection(),
+ eq(ImGroupAddSourceEnum.INVITE.getSource()), eq(1L));
+ // 楠岃瘉锛氭帹閫� GROUP_CREATE 閫氱煡锛宲ayload memberUserIds 鍚叏鍛橈紙鍒涘缓鑰� + 閭�璇凤級
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), anyCollection(), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_CREATE.getType(), dtoCaptor.getValue().getType());
+ }
+
+ @Test
+ public void testCreateGroup_initialMemberNotFriend() {
+ // 鍑嗗锛氬垵濮嬫垚鍛橀噷鏈夐潪濂藉弸
+ ImGroupCreateReqVO reqVO = new ImGroupCreateReqVO();
+ reqVO.setName("娴嬭瘯缇�");
+ reqVO.setMemberUserIds(new ArrayList<>(List.of(2L, 3L)));
+ // 鍙湁 2 鏄ソ鍙嬶紝3 涓嶆槸
+ when(friendService.getActiveFriendList(eq(1L), anyCollection())).thenReturn(List.of(
+ ImFriendDO.builder().userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+ AdminUserRespDTO u3 = new AdminUserRespDTO();
+ u3.setId(3L);
+ u3.setNickname("鏉庡洓");
+ when(adminUserApi.getUserMap(anyCollection())).thenReturn(Map.of(3L, u3));
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.createGroup(reqVO, 1L));
+ assertEquals(GROUP_INVITE_NOT_FRIEND.getCode(), exception.getCode());
+ verify(groupMapper, never()).insert(any(ImGroupDO.class));
+ }
+
+ // ========== updateGroup ==========
+
+ @Test
+ public void testUpdateGroup_notOwner() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗锛氬綋鍓嶇敤鎴蜂笉鏄兢涓�
+ ImGroupDO group = ImGroupDO.builder().id(10L).name("缇�").ownerUserId(99L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ImGroupUpdateReqVO reqVO = new ImGroupUpdateReqVO();
+ reqVO.setId(10L);
+ reqVO.setName("鏂板悕瀛�");
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.updateGroup(reqVO, 1L));
+ assertEquals(GROUP_NOT_OWNER.getCode(), exception.getCode());
+ }
+ }
+
+ @Test
+ public void testUpdateGroup_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗
+ ImGroupDO group = ImGroupDO.builder().id(10L).name("鏃у悕瀛�").ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ImGroupUpdateReqVO reqVO = new ImGroupUpdateReqVO();
+ reqVO.setId(10L);
+ reqVO.setName("鏂板悕瀛�");
+
+ // 璋冪敤
+ ImGroupDO result = groupService.updateGroup(reqVO, 1L);
+
+ // 鏂█锛氭洿鏂颁簡鏁版嵁搴�
+ verify(groupMapper).updateById(any(ImGroupDO.class));
+ assertEquals("鏂板悕瀛�", result.getName());
+ // 鎺ㄩ�� GROUP_NAME_UPDATE 閫氱煡缁欏叏鍛�
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), anyCollection(), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_NAME_UPDATE.getType(), dtoCaptor.getValue().getType());
+ }
+ }
+
+ @Test
+ public void testUpdateGroup_joinApprovalChanged() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗
+ ImGroupDO group = ImGroupDO.builder().id(10L).name("缇�").ownerUserId(1L)
+ .joinApproval(false).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ImGroupUpdateReqVO reqVO = new ImGroupUpdateReqVO();
+ reqVO.setId(10L);
+ reqVO.setJoinApproval(true);
+
+ // 璋冪敤
+ ImGroupDO result = groupService.updateGroup(reqVO, 1L);
+
+ // 鏂█
+ verify(groupMapper).updateById(any(ImGroupDO.class));
+ assertTrue(result.getJoinApproval());
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), anyCollection(), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_INFO_UPDATE.getType(), dtoCaptor.getValue().getType());
+ }
+ }
+
+ @Test
+ public void testUpdateGroup_joinApprovalSame() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗
+ ImGroupDO group = ImGroupDO.builder().id(10L).name("缇�").ownerUserId(1L)
+ .joinApproval(true).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ImGroupUpdateReqVO reqVO = new ImGroupUpdateReqVO();
+ reqVO.setId(10L);
+ reqVO.setJoinApproval(true);
+
+ // 璋冪敤
+ ImGroupDO result = groupService.updateGroup(reqVO, 1L);
+
+ // 鏂█
+ verify(groupMapper).updateById(any(ImGroupDO.class));
+ assertTrue(result.getJoinApproval());
+ verify(groupMessageService, never()).sendGroupMessage(anyLong(), anyCollection(), any());
+ }
+ }
+
+ // ========== dissolveGroup ==========
+
+ @Test
+ public void testDissolveGroup_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗
+ ImGroupDO group = ImGroupDO.builder().id(10L).name("缇�").ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ // 璋冪敤
+ groupService.dissolveGroup(10L, 1L);
+
+ // 鏂█锛氱兢鐘舵�佸彉涓� DISABLE + 缇ゆ垚鍛樺叏閮ㄧЩ闄� + 娓呯悊宸茶缂撳瓨
+ ArgumentCaptor<ImGroupDO> captor = ArgumentCaptor.forClass(ImGroupDO.class);
+ verify(groupMapper).updateById(captor.capture());
+ assertEquals(CommonStatusEnum.DISABLE.getStatus(), captor.getValue().getStatus());
+ assertNotNull(captor.getValue().getDissolvedTime());
+ verify(groupMemberService).removeGroupMembersByGroupId(10L);
+ // 鎺ㄩ�� GROUP_DISSOLVE 閫氱煡锛坰end-before-remove锛宻endGroupMessage 鍐呴儴鏌� active 鑷姩瑕嗙洊鍏ㄥ憳锛屽惈缇や富澶氱鍚屾锛�
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_DISSOLVE.getType(), dtoCaptor.getValue().getType());
+ }
+ }
+
+ @Test
+ public void testDissolveGroup_banned_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗锛氬凡灏佺浣嗘湭瑙f暎鐨勭兢锛岀兢涓讳粛鍙В鏁�
+ ImGroupDO group = ImGroupDO.builder().id(10L).name("缇�").ownerUserId(1L)
+ .banned(true).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ // 璋冪敤
+ groupService.dissolveGroup(10L, 1L);
+
+ // 鏂█锛氬皝绂佺姸鎬佷笉闃绘瑙f暎
+ verify(groupMapper).updateById(argThat((ImGroupDO update) ->
+ CommonStatusEnum.DISABLE.getStatus().equals(update.getStatus())));
+ verify(groupMemberService).removeGroupMembersByGroupId(10L);
+ }
+ }
+
+ @Test
+ public void testDissolveGroupByManager_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗锛氱鐞嗗憳瑙f暎灏佺缇わ紝涓嶈姹傜鐞嗗憳鏄兢涓�
+ ImGroupDO group = ImGroupDO.builder().id(10L).name("缇�").ownerUserId(1L)
+ .banned(true).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ // 璋冪敤
+ groupService.dissolveGroupByManager(99L, 10L);
+
+ // 鏂█锛氫娇鐢ㄧ鐞嗗憳缂栧彿鍙戦�氱煡骞跺畬鎴愭竻鐞�
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(99L), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_DISSOLVE.getType(), dtoCaptor.getValue().getType());
+ verify(groupMemberService).removeGroupMembersByGroupId(10L);
+ }
+ }
+
+ @Test
+ public void testDissolveGroup_notOwner() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.dissolveGroup(10L, 1L));
+ assertEquals(GROUP_NOT_OWNER.getCode(), exception.getCode());
+ }
+ }
+
+ // ========== inviteGroupMember ==========
+
+ @Test
+ public void testInviteGroupMember_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗锛氱兢瀛樺湪 + joinApproval=false锛堣嚜鐢辫繘缇わ級 + 褰撳墠鐢ㄦ埛鏄兢涓�
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .joinApproval(false)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+
+ // 褰撳墠鎴愬憳鍙湁缇や富
+ List<ImGroupMemberDO> activeMembers = new ArrayList<>();
+ activeMembers.add(ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(activeMembers);
+
+ // 琚個璇蜂汉 2 鍜� 3 閮芥槸濂藉弸
+ ImGroupMemberInviteReqVO reqVO = new ImGroupMemberInviteReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(new ArrayList<>(List.of(2L, 3L)));
+ List<ImFriendDO> friends = List.of(
+ ImFriendDO.builder().userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImFriendDO.builder().userId(1L).friendUserId(3L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ );
+ when(friendService.getActiveFriendList(eq(1L), anyCollection())).thenReturn(friends);
+
+ // 璋冪敤
+ groupService.inviteGroupMember(1L, reqVO);
+
+ // 鏂█锛氭牎楠岀兢鎴愬憳 + 鎵归噺娣诲姞鎴愬憳锛堝甫 INVITE 鏉ユ簮 + 閭�璇蜂汉锛�+ 鎺ㄩ�� GROUP_MEMBER_INVITE
+ verify(groupMemberService).validateMemberInGroup(10L, 1L);
+ verify(groupMemberService).addGroupMembers(eq(10L), anyCollection(),
+ eq(ImGroupAddSourceEnum.INVITE.getSource()), eq(1L));
+ verify(groupRequestService, never()).createInviteRequestList(anyLong(), anyLong(), anyCollection());
+ verify(webSocketService, never()).sendNotificationAsync(anyCollection(), anyInt(), anyInt(), any());
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), anyCollection(), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_MEMBER_INVITE.getType(), dtoCaptor.getValue().getType());
+ }
+ }
+
+ @Test
+ public void testInviteGroupMember_approval_normalRoutesToApproval() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗锛歫oinApproval=true锛屽紑鍚鎵癸紱鏅�氭垚鍛橀個璇疯蛋瀹℃壒锛岃惤 group_request
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .joinApproval(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(99L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ ImGroupMemberInviteReqVO reqVO = new ImGroupMemberInviteReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(new ArrayList<>(List.of(2L, 3L)));
+ when(friendService.getActiveFriendList(eq(1L), anyCollection())).thenReturn(List.of(
+ ImFriendDO.builder().userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImFriendDO.builder().userId(1L).friendUserId(3L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ // 璋冪敤
+ groupService.inviteGroupMember(1L, reqVO);
+
+ // 鏂█锛氳蛋瀹℃壒鍒嗘敮锛氳皟 createInviteRequestList锛涗笉鍐欑兢鎴愬憳銆佷笉鎺� 1509
+ verify(groupRequestService).createInviteRequestList(eq(10L), eq(1L), anyCollection());
+ verify(groupMemberService, never()).addGroupMembers(anyLong(), anyCollection(), any(), any());
+ verify(groupMessageService, never()).sendGroupMessage(anyLong(), any(ImGroupMessageSendDTO.class));
+ }
+ }
+
+ @Test
+ public void testInviteGroupMember_approval_ownerBypassesApproval() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗锛歫oinApproval=true锛屼絾閭�璇蜂汉鏄兢涓伙紱瑙嗗悓宸插鎵癸紝鐩磋繘缇�
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .joinApproval(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ ImGroupMemberInviteReqVO reqVO = new ImGroupMemberInviteReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(new ArrayList<>(List.of(2L, 3L)));
+ when(friendService.getActiveFriendList(eq(1L), anyCollection())).thenReturn(List.of(
+ ImFriendDO.builder().userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImFriendDO.builder().userId(1L).friendUserId(3L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ // 璋冪敤
+ groupService.inviteGroupMember(1L, reqVO);
+
+ // 鏂█锛氱粫杩囧鎵癸紝鐩存帴 addGroupMembers + 鎺� 1509锛涗笉钀� group_request
+ verify(groupRequestService, never()).createInviteRequestList(anyLong(), anyLong(), anyCollection());
+ verify(groupMemberService).addGroupMembers(eq(10L), anyCollection(),
+ eq(ImGroupAddSourceEnum.INVITE.getSource()), eq(1L));
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), anyCollection(), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_MEMBER_INVITE.getType(), dtoCaptor.getValue().getType());
+ }
+ }
+
+ @Test
+ public void testInviteGroupMember_notFriend() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L))
+ .thenReturn(List.of(ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ ImGroupMemberInviteReqVO reqVO = new ImGroupMemberInviteReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(new ArrayList<>(List.of(2L, 3L)));
+ // 鍙湁 2 鏄ソ鍙嬶紝3 涓嶆槸
+ when(friendService.getActiveFriendList(eq(1L), anyCollection())).thenReturn(List.of(
+ ImFriendDO.builder().userId(1L).friendUserId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+ AdminUserRespDTO u3 = new AdminUserRespDTO(); u3.setId(3L); u3.setNickname("鏉庡洓");
+ when(adminUserApi.getUserMap(anyCollection())).thenReturn(Map.of(3L, u3));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.inviteGroupMember(1L, reqVO));
+ assertEquals(GROUP_INVITE_NOT_FRIEND.getCode(), exception.getCode());
+ }
+ }
+
+ @Test
+ public void testInviteGroupMember_memberExceed() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗锛氱兢 10 宸叉湁 499 浜猴紙閫艰繎 MAX_GROUP_MEMBER=500锛夛紝鍐嶉個璇� 2 浜� 鈫� 501 瓒呴檺
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ List<ImGroupMemberDO> activeMembers = new ArrayList<>();
+ for (long i = 1; i <= 499; i++) {
+ activeMembers.add(ImGroupMemberDO.builder().groupId(10L).userId(i)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ }
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(activeMembers);
+
+ ImGroupMemberInviteReqVO reqVO = new ImGroupMemberInviteReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(new ArrayList<>(List.of(600L, 601L)));
+ // 琚個璇蜂汉閮芥槸濂藉弸
+ when(friendService.getActiveFriendList(eq(1L), anyCollection())).thenReturn(List.of(
+ ImFriendDO.builder().userId(1L).friendUserId(600L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImFriendDO.builder().userId(1L).friendUserId(601L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ ));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.inviteGroupMember(1L, reqVO));
+ assertEquals(GROUP_MEMBER_EXCEED.getCode(), exception.getCode());
+ // 鏂█锛氫笉鍔犳垚鍛樸�佷笉鎺ㄩ��
+ verify(groupMemberService, never()).addGroupMembers(anyLong(), anyCollection());
+ }
+ }
+
+ @Test
+ public void testInviteGroupMember_skipsMembersAlreadyInGroup() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ // 鍑嗗
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ // 鐢ㄦ埛 2 宸插湪缇や腑
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ ));
+
+ ImGroupMemberInviteReqVO reqVO = new ImGroupMemberInviteReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(new ArrayList<>(List.of(2L))); // 鍙個璇� 2锛屼粬宸插湪缇や腑
+
+ // 璋冪敤
+ groupService.inviteGroupMember(1L, reqVO);
+
+ // 鏂█锛氫笉浼氳Е鍙戞坊鍔犮�佷笉浼氭帹閫�
+ verify(groupMemberService, never()).addGroupMembers(anyLong(), anyCollection());
+ verify(webSocketService, never()).sendNotificationAsync(anyCollection(), anyInt(), anyInt(), any());
+ }
+ }
+
+ // ========== quitGroup ==========
+
+ @Test
+ public void testQuitGroup_ownerCannotQuit() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.quitGroup(10L, 1L));
+ assertEquals(GROUP_OWNER_CANNOT_QUIT.getCode(), exception.getCode());
+ }
+ }
+
+ @Test
+ public void testQuitGroup_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ groupService.quitGroup(10L, 1L);
+
+ verify(groupMemberService).removeGroupMember(10L, 1L);
+ // 鎺ㄩ�� GROUP_MEMBER_QUIT 閫氱煡缁欏叏鍛橈紙鍚� quitter锛屽墠绔嚜鍒ゆ竻缇わ級
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_MEMBER_QUIT.getType(), dtoCaptor.getValue().getType());
+ }
+ }
+
+ @Test
+ public void testQuitGroup_bannedGroupAllowed() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .banned(true).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ groupService.quitGroup(10L, 1L);
+
+ verify(groupMemberService).removeGroupMember(10L, 1L);
+ verify(groupMessageService).sendGroupMessage(eq(1L), any(ImGroupMessageSendDTO.class));
+ }
+ }
+
+ // ========== removeGroupMember ==========
+
+ @Test
+ public void testRemoveGroupMember_cannotRemoveSelf() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole()).build());
+
+ ImGroupMemberRemoveReqVO reqVO = new ImGroupMemberRemoveReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(List.of(1L, 2L));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.removeGroupMember(1L, reqVO));
+ assertEquals(GROUP_CANNOT_REMOVE_SELF.getCode(), exception.getCode());
+ }
+ }
+
+ @Test
+ public void testRemoveGroupMember_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ // 鎿嶄綔鑰咃細缇や富
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole()).build());
+ // 鐩爣锛氫袱涓櫘閫氭垚鍛�
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(3L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ ImGroupMemberRemoveReqVO reqVO = new ImGroupMemberRemoveReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(List.of(2L, 3L));
+
+ groupService.removeGroupMember(1L, reqVO);
+
+ verify(groupMemberService).removeGroupMembers(eq(10L), anyCollection());
+ // 鎺ㄩ�� GROUP_MEMBER_KICK 閫氱煡缁欏叏鍛橈紙鍚韪㈣�咃紝鍓嶇鑷垽娓呯兢锛�
+ ArgumentCaptor<ImGroupMessageSendDTO> dtoCaptor = ArgumentCaptor.forClass(ImGroupMessageSendDTO.class);
+ verify(groupMessageService).sendGroupMessage(eq(1L), dtoCaptor.capture());
+ assertEquals(ImContentTypeEnum.GROUP_MEMBER_KICK.getType(), dtoCaptor.getValue().getType());
+ }
+ }
+
+ @Test
+ public void testRemoveGroupMember_adminCannotRemoveAdmin() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ // 鎿嶄綔鑰咃細绠$悊鍛�
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole()).build());
+ // 鐩爣锛氬彟涓�涓鐞嗗憳
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ ImGroupMemberRemoveReqVO reqVO = new ImGroupMemberRemoveReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(List.of(2L));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.removeGroupMember(1L, reqVO));
+ assertEquals(GROUP_REMOVE_ADMIN_DENIED.getCode(), exception.getCode());
+ verify(groupMemberService, never()).removeGroupMembers(anyLong(), anyCollection());
+ }
+ }
+
+ @Test
+ public void testRemoveGroupMember_ownerCannotBeRemoved() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ // 鎿嶄綔鑰咃細缇や富锛堜笉鑳借涪鑷繁锛涜繖閲屾崲鎴愬彟涓�涓� userId 鐨勭兢涓昏涔� 鈥� 鐢� ADMIN 鎿嶄綔缇や富锛�
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole()).build());
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(99L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()));
+
+ ImGroupMemberRemoveReqVO reqVO = new ImGroupMemberRemoveReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(List.of(99L));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.removeGroupMember(1L, reqVO));
+ assertEquals(GROUP_REMOVE_OWNER_DENIED.getCode(), exception.getCode());
+ }
+ }
+
+ @Test
+ public void testRemoveGroupMember_skipInactiveTargets() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ // 鎿嶄綔鑰咃細缇や富
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.OWNER.getRole()).build());
+ // 鐩爣锛�2L 鏈夋晥鏅�氭垚鍛橈紱3L 宸查��缇わ紙DISABLE锛夌殑鍘嗗彶绠$悊鍛橈紝搴旇璺宠繃鑰岄潪鎷︽埅鏁存壒
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole())
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(3L)
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole())
+ .status(CommonStatusEnum.DISABLE.getStatus()).build()));
+
+ ImGroupMemberRemoveReqVO reqVO = new ImGroupMemberRemoveReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMemberUserIds(List.of(2L, 3L));
+
+ groupService.removeGroupMember(1L, reqVO);
+
+ // 浠呮湁鏁堟垚鍛� 2L 杩涘叆绉婚櫎锛屽凡閫�缇ょ殑 3L 琚烦杩�
+ ArgumentCaptor<Collection> removeCaptor = ArgumentCaptor.forClass(Collection.class);
+ verify(groupMemberService).removeGroupMembers(eq(10L), removeCaptor.capture());
+ assertEquals(Set.of(2L), Set.copyOf(removeCaptor.getValue()));
+ }
+ }
+
+ // ========== addGroupAdmin ==========
+
+ @Test
+ public void testAddGroupAdmin_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+ // 鐩爣 3 鏄櫘閫氭垚鍛�
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().userId(3L).status(CommonStatusEnum.ENABLE.getStatus())
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build()));
+ // 缇ら噷宸叉湁 1 涓� ADMIN锛�1 + 1 鈮� 3 涓嶈秴涓婇檺
+ when(groupMemberService.getGroupMemberCountByRole(10L, ImGroupMemberRoleEnum.ADMIN.getRole()))
+ .thenReturn(1L);
+ when(groupMemberService.updateGroupMemberRole(eq(10L), anyCollection(),
+ eq(ImGroupMemberRoleEnum.ADMIN.getRole()))).thenReturn(1);
+
+ ImGroupAdminAddReqVO reqVO = new ImGroupAdminAddReqVO();
+ reqVO.setId(10L);
+ reqVO.setUserIds(List.of(3L));
+
+ groupService.addGroupAdmin(1L, reqVO);
+
+ verify(groupMemberService).updateGroupMemberRole(eq(10L), argThat((Set<Long> ids) ->
+ ids.size() == 1 && ids.contains(3L)),
+ eq(ImGroupMemberRoleEnum.ADMIN.getRole()));
+ }
+ }
+
+ @Test
+ public void testAddGroupAdmin_exceedsLimit() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().userId(5L).status(CommonStatusEnum.ENABLE.getStatus())
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build()));
+ // 缇ら噷宸叉湁 3 涓� ADMIN锛堣揪鍒颁笂闄愶級锛屽啀鍔� 1 浼氳秴
+ when(groupMemberService.getGroupMemberCountByRole(10L, ImGroupMemberRoleEnum.ADMIN.getRole()))
+ .thenReturn(3L);
+
+ ImGroupAdminAddReqVO reqVO = new ImGroupAdminAddReqVO();
+ reqVO.setId(10L);
+ reqVO.setUserIds(List.of(5L));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.addGroupAdmin(1L, reqVO));
+ assertEquals(GROUP_ADMIN_MAX_LIMIT.getCode(), exception.getCode());
+ verify(groupMemberService, never()).updateGroupMemberRole(anyLong(), anyCollection(), anyInt());
+ }
+ }
+
+ @Test
+ public void testAddGroupAdmin_targetIsOwner() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().userId(1L).status(CommonStatusEnum.ENABLE.getStatus())
+ .role(ImGroupMemberRoleEnum.OWNER.getRole()).build()));
+
+ ImGroupAdminAddReqVO reqVO = new ImGroupAdminAddReqVO();
+ reqVO.setId(10L);
+ reqVO.setUserIds(List.of(1L));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.addGroupAdmin(1L, reqVO));
+ assertEquals(GROUP_ADMIN_TARGET_IS_OWNER.getCode(), exception.getCode());
+ }
+ }
+
+ @Test
+ public void testAddGroupAdmin_idempotentSkipWhenAlreadyAdmin() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+ // 鐩爣宸叉槸 ADMIN锛氬啀鍔犳棤闇�鎿嶄綔
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().userId(2L).status(CommonStatusEnum.ENABLE.getStatus())
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole()).build()));
+
+ ImGroupAdminAddReqVO reqVO = new ImGroupAdminAddReqVO();
+ reqVO.setId(10L);
+ reqVO.setUserIds(List.of(2L));
+
+ groupService.addGroupAdmin(1L, reqVO);
+
+ verify(groupMemberService, never()).updateGroupMemberRole(anyLong(), anyCollection(), anyInt());
+ verify(groupMemberService, never()).getGroupMemberCountByRole(anyLong(), anyInt());
+ }
+ }
+
+ // ========== removeGroupAdmin ==========
+
+ @Test
+ public void testRemoveGroupAdmin_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().userId(2L).status(CommonStatusEnum.ENABLE.getStatus())
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole()).build()));
+ when(groupMemberService.updateGroupMemberRole(eq(10L), anyCollection(),
+ eq(ImGroupMemberRoleEnum.NORMAL.getRole()))).thenReturn(1);
+
+ ImGroupAdminRemoveReqVO reqVO = new ImGroupAdminRemoveReqVO();
+ reqVO.setId(10L);
+ reqVO.setUserIds(List.of(2L));
+
+ groupService.removeGroupAdmin(1L, reqVO);
+
+ verify(groupMemberService).updateGroupMemberRole(eq(10L), argThat((Set<Long> ids) ->
+ ids.size() == 1 && ids.contains(2L)),
+ eq(ImGroupMemberRoleEnum.NORMAL.getRole()));
+ }
+ }
+
+ @Test
+ public void testRemoveGroupAdmin_idempotentSkipWhenAlreadyMember() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+ // 鐩爣宸叉槸 MEMBER锛氭挙閿�鏃犻渶鎿嶄綔
+ when(groupMemberService.getGroupMembers(eq(10L), anyCollection())).thenReturn(List.of(
+ ImGroupMemberDO.builder().userId(2L).status(CommonStatusEnum.ENABLE.getStatus())
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build()));
+
+ ImGroupAdminRemoveReqVO reqVO = new ImGroupAdminRemoveReqVO();
+ reqVO.setId(10L);
+ reqVO.setUserIds(List.of(2L));
+
+ groupService.removeGroupAdmin(1L, reqVO);
+
+ verify(groupMemberService, never()).updateGroupMemberRole(anyLong(), anyCollection(), anyInt());
+ }
+ }
+
+ // ========== transferGroupOwner ==========
+
+ @Test
+ public void testTransferGroupOwner_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+ when(groupMemberService.validateMemberInGroup(10L, 2L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build());
+ when(groupMemberService.updateGroupMemberRole(eq(10L), eq(Set.of(2L)),
+ eq(ImGroupMemberRoleEnum.OWNER.getRole()))).thenReturn(1);
+ when(groupMemberService.updateGroupMemberRole(eq(10L), eq(Set.of(1L)),
+ eq(ImGroupMemberRoleEnum.NORMAL.getRole()))).thenReturn(1);
+
+ ImGroupTransferOwnerReqVO reqVO = new ImGroupTransferOwnerReqVO();
+ reqVO.setId(10L);
+ reqVO.setNewOwnerUserId(2L);
+
+ groupService.transferGroupOwner(1L, reqVO);
+
+ // 缇よ〃 owner 鍒囨崲
+ ArgumentCaptor<ImGroupDO> groupCaptor = ArgumentCaptor.forClass(ImGroupDO.class);
+ verify(groupMapper).updateById(groupCaptor.capture());
+ assertEquals(2L, groupCaptor.getValue().getOwnerUserId());
+ // 鏃х兢涓� 鈫� MEMBER锛涙柊缇や富 鈫� OWNER
+ verify(groupMemberService).updateGroupMemberRole(eq(10L), eq(Set.of(1L)),
+ eq(ImGroupMemberRoleEnum.NORMAL.getRole()));
+ verify(groupMemberService).updateGroupMemberRole(eq(10L), eq(Set.of(2L)),
+ eq(ImGroupMemberRoleEnum.OWNER.getRole()));
+ }
+ }
+
+ @Test
+ public void testTransferGroupOwner_toSelf() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+
+ ImGroupTransferOwnerReqVO reqVO = new ImGroupTransferOwnerReqVO();
+ reqVO.setId(10L);
+ reqVO.setNewOwnerUserId(1L);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.transferGroupOwner(1L, reqVO));
+ assertEquals(GROUP_TRANSFER_OWNER_TO_SELF.getCode(), exception.getCode());
+ verify(groupMapper, never()).updateById(any(ImGroupDO.class));
+ }
+ }
+
+ @Test
+ public void testTransferGroupOwner_notOwner() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).ownerUserId(99L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectByIdForUpdate(10L)).thenReturn(group);
+
+ ImGroupTransferOwnerReqVO reqVO = new ImGroupTransferOwnerReqVO();
+ reqVO.setId(10L);
+ reqVO.setNewOwnerUserId(2L);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.transferGroupOwner(1L, reqVO));
+ assertEquals(GROUP_NOT_OWNER.getCode(), exception.getCode());
+ }
+ }
+
+ // ========== banGroup ==========
+
+ @Test
+ public void testBanGroup_dissolved() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).status(CommonStatusEnum.DISABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ImGroupManagerBanReqVO reqVO = new ImGroupManagerBanReqVO();
+ reqVO.setId(10L).setReason("杩濊");
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.banGroup(1L, reqVO));
+ assertEquals(GROUP_DISSOLVED.getCode(), exception.getCode());
+ verify(groupMapper, never()).updateById(any(ImGroupDO.class));
+ verify(groupMessageService, never()).sendGroupMessage(anyLong(), any(ImGroupMessageSendDTO.class));
+ }
+ }
+
+ @Test
+ public void testBanGroup_alreadyBannedSkip() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).banned(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ImGroupManagerBanReqVO reqVO = new ImGroupManagerBanReqVO();
+ reqVO.setId(10L).setReason("杩濊");
+
+ groupService.banGroup(1L, reqVO);
+
+ verify(groupMapper, never()).updateById(any(ImGroupDO.class));
+ verify(groupMessageService, never()).sendGroupMessage(anyLong(), any(ImGroupMessageSendDTO.class));
+ }
+ }
+
+ // ========== muteMember ==========
+
+ @Test
+ public void testMuteMember_normalCannotMuteAdmin() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build());
+ when(groupMemberService.validateMemberInGroup(10L, 2L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .role(ImGroupMemberRoleEnum.ADMIN.getRole()).build());
+
+ ImGroupMuteMemberReqVO reqVO = new ImGroupMuteMemberReqVO();
+ reqVO.setId(10L).setUserId(2L).setMutedSeconds(60);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.muteMember(1L, reqVO));
+ assertEquals(GROUP_NOT_OWNER_OR_ADMIN.getCode(), exception.getCode());
+ verify(groupMemberService, never()).updateGroupMemberMuteEndTime(anyLong(), anyLong(), any());
+ verify(groupMessageService, never()).sendGroupMessage(anyLong(), any(ImGroupMessageSendDTO.class));
+ }
+ }
+
+ // ========== validateGroupExists ==========
+
+ @Test
+ public void testValidateGroupExists_notExists() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ when(groupMapper.selectById(10L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.validateGroupExists(10L));
+ assertEquals(GROUP_NOT_EXISTS.getCode(), exception.getCode());
+ }
+ }
+
+ @Test
+ public void testValidateGroupExists_banned() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L).banned(true)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.validateGroupExists(10L));
+ assertEquals(GROUP_BANNED.getCode(), exception.getCode());
+ }
+ }
+
+ @Test
+ public void testValidateGroupExists_dissolved() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupServiceImpl.class)))
+ .thenReturn(groupService);
+
+ ImGroupDO group = ImGroupDO.builder().id(10L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build();
+ when(groupMapper.selectById(10L)).thenReturn(group);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupService.validateGroupExists(10L));
+ assertEquals(GROUP_DISSOLVED.getCode(), exception.getCode());
+ }
+ }
+
+ // ========== getMyGroupList ==========
+
+ @Test
+ public void testGetMyGroupList_noMembers() {
+ when(groupMemberService.getGroupMemberListByUserId(1L)).thenReturn(new ArrayList<>());
+
+ List<ImGroupDO> result = groupService.getMyGroupList(1L);
+ assertTrue(result.isEmpty());
+ verify(groupMapper, never()).selectByIds(anyCollection());
+ }
+
+ @Test
+ public void testGetMyGroupList_success() {
+ // 鏇剧粡鍔犲叆鐨勬墍鏈夌兢锛堝惈閫�缇わ級
+ when(groupMemberService.getGroupMemberListByUserId(1L)).thenReturn(new ArrayList<>(List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(20L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupMemberDO.builder().groupId(30L).userId(1L)
+ .status(CommonStatusEnum.DISABLE.getStatus()).build()
+ )));
+ List<ImGroupDO> groups = List.of(
+ ImGroupDO.builder().id(10L).status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupDO.builder().id(20L).status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImGroupDO.builder().id(30L).status(CommonStatusEnum.ENABLE.getStatus()).build()
+ );
+ when(groupMapper.selectByIds(anyCollection())).thenReturn(groups);
+
+ List<ImGroupDO> result = groupService.getMyGroupList(1L);
+ assertEquals(3, result.size());
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImplTest.java
new file mode 100644
index 0000000..bbe516a
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImChannelMessageServiceImplTest.java
@@ -0,0 +1,94 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImChannelMessageDO;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImChannelMessageMapper;
+import cn.iocoder.yudao.module.im.service.channel.ImChannelMaterialService;
+import cn.iocoder.yudao.module.im.service.conversation.ImConversationReadService;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImChannelMessageServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImChannelMessageServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImChannelMessageServiceImpl channelMessageService;
+
+ @Mock
+ private ImChannelMessageMapper channelMessageMapper;
+ @Mock
+ private ImChannelMaterialService channelMaterialService;
+ @Mock
+ private ImWebSocketService webSocketService;
+ @Mock
+ private ImConversationReadService conversationReadService;
+
+ @Test
+ public void testReadChannelMessages_messageNotExists() {
+ // 鍑嗗锛歮essageId 涓嶅瓨鍦紙浼�� / 鏈潵 id锛�
+ when(channelMessageMapper.selectById(999L)).thenReturn(null);
+
+ // 璋冪敤
+ channelMessageService.readChannelMessages(1L, 10L, 999L);
+
+ // 鏂█锛氫笉鎺ㄨ繘璇讳綅缃�
+ verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void testReadChannelMessages_wrongChannel() {
+ // 鍑嗗锛氭秷鎭睘浜庡埆鐨勯閬�
+ ImChannelMessageDO message = ImChannelMessageDO.builder()
+ .id(100L).channelId(20L).sendTime(LocalDateTime.now()).build();
+ when(channelMessageMapper.selectById(100L)).thenReturn(message);
+
+ // 璋冪敤锛氬0绉拌鐨勬槸棰戦亾 10
+ channelMessageService.readChannelMessages(1L, 10L, 100L);
+
+ // 鏂█锛氫笉鎺ㄨ繘璇讳綅缃�
+ verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void testReadChannelMessages_notVisible() {
+ // 鍑嗗锛氬畾鍚戞秷鎭紝鎺ユ敹浜轰笉鍚綋鍓嶇敤鎴�
+ ImChannelMessageDO message = ImChannelMessageDO.builder()
+ .id(100L).channelId(10L).receiverUserIds(List.of(2L, 3L)).sendTime(LocalDateTime.now()).build();
+ when(channelMessageMapper.selectById(100L)).thenReturn(message);
+
+ // 璋冪敤
+ channelMessageService.readChannelMessages(1L, 10L, 100L);
+
+ // 鏂█锛氫笉鎺ㄨ繘璇讳綅缃�
+ verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void testReadChannelMessages_notAdvanced() {
+ // 鍑嗗锛氭秷鎭湡瀹炲彲瑙侊紝浣嗚浣嶇疆鏈墠杩涳紙updateConversationReadPosition 杩斿洖 false锛�
+ ImChannelMessageDO message = ImChannelMessageDO.builder()
+ .id(100L).channelId(10L).sendTime(LocalDateTime.now()).build();
+ when(channelMessageMapper.selectById(100L)).thenReturn(message);
+ when(conversationReadService.updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong()))
+ .thenReturn(false);
+
+ // 璋冪敤
+ channelMessageService.readChannelMessages(1L, 10L, 100L);
+
+ // 鏂█锛氳浣嶇疆鏈墠杩� 鈫� 涓嶆帹 READ 浜嬩欢
+ verify(webSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImplTest.java
new file mode 100644
index 0000000..ffa1bb5
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImGroupMessageServiceImplTest.java
@@ -0,0 +1,1052 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageListReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.group.ImGroupMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImGroupMessageDO;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImGroupMessageMapper;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.group.ImGroupMemberRoleEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.conversation.ImConversationReadService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.im.service.group.ImGroupService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImGroupMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.sensitiveword.ImSensitiveWordService;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImGroupMessageNotification;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.RecallMessage;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Spy;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImGroupMessageServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImGroupMessageServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImGroupMessageServiceImpl groupMessageService;
+
+ @Mock
+ private ImGroupMessageMapper groupMessageMapper;
+ @Mock
+ private ImGroupService groupService;
+ @Mock
+ private ImGroupMemberService groupMemberService;
+ @Mock
+ private ImSensitiveWordService sensitiveWordService;
+ @Mock
+ private ImConversationReadService conversationReadService;
+ @Mock
+ private ImWebSocketService imWebSocketService;
+
+ @Spy
+ private ImProperties imProperties = new ImProperties();
+
+ private ImGroupMessageSendReqVO buildSendReqVO() {
+ ImGroupMessageSendReqVO reqVO = new ImGroupMessageSendReqVO();
+ reqVO.setClientMessageId("test-uuid-group-001");
+ reqVO.setGroupId(10L);
+ reqVO.setType(ImContentTypeEnum.TEXT.getType());
+ reqVO.setContent("{\"content\":\"缇よ亰浣犲ソ\"}");
+ return reqVO;
+ }
+
+ // ========== 鍙戦�佹祴璇� ==========
+
+ @Test
+ public void testSendMessage_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupMessageServiceImpl.class)))
+ .thenReturn(groupMessageService);
+
+ // 鍑嗗
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ reqVO.setReceipt(true);
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001"))
+ .thenReturn(null);
+ ImGroupDO group = new ImGroupDO();
+ group.setId(10L);
+ group.setName("娴嬭瘯缇�");
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+
+ ImGroupMemberDO member = ImGroupMemberDO.builder()
+ .groupId(10L).userId(1L).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(member);
+
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L))
+ .thenReturn(List.of(1L, 2L, 3L));
+ when(groupMessageMapper.insert(any(ImGroupMessageDO.class))).thenAnswer(invocation -> {
+ ImGroupMessageDO msg = invocation.getArgument(0);
+ msg.setId(99L);
+ return 1;
+ });
+
+ // 璋冪敤
+ ImGroupMessageDO result = groupMessageService.sendGroupMessage(1L, reqVO);
+
+ // 鏂█
+ assertNotNull(result);
+ assertEquals(1L, result.getSenderId());
+ assertEquals(10L, result.getGroupId());
+ assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), result.getStatus());
+ assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), result.getReceiptStatus());
+
+ // 楠岃瘉鎺ㄩ�佺粰 3 涓兢鎴愬憳锛堝惈鍙戦�佽�呰嚜宸憋紝鐢ㄤ簬澶氱鍚屾锛�
+ ArgumentCaptor<ImGroupMessageNotification> payloadCaptor =
+ ArgumentCaptor.forClass(ImGroupMessageNotification.class);
+ verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) ->
+ ids.size() == 3 && ids.contains(1L) && ids.contains(2L) && ids.contains(3L)),
+ eq(ImConversationTypeEnum.GROUP.getType()), eq(ImContentTypeEnum.TEXT.getType()),
+ payloadCaptor.capture());
+ ImGroupMessageNotification payload = payloadCaptor.getValue();
+ assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), payload.getReceiptStatus());
+ assertEquals(0, payload.getReadCount());
+ assertEquals(List.of(1L, 2L, 3L), payload.getReceiverUserIds());
+ }
+ }
+
+ @Test
+ public void testSendMessage_senderAlwaysVisible() {
+ // 杈圭晫锛氭垚鍛樼紦瀛樻紡鎺夊彂閫佽�咃紙鐞嗚涓� validateMemberInGroup 宸叉尅锛岃繖閲岀函闃插尽锛夛紱鍙戦�佽�呬粛蹇呴』鍥哄寲杩� receiver_user_ids
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupMessageServiceImpl.class)))
+ .thenReturn(groupMessageService);
+
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001"))
+ .thenReturn(null);
+ ImGroupDO group = new ImGroupDO();
+ group.setId(10L);
+ group.setName("娴嬭瘯缇�");
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ ImGroupMemberDO member = ImGroupMemberDO.builder()
+ .groupId(10L).userId(1L).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(member);
+ // 鎴愬憳缂撳瓨鍙繑鍥� {2,3}锛屾紡鎺夊彂閫佽�� 1
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L))
+ .thenReturn(List.of(2L, 3L));
+ when(groupMessageMapper.insert(any(ImGroupMessageDO.class))).thenAnswer(invocation -> {
+ ImGroupMessageDO msg = invocation.getArgument(0);
+ msg.setId(99L);
+ return 1;
+ });
+
+ ImGroupMessageDO result = groupMessageService.sendGroupMessage(1L, reqVO);
+
+ // 鏂█锛氬浐鍖栧揩鐓у繀鍚彂閫佽�咃紝鎺ㄩ�佺洰鏍囪ˉ鍥炲彂閫佽�� = {1,2,3}
+ assertTrue(result.getReceiverUserIds().contains(1L), "鍙戦�佽�呭繀椤诲湪 receiver_user_ids 蹇収鍐�");
+ verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) ->
+ ids.size() == 3 && ids.contains(1L) && ids.contains(2L) && ids.contains(3L)),
+ anyInt(), anyInt(), any());
+ }
+ }
+
+ @Test
+ public void testSendMessage_clientMessageIdIdempotent() {
+ // 鍑嗗
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ ImGroupMessageDO existing = ImGroupMessageDO.builder()
+ .id(100L).clientMessageId("test-uuid-group-001").senderId(1L).groupId(10L)
+ .type(0).content("{\"content\":\"缇よ亰浣犲ソ\"}").status(0)
+ .sendTime(LocalDateTime.now()).build();
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001"))
+ .thenReturn(existing);
+
+ // 璋冪敤
+ ImGroupMessageDO result = groupMessageService.sendGroupMessage(1L, reqVO);
+
+ // 鏂█
+ assertEquals(100L, result.getId());
+ verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class));
+ }
+
+ @Test
+ public void testSendMessage_notInGroup() {
+ // 鍑嗗
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001"))
+ .thenReturn(null);
+ ImGroupDO group = new ImGroupDO();
+ group.setId(10L);
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ when(groupMemberService.validateMemberInGroup(10L, 1L))
+ .thenThrow(new ServiceException(GROUP_MEMBER_NOT_IN_GROUP.getCode(), GROUP_MEMBER_NOT_IN_GROUP.getMsg()));
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.sendGroupMessage(1L, reqVO));
+ assertEquals(GROUP_MEMBER_NOT_IN_GROUP.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testSendMessage_quoteDirectedMessageRejected() {
+ // 鍑嗗锛氬彂閫佷汉 1 鍦ㄧ兢 10锛屽綋鍓嶆湁鏁堟垚鍛橈紙骞挎挱鍙椾紬锛�= {1,2,3}
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ reqVO.setContent("{\"content\":\"寮曠敤\",\"quote\":{\"messageId\":500}}");
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001")).thenReturn(null);
+ ImGroupDO group = new ImGroupDO();
+ group.setId(10L);
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ ImGroupMemberDO member = ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(member);
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L, 2L, 3L));
+ // 琚紩鐢ㄥ師娑堟伅锛氬畾鍚戠粰 {1,2}锛堝鍙戦�佷汉 1 鍙锛屼絾涓嶈鐩栧箍鎾彈浼� {1,2,3}锛�
+ ImGroupMessageDO original = ImGroupMessageDO.builder().id(500L).groupId(10L).senderId(2L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus()).receiverUserIds(List.of(1L, 2L))
+ .type(ImContentTypeEnum.TEXT.getType()).content("{\"content\":\"瀵哱"}")
+ .sendTime(LocalDateTime.now()).build();
+ when(groupMessageMapper.selectById(500L)).thenReturn(original);
+
+ // 璋冪敤骞舵柇瑷�锛氬紩鐢ㄥ畾鍚戞秷鎭鎷掔粷锛岄伩鍏嶅師鏂囬殢骞挎挱娉勬紡缁欏叏缇�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.sendGroupMessage(1L, reqVO));
+ assertEquals(MESSAGE_QUOTE_INVALID.getCode(), exception.getCode());
+ verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class));
+ }
+
+ @Test
+ public void testSendMessage_quoteBroadcastAccepted() {
+ // 鍑嗗锛氬箍鎾彈浼� {1,2,3}锛岃寮曠敤鍘熸秷鎭揩鐓ц鐩栧叏閮ㄥ彈浼� 鈫� 鍏佽寮曠敤
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ reqVO.setContent("{\"content\":\"寮曠敤\",\"quote\":{\"messageId\":500}}");
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001")).thenReturn(null);
+ ImGroupDO group = new ImGroupDO();
+ group.setId(10L);
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ ImGroupMemberDO member = ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(member);
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L, 2L, 3L));
+ ImGroupMessageDO original = ImGroupMessageDO.builder().id(500L).groupId(10L).senderId(2L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus()).receiverUserIds(List.of(1L, 2L, 3L))
+ .type(ImContentTypeEnum.TEXT.getType()).content("{\"content\":\"鍏紑\"}")
+ .sendTime(LocalDateTime.now()).build();
+ when(groupMessageMapper.selectById(500L)).thenReturn(original);
+ when(groupMessageMapper.insert(any(ImGroupMessageDO.class))).thenAnswer(invocation -> {
+ invocation.<ImGroupMessageDO>getArgument(0).setId(99L);
+ return 1;
+ });
+
+ // 璋冪敤骞舵柇瑷�锛氭甯稿叆搴�
+ ImGroupMessageDO result = groupMessageService.sendGroupMessage(1L, reqVO);
+ assertEquals(99L, result.getId());
+ verify(groupMessageMapper).insert(any(ImGroupMessageDO.class));
+ }
+
+ // ========== pull 娴嬭瘯 ==========
+
+ @Test
+ public void testPullMessages_doesNotOverwriteStatus() {
+ // 鍑嗗锛氭媺鍒颁袱鏉℃秷鎭紱Phase 2 璧� pull 涓嶅啀鎸夎浣嶇疆瑕嗙洊 status锛屽凡璇荤敱鍓嶇鎸夎浣嶇疆鍒ゆ柇
+ LocalDateTime now = LocalDateTime.now();
+ ImGroupMemberDO member = ImGroupMemberDO.builder()
+ .groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(now.minusDays(10)).build();
+ when(groupMemberService.getGroupMemberListByUserId(1L)).thenReturn(List.of(member));
+
+ ImGroupMessageDO low = ImGroupMessageDO.builder()
+ .id(5L).groupId(10L).senderId(2L).receiverUserIds(List.of(1L))
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(now.minusHours(2)).build();
+ ImGroupMessageDO high = ImGroupMessageDO.builder()
+ .id(10L).groupId(10L).senderId(2L).receiverUserIds(List.of(1L))
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(now.minusHours(1)).build();
+ when(groupMessageMapper.selectListByMinId(eq(1L), anyCollection(), eq(0L),
+ any(LocalDateTime.class), eq(100)))
+ .thenReturn(List.of(low, high));
+
+ List<ImGroupMessageDO> result = groupMessageService.pullGroupMessageList(1L, 0L, 100);
+
+ // 鏂█锛歴tatus 淇濇寔 DB 鍘熷�硷紙閮� NORMAL锛夛紝pull 涓嶈鐩�
+ assertEquals(2, result.size());
+ assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), result.get(0).getStatus());
+ assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), result.get(1).getStatus());
+ }
+
+ @Test
+ public void testPullMessages_receiptReadCountForSender() {
+ // 鍑嗗锛氭湰浜哄彂閫佺殑鍥炴墽娑堟伅锛屽彲瑙佹垚鍛� {1,2,3}锛屽垎姣嶆帓闄ゅ彂閫佽�呭悗涓� {2,3}
+ LocalDateTime now = LocalDateTime.now();
+ ImGroupMemberDO member = ImGroupMemberDO.builder()
+ .groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(now.minusDays(10)).build();
+ when(groupMemberService.getGroupMemberListByUserId(1L)).thenReturn(List.of(member));
+
+ ImGroupMessageDO receiptMsg = ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(1L)
+ .receiverUserIds(List.of(1L, 2L, 3L))
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .receiptStatus(ImMessageReceiptStatusEnum.PENDING.getStatus())
+ .sendTime(now.minusHours(1)).build();
+ when(groupMessageMapper.selectListByMinId(eq(1L), anyCollection(), eq(0L),
+ any(LocalDateTime.class), eq(100)))
+ .thenReturn(List.of(receiptMsg));
+
+ Map<Long, Long> positions = new HashMap<>();
+ positions.put(1L, 100L);
+ positions.put(2L, 100L);
+ positions.put(3L, 50L);
+ when(conversationReadService.getUserReadMessageIdMap(eq(ImConversationTypeEnum.GROUP.getType()), eq(10L)))
+ .thenReturn(positions);
+
+ List<ImGroupMemberDO> allMembers = List.of(
+ member,
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(now.minusDays(20)).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(3L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(now.minusDays(20)).build()
+ );
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(allMembers);
+
+ List<ImGroupMessageDO> result = groupMessageService.pullGroupMessageList(1L, 0L, 100);
+
+ // 鏂█锛氬垎姣� {2,3}锛屼粎鐢ㄦ埛 2 璇诲埌 >=100 鈫� readCount==1
+ assertEquals(1, result.size());
+ assertEquals(1, result.get(0).getReadCount());
+ }
+
+ @Test
+ public void testPullMessages_noReceiptMessageSkipsReadCount() {
+ // 鍑嗗锛氭湰浜哄彂閫佷絾涓嶉渶瑕佸洖鎵э紙NO_RECEIPT锛夌殑娑堟伅鈥斺�斾笉琛� readCount锛宻tatus 涔熶笉琚鐩�
+ LocalDateTime now = LocalDateTime.now();
+ ImGroupMemberDO member = ImGroupMemberDO.builder()
+ .groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(now.minusDays(10)).build();
+ when(groupMemberService.getGroupMemberListByUserId(1L)).thenReturn(List.of(member));
+
+ ImGroupMessageDO noReceiptMsg = ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(1L)
+ .receiverUserIds(List.of(1L, 2L, 3L))
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .receiptStatus(ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus())
+ .sendTime(now.minusHours(1)).build();
+ when(groupMessageMapper.selectListByMinId(eq(1L), anyCollection(), eq(0L),
+ any(LocalDateTime.class), eq(100)))
+ .thenReturn(List.of(noReceiptMsg));
+
+ List<ImGroupMessageDO> result = groupMessageService.pullGroupMessageList(1L, 0L, 100);
+
+ // 鏂█锛歴tatus 淇濇寔 NORMAL锛坧ull 涓嶈鐩栵級锛孨O_RECEIPT 涓嶈ˉ readCount锛屼篃涓嶆煡 readCount 鐩稿叧鐨勮浣嶇疆鏄犲皠
+ assertEquals(1, result.size());
+ assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), result.get(0).getStatus());
+ assertNull(result.get(0).getReadCount());
+ verify(conversationReadService, never()).getUserReadMessageIdMap(anyInt(), anyLong());
+ }
+
+ // ========== 鎾ゅ洖娴嬭瘯 ==========
+
+ @Test
+ public void testRecallMessage_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupMessageServiceImpl.class)))
+ .thenReturn(groupMessageService);
+
+ // 鍑嗗锛氭秷鎭敱鐢ㄦ埛 1 鍙戦�侊紝鍒氬彂閫� 5 鍒嗛挓鍐�
+ ImGroupMessageDO message = ImGroupMessageDO.builder()
+ .id(50L).senderId(1L).groupId(10L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(LocalDateTime.now()).build();
+ when(groupMessageMapper.selectById(50L)).thenReturn(message);
+ // 鎾ゅ洖鍓嶉渶瑕佹牎楠岀敤鎴蜂粛鍦ㄧ兢涓�
+ ImGroupMemberDO selfMember = ImGroupMemberDO.builder()
+ .groupId(10L).userId(1L).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(selfMember);
+ when(groupMessageMapper.updateById(any(ImGroupMessageDO.class))).thenReturn(1);
+ when(groupMessageMapper.insert(any(ImGroupMessageDO.class))).thenReturn(1);
+
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L))
+ .thenReturn(List.of(1L, 2L));
+
+ // 璋冪敤
+ ImGroupMessageDO result = groupMessageService.recallGroupMessage(1L, 50L);
+
+ // 鏂█锛氳繑鍥炴挙鍥炴秷鎭�
+ assertNotNull(result);
+ // 楠岃瘉锛氭洿鏂板師娑堟伅鐘舵�� + 鎻掑叆 RecallMessage
+ verify(groupMessageMapper).updateById(any(ImGroupMessageDO.class));
+ verify(groupMessageMapper).insert(any(ImGroupMessageDO.class));
+ // 楠岃瘉锛氱粰 2 涓椿璺冩垚鍛樻帹閫佹挙鍥炴彁绀�
+ verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) ->
+ ids.size() == 2 && ids.contains(1L) && ids.contains(2L)),
+ anyInt(), anyInt(), any());
+ }
+ }
+
+ @Test
+ public void testRecallMessage_notOwn() {
+ // 鍑嗗
+ ImGroupMessageDO message = ImGroupMessageDO.builder()
+ .id(50L).senderId(2L).groupId(10L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(LocalDateTime.now()).build();
+ when(groupMessageMapper.selectById(50L)).thenReturn(message);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build());
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.recallGroupMessage(1L, 50L));
+ assertEquals(MESSAGE_RECALL_DENIED.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testRecallMessage_alreadyRecalled() {
+ // 鍑嗗
+ ImGroupMessageDO message = ImGroupMessageDO.builder()
+ .id(50L).senderId(1L).groupId(10L)
+ .status(ImMessageStatusEnum.RECALL.getStatus())
+ .sendTime(LocalDateTime.now()).build();
+ when(groupMessageMapper.selectById(50L)).thenReturn(message);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build());
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.recallGroupMessage(1L, 50L));
+ assertEquals(MESSAGE_ALREADY_RECALLED.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testRecallMessage_timeout() {
+ // 鍑嗗锛氭秷鎭彂閫佷簬 10 鍒嗛挓鍓嶏紙瓒呰繃 5 鍒嗛挓绐楀彛锛�
+ ImGroupMessageDO message = ImGroupMessageDO.builder()
+ .id(50L).senderId(1L).groupId(10L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(LocalDateTime.now().minusMinutes(10)).build();
+ when(groupMessageMapper.selectById(50L)).thenReturn(message);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .role(ImGroupMemberRoleEnum.NORMAL.getRole()).build());
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.recallGroupMessage(1L, 50L));
+ assertEquals(MESSAGE_RECALL_TIMEOUT.getCode(), exception.getCode());
+ }
+
+ // ========== 缇ゅ凡璇绘祴璇� ==========
+
+ @Test
+ public void testReadMessages_messageInvisible() {
+ // 鍑嗗锛氭秷鎭笉鍦ㄧ敤鎴锋帴鏀跺揩鐓у唴
+ when(groupMessageMapper.selectById(100L)).thenReturn(ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(2L).receiverUserIds(List.of(2L))
+ .sendTime(LocalDateTime.now()).build());
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.readGroupMessages(1L, 10L, 100L));
+ assertEquals(MESSAGE_NOT_IN_GROUP.getCode(), exception.getCode());
+ verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void testGetReadUserIds_withVisibleScope() {
+ // 鍑嗗锛氬彂閫佽�呯敤鎴� 5 鏄兢鎴愬憳
+ ImGroupMemberDO currentMember = ImGroupMemberDO.builder()
+ .groupId(10L).userId(5L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build();
+ when(groupMemberService.validateMemberInGroup(10L, 5L)).thenReturn(currentMember);
+
+ // 鍑嗗锛氭秷鎭敱鐢ㄦ埛 5 鍙戯紝蹇収鍙鑼冨洿涓� {1,2,5}锛堢敤鎴� 3 涓嶅湪蹇収鍐� 鈫� 涓嶅彲瑙侊級
+ ImGroupMessageDO message = ImGroupMessageDO.builder()
+ .id(80L).groupId(10L).senderId(5L)
+ .receiverUserIds(List.of(1L, 2L, 5L))
+ .sendTime(LocalDateTime.of(2026, 4, 12, 10, 0, 0)).build();
+ when(groupMessageMapper.selectById(80L)).thenReturn(message);
+
+ // 鍑嗗锛氱兢鎴愬憳涓�瑙�
+ // 鐢ㄦ埛 1: 鍦ㄥ揩鐓у唴
+ // 鐢ㄦ埛 2: 鍦ㄥ揩鐓у唴
+ // 鐢ㄦ埛 3: 涓嶅湪蹇収鍐� 鈫� 涓嶅彲瑙�
+ // 鐢ㄦ埛 5: 鍙戦�佽�咃紝涓嶈鍏ュ洖鎵�
+ List<ImGroupMemberDO> allMembers = List.of(
+ currentMember,
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(3L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(5L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.of(2026, 1, 1, 0, 0, 0)).build() // 鍙戦�佽��
+ );
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(allMembers);
+
+ // 鍑嗗锛氬凡璇讳綅缃� 鈥� 鐢ㄦ埛 1 璇诲埌 100, 鐢ㄦ埛 2 璇诲埌 50, 鐢ㄦ埛 3 璇诲埌 200
+ Map<Long, Long> positions = new HashMap<>();
+ positions.put(1L, 100L);
+ positions.put(2L, 50L);
+ positions.put(3L, 200L);
+ when(conversationReadService.getUserReadMessageIdMap(eq(ImConversationTypeEnum.GROUP.getType()), eq(10L)))
+ .thenReturn(positions);
+
+ // 璋冪敤锛氭煡璇� messageId=80 鐨勫凡璇荤敤鎴�
+ List<Long> readUsers = groupMessageService.getGroupReadUserIds(5L, 10L, 80L);
+
+ // 鏂█锛�
+ // 鐢ㄦ埛 1: 鍙 + readMaxId=100>=80 鈫� 宸茶 鉁�
+ // 鐢ㄦ埛 2: 鍙 + readMaxId=50<80 鈫� 鏈 鉁�
+ // 鐢ㄦ埛 3: 涓嶅湪蹇収鍐� 鈫� 涓嶅彲瑙� 鈫� 涓嶇畻
+ // 鐢ㄦ埛 5: 鍙戦�佽�� 鈫� 鎺掗櫎
+ assertEquals(1, readUsers.size());
+ assertTrue(readUsers.contains(1L));
+ assertFalse(readUsers.contains(2L));
+ assertFalse(readUsers.contains(3L));
+ assertFalse(readUsers.contains(5L));
+ }
+
+ @Test
+ public void testGetReadUserIds_notInGroup() {
+ // 鍑嗗锛氬綋鍓嶇敤鎴蜂笉鍦ㄧ兢涓�
+ when(groupMemberService.validateMemberInGroup(10L, 99L))
+ .thenThrow(new ServiceException(GROUP_MEMBER_NOT_IN_GROUP.getCode(), GROUP_MEMBER_NOT_IN_GROUP.getMsg()));
+
+ // 璋冪敤骞舵柇瑷�锛氳秺鏉冩牎楠�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.getGroupReadUserIds(99L, 10L, 80L));
+ assertEquals(GROUP_MEMBER_NOT_IN_GROUP.getCode(), exception.getCode());
+ }
+
+ // ========== 鍙戦�佽竟鐣� ==========
+
+ @Test
+ public void testSendMessage_receiptPending() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupMessageServiceImpl.class)))
+ .thenReturn(groupMessageService);
+
+ // 鍑嗗锛歳eqVO.receipt=true
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ reqVO.setReceipt(true);
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001"))
+ .thenReturn(null);
+ ImGroupDO group = new ImGroupDO();
+ group.setId(10L);
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ ImGroupMemberDO member = ImGroupMemberDO.builder()
+ .groupId(10L).userId(1L).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(member);
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L));
+ when(groupMessageMapper.insert(any(ImGroupMessageDO.class))).thenReturn(1);
+
+ // 璋冪敤
+ ImGroupMessageDO result = groupMessageService.sendGroupMessage(1L, reqVO);
+
+ // 鏂█锛歳eceipt=true 鈫� 鍥炴墽鐘舵�佷负 PENDING
+ assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), result.getReceiptStatus());
+ }
+ }
+
+ @Test
+ public void testSendMessage_sensitiveWordBlocked() {
+ // 鍑嗗锛氭枃鏈秷鎭懡涓晱鎰熻瘝
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001"))
+ .thenReturn(null);
+ ImGroupDO group = new ImGroupDO();
+ group.setId(10L);
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ doThrow(new ServiceException(MESSAGE_SENSITIVE_WORD_BLOCKED))
+ .when(sensitiveWordService).validateText(reqVO.getContent());
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.sendGroupMessage(1L, reqVO));
+ assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode());
+ // 鏂█锛氫笉鍏ュ簱銆佷笉鎺ㄩ��
+ verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class));
+ verify(imWebSocketService, never()).sendNotificationAsync(anyCollection(), anyInt(), anyInt(), any());
+ }
+
+ // ========== 鎾ゅ洖杈圭晫 ==========
+
+ @Test
+ public void testRecallMessage_notExists() {
+ when(groupMessageMapper.selectById(50L)).thenReturn(null);
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.recallGroupMessage(1L, 50L));
+ assertEquals(MESSAGE_NOT_EXISTS.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testRecallMessage_senderNotInGroup() {
+ // 鍑嗗锛氭秷鎭悎娉曘�佸彲鎾ゅ洖鏃堕棿鍐咃紝浣嗗彂閫佷汉宸查��缇�
+ ImGroupMessageDO message = ImGroupMessageDO.builder()
+ .id(50L).senderId(1L).groupId(10L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(LocalDateTime.now()).build();
+ when(groupMessageMapper.selectById(50L)).thenReturn(message);
+ when(groupMemberService.validateMemberInGroup(10L, 1L))
+ .thenThrow(new ServiceException(GROUP_MEMBER_NOT_IN_GROUP.getCode(), GROUP_MEMBER_NOT_IN_GROUP.getMsg()));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.recallGroupMessage(1L, 50L));
+ assertEquals(GROUP_MEMBER_NOT_IN_GROUP.getCode(), exception.getCode());
+ // 鏂█锛氫笉鎵ц鏇存柊銆佷笉鎻� tip
+ verify(groupMessageMapper, never()).updateById(any(ImGroupMessageDO.class));
+ verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class));
+ }
+
+ // ========== 宸茶浜嬩欢 ==========
+
+ @Test
+ public void testReadGroupMessages_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupMessageServiceImpl.class)))
+ .thenReturn(groupMessageService);
+
+ // 鍑嗗锛氭秷鎭鐢ㄦ埛鍙锛涘凡璇讳綅缃粠 5 鍓嶈繘鍒� 100
+ when(groupMessageMapper.selectById(100L)).thenReturn(ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(2L).receiverUserIds(List.of(1L))
+ .sendTime(LocalDateTime.now()).build());
+ when(conversationReadService.getConversationReadMessageId(1L, ImConversationTypeEnum.GROUP.getType(), 10L))
+ .thenReturn(5L);
+ when(conversationReadService.updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L))
+ .thenReturn(true);
+ // readGroupMessageEvent 鍐呴儴浼氳皟 selectListByGroupIdAndPendingReceipt 鈫� 杩斿洖绌虹畝鍖栨祦绋�
+ when(groupMessageMapper.selectListByGroupIdAndPendingReceipt(10L, 5L, 100L)).thenReturn(List.of());
+
+ // 璋冪敤
+ groupMessageService.readGroupMessages(1L, 10L, 100L);
+
+ // 鏂█锛氬凡璇讳綅缃洿鏂� + READ 浜嬩欢
+ verify(conversationReadService).updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L);
+ verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any());
+ verify(groupMemberService, never()).validateMemberInGroup(10L, 1L);
+ }
+ }
+
+ @Test
+ public void testReadGroupMessages_disabled() {
+ // 鍑嗗锛氬叧闂兢鑱婂凡璇�
+ imProperties.getMessage().setGroupReadEnabled(false);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.readGroupMessages(1L, 10L, 100L));
+ assertEquals(MESSAGE_GROUP_READ_DISABLED.getCode(), exception.getCode());
+ // 鏂█锛氬凡璇讳綅缃笉鍐欍�佷笉鎺ㄩ��
+ verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong());
+ verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testGetGroupReadUserIds_disabled() {
+ // 鍑嗗锛氬叧闂兢鑱婂凡璇�
+ imProperties.getMessage().setGroupReadEnabled(false);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.getGroupReadUserIds(1L, 10L, 100L));
+ assertEquals(MESSAGE_GROUP_READ_DISABLED.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testSendGroupMessage_groupReadDisabled_forcesNoReceipt() {
+ // 鍏抽棴缇ゅ凡璇伙細鍙戦�佹柟浼� receipt=true 涔熷己鍒惰惤 NO_RECEIPT
+ imProperties.getMessage().setGroupReadEnabled(false);
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupMessageServiceImpl.class)))
+ .thenReturn(groupMessageService);
+
+ ImGroupMessageSendReqVO reqVO = buildSendReqVO();
+ reqVO.setReceipt(true); // 鍙戦�佹柟鏄庣‘瑕佹眰鍥炴墽
+ when(groupMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-group-001"))
+ .thenReturn(null);
+ ImGroupDO group = new ImGroupDO();
+ group.setId(10L);
+ when(groupService.validateGroupExists(10L)).thenReturn(group);
+ ImGroupMemberDO member = ImGroupMemberDO.builder()
+ .groupId(10L).userId(1L).status(CommonStatusEnum.ENABLE.getStatus()).build();
+ when(groupMemberService.validateMemberInGroup(10L, 1L)).thenReturn(member);
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L, 2L));
+
+ ImGroupMessageDO result = groupMessageService.sendGroupMessage(1L, reqVO);
+
+ assertEquals(ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus(), result.getReceiptStatus(),
+ "缇ゅ凡璇诲叧闂椂鍗充娇鍙戦�佹柟浼� receipt=true 涔熷己鍒惰惤 NO_RECEIPT");
+ }
+ }
+
+ @Test
+ public void testReadGroupMessages_cursorAlreadyAhead() {
+ // 鍑嗗锛氬凡璇绘父鏍囧凡 >= 鐩爣锛岀洿鎺ヨ繑鍥�
+ when(groupMessageMapper.selectById(100L)).thenReturn(ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(2L).receiverUserIds(List.of(1L))
+ .sendTime(LocalDateTime.now()).build());
+ when(conversationReadService.getConversationReadMessageId(1L, ImConversationTypeEnum.GROUP.getType(), 10L))
+ .thenReturn(200L);
+ // CAS 鍛戒腑鏃т綅缃� 200 > 100锛屽崟璋冩洿鏂颁笉鍓嶈繘锛岃繑鍥� false
+ when(conversationReadService.updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L))
+ .thenReturn(false);
+
+ // 璋冪敤
+ groupMessageService.readGroupMessages(1L, 10L, 100L);
+
+ // 鏂█锛氳皟鐢ㄤ簡 CAS 鏇存柊浣嗚浣嶇疆鏈墠杩� 鈫� 涓嶆帹閫�
+ verify(conversationReadService).updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L);
+ verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testReadGroupMessages_messageNotInGroup() {
+ // 鍑嗗锛歮essageId 灞炰簬鍏跺畠缇�
+ when(groupMessageMapper.selectById(100L)).thenReturn(ImGroupMessageDO.builder()
+ .id(100L).groupId(20L).senderId(2L).sendTime(LocalDateTime.now()).build());
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.readGroupMessages(1L, 10L, 100L));
+ assertEquals(MESSAGE_NOT_IN_GROUP.getCode(), exception.getCode());
+ verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void testReadGroupMessages_quitMemberVisibleMessage_success() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImGroupMessageServiceImpl.class)))
+ .thenReturn(groupMessageService);
+
+ // 鍑嗗锛氬巻鍙叉秷鎭殑鎺ユ敹蹇収鍖呭惈鐢ㄦ埛
+ when(groupMessageMapper.selectById(100L)).thenReturn(ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(2L).receiverUserIds(List.of(1L, 2L))
+ .sendTime(LocalDateTime.now().minusMinutes(1)).build());
+ when(conversationReadService.getConversationReadMessageId(1L, ImConversationTypeEnum.GROUP.getType(), 10L))
+ .thenReturn(0L);
+ when(conversationReadService.updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L))
+ .thenReturn(true);
+ when(groupMessageMapper.selectListByGroupIdAndPendingReceipt(10L, 0L, 100L)).thenReturn(List.of());
+
+ // 璋冪敤
+ groupMessageService.readGroupMessages(1L, 10L, 100L);
+
+ // 鏂█锛氫笉鏍¢獙褰撳墠鍦ㄧ兢锛岀洿鎺ユ帹杩涘凡璇讳綅缃�
+ verify(groupMemberService, never()).validateMemberInGroup(10L, 1L);
+ verify(conversationReadService).updateConversationReadPosition(1L, ImConversationTypeEnum.GROUP.getType(), 10L, 100L);
+ }
+ }
+
+ @Test
+ public void testReadGroupMessages_quitMemberInvisibleMessage() {
+ // 鍑嗗锛氭秷鎭笉鍦ㄥ巻鍙叉帴鏀跺揩鐓у唴
+ when(groupMessageMapper.selectById(100L)).thenReturn(ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(2L).receiverUserIds(List.of(2L))
+ .sendTime(LocalDateTime.now()).build());
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.readGroupMessages(1L, 10L, 100L));
+ assertEquals(MESSAGE_NOT_IN_GROUP.getCode(), exception.getCode());
+ verify(conversationReadService, never()).updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong());
+ }
+
+ // ========== 鍥炴墽鐘舵�佽縼绉� ==========
+
+ @Test
+ public void testReadGroupMessageEvent_receiptDoneTransition() {
+ // 鍑嗗锛氭秷鎭� 100 鍙戦�佽�� 5锛岀兢 10 娲昏穬鎴愬憳 {5,1,2}锛屽彲瑙佺敤鎴蜂腑闄ゅ彂閫佽�呭 {1,2}
+ // 宸茶浣嶇疆 1鈫�100銆�2鈫�100 鈫� 鍏ㄩ儴宸茶 鈫� 杩佺Щ涓� DONE
+ ImGroupMessageDO pending = ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(5L)
+ .receiverUserIds(List.of(5L, 1L, 2L))
+ .sendTime(LocalDateTime.now().minusMinutes(1))
+ .receiptStatus(ImMessageReceiptStatusEnum.PENDING.getStatus())
+ .status(ImMessageStatusEnum.NORMAL.getStatus()).build();
+ when(groupMessageMapper.selectListByGroupIdAndPendingReceipt(10L, 0L, 100L))
+ .thenReturn(List.of(pending));
+ List<ImGroupMemberDO> activeMembers = List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(5L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.now().minusDays(10)).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.now().minusDays(10)).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.now().minusDays(10)).build()
+ );
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(activeMembers);
+ Map<Long, Long> positions = new HashMap<>();
+ positions.put(1L, 100L);
+ positions.put(2L, 100L);
+ when(conversationReadService.getUserReadMessageIdMap(ImConversationTypeEnum.GROUP.getType(), 10L))
+ .thenReturn(positions);
+
+ // 璋冪敤
+ groupMessageService.readGroupMessageEvent(1L, 10L, 0L, 100L);
+
+ // 鏂█锛氭秷鎭洖鎵х姸鎬佹洿鏂颁负 DONE
+ ArgumentCaptor<ImGroupMessageDO> captor = ArgumentCaptor.forClass(ImGroupMessageDO.class);
+ verify(groupMessageMapper).updateById(captor.capture());
+ assertEquals(100L, captor.getValue().getId());
+ assertEquals(ImMessageReceiptStatusEnum.DONE.getStatus(), captor.getValue().getReceiptStatus());
+ // 鏂█锛氱粰娑堟伅鍙戦�佹柟锛�5锛夋帹閫� RECEIPT 浜嬩欢
+ verify(imWebSocketService).sendNotificationAsync(eq(5L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testReadGroupMessageEvent_receiptStaysPendingWhenPartialRead() {
+ // 鍑嗗锛氱敤鎴� 2 杩樻病璇诲埌 100 鈫� 浠嶄负 PENDING锛屼笉鏇存柊 DB
+ ImGroupMessageDO pending = ImGroupMessageDO.builder()
+ .id(100L).groupId(10L).senderId(5L)
+ .receiverUserIds(List.of(5L, 1L, 2L))
+ .sendTime(LocalDateTime.now().minusMinutes(1))
+ .receiptStatus(ImMessageReceiptStatusEnum.PENDING.getStatus())
+ .status(ImMessageStatusEnum.NORMAL.getStatus()).build();
+ when(groupMessageMapper.selectListByGroupIdAndPendingReceipt(10L, 0L, 100L))
+ .thenReturn(List.of(pending));
+ List<ImGroupMemberDO> activeMembers = List.of(
+ ImGroupMemberDO.builder().groupId(10L).userId(5L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.now().minusDays(10)).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.now().minusDays(10)).build(),
+ ImGroupMemberDO.builder().groupId(10L).userId(2L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.now().minusDays(10)).build()
+ );
+ when(groupMemberService.getActiveGroupMemberListByGroupId(10L)).thenReturn(activeMembers);
+ Map<Long, Long> positions = new HashMap<>();
+ positions.put(1L, 100L);
+ positions.put(2L, 50L); // 杩樻病璇诲埌 100
+ when(conversationReadService.getUserReadMessageIdMap(ImConversationTypeEnum.GROUP.getType(), 10L))
+ .thenReturn(positions);
+
+ groupMessageService.readGroupMessageEvent(1L, 10L, 0L, 100L);
+
+ // 鏂█锛氬洖鎵х姸鎬佷繚鎸� PENDING锛屼笉鏇存柊 DB
+ verify(groupMessageMapper, never()).updateById(any(ImGroupMessageDO.class));
+ // 浠嶇劧鎺ㄩ�� RECEIPT 浜嬩欢缁欏彂閫佹柟锛堟惡甯﹀凡璇讳汉鏁帮級
+ verify(imWebSocketService).sendNotificationAsync(eq(5L), anyInt(), anyInt(), any());
+ }
+
+ // ========== 瀹氬悜缇ゆ秷鎭� ==========
+
+ @Test
+ public void testSendGroupMessage_noReceiverUserIds_broadcastsToAllMembers() {
+ // 鍑嗗锛氭棤瀹氬悜 鈫� 搴斿彂缁欐墍鏈� ENABLE 鎴愬憳锛堝惈鍙戦�佽�呰嚜宸憋紝澶氱鍚屾锛�
+ ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO()
+ .setGroupId(10L).setType(ImContentTypeEnum.RECALL.getType())
+ .setContent("{\"messageId\":1}");
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L))
+ .thenReturn(List.of(1L, 2L, 3L, 4L));
+
+ groupMessageService.sendGroupMessage(1L, dto);
+
+ verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) ->
+ ids.size() == 4 && ids.contains(1L) && ids.contains(2L)
+ && ids.contains(3L) && ids.contains(4L)),
+ anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testSendGroupMessage_withReceiverUserIds_onlyTargetedPlusSender() {
+ // 鍑嗗锛氬畾鍚戠粰 {2,3}锛屽彂閫佽�� 1锛涚兢鎴愬憳 {1,2,3,4}
+ // 棰勬湡鎺ㄩ�佺洰鏍囷細{1,2,3}锛堝彂閫佽�呰嚜宸卞绔悓姝� + 瀹氬悜鍒楄〃锛夛紱4 琚繃婊�
+ ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO()
+ .setGroupId(10L).setType(ImContentTypeEnum.RECALL.getType())
+ .setContent("{\"messageId\":1}")
+ .setReceiverUserIds(List.of(2L, 3L));
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L))
+ .thenReturn(List.of(1L, 2L, 3L, 4L));
+
+ groupMessageService.sendGroupMessage(1L, dto);
+
+ verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) ->
+ ids.size() == 3 && ids.contains(1L) && ids.contains(2L)
+ && ids.contains(3L) && !ids.contains(4L)),
+ anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testSendGroupMessage_withReceiverUserIds_senderAlwaysIncluded() {
+ // 杈圭晫锛氬彂閫佽�呬笉鍦ㄧ兢鎴愬憳缂撳瓨閲岋紙鐞嗚涓婂簲鍏堣 validateMemberInGroup 鎸′綇锛岃繖閲岀函闃插尽锛�
+ // 棰勬湡锛氬畾鍚戠敤鎴� + 鍙戦�佽�呰嚜宸憋紙濮嬬粓绾冲叆蹇収淇濊瘉澶氱鍚屾锛夛紱闈炲畾鍚戞垚鍛� 4 琚繃婊�
+ ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO()
+ .setGroupId(10L).setType(ImContentTypeEnum.RECALL.getType())
+ .setContent("{\"messageId\":1}")
+ .setReceiverUserIds(List.of(2L, 3L));
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L))
+ .thenReturn(List.of(1L, 2L, 3L, 4L));
+
+ groupMessageService.sendGroupMessage(99L, dto);
+
+ verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) ->
+ ids.size() == 3 && ids.contains(2L) && ids.contains(3L)
+ && ids.contains(99L) && !ids.contains(4L)),
+ anyInt(), anyInt(), any());
+ }
+
+ // ========== DTO 缇ゆ秷鎭� ==========
+
+ @Test
+ public void testSendGroupMessage_dto_persistsAndSerializesPojoContent() {
+ // 鍑嗗锛歱ersistent=true 绫诲瀷 + POJO content
+ ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO()
+ .setGroupId(10L).setType(ImContentTypeEnum.RECALL.getType())
+ .setContent(new RecallMessage().setMessageId(50L));
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L));
+
+ groupMessageService.sendGroupMessage(1L, dto);
+
+ // 鏂█锛氬叆搴� + 绯荤粺瀛楁鍏滃簳 + content 搴忓垪鍖栦负 JSON + receiptStatus=NO_RECEIPT
+ ArgumentCaptor<ImGroupMessageDO> captor = ArgumentCaptor.forClass(ImGroupMessageDO.class);
+ verify(groupMessageMapper).insert(captor.capture());
+ ImGroupMessageDO message = captor.getValue();
+ assertEquals(1L, message.getSenderId());
+ assertEquals(10L, message.getGroupId());
+ assertEquals(ImContentTypeEnum.RECALL.getType(), message.getType());
+ assertEquals("{\"messageId\":50}", message.getContent());
+ assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), message.getStatus());
+ assertEquals(ImMessageReceiptStatusEnum.NO_RECEIPT.getStatus(), message.getReceiptStatus());
+ assertNotNull(message.getClientMessageId());
+ assertNotNull(message.getSendTime());
+ }
+
+ @Test
+ public void testSendGroupMessage_dto_receiptPending() {
+ // 鍑嗗锛歞to.receipt=true 鈫� receiptStatus=PENDING
+ ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO()
+ .setGroupId(10L).setType(ImContentTypeEnum.RECALL.getType())
+ .setContent("{\"messageId\":50}").setReceipt(true);
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L));
+
+ groupMessageService.sendGroupMessage(1L, dto);
+
+ ArgumentCaptor<ImGroupMessageDO> captor = ArgumentCaptor.forClass(ImGroupMessageDO.class);
+ verify(groupMessageMapper).insert(captor.capture());
+ assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), captor.getValue().getReceiptStatus());
+ }
+
+ @Test
+ public void testSendGroupMessage_dto_nonPersistentTypeNotInserted() {
+ // 鍑嗗锛歱ersistent=false 绫诲瀷锛圧ECEIPT 鍥炴墽锛夆啋 涓嶅叆搴擄紝浠呮帹閫�
+ ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO()
+ .setGroupId(10L).setType(ImContentTypeEnum.RECEIPT.getType());
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L, 2L));
+
+ groupMessageService.sendGroupMessage(1L, dto);
+
+ verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class));
+ verify(imWebSocketService).sendNotificationAsync(anyCollection(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testSendGroupMessage_dto_groupMemberNicknameUpdateNotInserted() {
+ // 鍑嗗锛氭垚鍛樻樀绉板彉鏇村彧鍋氬湪绾垮悓姝ワ紝涓嶅叆搴�
+ ImGroupMessageSendDTO dto = ImGroupMessageSendDTO.ofGroupMemberNicknameUpdate(10L, 1L, "缇ゆ樀绉�");
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(10L)).thenReturn(List.of(1L, 2L));
+
+ groupMessageService.sendGroupMessage(1L, dto);
+
+ verify(groupMessageMapper, never()).insert(any(ImGroupMessageDO.class));
+ verify(imWebSocketService).sendNotificationAsync(argThat((Collection<Long> ids) ->
+ ids.size() == 2 && ids.contains(1L) && ids.contains(2L)),
+ anyInt(), eq(ImContentTypeEnum.GROUP_MEMBER_NICKNAME_UPDATE.getType()), any());
+ }
+
+ @Test
+ public void testSendGroupMessage_threeArg_explicitTargetsBypassActiveMembers() {
+ // 鍑嗗锛氳皟鐢ㄦ柟浼犲叆鏄惧紡 targets锛堣В鏁e満鏅垚鍛樺凡琚壒閲� DISABLE锛屽繀椤绘寜绉婚櫎鍓嶅揩鐓ф帹閫侊級
+ Set<Long> targets = Set.of(1L, 2L, 3L);
+ ImGroupMessageSendDTO dto = new ImGroupMessageSendDTO()
+ .setGroupId(10L).setType(ImContentTypeEnum.GROUP_DISSOLVE.getType()).setContent("{}");
+
+ groupMessageService.sendGroupMessage(1L, targets, dto);
+
+ // 鏂█锛氫笉璇诲彇 active members锛屾寜璋冪敤鏂� targets 鎺ㄩ��
+ verify(groupMemberService, never()).getActiveGroupMemberUserIdsByGroupId(anyLong());
+ verify(imWebSocketService).sendNotificationAsync(eq(targets), anyInt(), anyInt(), any());
+ }
+
+ // ========== getGroupMessageList ==========
+
+ @Test
+ public void testGetGroupMessageList_delegatesToMapper() {
+ // 鍑嗗锛氬彲瑙佹�х敱 SQL 鎸� receiver_user_ids 蹇収杩囨护锛孲ervice 鐩存帴閫忎紶 mapper 缁撴灉
+ ImGroupMemberDO member = ImGroupMemberDO.builder()
+ .id(50L).groupId(10L).userId(1L)
+ .status(CommonStatusEnum.ENABLE.getStatus())
+ .joinTime(LocalDateTime.now().minusDays(5)).build();
+ when(groupMemberService.getGroupMember(10L, 1L)).thenReturn(member);
+
+ ImGroupMessageListReqVO reqVO = new ImGroupMessageListReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setMaxId(100L);
+ reqVO.setLimit(20);
+
+ List<ImGroupMessageDO> mockList = List.of(
+ ImGroupMessageDO.builder().id(99L).groupId(10L).senderId(2L)
+ .receiverUserIds(List.of(1L)).sendTime(LocalDateTime.now()).build()
+ );
+ when(groupMessageMapper.selectHistoryListByUser(1L, 10L, 100L, 20)).thenReturn(mockList);
+
+ // 璋冪敤
+ List<ImGroupMessageDO> result = groupMessageService.getGroupMessageList(1L, reqVO);
+
+ // 鏂█锛氶�忎紶鍒� mapper锛屽弬鏁颁竴鑷�
+ assertEquals(1, result.size());
+ assertEquals(99L, result.get(0).getId());
+ verify(groupMessageMapper).selectHistoryListByUser(1L, 10L, 100L, 20);
+ }
+
+ @Test
+ public void testGetGroupMessageList_notInGroup() {
+ // 鍑嗗锛氱敤鎴蜂粠鏈湪缇や腑锛坓etGroupMember 杩斿洖 null锛�
+ ImGroupMessageListReqVO reqVO = new ImGroupMessageListReqVO();
+ reqVO.setGroupId(10L);
+ reqVO.setLimit(20);
+ when(groupMemberService.getGroupMember(10L, 1L)).thenReturn(null);
+
+ // 璋冪敤骞舵柇瑷�锛氶壌鏉冨け璐�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> groupMessageService.getGroupMessageList(1L, reqVO));
+ assertEquals(GROUP_MEMBER_NOT_IN_GROUP.getCode(), exception.getCode());
+ // 鏂█锛氫笉鏌ヨ DB
+ verify(groupMessageMapper, never()).selectHistoryListByUser(anyLong(), anyLong(), anyLong(), anyInt());
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImplTest.java
new file mode 100644
index 0000000..91436cf
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImplTest.java
@@ -0,0 +1,445 @@
+package cn.iocoder.yudao.module.im.service.message;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageListReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
+import cn.iocoder.yudao.module.im.dal.mysql.message.ImPrivateMessageMapper;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageReceiptStatusEnum;
+import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.conversation.ImConversationReadService;
+import cn.iocoder.yudao.module.im.service.friend.ImFriendService;
+import cn.iocoder.yudao.module.im.service.sensitiveword.ImSensitiveWordService;
+import cn.iocoder.yudao.module.im.service.message.dto.ImPrivateMessageSendDTO;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReadNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImMessageReceiptNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImPrivateMessageNotification;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.RecallMessage;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImPrivateMessageServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImPrivateMessageServiceImpl privateMessageService;
+
+ @Mock
+ private ImPrivateMessageMapper privateMessageMapper;
+ @Mock
+ private ImFriendService friendService;
+ @Mock
+ private ImSensitiveWordService sensitiveWordService;
+ @Mock
+ private ImConversationReadService conversationReadService;
+ @Mock
+ private ImWebSocketService imWebSocketService;
+
+ @Spy
+ private ImProperties imProperties = new ImProperties();
+
+ private ImPrivateMessageSendReqVO buildSendReqVO() {
+ ImPrivateMessageSendReqVO reqVO = new ImPrivateMessageSendReqVO();
+ reqVO.setClientMessageId("test-uuid-001");
+ reqVO.setReceiverId(2L);
+ reqVO.setType(ImContentTypeEnum.TEXT.getType());
+ reqVO.setContent("{\"content\":\"浣犲ソ\"}");
+ return reqVO;
+ }
+
+ // ========== 鍙戦�佹祴璇� ==========
+
+ @Test
+ public void testSendMessage_success() {
+ // 鍑嗗
+ ImPrivateMessageSendReqVO reqVO = buildSendReqVO();
+ when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001"))
+ .thenReturn(null);
+ when(privateMessageMapper.insert(any(ImPrivateMessageDO.class))).thenAnswer(invocation -> {
+ ImPrivateMessageDO msg = invocation.getArgument(0);
+ msg.setId(99L);
+ return 1;
+ });
+
+ // 璋冪敤
+ ImPrivateMessageDO result = privateMessageService.sendPrivateMessage(1L, reqVO);
+
+ // 鏂█
+ assertNotNull(result);
+ assertEquals(1L, result.getSenderId());
+ assertEquals(2L, result.getReceiverId());
+ assertEquals(ImContentTypeEnum.TEXT.getType(), result.getType());
+ assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), result.getStatus());
+ assertEquals(ImMessageReceiptStatusEnum.PENDING.getStatus(), result.getReceiptStatus(),
+ "鐢ㄦ埛绉佽亰娑堟伅榛樿闇�瑕佸洖鎵э紙PENDING锛�");
+ assertNotNull(result.getSendTime());
+
+ // 楠岃瘉璋冪敤
+ verify(friendService).validateFriend(1L, 2L);
+ verify(sensitiveWordService).validateText(reqVO.getContent());
+ verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class));
+ // 楠岃瘉鎺ㄩ�佺粰鎺ユ敹鏂瑰拰鍙戦�佹柟
+ verify(imWebSocketService).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any());
+ verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testSendMessage_clientMessageIdIdempotent() {
+ // 鍑嗗锛氭ā鎷熷凡瀛樺湪娑堟伅
+ ImPrivateMessageSendReqVO reqVO = buildSendReqVO();
+ ImPrivateMessageDO existingMessage = ImPrivateMessageDO.builder()
+ .id(100L).clientMessageId("test-uuid-001").senderId(1L).receiverId(2L)
+ .type(0).content("{\"content\":\"浣犲ソ\"}").status(0)
+ .sendTime(LocalDateTime.now()).build();
+ when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001"))
+ .thenReturn(existingMessage);
+
+ // 璋冪敤
+ ImPrivateMessageDO result = privateMessageService.sendPrivateMessage(1L, reqVO);
+
+ // 鏂█锛氳繑鍥炲凡瀛樺湪鐨勬秷鎭�
+ assertEquals(100L, result.getId());
+ // 楠岃瘉涓嶄細閲嶅鎻掑叆
+ verify(privateMessageMapper, never()).insert(any(ImPrivateMessageDO.class));
+ }
+
+ @Test
+ public void testSendMessage_notFriend() {
+ // 鍑嗗
+ ImPrivateMessageSendReqVO reqVO = buildSendReqVO();
+ when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001"))
+ .thenReturn(null);
+ doThrow(new ServiceException(FRIEND_NOT_FRIEND))
+ .when(friendService).validateFriend(1L, 2L);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.sendPrivateMessage(1L, reqVO));
+ assertEquals(FRIEND_NOT_FRIEND.getCode(), exception.getCode());
+ }
+
+ // ========== pull 娴嬭瘯 ==========
+
+ @Test
+ public void testPullMessages_success() {
+ // 鍑嗗
+ List<ImPrivateMessageDO> mockMessages = ListUtil.of(
+ ImPrivateMessageDO.builder().id(1L).senderId(1L).receiverId(2L).build(),
+ ImPrivateMessageDO.builder().id(2L).senderId(2L).receiverId(1L).build()
+ );
+ when(privateMessageMapper.selectListByMinId(eq(1L), eq(0L), any(LocalDateTime.class), eq(100)))
+ .thenReturn(mockMessages);
+
+ // 璋冪敤
+ List<ImPrivateMessageDO> result = privateMessageService.pullPrivateMessageList(1L, 0L, 100);
+
+ // 鏂█
+ assertEquals(2, result.size());
+ }
+
+ @Test
+ public void testPullMessages_sizeExceeded() {
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.pullPrivateMessageList(1L, 0L, 1001));
+ assertEquals(MESSAGE_PULL_SIZE_EXCEEDED.getCode(), exception.getCode());
+ }
+
+ // ========== 宸茶娴嬭瘯 ==========
+
+ @Test
+ public void testReadMessages_success() {
+ // 鍑嗗锛氬墠绔笂鎶ュ凡璇诲埌 messageId=5锛沵apper 杩斿洖鏇存柊琛屾暟 2 琛ㄧず鏈夊緟鍥炴墽娑堟伅琚爣璁板畬鎴�
+ when(privateMessageMapper.updateBySenderIdAndReceiverIdAndIdLeAndReceiptStatus(
+ eq(2L), eq(1L), eq(5L),
+ eq(ImMessageReceiptStatusEnum.PENDING.getStatus()), any(ImPrivateMessageDO.class)))
+ .thenReturn(2);
+ // 璇讳綅缃墠杩� 鈫� 鎵嶄笅鍙戜簨浠�
+ when(conversationReadService.updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong()))
+ .thenReturn(true);
+
+ // 璋冪敤
+ privateMessageService.readPrivateMessages(1L, 2L, 5L);
+
+ // 鏂█锛氭妸寰呭洖鎵�(PENDING)娑堟伅鏍囪涓哄凡瀹屾垚锛圖ONE锛夛紱status 涓嶅啀鍐� READ
+ verify(privateMessageMapper).updateBySenderIdAndReceiverIdAndIdLeAndReceiptStatus(
+ eq(2L), eq(1L), eq(5L),
+ eq(ImMessageReceiptStatusEnum.PENDING.getStatus()), any(ImPrivateMessageDO.class));
+
+ // 鏂█锛氬彂閫佷簡 READ + RECEIPT 浜嬩欢锛宲ayload 瀛楁姝g‘
+ ArgumentCaptor<Long> userCaptor = ArgumentCaptor.forClass(Long.class);
+ ArgumentCaptor<Integer> contentTypeCaptor = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Object> payloadCaptor = ArgumentCaptor.forClass(Object.class);
+ verify(imWebSocketService, times(2)).sendNotificationAsync(
+ userCaptor.capture(), eq(ImConversationTypeEnum.PRIVATE.getType()),
+ contentTypeCaptor.capture(), payloadCaptor.capture());
+
+ // 绗竴娆★細鍙戠粰鑷繁鐨� READ 浜嬩欢
+ assertEquals(1L, userCaptor.getAllValues().get(0));
+ assertEquals(ImContentTypeEnum.READ.getType(), contentTypeCaptor.getAllValues().get(0));
+ ImMessageReadNotification readPayload = (ImMessageReadNotification) payloadCaptor.getAllValues().get(0);
+ assertEquals(1L, readPayload.getSenderId());
+ assertEquals(2L, readPayload.getReceiverId());
+ assertEquals(5L, readPayload.getId(), "READ id 搴斾负鍓嶇涓婃姤鐨� messageId");
+
+ // 绗簩娆★細鍙戠粰瀵规柟鐨� RECEIPT 浜嬩欢
+ assertEquals(2L, userCaptor.getAllValues().get(1));
+ assertEquals(ImContentTypeEnum.RECEIPT.getType(), contentTypeCaptor.getAllValues().get(1));
+ ImMessageReceiptNotification receiptPayload =
+ (ImMessageReceiptNotification) payloadCaptor.getAllValues().get(1);
+ assertEquals(5L, receiptPayload.getId(), "RECEIPT id 搴斾负鍓嶇涓婃姤鐨� messageId");
+ }
+
+ // ========== 鎾ゅ洖娴嬭瘯 ==========
+
+ @Test
+ public void testRecallMessage_success() {
+ // 鍑嗗
+ ImPrivateMessageDO message = ImPrivateMessageDO.builder()
+ .id(10L).senderId(1L).receiverId(2L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(LocalDateTime.now()).build(); // 鍒氬彂閫侊紝5 鍒嗛挓鍐�
+ when(privateMessageMapper.selectById(10L)).thenReturn(message);
+ when(privateMessageMapper.updateById(any(ImPrivateMessageDO.class))).thenReturn(1);
+ when(privateMessageMapper.insert(any(ImPrivateMessageDO.class))).thenReturn(1);
+
+ // 璋冪敤
+ ImPrivateMessageDO result = privateMessageService.recallPrivateMessage(1L, 10L);
+
+ // 鏂█锛氳繑鍥炴挙鍥炴秷鎭�
+ assertNotNull(result);
+ // 楠岃瘉锛氭洿鏂板師娑堟伅鐘舵�� + 鎻掑叆 RecallMessage
+ verify(privateMessageMapper).updateById(any(ImPrivateMessageDO.class));
+ verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class));
+ // 楠岃瘉鎺ㄩ�佷簡娑堟伅锛堢粰鎺ユ敹鏂瑰拰鍙戦�佹柟锛�
+ verify(imWebSocketService, times(2)).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testRecallMessage_notOwn() {
+ // 鍑嗗
+ ImPrivateMessageDO message = ImPrivateMessageDO.builder()
+ .id(10L).senderId(2L).receiverId(1L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(LocalDateTime.now()).build();
+ when(privateMessageMapper.selectById(10L)).thenReturn(message);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.recallPrivateMessage(1L, 10L));
+ assertEquals(MESSAGE_RECALL_DENIED.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testRecallMessage_alreadyRecalled() {
+ // 鍑嗗
+ ImPrivateMessageDO message = ImPrivateMessageDO.builder()
+ .id(10L).senderId(1L).receiverId(2L)
+ .status(ImMessageStatusEnum.RECALL.getStatus())
+ .sendTime(LocalDateTime.now()).build();
+ when(privateMessageMapper.selectById(10L)).thenReturn(message);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.recallPrivateMessage(1L, 10L));
+ assertEquals(MESSAGE_ALREADY_RECALLED.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testRecallMessage_notExists() {
+ // 鍑嗗
+ when(privateMessageMapper.selectById(10L)).thenReturn(null);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.recallPrivateMessage(1L, 10L));
+ assertEquals(MESSAGE_NOT_EXISTS.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testRecallMessage_timeout() {
+ // 鍑嗗锛氭秷鎭彂閫佷簬 10 鍒嗛挓鍓嶏紙瓒呰繃 5 鍒嗛挓绐楀彛锛�
+ ImPrivateMessageDO message = ImPrivateMessageDO.builder()
+ .id(10L).senderId(1L).receiverId(2L)
+ .status(ImMessageStatusEnum.NORMAL.getStatus())
+ .sendTime(LocalDateTime.now().minusMinutes(10)).build();
+ when(privateMessageMapper.selectById(10L)).thenReturn(message);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.recallPrivateMessage(1L, 10L));
+ assertEquals(MESSAGE_RECALL_TIMEOUT.getCode(), exception.getCode());
+ // 鏂█锛氫笉鎺ㄩ�併�佷笉鎻� tipMessage
+ verify(privateMessageMapper, never()).insert(any(ImPrivateMessageDO.class));
+ }
+
+ @Test
+ public void testSendMessage_sensitiveWordBlocked() {
+ // 鍑嗗锛氭枃鏈秷鎭懡涓晱鎰熻瘝
+ ImPrivateMessageSendReqVO reqVO = buildSendReqVO();
+ when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001"))
+ .thenReturn(null);
+ doThrow(new ServiceException(MESSAGE_SENSITIVE_WORD_BLOCKED))
+ .when(sensitiveWordService).validateText(reqVO.getContent());
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.sendPrivateMessage(1L, reqVO));
+ assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode());
+ // 鏂█锛氫笉鍏ュ簱銆佷笉鎺ㄩ��
+ verify(privateMessageMapper, never()).insert(any(ImPrivateMessageDO.class));
+ verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testReadMessages_disabled() {
+ // 鍑嗗锛氬叧闂鑱婂凡璇�
+ imProperties.getMessage().setPrivateReadEnabled(false);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.readPrivateMessages(1L, 2L, 5L));
+ assertEquals(MESSAGE_PRIVATE_READ_DISABLED.getCode(), exception.getCode());
+ // 鏂█锛氫笉鏇存柊娑堟伅鐘舵�併�佷笉鎺ㄩ��
+ verify(privateMessageMapper, never()).updateBySenderIdAndReceiverIdAndIdLeAndReceiptStatus(
+ anyLong(), anyLong(), anyLong(), anyInt(), any(ImPrivateMessageDO.class));
+ verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testReadMessages_notAdvanced() {
+ // 鍑嗗锛氳浣嶇疆鏈墠杩涳紙宸茶杩� / CAS 澶辫触锛夛紝涓嶄笅鍙戜簨浠�
+ when(conversationReadService.updateConversationReadPosition(anyLong(), anyInt(), anyLong(), anyLong()))
+ .thenReturn(false);
+
+ // 璋冪敤
+ privateMessageService.readPrivateMessages(1L, 2L, 5L);
+
+ // 鏂█锛氳浣嶇疆娌″墠杩涳紝涓嶆帹閫� READ / RECEIPT
+ verify(imWebSocketService, never()).sendNotificationAsync(anyLong(), anyInt(), anyInt(), any());
+ }
+
+ // ========== getMaxReadMessageId 娴嬭瘯 ==========
+
+ @Test
+ public void testGetMaxReadMessageId_hit() {
+ // 鍑嗗锛氬鏂�(2) 鍦ㄤ笌鎴�(1) 鐨勪細璇濋噷璇讳綅缃�=10
+ when(conversationReadService.getConversationReadMessageId(eq(2L), anyInt(), eq(1L)))
+ .thenReturn(10L);
+
+ // 璋冪敤
+ Long result = privateMessageService.getMaxReadMessageId(1L, 2L);
+
+ // 鏂█
+ assertEquals(10L, result);
+ }
+
+ @Test
+ public void testGetMaxReadMessageId_miss() {
+ // 鍑嗗锛氬鏂逛竴鏉¢兘娌¤杩囷紙璇讳綅缃负 null锛�
+ when(conversationReadService.getConversationReadMessageId(eq(2L), anyInt(), eq(1L)))
+ .thenReturn(null);
+
+ // 璋冪敤
+ Long result = privateMessageService.getMaxReadMessageId(1L, 2L);
+
+ // 鏂█锛氬師鏍疯繑鍥� null锛屽墠绔寜 falsy 璺宠繃
+ assertNull(result);
+ }
+
+ @Test
+ public void testGetMaxReadMessageId_disabled() {
+ // 鍑嗗锛氬叧闂鑱婂凡璇�
+ imProperties.getMessage().setPrivateReadEnabled(false);
+
+ // 璋冪敤骞舵柇瑷�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> privateMessageService.getMaxReadMessageId(1L, 2L));
+ assertEquals(MESSAGE_PRIVATE_READ_DISABLED.getCode(), exception.getCode());
+ }
+
+ // ========== DTO 绉佽亰娑堟伅 ==========
+
+ @Test
+ public void testSendPrivateMessage_dto_persistsAndSerializesPojoContent() {
+ // 鍑嗗锛歱ersistent=true 绫诲瀷 + POJO content
+ ImPrivateMessageSendDTO dto = new ImPrivateMessageSendDTO()
+ .setReceiverId(2L).setType(ImContentTypeEnum.RECALL.getType())
+ .setContent(new RecallMessage().setMessageId(50L));
+
+ privateMessageService.sendPrivateMessage(1L, dto);
+
+ // 鏂█锛氬叆搴� + 绯荤粺瀛楁鍏滃簳 + content 搴忓垪鍖栦负 JSON
+ ArgumentCaptor<ImPrivateMessageDO> captor = ArgumentCaptor.forClass(ImPrivateMessageDO.class);
+ verify(privateMessageMapper).insert(captor.capture());
+ ImPrivateMessageDO message = captor.getValue();
+ assertEquals(1L, message.getSenderId());
+ assertEquals(2L, message.getReceiverId());
+ assertEquals(ImContentTypeEnum.RECALL.getType(), message.getType());
+ assertEquals("{\"messageId\":50}", message.getContent());
+ assertEquals(ImMessageStatusEnum.NORMAL.getStatus(), message.getStatus());
+ assertNotNull(message.getClientMessageId());
+ assertNotNull(message.getSendTime());
+ // 鏂█锛歴ender + receiver 鍙岀鎺ㄩ��
+ verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any());
+ verify(imWebSocketService).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testSendPrivateMessage_dto_nonPersistentTypeNotInserted() {
+ // 鍑嗗锛歱ersistent=false 绫诲瀷锛團RIEND_DELETE 閫氱煡锛夆啋 涓嶅叆搴擄紱浠呮帹 sender 澶氱锛宺eceiver 涓嶆劅鐭�
+ ImPrivateMessageSendDTO dto = new ImPrivateMessageSendDTO()
+ .setReceiverId(2L).setType(ImContentTypeEnum.FRIEND_DELETE.getType());
+
+ privateMessageService.sendPrivateMessage(1L, dto);
+
+ verify(privateMessageMapper, never()).insert(any(ImPrivateMessageDO.class));
+ verify(imWebSocketService).sendNotificationAsync(eq(1L), anyInt(), anyInt(), any());
+ verify(imWebSocketService, never()).sendNotificationAsync(eq(2L), anyInt(), anyInt(), any());
+ }
+
+ // ========== getPrivateMessageList ==========
+
+ @Test
+ public void testGetPrivateMessageList_delegatesToMapper() {
+ // 鍑嗗
+ ImPrivateMessageListReqVO reqVO = new ImPrivateMessageListReqVO();
+ reqVO.setReceiverId(2L);
+ reqVO.setMaxId(100L);
+ reqVO.setLimit(20);
+ List<ImPrivateMessageDO> mockList = ListUtil.of(
+ ImPrivateMessageDO.builder().id(99L).senderId(1L).receiverId(2L).build(),
+ ImPrivateMessageDO.builder().id(98L).senderId(2L).receiverId(1L).build()
+ );
+ when(privateMessageMapper.selectHistoryList(1L, 2L, 100L, 20)).thenReturn(mockList);
+
+ // 璋冪敤
+ List<ImPrivateMessageDO> result = privateMessageService.getPrivateMessageList(1L, reqVO);
+
+ // 鏂█锛氶�忎紶鍒� mapper锛屽弬鏁颁竴鑷�
+ assertEquals(2, result.size());
+ verify(privateMessageMapper).selectHistoryList(1L, 2L, 100L, 20);
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImplTest.java
new file mode 100644
index 0000000..b178022
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImplTest.java
@@ -0,0 +1,391 @@
+package cn.iocoder.yudao.module.im.service.rtc;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallCreateReqVO;
+import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallInviteReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupMemberDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
+import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcParticipantDO;
+import cn.iocoder.yudao.module.im.dal.mysql.rtc.ImRtcCallMapper;
+import cn.iocoder.yudao.module.im.dal.mysql.rtc.ImRtcParticipantMapper;
+import cn.iocoder.yudao.module.im.dal.redis.rtc.ImRtcCallLockRedisDAO;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcCallStatusEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantRoleEnum;
+import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantStatusEnum;
+import cn.iocoder.yudao.module.im.framework.config.ImProperties;
+import cn.iocoder.yudao.module.im.service.group.ImGroupMemberService;
+import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.dao.DuplicateKeyException;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.RTC_GROUP_INVITEE_OVER_LIMIT;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.RTC_GROUP_INVITEE_REQUIRED;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.RTC_SELF_BUSY;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImRtcCallServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImRtcCallServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImRtcCallServiceImpl rtcCallService;
+
+ @Mock
+ private ImRtcParticipantMapper rtcParticipantMapper;
+ @Mock
+ private ImRtcCallMapper rtcCallMapper;
+ @Mock
+ private ImRtcCallLockRedisDAO rtcCallLockRedisDAO;
+ @Mock
+ private AdminUserApi adminUserApi;
+ @Mock
+ private ImWebSocketService webSocketService;
+ @Mock
+ private ImProperties imProperties;
+ @Mock
+ private ImGroupMemberService groupMemberService;
+
+ // ========== timeoutInvitingParticipants ==========
+
+ @Test
+ public void testTimeoutInvitingParticipants_emptyCandidates_returnsZeroAndNoDownstream() {
+ // 鍑嗗锛氭棤瓒呮椂鍊欓��
+ when(rtcParticipantMapper.selectListByStatusAndInviteTimeBefore(
+ eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), any(LocalDateTime.class)))
+ .thenReturn(Collections.emptyList());
+
+ // 璋冪敤
+ int result = rtcCallService.timeoutInvitingParticipants(1);
+
+ // 鏂█锛氳繑鍥� 0锛涙棤鍊欓�夋椂涓嶅簲瑙﹀彂 user 棰勬煡 / call 鏌ヨ / 鎺ㄩ��
+ assertEquals(0, result);
+ verifyNoInteractions(adminUserApi, rtcCallMapper, webSocketService);
+ }
+
+ @Test
+ public void testTimeoutInvitingParticipants_thresholdConvertedToCutoff() {
+ // 鍑嗗锛氶槇鍊� 5 鍒嗛挓锛沵ock 绌哄�欓�夐伩鍏嶈Е鍙戝悗缁�昏緫
+ when(rtcParticipantMapper.selectListByStatusAndInviteTimeBefore(any(), any(LocalDateTime.class)))
+ .thenReturn(Collections.emptyList());
+
+ // 璋冪敤
+ LocalDateTime before = LocalDateTime.now();
+ rtcCallService.timeoutInvitingParticipants(5);
+
+ // 鏂█锛歝utoff = now - 5 鍒嗛挓锛堝厑璁� 5 绉掓紓绉伙級
+ ArgumentCaptor<LocalDateTime> cutoffCaptor = ArgumentCaptor.forClass(LocalDateTime.class);
+ verify(rtcParticipantMapper).selectListByStatusAndInviteTimeBefore(
+ eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), cutoffCaptor.capture());
+ LocalDateTime cutoff = cutoffCaptor.getValue();
+ LocalDateTime expected = before.minusMinutes(5);
+ assertTrue(Duration.between(cutoff, expected).abs().getSeconds() < 5,
+ "cutoff 搴斿綋绾︾瓑浜� now - 5 min锛涘疄闄咃細" + cutoff);
+ }
+
+ @Test
+ public void testTimeoutInvitingParticipants_casAllFails_noPushNoEndSession() {
+ // 鍑嗗锛氬�欓�夐潪绌轰絾姣忎釜 CAS 閮藉け璐ワ紙骞跺彂宸插彉鐘舵�侊級
+ ImRtcParticipantDO p = buildParticipant(10L, "r1", 100L, ImRtcParticipantStatusEnum.INVITING);
+ when(rtcParticipantMapper.selectListByStatusAndInviteTimeBefore(any(), any()))
+ .thenReturn(ListUtil.of(p));
+ when(adminUserApi.getUserMap(anySet())).thenReturn(MapUtil.of(100L, buildUser(100L)));
+ when(rtcParticipantMapper.updateByIdAndStatus(eq(10L), eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), any()))
+ .thenReturn(0);
+
+ // 璋冪敤
+ int result = rtcCallService.timeoutInvitingParticipants(1);
+
+ // 鏂█锛欳AS 鍏ㄥけ璐ユ椂杩斿洖 0锛涗笉鏌� call銆佷笉鎺ㄩ��
+ assertEquals(0, result);
+ verify(rtcCallMapper, never()).selectByRoom(any());
+ verifyNoInteractions(webSocketService);
+ }
+
+ @Test
+ public void testTimeoutInvitingParticipants_groupCall_pushesNoAnswerSkipsEndSession() {
+ // 鍑嗗锛氱兢閫氳瘽鍗曞�欓�� CAS 鎴愬姛锛泂houldCloseGroupRoom 閫氳繃 selectListByRoom 澶� JOINED 璁╁叾杩� false锛岃烦杩� endSession
+ ImRtcParticipantDO p = buildParticipant(10L, "r1", 100L, ImRtcParticipantStatusEnum.INVITING);
+ when(rtcParticipantMapper.selectListByStatusAndInviteTimeBefore(any(), any()))
+ .thenReturn(ListUtil.of(p));
+ when(adminUserApi.getUserMap(anySet())).thenReturn(MapUtil.of(100L, buildUser(100L)));
+ when(rtcParticipantMapper.updateByIdAndStatus(eq(10L), eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), any()))
+ .thenReturn(1);
+ ImRtcCallDO call = buildCall("r1", 200L, ImConversationTypeEnum.GROUP, 999L);
+ when(rtcCallMapper.selectByRoom("r1")).thenReturn(call);
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(999L)).thenReturn(ListUtil.of(200L, 201L));
+ // 鎴垮唴 2 涓� JOINED + 1 涓� INVITING 鈫� shouldCloseGroupRoom 杩� false
+ when(rtcParticipantMapper.selectListByRoom("r1")).thenReturn(ListUtil.of(
+ buildParticipant(20L, "r1", 200L, ImRtcParticipantStatusEnum.JOINED),
+ buildParticipant(21L, "r1", 201L, ImRtcParticipantStatusEnum.JOINED),
+ buildParticipant(22L, "r1", 202L, ImRtcParticipantStatusEnum.INVITING)
+ ));
+
+ // 璋冪敤
+ int result = rtcCallService.timeoutInvitingParticipants(1);
+
+ // 鏂█锛氭垚鍔� 1 涓紱NO_ANSWER 淇′护鎺ㄥ埌涓诲彨锛涗笉瑙﹀彂 endSession
+ assertEquals(1, result);
+ verify(webSocketService).sendNotificationAsync(eq(200L), anyInt(), anyInt(), any());
+ verify(rtcCallMapper, never()).updateByIdAndStatusIn(any(), anyCollection(), any());
+ }
+
+ @Test
+ public void testTimeoutInvitingParticipants_callMissing_silentSkip() {
+ // 鍑嗗锛欳AS 鎴愬姛鍚庨�氳瘽涓昏〃缂哄け锛堝紓甯稿厹搴曞満鏅級
+ ImRtcParticipantDO p = buildParticipant(10L, "r1", 100L, ImRtcParticipantStatusEnum.INVITING);
+ when(rtcParticipantMapper.selectListByStatusAndInviteTimeBefore(any(), any()))
+ .thenReturn(ListUtil.of(p));
+ when(adminUserApi.getUserMap(anySet())).thenReturn(MapUtil.of(100L, buildUser(100L)));
+ when(rtcParticipantMapper.updateByIdAndStatus(eq(10L), eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), any()))
+ .thenReturn(1);
+ when(rtcCallMapper.selectByRoom("r1")).thenReturn(null);
+
+ // 璋冪敤
+ int result = rtcCallService.timeoutInvitingParticipants(1);
+
+ // 鏂█锛欳AS 宸叉垚鍔熶絾 call 缂哄け瑙嗕负閮ㄥ垎澶辫触杩� 0锛涗笉搴旀帹閫�
+ assertEquals(0, result);
+ verifyNoInteractions(webSocketService);
+ }
+
+ // ========== noAnswerCallCheck ==========
+
+ @Test
+ public void testNoAnswerCallCheck_authFails_silentNoOp() {
+ // 鍑嗗锛歴electByRoomAndUserId 杩� null 瑕嗙洊涓夌閴存潈澶辫触鍦烘櫙锛堥潪鍙備笌鑰� / 闈炴硶 room / null room锛�
+ when(rtcParticipantMapper.selectByRoomAndUserId(any(), eq(100L))).thenReturn(null);
+
+ // 璋冪敤
+ rtcCallService.noAnswerCallCheck(100L, "r1");
+ rtcCallService.noAnswerCallCheck(100L, "");
+ rtcCallService.noAnswerCallCheck(100L, null);
+
+ // 鏂█锛氫粎閴存潈鏌ヨ浜� 3 娆★紱涓嶅簲杩涘叆鍚庣画瓒呮椂鎵弿 / 鎺ㄩ��
+ verify(rtcParticipantMapper, times(3)).selectByRoomAndUserId(any(), eq(100L));
+ verify(rtcParticipantMapper, never()).selectListByRoomAndStatusAndInviteTimeBefore(any(), any(), any());
+ verifyNoInteractions(adminUserApi, webSocketService);
+ }
+
+ @Test
+ public void testNoAnswerCallCheck_usesBackendThreshold_notFrontend() {
+ // 鍑嗗锛氶壌鏉冮�氳繃 + 鍚庣閰嶇疆闃堝�� 2 鍒嗛挓 + 鏃犲�欓�夛紙閬垮厤瑙﹀彂鎺ㄩ�侊級
+ when(rtcParticipantMapper.selectByRoomAndUserId("r1", 100L))
+ .thenReturn(buildParticipant(10L, "r1", 100L, ImRtcParticipantStatusEnum.INVITING));
+ ImProperties.Rtc rtcConfig = new ImProperties.Rtc();
+ rtcConfig.setInviteTimeoutMinutes(2);
+ when(imProperties.getRtc()).thenReturn(rtcConfig);
+ when(rtcParticipantMapper.selectListByRoomAndStatusAndInviteTimeBefore(
+ eq("r1"), eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), any(LocalDateTime.class)))
+ .thenReturn(Collections.emptyList());
+
+ // 璋冪敤
+ LocalDateTime before = LocalDateTime.now();
+ rtcCallService.noAnswerCallCheck(100L, "r1");
+
+ // 鏂█锛氭壂鎻忔椂浣跨敤 cutoff = now - 2 鍒嗛挓锛堝悗绔厤缃級锛岃�岄潪鍓嶇 60s
+ ArgumentCaptor<LocalDateTime> cutoffCaptor = ArgumentCaptor.forClass(LocalDateTime.class);
+ verify(rtcParticipantMapper).selectListByRoomAndStatusAndInviteTimeBefore(
+ eq("r1"), eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), cutoffCaptor.capture());
+ LocalDateTime cutoff = cutoffCaptor.getValue();
+ LocalDateTime expected = before.minusMinutes(2);
+ assertTrue(Duration.between(cutoff, expected).abs().getSeconds() < 5,
+ "cutoff 搴斿綋绾︾瓑浜� now - 2 min锛堝悗绔厤缃級锛涘疄闄咃細" + cutoff);
+ }
+
+ @Test
+ public void testNoAnswerCallCheck_groupCall_pushesNoAnswer() {
+ // 鍑嗗锛氶壌鏉冮�氳繃 + 鍗曞�欓�� CAS 鎴愬姛 + 缇ら�氳瘽涓嶅叧鎴�
+ when(rtcParticipantMapper.selectByRoomAndUserId("r1", 100L))
+ .thenReturn(buildParticipant(10L, "r1", 100L, ImRtcParticipantStatusEnum.INVITING));
+ ImProperties.Rtc rtcConfig = new ImProperties.Rtc();
+ rtcConfig.setInviteTimeoutMinutes(1);
+ when(imProperties.getRtc()).thenReturn(rtcConfig);
+ ImRtcParticipantDO timeoutTarget = buildParticipant(11L, "r1", 101L, ImRtcParticipantStatusEnum.INVITING);
+ when(rtcParticipantMapper.selectListByRoomAndStatusAndInviteTimeBefore(
+ eq("r1"), eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), any()))
+ .thenReturn(ListUtil.of(timeoutTarget));
+ when(adminUserApi.getUserMap(anySet())).thenReturn(MapUtil.of(101L, buildUser(101L)));
+ when(rtcParticipantMapper.updateByIdAndStatus(eq(11L), eq(ImRtcParticipantStatusEnum.INVITING.getStatus()), any()))
+ .thenReturn(1);
+ ImRtcCallDO call = buildCall("r1", 200L, ImConversationTypeEnum.GROUP, 999L);
+ when(rtcCallMapper.selectByRoom("r1")).thenReturn(call);
+ when(groupMemberService.getActiveGroupMemberUserIdsByGroupId(999L)).thenReturn(ListUtil.of(200L, 201L));
+ // 璁� shouldCloseGroupRoom 杩� false
+ when(rtcParticipantMapper.selectListByRoom("r1")).thenReturn(ListUtil.of(
+ buildParticipant(20L, "r1", 200L, ImRtcParticipantStatusEnum.JOINED),
+ buildParticipant(21L, "r1", 201L, ImRtcParticipantStatusEnum.JOINED)
+ ));
+
+ // 璋冪敤
+ rtcCallService.noAnswerCallCheck(100L, "r1");
+
+ // 鏂█锛歂O_ANSWER 淇′护鎺ㄥ埌涓诲彨 200L锛涗笉瑙﹀彂 endSession
+ verify(webSocketService).sendNotificationAsync(eq(200L), anyInt(), anyInt(), any());
+ verify(rtcCallMapper, never()).updateByIdAndStatusIn(any(), anyCollection(), any());
+ }
+
+ // ========== createCall ==========
+
+ @Test
+ public void testCreateCall_groupOnlyInviteSelf_throwInviteeRequired() throws Exception {
+ when(imProperties.getRtc()).thenReturn(new ImProperties.Rtc());
+ when(rtcCallLockRedisDAO.lockGroup(eq(10L), any())).thenAnswer(invocation -> {
+ @SuppressWarnings("unchecked")
+ Callable<ImRtcCallDO> callable = invocation.getArgument(1);
+ return callable.call();
+ });
+ ImRtcCallCreateReqVO reqVO = new ImRtcCallCreateReqVO();
+ reqVO.setConversationType(ImConversationTypeEnum.GROUP.getType());
+ reqVO.setGroupId(10L);
+ reqVO.setInviteeIds(CollUtil.newHashSet(100L));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> rtcCallService.createCall(100L, reqVO));
+
+ assertEquals(RTC_GROUP_INVITEE_REQUIRED.getCode(), exception.getCode());
+ verify(rtcParticipantMapper, never()).insertBatch(anyList());
+ }
+
+ // ========== acceptCall / joinCall 蹇欑嚎鏍¢獙 ==========
+
+ @Test
+ public void testAcceptCall_joinedOtherRoom_throwSelfBusy() {
+ // 鍑嗗锛氬綋鍓嶉�氳瘽浠嶅湪閭�璇蜂腑锛屼絾鐢ㄦ埛宸插姞鍏ュ彟涓�涓埧闂�
+ when(imProperties.getRtc()).thenReturn(new ImProperties.Rtc());
+ ImRtcCallDO call = buildCall("r1", 200L, ImConversationTypeEnum.PRIVATE, null);
+ when(rtcCallMapper.selectByRoom("r1")).thenReturn(call);
+ when(rtcParticipantMapper.selectByRoomAndUserId("r1", 100L))
+ .thenReturn(buildParticipant(10L, "r1", 100L, ImRtcParticipantStatusEnum.INVITING));
+ when(rtcParticipantMapper.selectLastOneByUserIdAndStatusInAndRoomNot(eq(100L), anyCollection(), eq("r1")))
+ .thenReturn(buildParticipant(11L, "r2", 100L, ImRtcParticipantStatusEnum.JOINED));
+
+ // 璋冪敤 + 鏂█锛氭嫆缁濇帴鍚紝涓嶈鐩栧叾瀹冩埧闂寸姸鎬�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> rtcCallService.acceptCall(100L, "r1"));
+ assertEquals(RTC_SELF_BUSY.getCode(), exception.getCode());
+ verify(rtcParticipantMapper, never()).updateByIdAndStatus(eq(10L), any(), any());
+ }
+
+ @Test
+ public void testJoinCall_joinedOtherRoom_throwSelfBusy() {
+ // 鍑嗗锛氱兢閫氳瘽娲昏穬锛岀敤鎴峰凡鍔犲叆鍙︿竴涓埧闂�
+ when(imProperties.getRtc()).thenReturn(new ImProperties.Rtc());
+ ImRtcCallDO call = buildCall("r1", 200L, ImConversationTypeEnum.GROUP, 999L);
+ when(rtcCallMapper.selectByRoom("r1")).thenReturn(call);
+ when(groupMemberService.validateMemberInGroup(999L, 100L)).thenReturn(new ImGroupMemberDO());
+ when(rtcParticipantMapper.selectLastOneByUserIdAndStatusInAndRoomNot(eq(100L), anyCollection(), eq("r1")))
+ .thenReturn(buildParticipant(11L, "r2", 100L, ImRtcParticipantStatusEnum.JOINED));
+
+ // 璋冪敤 + 鏂█锛氭嫆缁濆姞鍏ワ紝涓嶅啓鍙備笌鑰呯姸鎬�
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> rtcCallService.joinCall(100L, "r1"));
+ assertEquals(RTC_SELF_BUSY.getCode(), exception.getCode());
+ verify(rtcParticipantMapper, never()).insert(any(ImRtcParticipantDO.class));
+ verify(rtcParticipantMapper, never()).updateById(any(ImRtcParticipantDO.class));
+ }
+
+ @Test
+ public void testJoinCall_insertDuplicateKey_reuseExistingParticipant() {
+ // 鍑嗗锛氱兢閫氳瘽娲昏穬锛岄娆℃煡璇㈡棤鍙備笌鑰咃紝鎻掑叆鏃跺懡涓敮涓�閿�
+ when(imProperties.getRtc()).thenReturn(new ImProperties.Rtc());
+ ImRtcCallDO call = buildCall("r1", 200L, ImConversationTypeEnum.GROUP, 999L);
+ when(rtcCallMapper.selectByRoom("r1")).thenReturn(call);
+ when(groupMemberService.validateMemberInGroup(999L, 100L)).thenReturn(new ImGroupMemberDO());
+ when(rtcParticipantMapper.selectLastOneByUserIdAndStatusInAndRoomNot(eq(100L), anyCollection(), eq("r1")))
+ .thenReturn(null);
+ when(rtcParticipantMapper.selectByRoomAndUserId("r1", 100L))
+ .thenReturn(null, buildParticipant(10L, "r1", 100L, ImRtcParticipantStatusEnum.JOINED));
+ when(rtcParticipantMapper.insert(any(ImRtcParticipantDO.class))).thenThrow(new DuplicateKeyException("dup"));
+
+ // 璋冪敤
+ ImRtcCallDO result = rtcCallService.joinCall(100L, "r1");
+
+ // 鏂█锛氫笉鍚戜笂鎶涙暟鎹簱寮傚父
+ assertSame(call, result);
+ verify(rtcParticipantMapper, never()).updateById(any(ImRtcParticipantDO.class));
+ }
+
+ @Test
+ public void testInviteCall_overLimit_throws() throws Exception {
+ ImProperties.Rtc rtcConfig = new ImProperties.Rtc();
+ rtcConfig.setGroupMaxParticipants(3);
+ when(imProperties.getRtc()).thenReturn(rtcConfig);
+ ImRtcCallDO call = buildCall("r1", 200L, ImConversationTypeEnum.GROUP, 999L);
+ when(rtcCallMapper.selectByRoom("r1")).thenReturn(call);
+ when(rtcParticipantMapper.selectByRoomAndUserId("r1", 200L))
+ .thenReturn(buildParticipant(10L, "r1", 200L, ImRtcParticipantStatusEnum.JOINED));
+ when(rtcCallLockRedisDAO.lockGroup(eq(999L), any())).thenAnswer(invocation -> {
+ @SuppressWarnings("unchecked")
+ Callable<Void> callable = invocation.getArgument(1);
+ return callable.call();
+ });
+ when(rtcParticipantMapper.selectListByRoom("r1")).thenReturn(ListUtil.of(
+ buildParticipant(10L, "r1", 200L, ImRtcParticipantStatusEnum.JOINED),
+ buildParticipant(11L, "r1", 201L, ImRtcParticipantStatusEnum.JOINED),
+ buildParticipant(12L, "r1", 202L, ImRtcParticipantStatusEnum.INVITING)
+ ));
+ ImRtcCallInviteReqVO reqVO = new ImRtcCallInviteReqVO();
+ reqVO.setRoom("r1");
+ reqVO.setInviteeIds(CollUtil.newHashSet(203L));
+
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> rtcCallService.inviteCall(200L, reqVO));
+
+ assertEquals(RTC_GROUP_INVITEE_OVER_LIMIT.getCode(), exception.getCode());
+ verify(rtcParticipantMapper, never()).insertBatch(anyList());
+ }
+
+ // ========== 娴嬭瘯鏁版嵁鏋勯�� ==========
+
+ private ImRtcParticipantDO buildParticipant(Long id, String room, Long userId, ImRtcParticipantStatusEnum status) {
+ return new ImRtcParticipantDO()
+ .setId(id)
+ .setRoom(room)
+ .setUserId(userId)
+ .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole())
+ .setStatus(status.getStatus())
+ .setInviteTime(LocalDateTime.now());
+ }
+
+ private ImRtcCallDO buildCall(String room, Long inviterUserId, ImConversationTypeEnum conversationType, Long groupId) {
+ return new ImRtcCallDO()
+ .setRoom(room)
+ .setConversationType(conversationType.getType())
+ .setMediaType(1)
+ .setInviterUserId(inviterUserId)
+ .setGroupId(groupId)
+ .setStatus(ImRtcCallStatusEnum.RUNNING.getStatus())
+ .setStartTime(LocalDateTime.now());
+ }
+
+ private AdminUserRespDTO buildUser(Long id) {
+ AdminUserRespDTO user = new AdminUserRespDTO();
+ user.setId(id);
+ user.setNickname("user-" + id);
+ return user;
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImplTest.java
new file mode 100644
index 0000000..5e7711d
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/sensitiveword/ImSensitiveWordServiceImplTest.java
@@ -0,0 +1,278 @@
+package cn.iocoder.yudao.module.im.service.sensitiveword;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.controller.admin.manager.sensitiveword.vo.ImSensitiveWordSaveReqVO;
+import cn.iocoder.yudao.module.im.dal.dataobject.sensitiveword.ImSensitiveWordDO;
+import cn.iocoder.yudao.module.im.dal.mysql.sensitiveword.ImSensitiveWordMapper;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_SENSITIVE_WORD_BLOCKED;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.SENSITIVE_WORD_DUPLICATED;
+import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.SENSITIVE_WORD_NOT_EXISTS;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImSensitiveWordServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImSensitiveWordServiceImplTest extends BaseMockitoUnitTest {
+
+ private static final Long TENANT_ID = 1L;
+
+ @InjectMocks
+ private ImSensitiveWordServiceImpl sensitiveWordService;
+
+ @Mock
+ private ImSensitiveWordMapper imSensitiveWordMapper;
+
+ @BeforeEach
+ public void setUp() {
+ // 璁剧疆绉熸埛涓婁笅鏂囷紱validateText 涓� loadFresh 閮戒緷璧� TenantContextHolder
+ TenantContextHolder.setTenantId(TENANT_ID);
+ // mock 鍚敤鏁忔劅璇嶅垪琛紱LoadingCache 鍦ㄩ娆� validateText 鏃舵噿鍔犺浇锛屾棤闇�涓诲姩 init
+ // 鐢� lenient 閬垮厤 null / empty 绛変笉瑙﹀彂 cache load 鐨勭敤渚嬫姤 UnnecessaryStubbing
+ lenient().when(imSensitiveWordMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()))
+ .thenReturn(ListUtil.of(
+ ImSensitiveWordDO.builder().id(1L).word("badword")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImSensitiveWordDO.builder().id(2L).word("杩濈璇�")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ ));
+ }
+
+ @AfterEach
+ public void tearDown() {
+ // 娓呯悊绉熸埛涓婁笅鏂囷紝閬垮厤姹℃煋鍏跺畠娴嬭瘯
+ TenantContextHolder.clear();
+ }
+
+ @Test
+ public void testValidateText_null() {
+ // null 鐩存帴杩斿洖锛屼笉鎶涘紓甯�
+ assertDoesNotThrow(() -> sensitiveWordService.validateText(null));
+ }
+
+ @Test
+ public void testValidateText_empty() {
+ assertDoesNotThrow(() -> sensitiveWordService.validateText(""));
+ }
+
+ @Test
+ public void testValidateText_clean() {
+ // 姝e父鏂囨湰涓嶅簲鍛戒腑
+ assertDoesNotThrow(() -> sensitiveWordService.validateText("hello world"));
+ }
+
+ @Test
+ public void testValidateText_hitEnglish() {
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> sensitiveWordService.validateText("this contains badword here"));
+ assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testValidateText_hitChinese() {
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> sensitiveWordService.validateText("杩欐潯娑堟伅閲屾湁杩濈璇嶅摝"));
+ assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode());
+ }
+
+ @Test
+ public void testValidateText_lazyLoadsCacheOnFirstCall() {
+ // 璋冪敤锛氶娆� validateText 搴旇Е鍙� cache load
+ sensitiveWordService.validateText("hello world");
+
+ // 鏂█锛歮apper 鍚勮皟鐢� 1 娆★紙loadFresh 閲屽厛鍙� maxUpdateTime 鍐嶈璇嶅簱锛�
+ verify(imSensitiveWordMapper, times(1)).selectMaxUpdateTime(TENANT_ID);
+ verify(imSensitiveWordMapper, times(1)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Test
+ public void testValidateText_reusesCachedBsAcrossCalls() {
+ // 璋冪敤锛氳繛缁袱娆� validateText
+ sensitiveWordService.validateText("hello world");
+ sensitiveWordService.validateText("another text");
+
+ // 鏂█锛氱浜屾澶嶇敤 cache锛宮apper 浠嶅彧琚皟鐢� 1 娆�
+ verify(imSensitiveWordMapper, times(1)).selectMaxUpdateTime(TENANT_ID);
+ verify(imSensitiveWordMapper, times(1)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Test
+ public void testCreateSensitiveWord_invalidatesCacheAndReloadsOnNextValidate() {
+ // 鍑嗗锛氶娆� validateText 瑙﹀彂 cache load锛堟棫璇嶅簱锛�
+ sensitiveWordService.validateText("hello world");
+ verify(imSensitiveWordMapper, times(1)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+
+ // 鍑嗗锛歮apper 杩斿洖鏂拌瘝搴擄紙棰濆澶氫竴涓� newbad锛夛紝骞惰 createSensitiveWord 璧伴��
+ when(imSensitiveWordMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()))
+ .thenReturn(ListUtil.of(
+ ImSensitiveWordDO.builder().id(1L).word("badword")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImSensitiveWordDO.builder().id(2L).word("杩濈璇�")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build(),
+ ImSensitiveWordDO.builder().id(3L).word("newbad")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ ));
+ when(imSensitiveWordMapper.selectByWord("newbad")).thenReturn(null);
+
+ // 璋冪敤锛氭柊澧炴晱鎰熻瘝锛岃Е鍙� invalidate
+ ImSensitiveWordSaveReqVO reqVO = new ImSensitiveWordSaveReqVO();
+ reqVO.setWord("newbad");
+ reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+ sensitiveWordService.createSensitiveWord(reqVO);
+
+ // 璋冪敤锛氬啀娆� validateText锛屽簲瑙﹀彂閲嶆柊 load
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> sensitiveWordService.validateText("contains newbad here"));
+ assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode());
+ // 鏃ц瘝渚濈劧鍛戒腑
+ assertThrows(ServiceException.class,
+ () -> sensitiveWordService.validateText("contains badword here"));
+
+ // 鏂█锛歴electListByStatus 鍏辫璋冪敤 2 娆★紙棣栨 load + invalidate 鍚� reload锛�
+ verify(imSensitiveWordMapper, times(2)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Test
+ public void testCreateSensitiveWord_duplicateWord_throws() {
+ // 鍑嗗锛歮ock 宸插瓨鍦ㄥ悓鍚嶆晱鎰熻瘝
+ when(imSensitiveWordMapper.selectByWord("dup")).thenReturn(
+ ImSensitiveWordDO.builder().id(99L).word("dup")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+
+ // 璋冪敤 + 鏂█锛氶噸澶嶆晱鎰熻瘝鎶� SENSITIVE_WORD_DUPLICATED
+ ImSensitiveWordSaveReqVO reqVO = new ImSensitiveWordSaveReqVO();
+ reqVO.setWord("dup");
+ reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> sensitiveWordService.createSensitiveWord(reqVO));
+ assertEquals(SENSITIVE_WORD_DUPLICATED.getCode(), exception.getCode());
+
+ // 鏂█锛氭湭璧板埌 insert
+ verify(imSensitiveWordMapper, never()).insert(any(ImSensitiveWordDO.class));
+ }
+
+ @Test
+ public void testUpdateSensitiveWord_invalidatesCache() {
+ // 鍑嗗锛氶娆� validateText 瑙﹀彂 cache load
+ sensitiveWordService.validateText("hello world");
+ verify(imSensitiveWordMapper, times(1)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+
+ // 鍑嗗锛氳 update 鏍¢獙閫氳繃
+ when(imSensitiveWordMapper.selectById(1L)).thenReturn(
+ ImSensitiveWordDO.builder().id(1L).word("badword")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ when(imSensitiveWordMapper.selectByWord("updatedbad")).thenReturn(null);
+ // 鍑嗗锛歳eload 鏃惰繑鍥炴柊璇嶅簱
+ when(imSensitiveWordMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()))
+ .thenReturn(ListUtil.of(
+ ImSensitiveWordDO.builder().id(1L).word("updatedbad")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ ));
+
+ // 璋冪敤锛氭洿鏂版晱鎰熻瘝锛岃Е鍙� invalidate
+ ImSensitiveWordSaveReqVO reqVO = new ImSensitiveWordSaveReqVO();
+ reqVO.setId(1L);
+ reqVO.setWord("updatedbad");
+ reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+ sensitiveWordService.updateSensitiveWord(reqVO);
+
+ // 璋冪敤 + 鏂█锛氬啀娆� validateText 搴斾娇鐢ㄦ柊璇嶅簱
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> sensitiveWordService.validateText("contains updatedbad here"));
+ assertEquals(MESSAGE_SENSITIVE_WORD_BLOCKED.getCode(), exception.getCode());
+
+ // 鏂█锛歴electListByStatus 鍏辫璋冪敤 2 娆�
+ verify(imSensitiveWordMapper, times(2)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Test
+ public void testDeleteSensitiveWord_invalidatesCache() {
+ // 鍑嗗锛氶娆� validateText 瑙﹀彂 cache load
+ sensitiveWordService.validateText("hello world");
+ verify(imSensitiveWordMapper, times(1)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+
+ // 鍑嗗锛氳 delete 鏍¢獙閫氳繃
+ when(imSensitiveWordMapper.selectById(1L)).thenReturn(
+ ImSensitiveWordDO.builder().id(1L).word("badword")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build());
+ // 鍑嗗锛歳eload 鏃惰繑鍥炲墿浣欒瘝搴擄紙鍙墿涓枃閭f潯锛�
+ when(imSensitiveWordMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()))
+ .thenReturn(ListUtil.of(
+ ImSensitiveWordDO.builder().id(2L).word("杩濈璇�")
+ .status(CommonStatusEnum.ENABLE.getStatus()).build()
+ ));
+
+ // 璋冪敤锛氬垹闄� badword锛岃Е鍙� invalidate
+ sensitiveWordService.deleteSensitiveWord(1L);
+
+ // 璋冪敤 + 鏂█锛歜adword 宸茶鍒狅紝涓嶅啀鍛戒腑
+ assertDoesNotThrow(() -> sensitiveWordService.validateText("contains badword here"));
+ // 涓枃璇嶄緷鐒跺湪
+ assertThrows(ServiceException.class,
+ () -> sensitiveWordService.validateText("杩欐潯娑堟伅閲屾湁杩濈璇嶅摝"));
+
+ // 鏂█锛歴electListByStatus 鍏辫璋冪敤 2 娆�
+ verify(imSensitiveWordMapper, times(2)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Test
+ public void testDeleteSensitiveWord_notExists_throws() {
+ // 鍑嗗锛歴electById 杩斿洖 null
+ when(imSensitiveWordMapper.selectById(999L)).thenReturn(null);
+
+ // 璋冪敤 + 鏂█锛氭姏 SENSITIVE_WORD_NOT_EXISTS
+ ServiceException exception = assertThrows(ServiceException.class,
+ () -> sensitiveWordService.deleteSensitiveWord(999L));
+ assertEquals(SENSITIVE_WORD_NOT_EXISTS.getCode(), exception.getCode());
+
+ // 鏂█锛氭湭璧板埌 deleteById
+ verify(imSensitiveWordMapper, never()).deleteById(anyLong());
+ }
+
+ @Test
+ public void testDeleteSensitiveWordList_invalidatesCache() {
+ // 鍑嗗锛氶娆� validateText 瑙﹀彂 cache load
+ sensitiveWordService.validateText("hello world");
+ verify(imSensitiveWordMapper, times(1)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+
+ // 鍑嗗锛歳eload 鏃惰繑鍥炵┖璇嶅簱
+ when(imSensitiveWordMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()))
+ .thenReturn(ListUtil.of());
+
+ // 璋冪敤锛氭壒閲忓垹闄わ紝瑙﹀彂 invalidate
+ sensitiveWordService.deleteSensitiveWordList(ListUtil.of(1L, 2L));
+
+ // 璋冪敤 + 鏂█锛氭墍鏈夎瘝閮戒笉鍐嶅懡涓�
+ assertDoesNotThrow(() -> sensitiveWordService.validateText("contains badword here"));
+ assertDoesNotThrow(() -> sensitiveWordService.validateText("杩欐潯娑堟伅閲屾湁杩濈璇嶅摝"));
+
+ // 鏂█锛歞eleteByIds 琚皟鐢� 1 娆★紱selectListByStatus 鍏� 2 娆�
+ verify(imSensitiveWordMapper, times(1)).deleteByIds(ListUtil.of(1L, 2L));
+ verify(imSensitiveWordMapper, times(2)).selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ }
+
+ @Test
+ public void testDeleteSensitiveWordList_emptyIds_skip() {
+ // 璋冪敤锛氱┖鍒楄〃鐩存帴杩斿洖
+ sensitiveWordService.deleteSensitiveWordList(ListUtil.of());
+
+ // 鏂█锛歮apper 涓嶈璋冪敤
+ verify(imSensitiveWordMapper, never()).deleteByIds(anyList());
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImplTest.java
new file mode 100644
index 0000000..a55037d
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/statistics/ImStatisticsManagerServiceImplTest.java
@@ -0,0 +1,162 @@
+package cn.iocoder.yudao.module.im.service.statistics;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.dal.mysql.statistics.ImStatisticsManagerMapper;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+import java.math.BigInteger;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link ImStatisticsManagerServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImStatisticsManagerServiceImplTest extends BaseMockitoUnitTest {
+
+ private static final LocalDateTime BEGIN = LocalDateTime.of(2026, 1, 1, 0, 0);
+ private static final LocalDateTime END = LocalDateTime.of(2026, 2, 1, 0, 0);
+
+ @InjectMocks
+ private ImStatisticsManagerServiceImpl service;
+
+ @Mock
+ private ImStatisticsManagerMapper statisticsMapper;
+
+ // ========== 鍗曞�煎鎵� ==========
+
+ @Test
+ public void testGetTotalUserCount_delegate() {
+ when(statisticsMapper.selectTotalUserCount()).thenReturn(99L);
+ assertEquals(99L, service.getTotalUserCount());
+ }
+
+ @Test
+ public void testGetNewUserCount_delegate() {
+ when(statisticsMapper.selectNewUserCount(BEGIN, END)).thenReturn(10L);
+ assertEquals(10L, service.getNewUserCount(BEGIN, END));
+ }
+
+ @Test
+ public void testGetActiveUserCount_delegate() {
+ when(statisticsMapper.selectActiveUserCount(BEGIN, END)).thenReturn(5L);
+ assertEquals(5L, service.getActiveUserCount(BEGIN, END));
+ }
+
+ @Test
+ public void testGetTotalGroupCount_delegate() {
+ when(statisticsMapper.selectTotalGroupCount()).thenReturn(33L);
+ assertEquals(33L, service.getTotalGroupCount());
+ }
+
+ @Test
+ public void testGetPrivateMessageCount_delegate() {
+ when(statisticsMapper.selectPrivateMessageCount(BEGIN, END)).thenReturn(123L);
+ assertEquals(123L, service.getPrivateMessageCount(BEGIN, END));
+ }
+
+ @Test
+ public void testGetGroupMessageCount_delegate() {
+ when(statisticsMapper.selectGroupMessageCount(BEGIN, END)).thenReturn(456L);
+ assertEquals(456L, service.getGroupMessageCount(BEGIN, END));
+ }
+
+ // ========== 姣忔棩搴忓垪 ==========
+
+ @Test
+ public void testGetNewUserDailyCountMap_dateConvert() {
+ // 鍑嗗锛歞ate 瀛楁浠� SQL Date / String 娣峰叆锛宑ount 娣峰叆澶氱 Number
+ when(statisticsMapper.selectNewUserDailyCount(eq(BEGIN), eq(END))).thenReturn(Arrays.asList(
+ row("date", java.sql.Date.valueOf("2026-01-10"), "count", BigInteger.valueOf(5)),
+ row("date", "2026-01-11", "count", 8)));
+
+ // 璋冪敤
+ Map<LocalDateTime, Long> result = service.getNewUserDailyCountMap(BEGIN, END);
+
+ // 鏂█锛歞ate 鈫� LocalDateTime 璧峰闆剁偣
+ assertEquals(2, result.size());
+ assertEquals(5L, result.get(LocalDate.of(2026, 1, 10).atStartOfDay()));
+ assertEquals(8L, result.get(LocalDate.of(2026, 1, 11).atStartOfDay()));
+ }
+
+ @Test
+ public void testGetActiveUserDailyCountMap_dateConvert() {
+ when(statisticsMapper.selectActiveUserDailyCount(any(), any())).thenReturn(Arrays.asList(
+ row("date", "2026-01-10", "count", 3L)));
+
+ Map<LocalDateTime, Long> result = service.getActiveUserDailyCountMap(BEGIN, END);
+ assertEquals(3L, result.get(LocalDate.of(2026, 1, 10).atStartOfDay()));
+ }
+
+ @Test
+ public void testGetPrivateMessageDailyCountMap_dateConvert() {
+ when(statisticsMapper.selectPrivateMessageDailyCount(any(), any())).thenReturn(Arrays.asList(
+ row("date", "2026-01-10", "count", 7L)));
+ assertEquals(7L, service.getPrivateMessageDailyCountMap(BEGIN, END)
+ .get(LocalDate.of(2026, 1, 10).atStartOfDay()));
+ }
+
+ @Test
+ public void testGetGroupMessageDailyCountMap_dateConvert() {
+ when(statisticsMapper.selectGroupMessageDailyCount(any(), any())).thenReturn(Arrays.asList(
+ row("date", "2026-01-10", "count", 9L)));
+ assertEquals(9L, service.getGroupMessageDailyCountMap(BEGIN, END)
+ .get(LocalDate.of(2026, 1, 10).atStartOfDay()));
+ }
+
+ // ========== 鍒嗘《 / 鍒嗗竷 ==========
+
+ @Test
+ public void testGetGroupSizeCountMap() {
+ when(statisticsMapper.selectGroupSizeDistribution()).thenReturn(Arrays.asList(
+ row("range", "1-9 浜�", "count", BigInteger.valueOf(3)),
+ row("range", "10-49 浜�", "count", 2)));
+
+ Map<String, Long> result = service.getGroupSizeCountMap();
+ assertEquals(3L, result.get("1-9 浜�"));
+ assertEquals(2L, result.get("10-49 浜�"));
+ }
+
+ @Test
+ public void testGetMessageTypeCountMap() {
+ when(statisticsMapper.selectMessageTypeDistribution(BEGIN, END)).thenReturn(Arrays.asList(
+ row("type", 101L, "count", BigInteger.valueOf(8)),
+ row("type", 102, "count", 1)));
+
+ Map<Integer, Long> result = service.getMessageTypeCountMap(BEGIN, END);
+ assertEquals(8L, result.get(101));
+ assertEquals(1L, result.get(102));
+ }
+
+ @Test
+ public void testGetTopSenderCountMap_passesLimit() {
+ when(statisticsMapper.selectTopSenders(BEGIN, END, 3)).thenReturn(Arrays.asList(
+ row("userId", 1, "messageCount", BigInteger.valueOf(10)),
+ row("userId", 2L, "messageCount", 5)));
+
+ Map<Long, Long> result = service.getTopSenderCountMap(BEGIN, END, 3);
+ assertEquals(10L, result.get(1L));
+ assertEquals(5L, result.get(2L));
+ }
+
+ // ========== 宸ュ叿 ==========
+
+ private static Map<String, Object> row(String k1, Object v1, String k2, Object v2) {
+ Map<String, Object> map = new HashMap<>();
+ map.put(k1, v1);
+ map.put(k2, v2);
+ return map;
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImplTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImplTest.java
new file mode 100644
index 0000000..898aa1e
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/websocket/ImWebSocketServiceImplTest.java
@@ -0,0 +1,256 @@
+package cn.iocoder.yudao.module.im.service.websocket;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.im.enums.ImContentTypeEnum;
+import cn.iocoder.yudao.module.im.enums.ImConversationTypeEnum;
+import cn.iocoder.yudao.module.im.service.websocket.notification.ImNotificationWebSocketDTO;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImGroupMessageNotification;
+import cn.iocoder.yudao.module.im.service.websocket.notification.message.ImPrivateMessageNotification;
+import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link ImWebSocketServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImWebSocketServiceImplTest extends BaseMockitoUnitTest {
+
+ @InjectMocks
+ private ImWebSocketServiceImpl imWebSocketService;
+
+ @Mock
+ private WebSocketSenderApi webSocketSenderApi;
+
+ @AfterEach
+ public void tearDown() {
+ // 娓呯悊浜嬪姟鍚屾涓婁笅鏂囷紝閬垮厤涓叉壈鍏跺畠鐢ㄤ緥
+ if (TransactionSynchronizationManager.isSynchronizationActive()) {
+ TransactionSynchronizationManager.clearSynchronization();
+ }
+ }
+
+ // ========== 绉佽亰鎺ㄩ�� ==========
+
+ @Test
+ public void testSendNotificationAsync_private_noTransactionSendsImmediately() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImWebSocketServiceImpl.class)))
+ .thenReturn(imWebSocketService);
+
+ // 鍑嗗
+ ImPrivateMessageNotification dto = new ImPrivateMessageNotification().setSenderId(1L).setReceiverId(2L)
+ .setType(ImContentTypeEnum.TEXT.getType());
+
+ // 璋冪敤锛氭棤浜嬪姟锛屽簲绔嬪嵆鍙戦��
+ imWebSocketService.sendNotificationAsync(2L, ImConversationTypeEnum.PRIVATE.getType(),
+ ImContentTypeEnum.TEXT.getType(), dto);
+
+ // 鏂█
+ verify(webSocketSenderApi).sendObject(
+ eq(UserTypeEnum.ADMIN.getValue()), eq(2L), eq(ImNotificationWebSocketDTO.TYPE),
+ argThat(actual -> isNotification(actual, ImConversationTypeEnum.PRIVATE,
+ ImContentTypeEnum.TEXT, dto)));
+ }
+ }
+
+ @Test
+ public void testSendNotificationAsync_private_inTransactionDeferredUntilCommit() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImWebSocketServiceImpl.class)))
+ .thenReturn(imWebSocketService);
+
+ // 鍑嗗锛氬紑鍚簨鍔″悓姝�
+ TransactionSynchronizationManager.initSynchronization();
+ try {
+ ImPrivateMessageNotification dto = new ImPrivateMessageNotification().setSenderId(1L).setReceiverId(2L)
+ .setType(ImContentTypeEnum.TEXT.getType());
+
+ // 璋冪敤
+ imWebSocketService.sendNotificationAsync(2L, ImConversationTypeEnum.PRIVATE.getType(),
+ ImContentTypeEnum.TEXT.getType(), dto);
+
+ // 鏂█锛氫簨鍔℃湭鎻愪氦锛屾湭鎺ㄩ��
+ verify(webSocketSenderApi, never()).sendObject(anyInt(), anyLong(), anyString(), any());
+
+ // 妯℃嫙浜嬪姟鎻愪氦
+ List<TransactionSynchronization> syncs =
+ TransactionSynchronizationManager.getSynchronizations();
+ assertEquals(1, syncs.size());
+ syncs.forEach(TransactionSynchronization::afterCommit);
+
+ // 鏂█锛氭彁浜ゅ悗鎺ㄩ��
+ verify(webSocketSenderApi).sendObject(
+ eq(UserTypeEnum.ADMIN.getValue()), eq(2L), eq(ImNotificationWebSocketDTO.TYPE),
+ argThat(actual -> isNotification(actual, ImConversationTypeEnum.PRIVATE,
+ ImContentTypeEnum.TEXT, dto)));
+ } finally {
+ TransactionSynchronizationManager.clear();
+ }
+ }
+ }
+
+ // ========== 缇よ亰鎺ㄩ�� ==========
+
+ @Test
+ public void testSendNotificationAsync_group_fanOutToAllUsers() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImWebSocketServiceImpl.class)))
+ .thenReturn(imWebSocketService);
+
+ ImGroupMessageNotification dto = new ImGroupMessageNotification();
+ dto.setGroupId(10L);
+ dto.setSenderId(1L);
+ dto.setType(ImContentTypeEnum.TEXT.getType());
+
+ imWebSocketService.sendNotificationAsync(ListUtil.of(1L, 2L, 3L),
+ ImConversationTypeEnum.GROUP.getType(), ImContentTypeEnum.TEXT.getType(), dto);
+
+ verify(webSocketSenderApi).sendObject(
+ eq(UserTypeEnum.ADMIN.getValue()), eq(1L), eq(ImNotificationWebSocketDTO.TYPE),
+ argThat(actual -> isNotification(actual, ImConversationTypeEnum.GROUP,
+ ImContentTypeEnum.TEXT, dto)));
+ verify(webSocketSenderApi).sendObject(
+ eq(UserTypeEnum.ADMIN.getValue()), eq(2L), eq(ImNotificationWebSocketDTO.TYPE),
+ argThat(actual -> isNotification(actual, ImConversationTypeEnum.GROUP,
+ ImContentTypeEnum.TEXT, dto)));
+ verify(webSocketSenderApi).sendObject(
+ eq(UserTypeEnum.ADMIN.getValue()), eq(3L), eq(ImNotificationWebSocketDTO.TYPE),
+ argThat(actual -> isNotification(actual, ImConversationTypeEnum.GROUP,
+ ImContentTypeEnum.TEXT, dto)));
+ }
+ }
+
+ @Test
+ public void testSendNotificationAsync_group_senderExceptionDoesNotBreakOthers() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImWebSocketServiceImpl.class)))
+ .thenReturn(imWebSocketService);
+
+ ImGroupMessageNotification dto = new ImGroupMessageNotification();
+ dto.setGroupId(10L);
+ // 缁� 1 鍙风敤鎴锋帹閫佹椂鎶涘紓甯革紝涓嶈兘褰卞搷 2/3 鍙�
+ doThrow(new RuntimeException("user offline"))
+ .when(webSocketSenderApi).sendObject(anyInt(), eq(1L), anyString(), any());
+
+ imWebSocketService.sendNotificationAsync(ListUtil.of(1L, 2L, 3L),
+ ImConversationTypeEnum.GROUP.getType(), ImContentTypeEnum.TEXT.getType(), dto);
+
+ // 2L 鍜� 3L 涔熼兘琚帹閫�
+ verify(webSocketSenderApi).sendObject(anyInt(), eq(2L), anyString(), any());
+ verify(webSocketSenderApi).sendObject(anyInt(), eq(3L), anyString(), any());
+ }
+ }
+
+ @Test
+ public void testDoSendNotification_emptyUserIds_noSend() {
+ ImGroupMessageNotification dto = new ImGroupMessageNotification();
+ dto.setGroupId(10L);
+ dto.setType(ImContentTypeEnum.TEXT.getType());
+ ImNotificationWebSocketDTO notification = buildNotification(ImConversationTypeEnum.GROUP,
+ ImContentTypeEnum.TEXT, dto);
+
+ imWebSocketService.doSendNotification(Collections.emptyList(), notification);
+ imWebSocketService.doSendNotification(null, notification);
+
+ verifyNoInteractions(webSocketSenderApi);
+ }
+
+ @Test
+ public void testDoSendNotification_distinctUserIds() {
+ ImGroupMessageNotification dto = new ImGroupMessageNotification();
+ dto.setGroupId(10L);
+ dto.setType(ImContentTypeEnum.TEXT.getType());
+ ImNotificationWebSocketDTO notification = buildNotification(ImConversationTypeEnum.GROUP,
+ ImContentTypeEnum.TEXT, dto);
+
+ imWebSocketService.doSendNotification(Arrays.asList(1L, 2L, 1L, null), notification);
+
+ verify(webSocketSenderApi).sendObject(
+ eq(UserTypeEnum.ADMIN.getValue()), eq(1L), eq(ImNotificationWebSocketDTO.TYPE),
+ argThat(actual -> isNotification(actual, ImConversationTypeEnum.GROUP,
+ ImContentTypeEnum.TEXT, dto)));
+ verify(webSocketSenderApi).sendObject(
+ eq(UserTypeEnum.ADMIN.getValue()), eq(2L), eq(ImNotificationWebSocketDTO.TYPE),
+ argThat(actual -> isNotification(actual, ImConversationTypeEnum.GROUP,
+ ImContentTypeEnum.TEXT, dto)));
+ verifyNoMoreInteractions(webSocketSenderApi);
+ }
+
+ @Test
+ public void testSendNotificationAsync_private_exceptionSwallowed() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImWebSocketServiceImpl.class)))
+ .thenReturn(imWebSocketService);
+
+ // 鍑嗗锛歴ender 鎶涘紓甯�
+ ImPrivateMessageNotification dto = new ImPrivateMessageNotification().setSenderId(1L).setReceiverId(2L)
+ .setType(ImContentTypeEnum.TEXT.getType());
+ doThrow(new RuntimeException("user offline"))
+ .when(webSocketSenderApi).sendObject(anyInt(), anyLong(), anyString(), any());
+
+ // 璋冪敤锛氬紓甯稿簲琚悶鎺夛紝涓嶅悜涓婃姏
+ imWebSocketService.sendNotificationAsync(2L, ImConversationTypeEnum.PRIVATE.getType(),
+ ImContentTypeEnum.TEXT.getType(), dto);
+
+ verify(webSocketSenderApi).sendObject(anyInt(), eq(2L), anyString(), any());
+ }
+ }
+
+ @Test
+ public void testSendNotificationAsync_group_singleUserDefaultOverload() {
+ try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+ springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImWebSocketServiceImpl.class)))
+ .thenReturn(imWebSocketService);
+
+ ImGroupMessageNotification dto = new ImGroupMessageNotification();
+ dto.setGroupId(10L);
+ dto.setType(ImContentTypeEnum.TEXT.getType());
+
+ imWebSocketService.sendNotificationAsync(42L, ImConversationTypeEnum.GROUP.getType(),
+ ImContentTypeEnum.TEXT.getType(), dto);
+
+ verify(webSocketSenderApi).sendObject(
+ eq(UserTypeEnum.ADMIN.getValue()), eq(42L), eq(ImNotificationWebSocketDTO.TYPE),
+ argThat(actual -> isNotification(actual, ImConversationTypeEnum.GROUP,
+ ImContentTypeEnum.TEXT, dto)));
+ }
+ }
+
+ private static boolean isNotification(Object object, ImConversationTypeEnum conversationType,
+ ImContentTypeEnum contentType, Object payload) {
+ if (!(object instanceof ImNotificationWebSocketDTO notification)) {
+ return false;
+ }
+ return conversationType.getType().equals(notification.getConversationType())
+ && contentType.getType().equals(notification.getContentType())
+ && payload == notification.getPayload();
+ }
+
+ private static ImNotificationWebSocketDTO buildNotification(ImConversationTypeEnum conversationType,
+ ImContentTypeEnum contentType, Object payload) {
+ return new ImNotificationWebSocketDTO()
+ .setConversationType(conversationType.getType())
+ .setContentType(contentType.getType())
+ .setPayload(payload);
+ }
+
+}
diff --git a/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/util/ImMessageUtilsTest.java b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/util/ImMessageUtilsTest.java
new file mode 100644
index 0000000..a821bd0
--- /dev/null
+++ b/yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/util/ImMessageUtilsTest.java
@@ -0,0 +1,184 @@
+package cn.iocoder.yudao.module.im.util;
+
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.im.dal.dataobject.message.content.QuoteMessage;
+import org.junit.jupiter.api.Test;
+
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * {@link ImMessageUtils} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class ImMessageUtilsTest {
+
+ // ========== parseQuoteMessageId ==========
+
+ @Test
+ public void testParseQuoteMessageId_valid() {
+ // 鍑嗗锛歝ontent 鍚悎娉� quote 瀛楁
+ String content = "{\"text\":\"浣犲ソ\",\"quote\":{\"messageId\":1001,\"senderId\":2,\"type\":1}}";
+
+ // 璋冪敤 + 鏂█
+ assertEquals(1001L, ImMessageUtils.parseQuoteMessageId(content));
+ }
+
+ @Test
+ public void testParseQuoteMessageId_invalidJson() {
+ // 鍑嗗锛歝ontent 闈炲悎娉� JSON
+ // 璋冪敤 + 鏂█锛氳В鏋愬け璐ヨ繑鍥� null
+ assertNull(ImMessageUtils.parseQuoteMessageId("not a json"));
+ }
+
+ @Test
+ public void testParseQuoteMessageId_noQuoteField() {
+ // 鍑嗗锛歝ontent 鏃� quote 瀛楁
+ String content = "{\"text\":\"浣犲ソ\"}";
+
+ // 璋冪敤 + 鏂█
+ assertNull(ImMessageUtils.parseQuoteMessageId(content));
+ }
+
+ @Test
+ public void testParseQuoteMessageId_quoteIsNotMap() {
+ // 鍑嗗锛歲uote 瀛楁涓嶆槸瀵硅薄
+ String content = "{\"text\":\"浣犲ソ\",\"quote\":\"oops\"}";
+
+ // 璋冪敤 + 鏂█
+ assertNull(ImMessageUtils.parseQuoteMessageId(content));
+ }
+
+ @Test
+ public void testParseQuoteMessageId_messageIdMissing() {
+ // 鍑嗗锛歲uote 瀵硅薄鍐呮棤 messageId
+ String content = "{\"quote\":{\"senderId\":2}}";
+
+ // 璋冪敤 + 鏂█
+ assertNull(ImMessageUtils.parseQuoteMessageId(content));
+ }
+
+ // ========== appendQuote ==========
+
+ @Test
+ public void testAppendQuote_existingContent() {
+ // 鍑嗗锛氬凡鏈� text 瀛楁鐨� content
+ String content = "{\"text\":\"浣犲ソ\"}";
+ QuoteMessage quote = new QuoteMessage().setMessageId(1001L).setSenderId(2L).setType(1).setContent("{}");
+
+ // 璋冪敤
+ String result = ImMessageUtils.appendQuote(content, quote);
+
+ // 鏂█锛氫繚鐣欏師瀛楁锛屾敞鍏� quote
+ Map<String, Object> map = JsonUtils.parseMap(result);
+ assertEquals("浣犲ソ", map.get("text"));
+ assertTrue(map.get("quote") instanceof Map);
+ assertEquals(1001, ((Map<?, ?>) map.get("quote")).get("messageId"));
+ }
+
+ @Test
+ public void testAppendQuote_blankContent() {
+ // 鍑嗗锛歝ontent 涓虹┖瀛楃涓诧紝鏃犳硶瑙f瀽涓� map
+ QuoteMessage quote = new QuoteMessage().setMessageId(1001L);
+
+ // 璋冪敤
+ String result = ImMessageUtils.appendQuote("", quote);
+
+ // 鏂█锛氬唴閮ㄦ柊寤� map锛屼粎鍚� quote
+ Map<String, Object> map = JsonUtils.parseMap(result);
+ assertEquals(1, map.size());
+ assertTrue(map.containsKey("quote"));
+ }
+
+ @Test
+ public void testAppendQuote_overwriteExistingQuote() {
+ // 鍑嗗锛歝ontent 宸茬粡鏈変竴涓棫 quote锛屾湡鏈涜鏂� quote 瑕嗙洊
+ String content = "{\"text\":\"hi\",\"quote\":{\"messageId\":1}}";
+ QuoteMessage quote = new QuoteMessage().setMessageId(9999L).setSenderId(2L).setType(1);
+
+ // 璋冪敤
+ String result = ImMessageUtils.appendQuote(content, quote);
+
+ // 鏂█锛歲uote.messageId 琚鐩栦负鏂板��
+ Map<String, Object> map = JsonUtils.parseMap(result);
+ assertEquals(9999, ((Map<?, ?>) map.get("quote")).get("messageId"));
+ }
+
+ // ========== removeQuote ==========
+
+ @Test
+ public void testRemoveQuote_blankContent() {
+ // 璋冪敤 + 鏂█锛氱┖鍐呭鍘熸牱杩斿洖
+ assertEquals("", ImMessageUtils.removeQuote(""));
+ assertNull(ImMessageUtils.removeQuote(null));
+ }
+
+ @Test
+ public void testRemoveQuote_noQuoteField() {
+ // 鍑嗗锛歝ontent 瀛楃涓查噷娌℃湁 quote 鍏抽敭瀛楋紝鎻愬墠杩斿洖鍘熷��
+ String content = "{\"text\":\"浣犲ソ\"}";
+
+ // 璋冪敤 + 鏂█锛氬悓涓�寮曠敤鐩存帴杩斿洖
+ assertEquals(content, ImMessageUtils.removeQuote(content));
+ }
+
+ @Test
+ public void testRemoveQuote_withQuote() {
+ // 鍑嗗锛氬惈 quote 鐨� content
+ String content = "{\"text\":\"浣犲ソ\",\"quote\":{\"messageId\":1}}";
+
+ // 璋冪敤
+ String result = ImMessageUtils.removeQuote(content);
+
+ // 鏂█锛歲uote 琚Щ闄わ紝淇濈暀鍏跺畠瀛楁
+ Map<String, Object> map = JsonUtils.parseMap(result);
+ assertFalse(map.containsKey("quote"));
+ assertEquals("浣犲ソ", map.get("text"));
+ }
+
+ @Test
+ public void testRemoveQuote_invalidJsonContainingQuoteToken() {
+ // 鍑嗗锛氬瓧绗︿覆鍖呭惈 quote 瀛楅潰閲忎絾瑙f瀽澶辫触
+ String content = "not-a-json-but-has-\"quote\"-token";
+
+ // 璋冪敤 + 鏂█锛氳В鏋愬け璐ヨ繑鍥炲師鍊�
+ assertEquals(content, ImMessageUtils.removeQuote(content));
+ }
+
+ // ========== buildQuote ==========
+
+ @Test
+ public void testBuildQuote_stripsNestedQuote() {
+ // 鍑嗗锛氳寮曠敤娑堟伅鏈韩涔熷惈鏈� quote 瀛楁锛涢槻姝㈠祵濂�
+ String originalContent = "{\"text\":\"琚紩鐢╘",\"quote\":{\"messageId\":777}}";
+
+ // 璋冪敤
+ QuoteMessage quote = ImMessageUtils.buildQuote(1001L, 2L, 1, originalContent);
+
+ // 鏂█锛氬熀纭�瀛楁閫忎紶锛宑ontent 宸茶鍓ョ quote
+ assertEquals(1001L, quote.getMessageId());
+ assertEquals(2L, quote.getSenderId());
+ assertEquals(1, quote.getType());
+ Map<String, Object> contentMap = JsonUtils.parseMap(quote.getContent());
+ assertFalse(contentMap.containsKey("quote"));
+ assertEquals("琚紩鐢�", contentMap.get("text"));
+ }
+
+ @Test
+ public void testBuildQuote_originalWithoutQuote() {
+ // 鍑嗗锛氳寮曠敤娑堟伅鍘熸湰灏辨病 quote 瀛楁
+ String originalContent = "{\"text\":\"hi\"}";
+
+ // 璋冪敤
+ QuoteMessage quote = ImMessageUtils.buildQuote(1001L, 2L, 1, originalContent);
+
+ // 鏂█锛歝ontent 鍘熸牱淇濈暀
+ assertEquals(originalContent, quote.getContent());
+ }
+
+}
diff --git a/yudao-module-im/src/test/resources/application-unit-test.yaml b/yudao-module-im/src/test/resources/application-unit-test.yaml
new file mode 100644
index 0000000..44be16f
--- /dev/null
+++ b/yudao-module-im/src/test/resources/application-unit-test.yaml
@@ -0,0 +1,49 @@
+spring:
+ main:
+ lazy-initialization: true # 寮�鍚噿鍔犺浇锛屽姞蹇�熷害
+ banner-mode: off # 鍗曞厓娴嬭瘯锛岀鐢� Banner
+
+--- #################### 鏁版嵁搴撶浉鍏抽厤缃� ####################
+
+spring:
+ # 鏁版嵁婧愰厤缃」
+ datasource:
+ name: ruoyi-vue-pro
+ url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value,day; # MODE 浣跨敤 MySQL 妯″紡锛汥ATABASE_TO_UPPER 閰嶇疆琛ㄥ拰瀛楁浣跨敤灏忓啓
+ driver-class-name: org.h2.Driver
+ username: sa
+ password:
+ druid:
+ async-init: true # 鍗曞厓娴嬭瘯锛屽紓姝ュ垵濮嬪寲 Druid 杩炴帴姹狅紝鎻愬崌鍚姩閫熷害
+ initial-size: 1 # 鍗曞厓娴嬭瘯锛岄厤缃负 1锛屾彁鍗囧惎鍔ㄩ�熷害
+ sql:
+ init:
+ schema-locations: classpath:/sql/create_tables.sql
+ encoding: UTF-8
+
+ # Redis 閰嶇疆銆俁edisson 榛樿鐨勯厤缃冻澶熶娇鐢紝涓�鑸笉闇�瑕佽繘琛岃皟浼�
+ data:
+ redis:
+ host: 127.0.0.1 # 鍦板潃
+ port: 16379 # 绔彛锛堝崟鍏冩祴璇曪紝浣跨敤 16379 绔彛锛�
+ database: 0 # 鏁版嵁搴撶储寮�
+
+mybatis:
+ lazy-initialization: true # 鍗曞厓娴嬭瘯锛岃缃� MyBatis Mapper 寤惰繜鍔犺浇锛屽姞閫熸瘡涓崟鍏冩祴璇�
+
+--- #################### 瀹氭椂浠诲姟鐩稿叧閰嶇疆 ####################
+
+--- #################### 閰嶇疆涓績鐩稿叧閰嶇疆 ####################
+
+--- #################### 鏈嶅姟淇濋殰鐩稿叧閰嶇疆 ####################
+
+# Lock4j 閰嶇疆椤癸紙鍗曞厓娴嬭瘯锛岀鐢� Lock4j锛�
+
+--- #################### 鐩戞帶鐩稿叧閰嶇疆 ####################
+
+--- #################### 鑺嬮亾鐩稿叧閰嶇疆 ####################
+
+# 鑺嬮亾閰嶇疆椤癸紝璁剧疆褰撳墠椤圭洰鎵�鏈夎嚜瀹氫箟鐨勯厤缃�
+yudao:
+ info:
+ base-package: cn.iocoder.yudao.module
diff --git a/yudao-module-im/src/test/resources/sql/clean.sql b/yudao-module-im/src/test/resources/sql/clean.sql
new file mode 100644
index 0000000..c25a453
--- /dev/null
+++ b/yudao-module-im/src/test/resources/sql/clean.sql
@@ -0,0 +1,15 @@
+DELETE FROM "im_private_message";
+DELETE FROM "im_group_message";
+DELETE FROM "im_conversation_read";
+DELETE FROM "im_group";
+DELETE FROM "im_group_member";
+DELETE FROM "im_friend";
+DELETE FROM "im_friend_request";
+DELETE FROM "im_group_request";
+DELETE FROM "im_face_pack";
+DELETE FROM "im_face_pack_item";
+DELETE FROM "im_face_user_item";
+DELETE FROM "im_rtc_call";
+DELETE FROM "im_rtc_participant";
+DELETE FROM "im_sensitive_word";
+DELETE FROM "system_users";
diff --git a/yudao-module-im/src/test/resources/sql/create_tables.sql b/yudao-module-im/src/test/resources/sql/create_tables.sql
new file mode 100644
index 0000000..86579c4
--- /dev/null
+++ b/yudao-module-im/src/test/resources/sql/create_tables.sql
@@ -0,0 +1,349 @@
+CREATE TABLE IF NOT EXISTS "im_private_message" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "client_message_id" varchar(64) DEFAULT NULL COMMENT '瀹㈡埛绔秷鎭紪鍙�',
+ "sender_id" bigint NOT NULL COMMENT '鍙戦�佷汉缂栧彿',
+ "receiver_id" bigint NOT NULL COMMENT '鎺ユ敹浜虹紪鍙�',
+ "type" smallint NOT NULL COMMENT '娑堟伅绫诲瀷',
+ "content" varchar(8192) DEFAULT NULL COMMENT '娑堟伅鍐呭',
+ "status" tinyint NOT NULL COMMENT '娑堟伅鐘舵��',
+ "receipt_status" tinyint NOT NULL DEFAULT 0 COMMENT '鍥炴墽鐘舵��',
+ "send_time" timestamp NOT NULL COMMENT '鍙戦�佹椂闂�',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_private_message_sender_client" UNIQUE ("sender_id", "client_message_id", "tenant_id")
+) COMMENT 'IM 绉佽亰娑堟伅琛�';
+
+CREATE TABLE IF NOT EXISTS "im_group_message" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "client_message_id" varchar(64) DEFAULT NULL COMMENT '瀹㈡埛绔秷鎭紪鍙�',
+ "sender_id" bigint NOT NULL COMMENT '鍙戦�佷汉缂栧彿',
+ "group_id" bigint NOT NULL COMMENT '缇ょ紪鍙�',
+ "type" smallint NOT NULL COMMENT '娑堟伅绫诲瀷',
+ "content" varchar(8192) DEFAULT NULL COMMENT '娑堟伅鍐呭',
+ "status" tinyint NOT NULL COMMENT '娑堟伅鐘舵��',
+ "send_time" timestamp NOT NULL COMMENT '鍙戦�佹椂闂�',
+ "receiver_user_ids" text DEFAULT NULL COMMENT '瀹氬悜鎺ユ敹鐢ㄦ埛缂栧彿鍒楄〃',
+ "at_user_ids" varchar(1024) DEFAULT NULL COMMENT '@ 鐩爣鐢ㄦ埛缂栧彿鍒楄〃',
+ "receipt_status" tinyint NOT NULL DEFAULT 0 COMMENT '鍥炴墽鐘舵��',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_group_message_sender_client" UNIQUE ("sender_id", "client_message_id", "tenant_id")
+) COMMENT 'IM 缇よ亰娑堟伅琛�';
+
+CREATE TABLE IF NOT EXISTS "im_group" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "name" varchar(64) NOT NULL COMMENT '缇ゅ悕绉�',
+ "owner_user_id" bigint NOT NULL COMMENT '缇や富鐢ㄦ埛缂栧彿',
+ "avatar" varchar(512) DEFAULT NULL COMMENT '缇ゅご鍍�',
+ "notice" varchar(2048) DEFAULT NULL COMMENT '缇ゅ叕鍛�',
+ "banned" bit DEFAULT FALSE COMMENT '鏄惁灏佺',
+ "banned_reason" varchar(512) DEFAULT NULL COMMENT '灏佺鍘熷洜',
+ "banned_time" timestamp DEFAULT NULL COMMENT '灏佺鏃堕棿',
+ "status" tinyint NOT NULL COMMENT '缇ょ姸鎬�',
+ "dissolved_time" timestamp DEFAULT NULL COMMENT '瑙f暎鏃堕棿',
+ "muted_all" bit DEFAULT FALSE COMMENT '鏄惁鍏ㄧ兢绂佽█',
+ "join_approval" bit NOT NULL DEFAULT FALSE COMMENT '杩涚兢鏄惁闇�缇や富 / 绠$悊鍛樺鎵癸紱false 鑷敱杩涚兢锛宼rue 闇�瀹℃壒',
+ "pinned_message_ids" varchar(128) DEFAULT NULL COMMENT '缇ょ疆椤舵秷鎭紪鍙峰垪琛紝閫楀彿鍒嗛殧',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+) COMMENT 'IM 缇や俊鎭〃';
+
+CREATE TABLE IF NOT EXISTS "im_group_member" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "group_id" bigint NOT NULL COMMENT '缇ょ紪鍙�',
+ "user_id" bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ "display_user_name" varchar(64) DEFAULT NULL COMMENT '缁勫唴鏄剧ず鍚�',
+ "group_remark" varchar(64) DEFAULT NULL COMMENT '缇ゅ娉�',
+ "silent" bit DEFAULT FALSE COMMENT '鏄惁鍏嶆墦鎵�',
+ "status" tinyint NOT NULL COMMENT '鎴愬憳鐘舵��',
+ "role" tinyint NOT NULL DEFAULT 3 COMMENT '鎴愬憳瑙掕壊锛�1=缇や富 2=绠$悊鍛� 3=鏅�氭垚鍛�',
+ "join_time" timestamp DEFAULT NULL COMMENT '鍏ョ兢鏃堕棿',
+ "add_source" tinyint DEFAULT NULL COMMENT '鍔犲叆鏉ユ簮',
+ "inviter_user_id" bigint DEFAULT NULL COMMENT '閭�璇蜂汉鐢ㄦ埛缂栧彿锛涚敤鎴蜂富鍔ㄧ敵璇疯繘缇ゆ椂涓� NULL',
+ "quit_time" timestamp DEFAULT NULL COMMENT '閫�缇ゆ椂闂�',
+ "mute_end_time" timestamp DEFAULT NULL COMMENT '绂佽█鍒版湡鏃堕棿',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_group_member" UNIQUE ("group_id", "user_id", "tenant_id")
+) COMMENT 'IM 缇ゆ垚鍛樿〃';
+
+CREATE TABLE IF NOT EXISTS "im_friend" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "user_id" bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ "friend_user_id" bigint NOT NULL COMMENT '濂藉弸鐢ㄦ埛缂栧彿',
+ "silent" bit DEFAULT FALSE COMMENT '鏄惁鍏嶆墦鎵�',
+ "display_name" varchar(64) NOT NULL DEFAULT '' COMMENT '濂藉弸灞曠ず澶囨敞锛堜粎鑷繁鍙锛�',
+ "add_source" tinyint DEFAULT NULL COMMENT '娣诲姞鏉ユ簮',
+ "pinned" bit DEFAULT FALSE COMMENT '鏄惁缃《鑱旂郴浜�',
+ "blocked" bit DEFAULT FALSE COMMENT '鏄惁鎷夐粦',
+ "status" tinyint NOT NULL COMMENT '濂藉弸鐘舵��',
+ "add_time" timestamp DEFAULT NULL COMMENT '娣诲姞濂藉弸鏃堕棿',
+ "delete_time" timestamp DEFAULT NULL COMMENT '鍒犻櫎濂藉弸鏃堕棿',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_user_friend" UNIQUE ("user_id", "friend_user_id", "tenant_id")
+) COMMENT 'IM 濂藉弸鍏崇郴琛�';
+
+CREATE TABLE IF NOT EXISTS "im_friend_request" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "from_user_id" bigint NOT NULL COMMENT '鍙戣捣鏂圭敤鎴风紪鍙�',
+ "to_user_id" bigint NOT NULL COMMENT '鎺ユ敹鏂圭敤鎴风紪鍙�',
+ "handle_result" tinyint NOT NULL DEFAULT 0 COMMENT '澶勭悊缁撴灉锛�0鏈鐞嗭紱1鍚屾剰锛�2鎷掔粷',
+ "apply_content" varchar(255) DEFAULT NULL COMMENT '鐢宠鐞嗙敱',
+ "handle_content" varchar(255) DEFAULT NULL COMMENT '澶勭悊鐞嗙敱',
+ "display_name" varchar(64) DEFAULT NULL COMMENT '鍙戣捣鏂瑰鎺ユ敹鏂圭殑澶囨敞',
+ "add_source" tinyint DEFAULT NULL COMMENT '娣诲姞鏉ユ簮',
+ "handle_time" timestamp DEFAULT NULL COMMENT '澶勭悊鏃堕棿',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_friend_request" UNIQUE ("from_user_id", "to_user_id", "tenant_id")
+) COMMENT 'IM 濂藉弸鐢宠璁板綍琛�';
+
+CREATE TABLE IF NOT EXISTS "im_group_request" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "group_id" bigint NOT NULL COMMENT '缇ょ紪鍙�',
+ "user_id" bigint NOT NULL COMMENT '鐢宠浜� / 琚個璇蜂汉鐢ㄦ埛缂栧彿',
+ "inviter_user_id" bigint DEFAULT NULL COMMENT '閭�璇蜂汉鐢ㄦ埛缂栧彿锛汵ULL=涓诲姩鐢宠锛涢潪NULL=琚個璇峰緟瀹℃壒',
+ "apply_content" varchar(255) DEFAULT NULL COMMENT '鐢宠鐞嗙敱',
+ "add_source" tinyint DEFAULT NULL COMMENT '鍔犲叆鏉ユ簮',
+ "handle_result" tinyint NOT NULL DEFAULT 0 COMMENT '澶勭悊缁撴灉锛�0鏈鐞嗭紱1鍚屾剰锛�2鎷掔粷',
+ "handle_user_id" bigint DEFAULT NULL COMMENT '澶勭悊浜虹敤鎴风紪鍙�',
+ "handle_content" varchar(255) DEFAULT NULL COMMENT '澶勭悊鐞嗙敱',
+ "handle_time" timestamp DEFAULT NULL COMMENT '澶勭悊鏃堕棿',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_group_request" UNIQUE ("group_id", "user_id", "tenant_id")
+) COMMENT 'IM 鍔犵兢鐢宠璁板綍琛�';
+
+CREATE TABLE IF NOT EXISTS "im_face_pack" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "name" varchar(64) NOT NULL COMMENT '琛ㄦ儏鍖呭悕绉�',
+ "icon" varchar(512) DEFAULT NULL COMMENT '琛ㄦ儏鍖呭浘鏍囷紙闈㈡澘搴曢儴 tab 鏄剧ず锛�',
+ "sort" int NOT NULL DEFAULT 0 COMMENT '鎺掑簭',
+ "status" tinyint NOT NULL COMMENT '鐘舵��',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+) COMMENT 'IM 琛ㄦ儏鍖呰〃';
+
+CREATE TABLE IF NOT EXISTS "im_face_pack_item" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "pack_id" bigint NOT NULL COMMENT '鎵�灞炶〃鎯呭寘缂栧彿',
+ "url" varchar(512) NOT NULL COMMENT '琛ㄦ儏鍥� URL',
+ "name" varchar(64) DEFAULT NULL COMMENT '琛ㄦ儏鍚嶏紙鍙�夛紱濡傘�岀嫍澶淬�嶃�屾崅鑴搞�嶏級',
+ "width" int NOT NULL DEFAULT 0 COMMENT '娓叉煋瀹藉害锛堝儚绱狅級',
+ "height" int NOT NULL DEFAULT 0 COMMENT '娓叉煋楂樺害锛堝儚绱狅級',
+ "sort" int NOT NULL DEFAULT 0 COMMENT '鎺掑簭',
+ "status" tinyint NOT NULL COMMENT '鐘舵��',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+) COMMENT 'IM 琛ㄦ儏鍖呴」琛�';
+
+CREATE TABLE IF NOT EXISTS "im_rtc_call" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "room" varchar(64) NOT NULL COMMENT '涓氬姟閫氳瘽缂栧彿',
+ "conversation_type" tinyint NOT NULL COMMENT '浼氳瘽绫诲瀷',
+ "media_type" tinyint NOT NULL COMMENT '濯掍綋绫诲瀷',
+ "inviter_user_id" bigint NOT NULL COMMENT '鍙戣捣浜虹敤鎴风紪鍙�',
+ "group_id" bigint DEFAULT NULL COMMENT '缇ょ紪鍙�',
+ "status" tinyint NOT NULL COMMENT '閫氳瘽鐘舵��',
+ "end_reason" tinyint DEFAULT NULL COMMENT '缁撴潫鍘熷洜',
+ "start_time" timestamp NOT NULL COMMENT '鍙戣捣鏃堕棿',
+ "accept_time" timestamp DEFAULT NULL COMMENT '鎺ラ�氭椂闂�',
+ "end_time" timestamp DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+) COMMENT 'IM 閫氳瘽璁板綍琛�';
+
+CREATE TABLE IF NOT EXISTS "im_rtc_participant" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "call_id" bigint NOT NULL COMMENT '閫氳瘽缂栧彿',
+ "room" varchar(64) NOT NULL COMMENT '涓氬姟閫氳瘽缂栧彿',
+ "user_id" bigint NOT NULL COMMENT '鍙備笌鑰呯敤鎴风紪鍙�',
+ "role" tinyint NOT NULL COMMENT '鍙備笌瑙掕壊',
+ "status" tinyint NOT NULL COMMENT '鍙備笌鐘舵��',
+ "invite_time" timestamp NOT NULL COMMENT '琚個璇锋椂闂�',
+ "accept_time" timestamp DEFAULT NULL COMMENT '鎺ュ惉鏃堕棿',
+ "leave_time" timestamp DEFAULT NULL COMMENT '绂诲紑鏃堕棿',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_rtc_participant_room_user" UNIQUE ("room", "user_id", "tenant_id")
+) COMMENT 'IM 閫氳瘽鍙備笌鑰呰〃';
+
+CREATE TABLE IF NOT EXISTS "im_face_user_item" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "user_id" bigint NOT NULL COMMENT '鎵�灞炵敤鎴风紪鍙�',
+ "url" varchar(512) NOT NULL COMMENT '琛ㄦ儏鍥� URL',
+ "name" varchar(64) DEFAULT NULL COMMENT '琛ㄦ儏鍚嶏紙鍙�夛級',
+ "width" int NOT NULL DEFAULT 0 COMMENT '娓叉煋瀹藉害锛堝儚绱狅級',
+ "height" int NOT NULL DEFAULT 0 COMMENT '娓叉煋楂樺害锛堝儚绱狅級',
+ "sort" int NOT NULL DEFAULT 0 COMMENT '鎺掑簭',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_face_user_item_user_url_deleted" UNIQUE ("user_id", "url", "deleted")
+) COMMENT 'IM 鐢ㄦ埛绉佹湁琛ㄦ儏琛�';
+
+CREATE TABLE IF NOT EXISTS "im_channel" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "code" varchar(64) NOT NULL COMMENT '棰戦亾涓氬姟鐮侊紱鍞竴',
+ "name" varchar(64) NOT NULL COMMENT '棰戦亾鍚嶇О',
+ "avatar" varchar(512) DEFAULT NULL COMMENT '棰戦亾澶村儚',
+ "sort" int NOT NULL DEFAULT 0 COMMENT '鎺掑簭',
+ "status" tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵�侊紱0 鍚敤 1 鍋滅敤',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+) COMMENT 'IM 棰戦亾琛�';
+
+CREATE TABLE IF NOT EXISTS "im_channel_material" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "channel_id" bigint NOT NULL COMMENT '棰戦亾缂栧彿',
+ "type" tinyint NOT NULL COMMENT '鍐呭绫诲瀷锛�1 绔欏唴瀵屾枃鏈� 2 澶栭摼',
+ "title" varchar(128) NOT NULL COMMENT '鏍囬',
+ "cover_url" varchar(512) DEFAULT NULL COMMENT '灏侀潰鍥�',
+ "summary" varchar(255) DEFAULT NULL COMMENT '鎽樿',
+ "content" clob DEFAULT NULL COMMENT '姝f枃锛涘瘜鏂囨湰 HTML',
+ "url" varchar(512) DEFAULT NULL COMMENT '璺宠浆閾炬帴锛涗负绌烘椂鐐瑰嚮鍦ㄥ鎴风鍐呯疆璇︽儏椤垫媺 content锛涢潪绌哄垯璺� url',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+) COMMENT 'IM 棰戦亾绱犳潗琛�';
+
+CREATE TABLE IF NOT EXISTS "im_channel_message" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "channel_id" bigint NOT NULL COMMENT '棰戦亾缂栧彿锛涘啑浣� im_channel_material.channel_id 渚夸簬妫�绱�',
+ "material_id" bigint NOT NULL COMMENT '鍏宠仈绱犳潗缂栧彿',
+ "type" smallint NOT NULL COMMENT '娑堟伅绫诲瀷',
+ "content" varchar(8192) DEFAULT NULL COMMENT '娑堟伅鍐呭锛涙帹閫佹椂 payload JSON 蹇収锛涗笉鍚瘜鏂囨湰姝f枃',
+ "receiver_user_ids" text DEFAULT NULL COMMENT '鎺ユ敹浜虹紪鍙峰垪琛紱閫楀彿鍒嗛殧锛涗负绌鸿〃绀哄叏鍛�',
+ "send_time" timestamp NOT NULL COMMENT '鍙戦�佹椂闂�',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+) COMMENT 'IM 棰戦亾娑堟伅琛�';
+
+CREATE TABLE IF NOT EXISTS "im_conversation_read" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "user_id" bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ "conversation_type" tinyint NOT NULL COMMENT '浼氳瘽绫诲瀷',
+ "target_id" bigint NOT NULL COMMENT '鐩爣缂栧彿',
+ "message_id" bigint NOT NULL COMMENT '鏈�澶у凡璇绘秷鎭紪鍙�',
+ "read_time" timestamp NOT NULL COMMENT '鏈�杩戝凡璇绘椂闂�',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_conversation_read_user_target" UNIQUE ("user_id", "conversation_type", "target_id", "tenant_id")
+) COMMENT 'IM 浼氳瘽璇讳綅缃〃';
+
+CREATE TABLE IF NOT EXISTS "im_sensitive_word" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '缂栧彿',
+ "word" varchar(128) NOT NULL COMMENT '鏁忔劅璇�',
+ "status" tinyint NOT NULL DEFAULT 0 COMMENT '鐘舵�侊紱0 鍚敤 1 鍋滅敤',
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "uk_im_sensitive_word" UNIQUE ("word", "tenant_id")
+) COMMENT 'IM 鏁忔劅璇嶈〃';
+
+CREATE TABLE IF NOT EXISTS "system_users" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+ "username" varchar(30) NOT NULL DEFAULT '',
+ "password" varchar(100) NOT NULL DEFAULT '',
+ "nickname" varchar(30) NOT NULL DEFAULT '',
+ "remark" varchar(500) DEFAULT NULL,
+ "dept_id" bigint DEFAULT NULL,
+ "post_ids" varchar(255) DEFAULT NULL,
+ "email" varchar(50) DEFAULT '',
+ "mobile" varchar(11) DEFAULT '',
+ "sex" tinyint DEFAULT 0,
+ "avatar" varchar(100) DEFAULT '',
+ "status" tinyint NOT NULL DEFAULT 0,
+ "login_ip" varchar(50) DEFAULT '',
+ "login_date" timestamp DEFAULT NULL,
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+) COMMENT '鐢ㄦ埛淇℃伅琛�';
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java
index ca7db64..12bab8a 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java
@@ -1,10 +1,11 @@
package cn.iocoder.yudao.module.infra.controller.admin.file;
+import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.URLUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*;
@@ -27,7 +28,6 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
-import java.nio.charset.StandardCharsets;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -111,10 +111,10 @@
if (StrUtil.isEmpty(path)) {
throw new IllegalArgumentException("缁撳熬鐨� path 璺緞蹇呴』浼犻��");
}
- // 瑙g爜锛岃В鍐充腑鏂囪矾寰勭殑闂
+ // 瑙g爜锛岃В鍐充腑鏂囥��%銆�+ 绛夌壒娈婂瓧绗﹁矾寰勭殑闂
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/
// https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1432/
- path = URLUtil.decode(path, StandardCharsets.UTF_8, false);
+ path = HttpUtils.decodeUrlPath(path);
// 璇诲彇鍐呭
byte[] content = fileService.getFileContent(configId, path);
@@ -123,7 +123,9 @@
response.setStatus(HttpStatus.NOT_FOUND.value());
return;
}
- writeAttachment(response, path, content);
+ FileDO file = fileService.getFileByConfigIdAndPath(configId, path);
+ String filename = file != null && StrUtil.isNotEmpty(file.getName()) ? file.getName() : FileUtil.getName(path);
+ writeAttachment(response, filename, content);
}
@GetMapping("/page")
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java
index 06dff7c..dbdbd9c 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileUploadReqVO.java
@@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file;
-import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.infra.framework.file.core.utils.FilePathUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
@@ -26,10 +26,7 @@
}
public static boolean isDirectoryValid(String directory) {
- // 1. 涓嶈兘鍖呭惈 .. 闃叉鐩綍绌胯秺
- // 2. 涓嶈兘浠� / 鎴� \ 寮�澶达紝闃叉涓婁紶鍒版牴鐩綍
- return !StrUtil.contains(directory, "..")
- && !StrUtil.startWithAny(directory, "/", "\\");
+ return FilePathUtils.isDirectoryValid(directory);
}
}
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java
index c3e14a8..d3d60b3 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/app/file/AppFileController.java
@@ -36,7 +36,7 @@
@Parameter(name = "file", description = "鏂囦欢闄勪欢", required = true,
schema = @Schema(type = "string", format = "binary"))
@PermitAll
- public CommonResult<String> uploadFile(AppFileUploadReqVO uploadReqVO) throws Exception {
+ public CommonResult<String> uploadFile(@Valid AppFileUploadReqVO uploadReqVO) throws Exception {
MultipartFile file = uploadReqVO.getFile();
byte[] content = IoUtil.readBytes(file.getInputStream());
return success(fileService.createFile(content, file.getOriginalFilename(),
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java
index 11233a4..a5b17c6 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileMapper.java
@@ -23,4 +23,11 @@
.orderByDesc(FileDO::getId));
}
+ default FileDO selectLatestByConfigIdAndPath(Long configId, String path) {
+ return selectLastOne(new LambdaQueryWrapperX<FileDO>()
+ .eq(FileDO::getConfigId, configId)
+ .eq(FileDO::getPath, path)
+ .orderByAsc(FileDO::getId));
+ }
+
}
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java
index 2233f35..7cf23c8 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java
@@ -33,6 +33,7 @@
ErrorCode FILE_PATH_EXISTS = new ErrorCode(1_001_003_000, "鏂囦欢璺緞宸插瓨鍦�");
ErrorCode FILE_NOT_EXISTS = new ErrorCode(1_001_003_001, "鏂囦欢涓嶅瓨鍦�");
ErrorCode FILE_IS_EMPTY = new ErrorCode(1_001_003_002, "鏂囦欢涓虹┖");
+ ErrorCode FILE_PATH_INVALID = new ErrorCode(1_001_003_003, "鏂囦欢璺緞涓嶆纭�");
// ========== 浠g爜鐢熸垚鍣� 1-001-004-000 ==========
ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1_001_004_002, "琛ㄥ畾涔夊凡缁忓瓨鍦�");
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java
index b3c8116..d04b85c 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java
@@ -21,6 +21,9 @@
VUE3_VBEN5_ANTD_SCHEMA(40), // Vue3 VBEN5 + ANTD + schema 妯$増
VUE3_VBEN5_ANTD_GENERAL(41), // Vue3 VBEN5 + ANTD 鏍囧噯妯$増
+ VUE3_VBEN5_ANTDV_NEXT_SCHEMA(42), // Vue3 VBEN5 + Antdv Next + schema 妯$増
+ VUE3_VBEN5_ANTDV_NEXT_GENERAL(43), // Vue3 VBEN5 + Antdv Next 鏍囧噯妯$増
+
VUE3_VBEN5_EP_SCHEMA(50), // Vue3 VBEN5 + EP + schema 妯$増
VUE3_VBEN5_EP_GENERAL(51), // Vue3 VBEN5 + EP 鏍囧噯妯$増
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/AbstractFileClient.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/AbstractFileClient.java
index 7ddade3..d03caca 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/AbstractFileClient.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/AbstractFileClient.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.framework.file.core.client;
import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import lombok.extern.slf4j.Slf4j;
/**
@@ -72,7 +73,7 @@
* @return URL 璁块棶鍦板潃
*/
protected String formatFileUrl(String domain, String path) {
- return StrUtil.format("{}/admin-api/infra/file/{}/get/{}", domain, getId(), path);
+ return StrUtil.format("{}/admin-api/infra/file/{}/get/{}", domain, getId(), HttpUtils.encodeUrlPath(path));
}
}
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClient.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClient.java
index 6e5c022..9c3af16 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClient.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/local/LocalFileClient.java
@@ -3,8 +3,13 @@
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient;
+import cn.iocoder.yudao.module.infra.framework.file.core.utils.FilePathUtils;
-import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_PATH_INVALID;
/**
* 鏈湴鏂囦欢瀹㈡埛绔�
@@ -50,7 +55,13 @@
}
private String getFilePath(String path) {
- return config.getBasePath() + File.separator + path;
+ FilePathUtils.validatePath(path);
+ Path basePath = Paths.get(config.getBasePath()).toAbsolutePath().normalize();
+ Path filePath = basePath.resolve(path).normalize();
+ if (!filePath.startsWith(basePath)) {
+ throw exception(FILE_PATH_INVALID);
+ }
+ return filePath.toString();
}
}
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java
index aad9007..98d37d8 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java
@@ -116,13 +116,18 @@
@Override
public String presignGetUrl(String url, Integer expirationSeconds) {
// 1. 灏� url 杞崲涓� path
- String path = StrUtil.removePrefix(url, config.getDomain() + "/");
- path = HttpUtils.decodeUrlPath(HttpUtils.removeUrlQuery(path));
+ // 瀹屾暣 Domain URL 浼氳В鐮佽繕鍘熶负鍘熷瀵硅薄鍚嶏紱瑁� path 绾﹀畾宸茬粡鏄湭缂栫爜鐨勫璞″悕
+ boolean domainUrl = StrUtil.startWith(url, config.getDomain() + "/");
+ String path = domainUrl ? StrUtil.removePrefix(url, config.getDomain() + "/") : url;
+ if (domainUrl) {
+ path = HttpUtils.removeUrlPathQueryAndFragment(path);
+ path = HttpUtils.decodeUrlPath(path);
+ }
// 2.1 鎯呭喌涓�锛氬叕寮�璁块棶锛氭棤闇�绛惧悕
// 鑰冭檻鍒拌�佺増鏈殑鍏煎锛屾墍浠ュ繀椤绘槸 config.getEnablePublicAccess() 涓� false 鏃讹紝鎵嶈繘琛岀鍚�
if (!BooleanUtil.isFalse(config.getEnablePublicAccess())) {
- return config.getDomain() + "/" + path;
+ return config.getDomain() + "/" + HttpUtils.encodeUrlPath(path);
}
// 2.2 鎯呭喌浜岋細绉佹湁璁块棶锛氱敓鎴� GET 棰勭鍚� URL
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FilePathUtils.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FilePathUtils.java
new file mode 100644
index 0000000..e61bfe7
--- /dev/null
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FilePathUtils.java
@@ -0,0 +1,106 @@
+package cn.iocoder.yudao.module.infra.framework.file.core.utils;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_PATH_INVALID;
+
+/**
+ * 鏂囦欢璺緞宸ュ叿绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class FilePathUtils {
+
+ private FilePathUtils() {
+ }
+
+ /**
+ * 鏍¢獙鏂囦欢鍚嶆槸鍚﹀悎娉曪紝绂佹鎼哄甫鐩綍璺緞銆�
+ *
+ * @param name 鏂囦欢鍚�
+ * @return 鏂囦欢鍚�
+ */
+ public static String validateFileName(String name) {
+ if (StrUtil.isEmpty(name)) {
+ return name;
+ }
+ if (!isPathValid(name) || StrUtil.contains(name, StrUtil.SLASH) || !StrUtil.equals(name, FileUtil.getName(name))) {
+ throw exception(FILE_PATH_INVALID);
+ }
+ return name;
+ }
+
+ /**
+ * 鏍¢獙鏂囦欢鐩綍鏄惁鍚堟硶銆�
+ *
+ * @param directory 鏂囦欢鐩綍锛屽厑璁镐负绌�
+ * @return 鏄惁鍚堟硶
+ */
+ public static boolean isDirectoryValid(String directory) {
+ return StrUtil.isEmpty(directory) || isPathValid(directory);
+ }
+
+ /**
+ * 鏍¢獙鏂囦欢鐩綍鏄惁鍚堟硶锛屼笉鍚堟硶鏃舵姏鍑轰笟鍔″紓甯搞��
+ *
+ * @param directory 鏂囦欢鐩綍锛屽厑璁镐负绌�
+ */
+ public static void validateDirectory(String directory) {
+ if (!isDirectoryValid(directory)) {
+ throw exception(FILE_PATH_INVALID);
+ }
+ }
+
+ /**
+ * 鏍¢獙鏂囦欢鐩稿璺緞鏄惁鍚堟硶锛屼笉鍚堟硶鏃舵姏鍑轰笟鍔″紓甯搞��
+ *
+ * @param path 鏂囦欢鐩稿璺緞
+ */
+ public static void validatePath(String path) {
+ if (StrUtil.isEmpty(path) || !isPathValid(path)) {
+ throw exception(FILE_PATH_INVALID);
+ }
+ }
+
+ /**
+ * 鏍¢獙璺緞鏄惁涓哄畨鍏ㄧ殑鐩稿璺緞锛岀姝㈢粷瀵硅矾寰勩�乄indows 鐩樼銆佸弽鏂滄潬銆佺┖璺緞娈靛拰鐩綍绌胯秺銆�
+ *
+ * @param path 璺緞
+ * @return 鏄惁鍚堟硶
+ */
+ private static boolean isPathValid(String path) {
+ // 涓嶈兘浠� / 鎴� \ 寮�澶达紝閬垮厤浼犲叆缁濆璺緞
+ if (StrUtil.startWithAny(path, StrUtil.SLASH, "\\")) {
+ return false;
+ }
+ // 涓嶈兘鍖呭惈鍙嶆枩鏉犳垨绌哄瓧绗︼紝閬垮厤缁曡繃涓嶅悓绯荤粺鐨勮矾寰勮В鏋�
+ if (StrUtil.contains(path, "\\") || path.indexOf('\0') >= 0) {
+ return false;
+ }
+ // 涓嶈兘鏄� Windows 鐩樼璺緞锛屼緥濡� C:/test.jpg
+ if (path.length() >= 2 && Character.isLetter(path.charAt(0)) && path.charAt(1) == ':') {
+ return false;
+ }
+ try {
+ // 浣跨敤 JDK Path 鍐嶅厹搴曞垽鏂竴娆$粷瀵硅矾寰�
+ if (Paths.get(path).isAbsolute()) {
+ return false;
+ }
+ } catch (InvalidPathException ex) {
+ return false;
+ }
+ // 涓嶈兘鍖呭惈绌鸿矾寰勬銆佸綋鍓嶇洰褰曟垨涓婄骇鐩綍锛岄伩鍏嶇洰褰曠┛瓒�
+ for (String segment : path.split(StrUtil.SLASH, -1)) {
+ if (StrUtil.isEmpty(segment) || ".".equals(segment) || "..".equals(segment)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java
index f8cd1c4..3b0b533 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java
@@ -85,9 +85,9 @@
// 璁剧疆鍐呭鏄剧ず銆佷笅杞芥枃浠跺悕锛歨ttps://www.cnblogs.com/wq-9/articles/12165056.html
if (isImage(mineType)) {
// 鍙傝 https://github.com/YunaiV/ruoyi-vue-pro/issues/692 璁ㄨ
- response.setHeader("Content-Disposition", "inline;filename=" + HttpUtils.encodeUtf8(filename));
+ response.setHeader("Content-Disposition", buildContentDisposition("inline", filename));
} else {
- response.setHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
+ response.setHeader("Content-Disposition", buildContentDisposition("attachment", filename));
}
// 閽堝 video 鐨勭壒娈婂鐞嗭紝瑙e喅瑙嗛鍦板潃鍦ㄧЩ鍔ㄧ鎾斁鐨勫吋瀹规�ч棶棰�
if (StrUtil.containsIgnoreCase(mineType, "video")) {
@@ -98,6 +98,29 @@
IoUtil.write(response.getOutputStream(), false, content);
}
+ private static String buildContentDisposition(String dispositionType, String filename) {
+ return StrUtil.format("{};filename=\"{}\";filename*=UTF-8''{}",
+ dispositionType, buildFallbackFilename(filename), HttpUtils.encodeUrlPathSegment(filename));
+ }
+
+ private static String buildFallbackFilename(String filename) {
+ if (StrUtil.isEmpty(filename)) {
+ return "download";
+ }
+ StringBuilder result = new StringBuilder(filename.length());
+ for (int i = 0; i < filename.length(); i++) {
+ char ch = filename.charAt(i);
+ if (ch == '"' || ch == '\\') {
+ result.append('\\').append(ch);
+ } else if (ch >= 0x20 && ch <= 0x7E) {
+ result.append(ch);
+ } else {
+ result.append('_');
+ }
+ }
+ return result.toString();
+ }
+
/**
* 鍒ゆ柇鏄惁鏄浘鐗�
*
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
index 1ba0cd7..d675558 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
@@ -241,6 +241,46 @@
vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
.put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("views/modules/list_sub_erp.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
+ // VUE3_VBEN5_ANTDV_NEXT_SCHEMA
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/data.ts"),
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/data.ts"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/index.vue"),
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/form.vue"),
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/import.vue"),
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/import-form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("api/api.ts"),
+ vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/form_sub_normal.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/form_sub_inner.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/form_sub_erp.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/list_sub_inner.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/list_sub_erp.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
+ // VUE3_VBEN5_ANTDV_NEXT_GENERAL
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/index.vue"),
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/form.vue"),
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/import.vue"),
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/import-form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("api/api.ts"),
+ vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/form_sub_normal.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/form_sub_inner.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/form_sub_erp.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/list_sub_inner.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
+ .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/list_sub_erp.vue"), // 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
.build();
@Resource
@@ -419,7 +459,7 @@
private String prettyCode(String content, String vmPath) {
// Vue 鐣岄潰锛氬幓闄ゅ瓧娈靛悗闈㈠浣欑殑 , 閫楀彿锛岃В鍐冲墠绔殑 Pretty 浠g爜鏍煎紡妫�鏌ョ殑鎶ラ敊锛堥渶瑕佹帓闄� vben5銆乿ue3_admin_uniapp锛�
if (!StrUtil.containsAny(vmPath, "vben5", "vue3_admin_uniapp")) {
- content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
+ content = content.replaceAll(",\\r?\\n}", "\n}").replaceAll(",\\r?\\n }", "\n }");
}
// Vue 鐣岄潰锛氬幓闄ゅ鐨� dateFormatter锛屽彧鏈変竴涓殑鎯呭喌涓嬶紝璇存槑娌′娇鐢ㄥ埌
if (StrUtil.count(content, "dateFormatter") == 1) {
@@ -682,6 +722,14 @@
return "codegen/vue3_vben5_ele/general/" + path + ".vm";
}
+ private static String vue3Vben5AntdvNextSchemaTemplatePath(String path) {
+ return "codegen/vue3_vben5_antdv_next/schema/" + path + ".vm";
+ }
+
+ private static String vue3Vben5AntdvNextGeneralTemplatePath(String path) {
+ return "codegen/vue3_vben5_antdv_next/general/" + path + ".vm";
+ }
+
private static boolean isSubTemplate(String path) {
return path.contains("_sub");
}
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java
index 421bbe8..a561b4e 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java
@@ -86,4 +86,13 @@
*/
byte[] getFileContent(Long configId, String path) throws Exception;
+ /**
+ * 鑾峰緱鏂囦欢
+ *
+ * @param configId 閰嶇疆缂栧彿
+ * @param path 鏂囦欢璺緞
+ * @return 鏂囦欢
+ */
+ FileDO getFileByConfigIdAndPath(Long configId, String path);
+
}
diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java
index 639c689..7fe36cd 100644
--- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java
+++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java
@@ -15,6 +15,7 @@
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient;
+import cn.iocoder.yudao.module.infra.framework.file.core.utils.FilePathUtils;
import cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
@@ -70,11 +71,14 @@
@Override
@SneakyThrows
public String createFile(byte[] content, String name, String directory, String type) {
- // 1.1 澶勭悊 type 涓虹┖鐨勬儏鍐�
+ // 1.1 澶勭悊 name 鐨勫悎娉曟�э紝绂佹鎼哄甫鐩綍璺緞
+ name = FilePathUtils.validateFileName(name);
+
+ // 1.2.1 澶勭悊 type 涓虹┖鐨勬儏鍐�
if (StrUtil.isEmpty(type)) {
type = FileTypeUtils.getMineType(content, name);
}
- // 1.2 澶勭悊 name 涓虹┖鐨勬儏鍐�
+ // 1.2.2 澶勭悊 name 涓虹┖鐨勬儏鍐�
if (StrUtil.isEmpty(name)) {
name = DigestUtil.sha256Hex(content);
}
@@ -102,7 +106,11 @@
@VisibleForTesting
String generateUploadPath(String name, String directory) {
- // 1. 鐢熸垚鍓嶇紑銆佸悗缂�
+ // 1.1 澶勭悊 name 鍜� directory 鐨勫悎娉曟��
+ name = FilePathUtils.validateFileName(name);
+ FilePathUtils.validatePath(name);
+ FilePathUtils.validateDirectory(directory);
+ // 1.2 鐢熸垚鍓嶇紑銆佸悗缂�
String prefix = null;
if (PATH_PREFIX_DATE_ENABLE) {
prefix = LocalDateTimeUtil.format(LocalDateTimeUtil.now(), PURE_DATE_PATTERN);
@@ -159,7 +167,13 @@
@Override
public Long createFile(FileCreateReqVO createReqVO) {
+ // 1.1 鏍¢獙鍙傛暟鐨勫悎娉曟��
+ FilePathUtils.validatePath(createReqVO.getPath());
+ createReqVO.setName(FilePathUtils.validateFileName(createReqVO.getName()));
+ // 1.2 澶勭悊 URL 鐨勫悎娉曟�э紝绉婚櫎 URL 涓殑鏌ヨ鍙傛暟锛堜緥濡傜鍚嶅弬鏁帮級锛屼繚璇� URL 鐨勫敮涓�鎬�
createReqVO.setUrl(HttpUtils.removeUrlQuery(createReqVO.getUrl())); // 鐩殑锛氱Щ闄ょ鏈夋《鎯呭喌涓嬶紝URL 鐨勭鍚嶅弬鏁�
+
+ // 2. 淇濆瓨鍒版暟鎹簱
FileDO file = BeanUtils.toBean(createReqVO, FileDO.class);
fileMapper.insert(file);
return file.getId();
@@ -172,15 +186,17 @@
@Override
public void deleteFile(Long id) throws Exception {
- // 鏍¢獙瀛樺湪
+ // 1.1 鏍¢獙瀛樺湪
FileDO file = validateFileExists(id);
+ // 1.2 鏍¢獙璺緞鍚堟硶鎬э紝閬垮厤璇垹鏂囦欢瀛樺偍鍣ㄤ腑鐨勫叾浠栨枃浠�
+ FilePathUtils.validatePath(file.getPath());
- // 浠庢枃浠跺瓨鍌ㄥ櫒涓垹闄�
+ // 2.1 浠庢枃浠跺瓨鍌ㄥ櫒涓垹闄�
FileClient client = fileConfigService.getFileClient(file.getConfigId());
Assert.notNull(client, "瀹㈡埛绔�({}) 涓嶈兘涓虹┖", file.getConfigId());
client.delete(file.getPath());
- // 鍒犻櫎璁板綍
+ // 2.2 鍒犻櫎璁板綍
fileMapper.deleteById(id);
}
@@ -190,6 +206,7 @@
// 鍒犻櫎鏂囦欢
List<FileDO> files = fileMapper.selectByIds(ids);
for (FileDO file : files) {
+ FilePathUtils.validatePath(file.getPath());
// 鑾峰彇瀹㈡埛绔�
FileClient client = fileConfigService.getFileClient(file.getConfigId());
Assert.notNull(client, "瀹㈡埛绔�({}) 涓嶈兘涓虹┖", file.getPath());
@@ -211,9 +228,19 @@
@Override
public byte[] getFileContent(Long configId, String path) throws Exception {
+ // 1. 鏍¢獙璺緞鍚堟硶鎬�
+ FilePathUtils.validatePath(path);
+
+ // 2.1 鑾峰彇瀹㈡埛绔�
FileClient client = fileConfigService.getFileClient(configId);
Assert.notNull(client, "瀹㈡埛绔�({}) 涓嶈兘涓虹┖", configId);
+ // 2.2 鑾峰彇鏂囦欢鍐呭
return client.getContent(path);
}
+ @Override
+ public FileDO getFileByConfigIdAndPath(Long configId, String path) {
+ return fileMapper.selectLatestByConfigIdAndPath(configId, path);
+ }
+
}
diff --git a/yudao-module-infra/src/main/resources/codegen/java/service/serviceImpl.vm b/yudao-module-infra/src/main/resources/codegen/java/service/serviceImpl.vm
index c73bd7c..98d8358 100644
--- a/yudao-module-infra/src/main/resources/codegen/java/service/serviceImpl.vm
+++ b/yudao-module-infra/src/main/resources/codegen/java/service/serviceImpl.vm
@@ -1,6 +1,15 @@
package ${basePackage}.module.${table.moduleName}.service.${table.businessName};
import cn.hutool.core.collection.CollUtil;
+#set ($hasSubJoinMany = false)
+#foreach ($subTable in $subTables)
+#if ( $subTable.subJoinMany )
+#set ($hasSubJoinMany = true)
+#end
+#end
+#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 && $hasSubJoinMany )
+import cn.hutool.core.util.ObjectUtil;
+#end
import org.springframework.stereotype.Service;
import ${jakartaPackage}.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm
index 4008706..3a009db 100644
--- a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm
@@ -40,49 +40,13 @@
/>
</view>
#elseif ($column.htmlType == "datetime" && $listOperationCondition == "BETWEEN")
- #set ($AttrName = $javaField.substring(0,1).toUpperCase() + ${javaField.substring(1)})
- <view class="yd-search-form-item">
- <view class="yd-search-form-label">
- ${comment}
- </view>
- <view class="yd-search-form-date-range-container">
- <view @click="visible${AttrName}[0] = true">
- <view class="yd-search-form-date-range-picker">
- {{ formatDate(formData.${javaField}?.[0]) || '寮�濮嬫棩鏈�' }}
- </view>
- </view>
- -
- <view @click="visible${AttrName}[1] = true">
- <view class="yd-search-form-date-range-picker">
- {{ formatDate(formData.${javaField}?.[1]) || '缁撴潫鏃ユ湡' }}
- </view>
- </view>
- </view>
- <wd-datetime-picker-view v-if="visible${AttrName}[0]" v-model="temp${AttrName}[0]" type="date" />
- <view v-if="visible${AttrName}[0]" class="yd-search-form-date-range-actions">
- <wd-button size="small" plain @click="visible${AttrName}[0] = false">
- 鍙栨秷
- </wd-button>
- <wd-button size="small" type="primary" @click="handle${AttrName}0Confirm">
- 纭畾
- </wd-button>
- </view>
- <wd-datetime-picker-view v-if="visible${AttrName}[1]" v-model="temp${AttrName}[1]" type="date" />
- <view v-if="visible${AttrName}[1]" class="yd-search-form-date-range-actions">
- <wd-button size="small" plain @click="visible${AttrName}[1] = false">
- 鍙栨秷
- </wd-button>
- <wd-button size="small" type="primary" @click="handle${AttrName}1Confirm">
- 纭畾
- </wd-button>
- </view>
- </view>
+ <yd-search-date-range v-model="formData.${javaField}" label="${comment}" />
#elseif (($column.htmlType == "select" || $column.htmlType == "radio") && $dictType && "" != $dictType)
<view class="yd-search-form-item">
<view class="yd-search-form-label">
${comment}
</view>
- <wd-radio-group v-model="formData.${javaField}" shape="button">
+ <wd-radio-group v-model="formData.${javaField}" type="button">
<wd-radio :value="-1">
鍏ㄩ儴
</wd-radio>
@@ -177,7 +141,7 @@
reset: []
}>()
-const visible = ref(false)
+const visible = ref(false) // 鎼滅储寮圭獥鏄剧ず鐘舵��
const formData = reactive({
#foreach($column in $columns)
#if ($column.listOperation)
@@ -201,7 +165,7 @@
#end
#end
#end
-})
+}) // 鎼滅储琛ㄥ崟鏁版嵁
/** 鎼滅储鏉′欢 placeholder 鎷兼帴 */
const placeholder = computed(() => {
@@ -236,31 +200,7 @@
return conditions.length > 0 ? conditions.join(' | ') : '鎼滅储${table.classComment}'
})
-#if ($hasDateTimeBetween == 1)
-// 鏃堕棿鑼冨洿閫夋嫨鍣ㄧ姸鎬�
-#foreach($column in $columns)
- #if ($column.listOperation && $column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN")
- #set ($javaField = $column.javaField)
- #set ($AttrName = $javaField.substring(0,1).toUpperCase() + ${javaField.substring(1)})
-const visible${AttrName} = ref<[boolean, boolean]>([false, false])
-const temp${AttrName} = ref<[number, number]>([Date.now(), Date.now()])
-
-/** ${column.columnComment}[0]纭 */
-function handle${AttrName}0Confirm() {
- formData.${javaField} = [temp${AttrName}.value[0], formData.${javaField}?.[1]]
- visible${AttrName}.value[0] = false
-}
-
-/** ${column.columnComment}[1]纭 */
-function handle${AttrName}1Confirm() {
- formData.${javaField} = [formData.${javaField}?.[0], temp${AttrName}.value[1]]
- visible${AttrName}.value[1] = false
-}
- #end
-#end
-#end
-
-/** 鎼滅储 */
+/** 鎼滅储鎸夐挳鎿嶄綔 */
function handleSearch() {
visible.value = false
emit('search', {
@@ -277,7 +217,7 @@
})
}
-/** 閲嶇疆 */
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
function handleReset() {
#foreach($column in $columns)
#if ($column.listOperation)
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm
index b3302e5..bde41c2 100644
--- a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm
@@ -62,11 +62,12 @@
#end
#end
import type { ${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
+import { onUnload } from '@dcloudio/uni-app'
import { onMounted, ref } from 'vue'
-import { useToast } from 'wot-design-uni'
+import { useToast } from '@wot-ui/ui/components/wd-toast'
import { delete${simpleClassName}, get${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
import { useAccess } from '@/hooks/useAccess'
-import { navigateBackPlus } from '@/utils'
+import { delay, navigateBackPlus } from '@/utils'
#if ($hasDict == 1)
import { DICT_TYPE } from '@/utils/constants'
#end
@@ -87,8 +88,8 @@
const { hasAccessByCodes } = useAccess()
const toast = useToast()
-const formData = ref<${simpleClassName}>()
-const deleting = ref(false)
+const formData = ref<${simpleClassName}>() // 璇︽儏鏁版嵁
+const deleting = ref(false) // 鍒犻櫎鐘舵��
/** 杩斿洖涓婁竴椤� */
function handleBack() {
@@ -97,7 +98,7 @@
/** 鍔犺浇${table.classComment}璇︽儏 */
async function getDetail() {
- if (!props.id) {
+ if (!props.id || deleting.value) {
return
}
try {
@@ -131,9 +132,8 @@
try {
await delete${simpleClassName}(props.id)
toast.success('鍒犻櫎鎴愬姛')
- setTimeout(() => {
- handleBack()
- }, 500)
+ uni.$emit('${table.moduleName}:${table.businessName}:reload')
+ delay(handleBack)
} finally {
deleting.value = false
}
@@ -143,8 +143,14 @@
/** 鍒濆鍖� */
onMounted(() => {
+ uni.$on('${table.moduleName}:${table.businessName}:reload', getDetail)
getDetail()
})
+
+/** 鍗歌浇 */
+onUnload(() => {
+ uni.$off('${table.moduleName}:${table.businessName}:reload', getDetail)
+})
</script>
<style lang="scss" scoped>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm
index f163144..6c13045 100644
--- a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm
@@ -9,7 +9,7 @@
<!-- 琛ㄥ崟鍖哄煙 -->
<view>
- <wd-form ref="formRef" :model="formData" :rules="formRules">
+ <wd-form ref="formRef" :model="formData" :schema="formSchema">
<wd-cell-group border>
#foreach($column in $columns)
#if (($column.createOperation || $column.updateOperation) && !$column.primaryKey)
@@ -25,10 +25,23 @@
#elseif ($javaType == "Boolean")
#set ($dictMethod = "getBoolDictOptions")
#end
- ## 浼樺厛鍒ゆ柇鏄惁鏈夊瓧鍏革紝鏈夊瓧鍏稿垯浣跨敤 radio-group
- #if (($column.htmlType == "select" || $column.htmlType == "radio") && $dictType && "" != $dictType)
- <wd-cell title="${comment}" title-width="180rpx" prop="${javaField}" center>
- <wd-radio-group v-model="formData.${javaField}" shape="button">
+ ## 涓嬫媺閫夋嫨锛堝瓧鍏革級鈫� yd-form-picker锛屽唴閮ㄦ寜 dictType 瑙f瀽閫夐」锛岄�傚悎閫夐」杈冨
+ #if ($column.htmlType == "select" && $dictType && "" != $dictType)
+ <yd-form-picker
+ v-model="formData.${javaField}"
+ label="${comment}"
+ label-width="180rpx"
+ prop="${javaField}"
+ :dict-type="DICT_TYPE.${dictType.toUpperCase()}"
+#if ($javaType == "String")
+ dict-kind="str"
+#end
+ placeholder="璇烽�夋嫨${comment}"
+ />
+ ## 鍗曢�夛紙瀛楀吀锛夆啋 radio-group锛岄�傚悎閫夐」杈冨皯
+ #elseif ($column.htmlType == "radio" && $dictType && "" != $dictType)
+ <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}" center>
+ <wd-radio-group v-model="formData.${javaField}" type="button">
<wd-radio
v-for="dict in $dictMethod(DICT_TYPE.${dictType.toUpperCase()})"
:key="dict.value"
@@ -37,54 +50,78 @@
{{ dict.label }}
</wd-radio>
</wd-radio-group>
- </wd-cell>
+ </wd-form-item>
## 鏁板瓧绫诲瀷锛堟棤瀛楀吀锛�
#elseif (${javaType.toLowerCase()} == "long" || ${javaType.toLowerCase()} == "integer" || ${javaType.toLowerCase()} == "short" || ${javaType.toLowerCase()} == "double" || ${javaType.toLowerCase()} == "bigdecimal" || ${javaType.toLowerCase()} == "byte")
- <wd-cell title="${comment}" title-width="180rpx" prop="${javaField}" center>
+ <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
<wd-input-number
v-model="formData.${javaField}"
+#if (${javaType.toLowerCase()} == "double" || ${javaType.toLowerCase()} == "bigdecimal")
+ :precision="2"
+ input-type="number"
+#end
:min="0"
/>
- </wd-cell>
+ </wd-form-item>
## 甯冨皵绫诲瀷
#elseif (${javaType.toLowerCase()} == "boolean")
- <wd-cell title="${comment}" title-width="180rpx" prop="${javaField}" center>
+ <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}" center>
<wd-switch v-model="formData.${javaField}" />
- </wd-cell>
+ </wd-form-item>
## 鏃ユ湡鏃堕棿绫诲瀷
#elseif (${javaType.toLowerCase()} == "date" || ${javaType.toLowerCase()} == "localdate" || ${javaType.toLowerCase()} == "localdatetime")
#set ($pickerType = "date")
#if (${javaType.toLowerCase()} == "localdatetime")
#set ($pickerType = "datetime")
#end
+ <wd-form-item
+ title="${comment}"
+ title-width="180rpx"
+ prop="${javaField}"
+ is-link
+#if ($pickerType == "datetime")
+ :value="formatDateTime(formData.${javaField})"
+#else
+ :value="formatDate(formData.${javaField})"
+#end
+ placeholder="璇烽�夋嫨${comment}"
+ @click="${javaField}Visible = true"
+ />
<wd-datetime-picker
v-model="formData.${javaField}"
+ v-model:visible="${javaField}Visible"
type="${pickerType}"
- label="${comment}"
- label-width="180rpx"
- prop="${javaField}"
/>
## 鏂囨湰鍩�
#elseif ($column.htmlType == "textarea")
- <wd-textarea
- v-model="formData.${javaField}"
- label="${comment}"
- label-width="180rpx"
- placeholder="璇疯緭鍏�${comment}"
- :maxlength="200"
- show-word-limit
- clearable
- />
+ <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
+ <wd-textarea
+ v-model="formData.${javaField}"
+ clearable
+ placeholder="璇疯緭鍏�${comment}"
+ :maxlength="200"
+ show-word-limit
+ />
+ </wd-form-item>
+ ## 鍥剧墖涓婁紶 鈫� yd-upload-img锛堝寘 wd-form-item 鎵嶈兘娉ㄥ唽鍒� wd-form 鍋氭牎楠�/閿欒灞曠ず锛�
+ #elseif ($column.htmlType == "imageUpload")
+ <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
+ <yd-upload-img v-model="formData.${javaField}" directory="${table.moduleName}/${table.businessName}" />
+ </wd-form-item>
+ ## 鏂囦欢涓婁紶 鈫� yd-upload-file
+ #elseif ($column.htmlType == "fileUpload")
+ <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
+ <yd-upload-file v-model="formData.${javaField}" directory="${table.moduleName}/${table.businessName}" />
+ </wd-form-item>
## 榛樿锛氭枃鏈緭鍏�
#else
- <wd-input
- v-model="formData.${javaField}"
- label="${comment}"
- label-width="180rpx"
- prop="${javaField}"
- clearable
- placeholder="璇疯緭鍏�${comment}"
- />
+ <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
+ <wd-input
+ v-model="formData.${javaField}"
+ clearable
+ placeholder="璇疯緭鍏�${comment}"
+ />
+ </wd-form-item>
#end
#end
#end
@@ -107,7 +144,7 @@
</template>
<script lang="ts" setup>
-import type { FormInstance } from 'wot-design-uni/components/wd-form/types'
+import type { FormInstance } from '@wot-ui/ui/components/wd-form/types'
#set ($primaryJavaType = $primaryColumn.javaType.toLowerCase())
#if(${primaryJavaType} == "long" || ${primaryJavaType} == "integer" || ${primaryJavaType} == "short" || ${primaryJavaType} == "double" || ${primaryJavaType} == "bigdecimal" || ${primaryJavaType} == "byte")
#set ($primaryTsType = "number")
@@ -115,6 +152,8 @@
#set ($primaryTsType = "string")
#end
#set ($hasDict = 0)
+#set ($hasDate = 0)
+#set ($hasDateTime = 0)
#set ($hasGetDictOptions = 0)
#set ($hasGetIntDictOptions = 0)
#set ($hasGetStrDictOptions = 0)
@@ -124,22 +163,30 @@
&& ($column.htmlType == "select" || $column.htmlType == "radio")
&& $column.dictType && "" != $column.dictType)
#set ($hasDict = 1)
- #if ($column.javaType == "Integer" || $column.javaType == "Long" || $column.javaType == "Byte" || $column.javaType == "Short")
+ #if ($column.htmlType == "radio" && ($column.javaType == "Integer" || $column.javaType == "Long" || $column.javaType == "Byte" || $column.javaType == "Short"))
#set ($hasGetIntDictOptions = 1)
- #elseif ($column.javaType == "String")
+ #elseif ($column.htmlType == "radio" && $column.javaType == "String")
#set ($hasGetStrDictOptions = 1)
- #elseif ($column.javaType == "Boolean")
+ #elseif ($column.htmlType == "radio" && $column.javaType == "Boolean")
#set ($hasGetBoolDictOptions = 1)
- #else
+ #elseif ($column.htmlType == "radio")
#set ($hasGetDictOptions = 1)
#end
+ #end
+ #if (($column.createOperation || $column.updateOperation) && !$column.primaryKey
+ && (${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate"))
+ #set ($hasDate = 1)
+ #end
+ #if (($column.createOperation || $column.updateOperation) && !$column.primaryKey
+ && ${column.javaType.toLowerCase()} == "localdatetime")
+ #set ($hasDateTime = 1)
#end
#end
import type { ${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
import { computed, onMounted, ref } from 'vue'
-import { useToast } from 'wot-design-uni'
+import { useToast } from '@wot-ui/ui/components/wd-toast'
import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
-#if ($hasDict == 1)
+#if ($hasGetDictOptions == 1 || $hasGetIntDictOptions == 1 || $hasGetStrDictOptions == 1 || $hasGetBoolDictOptions == 1)
#set ($dictImportNames = "")
#if ($hasGetDictOptions == 1)
#set ($dictImportNames = "${dictImportNames}getDictOptions, ")
@@ -157,10 +204,23 @@
#set ($dictImportNames = $dictImportNames.substring(0, $dictImportNames.length() - 1))
import { $dictImportNames } from '@/hooks/useDict'
#end
-import { navigateBackPlus } from '@/utils'
+import { delay, navigateBackPlus } from '@/utils'
#if ($hasDict == 1)
import { DICT_TYPE } from '@/utils/constants'
#end
+#if ($hasDate == 1 || $hasDateTime == 1)
+ #set ($dateImportNames = "")
+ #if ($hasDate == 1)
+ #set ($dateImportNames = "${dateImportNames}formatDate, ")
+ #end
+ #if ($hasDateTime == 1)
+ #set ($dateImportNames = "${dateImportNames}formatDateTime, ")
+ #end
+ #set ($dateImportNames = $dateImportNames.trim())
+ #set ($dateImportNames = $dateImportNames.substring(0, $dateImportNames.length() - 1))
+import { $dateImportNames } from '@/utils/date'
+#end
+import { createFormSchema } from '@/utils/wot'
const props = defineProps<{
id?: ${primaryTsType} | any
@@ -175,7 +235,7 @@
const toast = useToast()
const getTitle = computed(() => props.id ? '缂栬緫${table.classComment}' : '鏂板${table.classComment}')
-const formLoading = ref(false)
+const formLoading = ref(false) // 琛ㄥ崟鎻愪氦鐘舵��
const formData = ref<${simpleClassName}>({
#foreach($column in $columns)
#if (($column.createOperation || $column.updateOperation) || $column.primaryKey)
@@ -195,8 +255,13 @@
#end
#end
#end
-})
-const formRules = {
+}) // 琛ㄥ崟鏁版嵁
+#foreach($column in $columns)
+ #if (($column.createOperation || $column.updateOperation) && !$column.primaryKey && (${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime"))
+const ${column.javaField}Visible = ref(false) // ${column.columnComment}閫夋嫨鍣ㄧ姸鎬�
+ #end
+#end
+const formSchema = createFormSchema({
#foreach($column in $columns)
#set ($javaFieldLower = $column.javaField.toLowerCase())
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey
@@ -204,8 +269,8 @@
${column.javaField}: [{ required: true, message: '${column.columnComment}涓嶈兘涓虹┖' }],
#end
#end
-}
-const formRef = ref<FormInstance>()
+}) // 琛ㄥ崟鏍¢獙瑙勫垯
+const formRef = ref<FormInstance>() // 琛ㄥ崟缁勪欢寮曠敤
/** 杩斿洖涓婁竴椤� */
function handleBack() {
@@ -236,9 +301,8 @@
await create${simpleClassName}(formData.value)
toast.success('鏂板鎴愬姛')
}
- setTimeout(() => {
- handleBack()
- }, 500)
+ uni.$emit('${table.moduleName}:${table.businessName}:reload')
+ delay(handleBack)
} finally {
formLoading.value = false
}
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm
index 2d7daaba..acf506e 100644
--- a/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/index.vue.vm
@@ -1,5 +1,5 @@
<template>
- <view class="yd-page-container">
+ <view class="yd-page-container yd-page-container-paging">
<!-- 椤堕儴瀵艰埅鏍� -->
<wd-navbar
title="${table.classComment}绠$悊"
@@ -11,14 +11,26 @@
<SearchForm @search="handleQuery" @reset="handleReset" />
<!-- ${table.classComment}鍒楄〃 -->
- <view class="p-24rpx">
- <view
- v-for="item in list"
- :key="item.${primaryColumn.javaField}"
- class="mb-24rpx overflow-hidden rounded-12rpx bg-white shadow-sm"
- @click="handleDetail(item)"
- >
- <view class="p-24rpx">
+ <z-paging
+ ref="pagingRef"
+ v-model="list"
+ :fixed="false"
+ class="min-h-0 flex-1"
+ :default-page-size="10"
+ :refresher-enabled="true"
+ :inside-more="true"
+ :loading-more-default-as-loading="true"
+ empty-view-text="鏆傛棤${table.classComment}鏁版嵁"
+ @query="queryList"
+ >
+ <view class="p-24rpx">
+ <view
+ v-for="item in list"
+ :key="item.${primaryColumn.javaField}"
+ class="mb-24rpx overflow-hidden rounded-12rpx bg-white shadow-sm"
+ @click="handleDetail(item)"
+ >
+ <view class="p-24rpx">
#set ($titleField = "")
#set ($statusField = "")
#set ($statusDictType = "")
@@ -35,14 +47,14 @@
#if ($titleField == "")
#set ($titleField = $primaryColumn.javaField)
#end
- <view class="mb-16rpx flex items-center justify-between">
- <view class="text-32rpx text-[#333] font-semibold">
- {{ item.${titleField} }}
- </view>
+ <view class="mb-16rpx flex items-center justify-between">
+ <view class="text-32rpx text-[#333] font-semibold">
+ {{ item.${titleField} }}
+ </view>
#if($statusField != "")
- <dict-tag :type="DICT_TYPE.${statusDictType.toUpperCase()}" :value="item.${statusField}" />
+ <dict-tag :type="DICT_TYPE.${statusDictType.toUpperCase()}" :value="item.${statusField}" />
#end
- </view>
+ </view>
#foreach($column in $columns)
#if ($column.listOperationResult && !$column.primaryKey && $column.javaField != $titleField && $column.javaField != $statusField)
#set ($javaField = $column.javaField)
@@ -50,36 +62,27 @@
#set ($dictType = $column.dictType)
#set ($javaType = $column.javaType)
#if ($dictType && "" != $dictType)
- <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
- <text class="mr-8rpx text-[#999]">${comment}锛�</text>
- <dict-tag :type="DICT_TYPE.${dictType.toUpperCase()}" :value="item.${javaField}" />
- </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">${comment}锛�</text>
+ <dict-tag :type="DICT_TYPE.${dictType.toUpperCase()}" :value="item.${javaField}" />
+ </view>
#elseif ($javaType == "LocalDateTime")
- <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
- <text class="mr-8rpx text-[#999]">${comment}锛�</text>
- <text class="line-clamp-1">{{ formatDateTime(item.${javaField}) || '-' }}</text>
- </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">${comment}锛�</text>
+ <text class="line-clamp-1">{{ formatDateTime(item.${javaField}) || '-' }}</text>
+ </view>
#else
- <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
- <text class="mr-8rpx text-[#999]">${comment}锛�</text>
- <text class="line-clamp-1">{{ item.${javaField} }}</text>
- </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">${comment}锛�</text>
+ <text class="line-clamp-1">{{ item.${javaField} }}</text>
+ </view>
#end
#end
#end
+ </view>
</view>
</view>
-
- <!-- 鍔犺浇鏇村 -->
- <view v-if="loadMoreState !== 'loading' && list.length === 0" class="py-100rpx text-center">
- <wd-status-tip image="content" tip="鏆傛棤${table.classComment}鏁版嵁" />
- </view>
- <wd-loadmore
- v-if="list.length > 0"
- :state="loadMoreState"
- @reload="loadMore"
- />
- </view>
+ </z-paging>
<!-- 鏂板鎸夐挳 -->
<wd-fab
@@ -108,8 +111,7 @@
#end
#end
import type { ${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
-import type { LoadMoreState } from '@/http/types'
-import { onReachBottom } from '@dcloudio/uni-app'
+import { onUnload } from '@dcloudio/uni-app'
import { onMounted, ref } from 'vue'
import { get${simpleClassName}Page } from '@/api/${table.moduleName}/${table.businessName}'
import { useAccess } from '@/hooks/useAccess'
@@ -130,13 +132,9 @@
})
const { hasAccessByCodes } = useAccess()
-const total = ref(0)
-const list = ref<${simpleClassName}[]>([])
-const loadMoreState = ref<LoadMoreState>('loading')
-const queryParams = ref({
- pageNo: 1,
- pageSize: 10,
-})
+const list = ref<${simpleClassName}[]>([]) // 鍒楄〃鏁版嵁
+const pagingRef = ref<any>() // 鍒嗛〉缁勪欢寮曠敤
+const queryParams = ref<Record<string, any>>({}) // 鏌ヨ鍙傛暟
/** 杩斿洖涓婁竴椤� */
function handleBack() {
@@ -144,28 +142,24 @@
}
/** 鏌ヨ${table.classComment}鍒楄〃 */
-async function getList() {
- loadMoreState.value = 'loading'
+async function queryList(pageNo: number, pageSize: number) {
try {
- const data = await get${simpleClassName}Page(queryParams.value)
- list.value = [...list.value, ...data.list]
- total.value = data.total
- loadMoreState.value = list.value.length >= total.value ? 'finished' : 'loading'
+ const params = {
+ ...queryParams.value,
+ pageNo,
+ pageSize,
+ }
+ const data = await get${simpleClassName}Page(params)
+ pagingRef.value?.completeByTotal(data.list, data.total)
} catch {
- queryParams.value.pageNo = queryParams.value.pageNo > 1 ? queryParams.value.pageNo - 1 : 1
- loadMoreState.value = 'error'
+ pagingRef.value?.complete(false)
}
}
/** 鎼滅储鎸夐挳鎿嶄綔 */
function handleQuery(data?: Record<string, any>) {
- queryParams.value = {
- ...data,
- pageNo: 1,
- pageSize: queryParams.value.pageSize,
- }
- list.value = []
- getList()
+ queryParams.value = { ...data }
+ reload()
}
/** 閲嶇疆鎸夐挳鎿嶄綔 */
@@ -173,13 +167,9 @@
handleQuery()
}
-/** 鍔犺浇鏇村 */
-function loadMore() {
- if (loadMoreState.value === 'finished') {
- return
- }
- queryParams.value.pageNo++
- getList()
+/** 閲嶆柊鍔犺浇 */
+function reload() {
+ pagingRef.value?.reload()
}
/** 鏂板${table.classComment} */
@@ -196,14 +186,14 @@
})
}
-/** 瑙﹀簳鍔犺浇鏇村 */
-onReachBottom(() => {
- loadMore()
-})
-
/** 鍒濆鍖� */
onMounted(() => {
- getList()
+ uni.$on('${table.moduleName}:${table.businessName}:reload', reload)
+})
+
+/** 鍗歌浇 */
+onUnload(() => {
+ uni.$off('${table.moduleName}:${table.businessName}:reload', reload)
})
</script>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/api/api.ts.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/api/api.ts.vm
new file mode 100644
index 0000000..c0139d4
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/api/api.ts.vm
@@ -0,0 +1,179 @@
+import type { PageParam, PageResult } from '@vben/request';
+import type { Dayjs } from 'dayjs';
+
+import { requestClient } from '#/api/request';
+#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
+
+export namespace ${simpleClassName}Api {
+ ## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subColumns = $subColumnsList.get($index))##褰撳墠瀛楁鏁扮粍
+ /** ${subTable.classComment}淇℃伅 */
+ export interface ${subSimpleClassName} {
+ #foreach ($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
+ ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
+ #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
+ ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
+ #else
+ ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
+ #end
+ #end
+ #end
+ }
+
+ #end
+ /** ${table.classComment}淇℃伅 */
+ export interface ${simpleClassName} {
+ #foreach ($column in $columns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
+ ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
+ #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
+ ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
+ #else
+ ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
+ #end
+ #end
+ #end
+ #if ( $table.templateType == 2 )
+ children?: ${simpleClassName}[];
+ #end
+ ## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ #if ( $table.templateType == 10 || $table.templateType == 12 )
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #if ( $subTable.subJoinMany )
+ ${subSimpleClassName.toLowerCase()}s?: ${subSimpleClassName}[]
+ #else
+ ${subSimpleClassName.toLowerCase()}?: ${subSimpleClassName}
+ #end
+ #end
+ #end
+ }
+}
+
+#if ( $table.templateType != 2 )
+/** 鏌ヨ${table.classComment}鍒嗛〉 */
+export function get${simpleClassName}Page(params: PageParam) {
+ return requestClient.get<PageResult<${simpleClassName}Api.${simpleClassName}>>('${baseURL}/page', { params });
+}
+#else
+/** 鏌ヨ${table.classComment}鍒楄〃 */
+export function get${simpleClassName}List(params: any) {
+ return requestClient.get<${simpleClassName}Api.${simpleClassName}[]>('${baseURL}/list', { params });
+}
+#end
+
+/** 鏌ヨ${table.classComment}璇︽儏 */
+export function get${simpleClassName}(id: number) {
+ return requestClient.get<${simpleClassName}Api.${simpleClassName}>(`${baseURL}/get?id=${id}`);
+}
+
+/** 鏂板${table.classComment} */
+export function create${simpleClassName}(data: ${simpleClassName}Api.${simpleClassName}) {
+ return requestClient.post('${baseURL}/create', data);
+}
+
+/** 淇敼${table.classComment} */
+export function update${simpleClassName}(data: ${simpleClassName}Api.${simpleClassName}) {
+ return requestClient.put('${baseURL}/update', data);
+}
+
+/** 鍒犻櫎${table.classComment} */
+export function delete${simpleClassName}(id: number) {
+ return requestClient.delete(`${baseURL}/delete?id=${id}`);
+}
+
+#if ( $table.templateType != 2 && $deleteBatchEnable)
+/** 鎵归噺鍒犻櫎${table.classComment} */
+export function delete${simpleClassName}List(ids: number[]) {
+ return requestClient.delete(`${baseURL}/delete-list?ids=${ids.join(',')}`)
+}
+#end
+
+/** 瀵煎嚭${table.classComment} */
+export function export${simpleClassName}(params: any) {
+ return requestClient.download('${baseURL}/export-excel', { params });
+}
+#if ($importEnable)
+
+/** 涓嬭浇${table.classComment}瀵煎叆妯℃澘 */
+export function import${simpleClassName}Template() {
+ return requestClient.download('${baseURL}/get-import-template');
+}
+
+/** 瀵煎叆${table.classComment} */
+export function import${simpleClassName}(data: FormData) {
+ return requestClient.post('${baseURL}/import', data);
+}
+#end
+
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subPrimaryColumn = $subPrimaryColumns.get($index))##褰撳墠 primary 瀛楁
+ #set ($subJoinColumn = $subJoinColumns.get($index))##褰撳墠 join 瀛楁
+ #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##棣栧瓧姣嶅ぇ鍐�
+ #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
+ #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+
+// ==================== 瀛愯〃锛�$subTable.classComment锛� ====================
+
+## 鎯呭喌涓�锛歁ASTER_ERP 鏃讹紝闇�瑕佸垎鏌ヨ椤靛瓙琛�
+#if ( $table.templateType == 11 )
+/** 鑾峰緱${subTable.classComment}鍒嗛〉 */
+export function get${subSimpleClassName}Page(params: PageParam) {
+ return requestClient.get<PageResult<${simpleClassName}Api.${subSimpleClassName}>>(`${baseURL}/${subSimpleClassName_strikeCase}/page`, { params });
+}
+ ## 鎯呭喌浜岋細闈� MASTER_ERP 鏃讹紝闇�瑕佸垪琛ㄦ煡璇㈠瓙琛�
+#else
+#if ( $subTable.subJoinMany )
+/** 鑾峰緱${subTable.classComment}鍒楄〃 */
+export function get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}: number) {
+ return requestClient.get<${simpleClassName}Api.${subSimpleClassName}[]>(`${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=${${subJoinColumn.javaField}}`);
+}
+#else
+/** 鑾峰緱${subTable.classComment} */
+export function get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}: number) {
+ return requestClient.get<${simpleClassName}Api.${subSimpleClassName}>(`${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=${${subJoinColumn.javaField}}`);
+}
+#end
+#end
+## 鐗规畩锛歁ASTER_ERP 鏃讹紝鏀寔鍗曚釜鐨勬柊澧炪�佷慨鏀广�佸垹闄ゆ搷浣�
+#if ( $table.templateType == 11 )
+/** 鏂板${subTable.classComment} */
+export function create${subSimpleClassName}(data: ${simpleClassName}Api.${subSimpleClassName}) {
+ return requestClient.post(`${baseURL}/${subSimpleClassName_strikeCase}/create`, data);
+}
+
+/** 淇敼${subTable.classComment} */
+export function update${subSimpleClassName}(data: ${simpleClassName}Api.${subSimpleClassName}) {
+ return requestClient.put(`${baseURL}/${subSimpleClassName_strikeCase}/update`, data);
+}
+
+/** 鍒犻櫎${subTable.classComment} */
+export function delete${subSimpleClassName}(id: number) {
+ return requestClient.delete(`${baseURL}/${subSimpleClassName_strikeCase}/delete?id=${id}`);
+}
+
+#if ($deleteBatchEnable)
+/** 鎵归噺鍒犻櫎${subTable.classComment} */
+export function delete${subSimpleClassName}List(ids: number[]) {
+ return requestClient.delete(`${baseURL}/${subSimpleClassName_strikeCase}/delete-list?ids=${ids.join(',')}`)
+}
+#end
+
+/** 鑾峰緱${subTable.classComment} */
+export function get${subSimpleClassName}(id: number) {
+ return requestClient.get<${simpleClassName}Api.${subSimpleClassName}>(`${baseURL}/${subSimpleClassName_strikeCase}/get?id=${id}`);
+}
+#end
+#end
+
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/form.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/form.vue.vm
new file mode 100644
index 0000000..03db716
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/form.vue.vm
@@ -0,0 +1,325 @@
+<script lang="ts" setup>
+import type { Rule } from 'antdv-next/es/form';
+import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
+
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { DICT_TYPE } from '@vben/constants';
+import { getDictOptions } from '@vben/hooks';
+import { Tinymce as RichTextarea } from '#/components/tinymce';
+import { ImageUpload, FileUpload } from "#/components/upload";
+import { message, Tabs, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'antdv-next';
+#if($table.templateType == 2)## 鏍戣〃闇�瑕佸鍏ヨ繖浜�
+import { get${simpleClassName}List } from '#/api/${table.moduleName}/${table.businessName}';
+import { handleTree } from '@vben/utils'
+#end
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+ #foreach ($subSimpleClassName in $subSimpleClassNames)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
+ import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
+ #end
+#end
+
+import { $t } from '#/locales';
+import { get${simpleClassName}, create${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+const emit = defineEmits(['success']);
+
+const formRef = ref();
+const formData = ref<Partial<${simpleClassName}Api.${simpleClassName}>>({
+#foreach ($column in $columns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if ($column.htmlType == "checkbox")
+ $column.javaField: [],
+ #else
+ $column.javaField: undefined,
+ #end
+ #end
+#end
+});
+const rules: Record<string, Rule[]> = {
+ #foreach ($column in $columns)
+ #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 鍒涘缓鎴栬�呮洿鏂版搷浣� && 瑕佹眰闈炵┖ && 闈炰富閿�
+ #set($comment=$column.columnComment)
+ $column.javaField: [{ required: true, message: '${comment}涓嶈兘涓虹┖', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
+ #end
+ #end
+};
+## 鐗规畩锛氭爲琛ㄤ笓灞為�昏緫
+#if ( $table.templateType == 2 )
+const ${classNameVar}Tree = ref<any[]>([]) // 鏍戝舰缁撴瀯
+#end
+const getTitle = computed(() => {
+ return formData.value?.id
+ ? $t('ui.actionTitle.edit', ['${table.classComment}'])
+ : $t('ui.actionTitle.create', ['${table.classComment}']);
+});
+
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+ #if ( $subTables && $subTables.size() > 0 )
+ /** 瀛愯〃鐨勮〃鍗� */
+ const subTabsName = ref('$subClassNameVars.get(0)')
+ #foreach ($subClassNameVar in $subClassNameVars)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ const ${subClassNameVar}FormRef = ref<InstanceType<typeof ${subSimpleClassName}Form>>()
+ #end
+ #end
+#end
+
+/** 閲嶇疆琛ㄥ崟 */
+function resetForm() {
+ formData.value = {
+ #foreach ($column in $columns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if ($column.htmlType == "checkbox")
+ $column.javaField: [],
+ #else
+ $column.javaField: undefined,
+ #end
+ #end
+ #end
+ };
+ formRef.value?.resetFields();
+}
+
+## 鐗规畩锛氭爲琛ㄤ笓灞為�昏緫
+#if ( $table.templateType == 2 )
+/** 鑾峰緱${table.classComment}鏍� */
+async function get${simpleClassName}Tree() {
+ ${classNameVar}Tree.value = []
+ const data = await get${simpleClassName}List({});
+ data.unshift({
+ id: 0,
+ name: '椤剁骇${table.classComment}',
+ });
+ ${classNameVar}Tree.value = handleTree(data);
+}
+#end
+
+const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ await formRef.value?.validate();
+ ## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ #if ( $table.templateType == 10 || $table.templateType == 12 )
+ #if ( $subTables && $subTables.size() > 0 )
+ // 鏍¢獙瀛愯〃鍗�
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #if ($subTable.subJoinMany) ## 涓�瀵瑰
+ ## TODO 鍒楄〃鍊兼牎楠岋紵
+ #else
+ try {
+ await ${subClassNameVar}FormRef.value?.validate()
+ } catch (e) {
+ subTabsName.value = '${subClassNameVar}'
+ return
+ }
+ #end
+ #end
+ #end
+ #end
+ modalApi.lock();
+ // 鎻愪氦琛ㄥ崟
+ const data = formData.value as ${simpleClassName}Api.${simpleClassName};
+ ## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ #if ( $table.templateType == 10 || $table.templateType == 12 )
+ #if ( $subTables && $subTables.size() > 0 )
+ // 鎷兼帴瀛愯〃鐨勬暟鎹�
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #if ($subTable.subJoinMany)
+ data.${subClassNameVar}s = ${subClassNameVar}FormRef.value?.getData();
+ #else
+ data.${subClassNameVar} = ${subClassNameVar}FormRef.value?.getValues();
+ #end
+ #end
+ #end
+ #end
+ try {
+ await (formData.value?.id ? update${simpleClassName}(data) : create${simpleClassName}(data));
+ // 鍏抽棴骞舵彁绀�
+ await modalApi.close();
+ emit('success');
+ message.success({
+ content: $t('ui.actionMessage.operationSuccess'),
+ });
+ } finally {
+ modalApi.unlock();
+ }
+ },
+ async onOpenChange(isOpen: boolean) {
+ if (!isOpen) {
+ resetForm()
+ return;
+ }
+ // 鍔犺浇鏁版嵁
+ let data = modalApi.getData<${simpleClassName}Api.${simpleClassName}>();
+ if (!data) {
+ return;
+ }
+ if (data.id) {
+ modalApi.lock();
+ try {
+ data = await get${simpleClassName}(data.id);
+ } finally {
+ modalApi.unlock();
+ }
+ }
+ formData.value = data;
+#if ( $table.templateType == 2 )
+ // 鍔犺浇鏍戞暟鎹�
+ await get${simpleClassName}Tree()
+#end
+ },
+});
+</script>
+
+<template>
+ <Modal :title="getTitle">
+ <Form
+ ref="formRef"
+ :model="formData"
+ :rules="rules"
+ :label-col="{ span: 5 }"
+ :wrapper-col="{ span: 18 }"
+ >
+ #foreach($column in $columns)
+ #if ($column.createOperation || $column.updateOperation)
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($javaType = $column.javaType)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ #if ( $table.templateType == 2 && $column.id == $treeParentColumn.id )
+ <Form.Item label="${comment}" name="${javaField}">
+ <TreeSelect
+ v-model:value="formData.${javaField}"
+ :treeData="${classNameVar}Tree"
+ #if ($treeNameColumn.javaField == "name")
+ :fieldNames="{
+ label: 'name',
+ value: 'id',
+ children: 'children',
+ }"
+ #else
+ :fieldNames="{
+ label: '$treeNameColumn.javaField',
+ value: 'id',
+ children: 'children',
+ }"
+ #end
+ checkable
+ treeDefaultExpandAll
+ placeholder="璇烽�夋嫨${comment}"
+ />
+ </Form.Item>
+ #elseif ($column.htmlType == "input" && !$column.primaryKey)## 蹇界暐涓婚敭锛屼笉鐢ㄥ湪琛ㄥ崟閲�
+ <Form.Item label="${comment}" name="${javaField}">
+ <Input v-model:value="formData.${javaField}" placeholder="璇疯緭鍏�${comment}" />
+ </Form.Item>
+ #elseif($column.htmlType == "imageUpload")## 鍥剧墖涓婁紶
+ <Form.Item label="${comment}" name="${javaField}">
+ <ImageUpload v-model:value="formData.${javaField}" />
+ </Form.Item>
+ #elseif($column.htmlType == "fileUpload")## 鏂囦欢涓婁紶
+ <Form.Item label="${comment}" name="${javaField}">
+ <FileUpload v-model:value="formData.${javaField}" />
+ </Form.Item>
+ #elseif($column.htmlType == "editor")## 鏂囨湰缂栬緫鍣�
+ <Form.Item label="${comment}" name="${javaField}">
+ <RichTextarea v-model="formData.${javaField}" height="500px" />
+ </Form.Item>
+ #elseif($column.htmlType == "select")## 涓嬫媺妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <Select v-model:value="formData.${javaField}" placeholder="璇烽�夋嫨${comment}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <SelectOption
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </SelectOption>
+ #else##娌℃暟鎹瓧鍏�
+ <SelectOption label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ #end
+ </Select>
+ </Form.Item>
+ #elseif($column.htmlType == "checkbox")## 澶氶�夋
+ <Form.Item label="${comment}" name="${javaField}">
+ <CheckboxGroup v-model:value="formData.${javaField}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <Checkbox
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </Checkbox>
+ #else##娌℃暟鎹瓧鍏�
+ <Checkbox label="璇烽�夋嫨瀛楀吀鐢熸垚" />
+ #end
+ </CheckboxGroup>
+ </Form.Item>
+ #elseif($column.htmlType == "radio")## 鍗曢�夋
+ <Form.Item label="${comment}" name="${javaField}">
+ <RadioGroup v-model:value="formData.${javaField}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <Radio
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </Radio>
+ #else##娌℃暟鎹瓧鍏�
+ <Radio value="1">璇烽�夋嫨瀛楀吀鐢熸垚</Radio>
+ #end
+ </RadioGroup>
+ </Form.Item>
+ #elseif($column.htmlType == "datetime")## 鏃堕棿妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <DatePicker
+ v-model:value="formData.${javaField}"
+ valueFormat="x"
+ placeholder="閫夋嫨${comment}"
+ />
+ </Form.Item>
+ #elseif($column.htmlType == "textarea")## 鏂囨湰妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <TextArea v-model:value="formData.${javaField}" placeholder="璇疯緭鍏�${comment}" />
+ </Form.Item>
+ #end
+ #end
+ #end
+ </Form>
+ ## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ #if ( $table.templateType == 10 || $table.templateType == 12 )
+ <!-- 瀛愯〃鐨勮〃鍗� -->
+ <Tabs v-model:active-key="subTabsName">
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+ <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
+ <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData?.id" />
+ </TabPane>
+ #end
+ </Tabs>
+ #end
+ </Modal>
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/import.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/import.vue.vm
new file mode 100644
index 0000000..b6b8f79
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/import.vue.vm
@@ -0,0 +1,71 @@
+<script lang="ts" setup>
+import type { FileType } from 'antdv-next/es/upload/interface';
+
+import { ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { downloadFileFromBlobPart } from '@vben/utils';
+
+import { Button, message, Upload } from 'antdv-next';
+
+import { import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}';
+
+defineOptions({ name: '${simpleClassName}Import' });
+
+const emit = defineEmits(['success']);
+const fileRef = ref<File | null>(null);
+
+const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ if (!fileRef.value) {
+ message.error('璇蜂笂浼犳枃浠�');
+ return;
+ }
+ modalApi.lock();
+ try {
+ const formData = new FormData();
+ formData.append('file', fileRef.value);
+ const response: any = await import${simpleClassName}(formData);
+ const data = response?.data ?? response ?? {};
+ let text = '瀵煎叆鎴愬姛鏁伴噺锛�' + (data.successCount || 0) + '锛涘鍏ュけ璐ユ暟閲忥細' + (data.failureCount || 0) + '锛�';
+ if (data.failureRows) {
+ Object.keys(data.failureRows).forEach((rowNo) => {
+ text += '< 绗�' + rowNo + '琛�: ' + data.failureRows[rowNo] + ' >';
+ });
+ }
+ message.info(text);
+ await modalApi.close();
+ emit('success');
+ } finally {
+ modalApi.unlock();
+ }
+ },
+});
+
+/** 涓婁紶鍓嶏細鎷︽埅 antd Upload 鐨勮嚜鍔ㄤ笂浼狅紝鏂囦欢瀛樺埌 ref */
+function beforeUpload(file: FileType) {
+ fileRef.value = file as unknown as File;
+ return false;
+}
+
+/** 涓嬭浇瀵煎叆妯℃澘 */
+async function handleDownload() {
+ const data = await import${simpleClassName}Template();
+ downloadFileFromBlobPart({ fileName: '${table.classComment}瀵煎叆妯℃澘.xls', source: data });
+}
+</script>
+
+<template>
+ <Modal title="瀵煎叆${table.classComment}" class="w-1/3">
+ <div class="mx-4">
+ <Upload :max-count="1" accept=".xls,.xlsx" :before-upload="beforeUpload">
+ <Button type="primary"> 閫夋嫨 Excel 鏂囦欢 </Button>
+ </Upload>
+ </div>
+ <template #prepend-footer>
+ <div class="flex flex-auto items-center">
+ <Button @click="handleDownload"> 涓嬭浇瀵煎叆妯℃澘 </Button>
+ </div>
+ </template>
+ </Modal>
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/index.vue.vm
new file mode 100644
index 0000000..166069d
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/index.vue.vm
@@ -0,0 +1,511 @@
+<script lang="ts" setup>
+import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
+
+import { ref, h, reactive, onMounted, nextTick } from 'vue';
+
+import { Page, useVbenModal } from '@vben/common-ui';
+import { DICT_TYPE } from '@vben/constants';
+import { getDictOptions } from '@vben/hooks';
+import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table';
+import { cloneDeep, downloadFileFromBlobPart, formatDateTime, isEmpty } from '@vben/utils';
+import { Button, Card, message, Tabs, Pagination, Form, RangePicker, DatePicker, Select, Input } from 'antdv-next';
+import ${simpleClassName}Form from './modules/form.vue';
+import { Download, Plus, RefreshCw, Search, Trash2 } from '@vben/icons';
+import { DictTag } from '#/components/dict-tag';
+import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
+import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
+
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 11 || $table.templateType == 12 )
+ #foreach ($subSimpleClassName in $subSimpleClassNames)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
+ import ${subSimpleClassName}List from './modules/${subSimpleClassName_strikeCase}-list.vue'
+ #end
+#end
+
+import { $t } from '#/locales';
+#if (${table.templateType} == 2)## 鏍戣〃鎺ュ彛
+import { handleTree } from '@vben/utils'
+import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
+#else## 鏍囧噯琛ㄦ帴鍙�
+import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}List,#end export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
+#end
+#if ($importEnable)
+import ${simpleClassName}Import from './modules/import-form.vue';
+#end
+
+#if ($table.templateType == 12 || $table.templateType == 11) ## 鍐呭祵鍜宔rp鎯呭喌
+/** 瀛愯〃鐨勫垪琛� */
+const subTabsName = ref('$subClassNameVars.get(0)')
+#if ($table.templateType == 11)
+const select${simpleClassName} = ref<${simpleClassName}Api.${simpleClassName}>();
+async function onCellClick({ row }: { row: ${simpleClassName}Api.${simpleClassName} }) {
+ select${simpleClassName}.value = row
+}
+#end
+#end
+
+const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑
+#if ( $table.templateType == 2 )
+const list = ref<any[]>([]) // 鏍戝垪琛ㄧ殑鏁版嵁
+#else
+const list = ref<${simpleClassName}Api.${simpleClassName}[]>([]) // 鍒楄〃鐨勬暟鎹�
+#end
+
+## 鐗规畩锛氭爲琛ㄤ笓灞為�昏緫锛堟爲涓嶉渶瑕佸垎椤垫帴鍙o級
+#if ( $table.templateType != 2 )
+const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁�
+#end
+const queryParams = reactive({
+## 鐗规畩锛氭爲琛ㄤ笓灞為�昏緫锛堟爲涓嶉渶瑕佸垎椤垫帴鍙o級
+#if ( $table.templateType != 2 )
+ pageNo: 1,
+ pageSize: 10,
+#end
+#foreach ($column in $columns)
+ #if ($column.listOperation)
+ #if ($column.listOperationCondition != 'BETWEEN')
+ $column.javaField: undefined,
+ #end
+ #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
+ $column.javaField: undefined,
+ #end
+ #end
+#end
+})
+const queryFormRef = ref() // 鎼滅储鐨勮〃鍗�
+const exportLoading = ref(false) // 瀵煎嚭鐨勫姞杞戒腑
+
+/** 鏌ヨ鍒楄〃 */
+async function getList() {
+ loading.value = true
+ try {
+ const params = cloneDeep(queryParams) as any;
+ #foreach ($column in $columns)
+ #if ($column.listOperation)
+ #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
+ if (params.${column.javaField} && Array.isArray(params.${column.javaField})) {
+ params.${column.javaField} = (params.${column.javaField} as string[]).join(',');
+ }
+ #end
+ #end
+ #end
+ ## 鐗规畩锛氭爲琛ㄤ笓灞為�昏緫锛堟爲涓嶉渶瑕佸垎椤垫帴鍙o級
+ #if ( $table.templateType == 2 )
+ list.value = await get${simpleClassName}List(params);
+ #else
+ const data = await get${simpleClassName}Page(params)
+ list.value = data.list
+ total.value = data.total
+ #end
+ } finally {
+ loading.value = false
+ }
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery() {
+#if ( $table.templateType != 2 )
+ queryParams.pageNo = 1
+#end
+ getList()
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function resetQuery() {
+ queryFormRef.value.resetFields()
+ handleQuery()
+}
+
+const [FormModal, formModalApi] = useVbenModal({
+ connectedComponent: ${simpleClassName}Form,
+ destroyOnClose: true,
+});
+#if ($importEnable)
+const [ImportFormModal, importFormModalApi] = useVbenModal({
+ connectedComponent: ${simpleClassName}Import,
+ destroyOnClose: true,
+});
+
+/** 瀵煎叆${table.classComment} */
+function handleImport() {
+ importFormModalApi.open();
+}
+#end
+
+/** 鍒涘缓${table.classComment} */
+function handleCreate() {
+ formModalApi.setData(null).open();
+}
+
+/** 缂栬緫${table.classComment} */
+function handleEdit(row: ${simpleClassName}Api.${simpleClassName}) {
+ formModalApi.setData(row).open();
+}
+
+#if (${table.templateType} == 2)## 鏍戣〃鐗规湁锛氭柊澧炰笅绾�
+/** 鏂板涓嬬骇${table.classComment} */
+function handleAppend(row: ${simpleClassName}Api.${simpleClassName}) {
+ formModalApi.setData({ ${treeParentColumn.javaField}: row.id }).open();
+}
+#end
+
+/** 鍒犻櫎${table.classComment} */
+async function handleDelete(row: ${simpleClassName}Api.${simpleClassName}) {
+ const hideLoading = message.loading({
+ content: $t('ui.actionMessage.deleting', [row.id]),
+ duration: 0,
+ });
+ try {
+ await delete${simpleClassName}(row.id!);
+ message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
+ await getList();
+ } finally {
+ hideLoading();
+ }
+}
+
+#if ($table.templateType != 2 && $deleteBatchEnable)
+/** 鎵归噺鍒犻櫎${table.classComment} */
+async function handleDeleteBatch() {
+ const hideLoading = message.loading({
+ content: $t('ui.actionMessage.deleting'),
+ duration: 0,
+ });
+ try {
+ await delete${simpleClassName}List(checkedIds.value);
+ checkedIds.value = [];
+ message.success($t('ui.actionMessage.deleteSuccess'));
+ await getList();
+ } finally {
+ hideLoading();
+ }
+}
+
+const checkedIds = ref<number[]>([])
+function handleRowCheckboxChange({
+ records,
+}: {
+ records: ${simpleClassName}Api.${simpleClassName}[];
+}) {
+ checkedIds.value = records.map((item) => item.id!);
+}
+#end
+
+/** 瀵煎嚭琛ㄦ牸 */
+async function handleExport() {
+try {
+ exportLoading.value = true;
+ const data = await export${simpleClassName}(queryParams);
+ downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data });
+}finally {
+ exportLoading.value = false;
+}
+}
+
+
+#if (${table.templateType} == 2)
+/** 鍒囨崲鏍戝舰灞曞紑/鏀剁缉鐘舵�� */
+const isExpanded = ref(true);
+function handleExpand() {
+ isExpanded.value = !isExpanded.value;
+ tableRef.value?.setAllTreeExpand(isExpanded.value);
+}
+#end
+
+/** 鍒濆鍖� */
+const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
+onMounted(() => {
+ getList();
+});
+</script>
+
+<template>
+ <Page auto-content-height>
+ <FormModal @success="getList" />
+#if ($importEnable)
+ <ImportFormModal @success="getList" />
+#end
+
+ <Card v-if="!hiddenSearchBar" class="mb-4">
+ <!-- 鎼滅储宸ヤ綔鏍� -->
+ <Form
+ :model="queryParams"
+ ref="queryFormRef"
+ layout="inline"
+ >
+ #foreach($column in $columns)
+ #if ($column.listOperation)
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($javaType = $column.javaType)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ #if ($column.htmlType == "input")
+ <Form.Item label="${comment}" name="${javaField}">
+ <Input
+ v-model:value="queryParams.${javaField}"
+ placeholder="璇疯緭鍏�${comment}"
+ allowClear
+ @pressEnter="handleQuery"
+ class="w-full"
+ />
+ </Form.Item>
+ #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")
+ <Form.Item label="${comment}" name="${javaField}">
+ <Select
+ v-model:value="queryParams.${javaField}"
+ placeholder="璇烽�夋嫨${comment}"
+ allowClear
+ class="w-full"
+ >
+ #if ("" != $dictType)## 璁剧疆浜� dictType 鏁版嵁瀛楀吀鐨勬儏鍐�
+ <SelectOption
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </SelectOption>
+ #else## 鏈缃� dictType 鏁版嵁瀛楀吀鐨勬儏鍐�
+ <SelectOption label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ #end
+ </Select>
+ </Form.Item>
+ #elseif($column.htmlType == "datetime")
+ #if ($column.listOperationCondition != "BETWEEN")## 闈炶寖鍥�
+ <Form.Item label="${comment}" name="${javaField}">
+ <DatePicker
+ v-model:value="queryParams.${javaField}"
+ valueFormat="YYYY-MM-DD"
+ placeholder="閫夋嫨${comment}"
+ allowClear
+ class="w-full"
+ />
+ </Form.Item>
+ #else## 鑼冨洿
+ <Form.Item label="${comment}" name="${javaField}">
+ <RangePicker
+ v-model:value="queryParams.${javaField}"
+ v-bind="getRangePickerDefaultProps()"
+ class="w-full"
+ />
+ </Form.Item>
+ #end
+ #end
+ #end
+ #end
+ <Form.Item>
+ <Button class="ml-2" @click="resetQuery"> 閲嶇疆 </Button>
+ <Button class="ml-2" @click="handleQuery" type="primary">
+ 鎼滅储
+ </Button>
+ </Form.Item>
+ </Form>
+ </Card>
+
+ <!-- 鍒楄〃 -->
+ <Card title="${table.classComment}">
+ <template #extra>
+ <VbenVxeTableToolbar
+ ref="tableToolbarRef"
+ v-model:hidden-search="hiddenSearchBar"
+ >
+ #if (${table.templateType} == 2)
+ <Button @click="handleExpand" class="mr-2">
+ {{ isExpanded ? '鏀剁缉' : '灞曞紑' }}
+ </Button>
+ #end
+ <Button
+ class="ml-2"
+ :icon="h(Plus)"
+ type="primary"
+ @click="handleCreate"
+ v-access:code="['${permissionPrefix}:create']"
+ >
+ {{ $t('ui.actionTitle.create', ['${table.classComment}']) }}
+ </Button>
+#if ($importEnable)
+ <Button
+ class="ml-2"
+ type="primary"
+ @click="handleImport"
+ v-access:code="['${permissionPrefix}:import']"
+ >
+ 瀵煎叆
+ </Button>
+#end
+ <Button
+ :icon="h(Download)"
+ type="primary"
+ class="ml-2"
+ :loading="exportLoading"
+ @click="handleExport"
+ v-access:code="['${permissionPrefix}:export']"
+ >
+ {{ $t('ui.actionTitle.export') }}
+ </Button>
+ #if ($table.templateType != 2 && $deleteBatchEnable)
+ <Button
+ :icon="h(Trash2)"
+ type="primary"
+ danger
+ class="ml-2"
+ :disabled="isEmpty(checkedIds)"
+ @click="handleDeleteBatch"
+ v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:delete']"
+ >
+ 鎵归噺鍒犻櫎
+ </Button>
+ #end
+ </VbenVxeTableToolbar>
+ </template>
+ <VxeTable
+ ref="tableRef"
+ :data="list"
+ #if ( $table.templateType == 2 )
+ :tree-config="{
+ parentField: '${treeParentColumn.javaField}',
+ rowField: 'id',
+ transform: true,
+ expandAll: true,
+ reserve: true,
+ }"
+ #end
+#if ($table.templateType == 11) ## erp鎯呭喌
+ @cell-click="onCellClick"
+ :row-config="{
+ keyField: 'id',
+ isHover: true,
+ isCurrent: true,
+ }"
+#end
+ show-overflow
+ :loading="loading"
+#if ($table.templateType != 2 && $deleteBatchEnable)
+ @checkboxAll="handleRowCheckboxChange"
+ @checkboxChange="handleRowCheckboxChange"
+#end
+ >
+#if ($table.templateType != 2 && $deleteBatchEnable)
+ <VxeColumn type="checkbox" width="40" />
+#end
+ ## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+ #if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
+ <!-- 瀛愯〃鐨勫垪琛� -->
+ <VxeColumn type="expand" width="60">
+ <template #content="{ row }">
+ <!-- 瀛愯〃鐨勮〃鍗� -->
+ <Tabs v-model:active-key="subTabsName" class="mx-8">
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+ <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
+ <${subSimpleClassName}List :${subJoinColumn_strikeCase}="row?.id" />
+ </TabPane>
+ #end
+ </Tabs>
+ </template>
+ </VxeColumn>
+ #end
+ #foreach($column in $columns)
+ #if ($column.listOperationResult)
+ #set ($dictType=$column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ #set ($comment=$column.columnComment)
+ #if ($column.javaType == "LocalDateTime")## 鏃堕棿绫诲瀷
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{row}">
+ {{formatDateTime(row.${javaField})}}
+ </template>
+ </VxeColumn>
+ #elseif($column.dictType && "" != $column.dictType)## 鏁版嵁瀛楀吀
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{row}">
+ <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
+ </template>
+ </VxeColumn>
+ #elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField)
+ <VxeColumn field="${javaField}" title="${comment}" align="center" tree-node/>
+ #else
+ <VxeColumn field="${javaField}" title="${comment}" align="center" />
+ #end
+ #end
+ #end
+ <VxeColumn field="operation" title="鎿嶄綔" align="center">
+ <template #default="{row}">
+#if ( $table.templateType == 2 )
+ <Button
+ size="small"
+ type="link"
+ @click="handleAppend(row)"
+ v-access:code="['${permissionPrefix}:create']"
+ >
+ 鏂板涓嬬骇
+ </Button>
+#end
+ <Button
+ size="small"
+ type="link"
+ @click="handleEdit(row)"
+ v-access:code="['${permissionPrefix}:update']"
+ >
+ {{ $t('ui.actionTitle.edit') }}
+ </Button>
+ <Button
+ size="small"
+ type="link"
+ danger
+ class="ml-2"
+ #if ( $table.templateType == 2 )
+ :disabled="!isEmpty(row?.children)"
+ #end
+ @click="handleDelete(row)"
+ v-access:code="['${permissionPrefix}:delete']"
+ >
+ {{ $t('ui.actionTitle.delete') }}
+ </Button>
+ </template>
+ </VxeColumn>
+ </VxeTable>
+#if ( $table.templateType != 2 )
+ <!-- 鍒嗛〉 -->
+ <div class="mt-2 flex justify-end">
+ <Pagination
+ :total="total"
+ v-model:current="queryParams.pageNo"
+ v-model:page-size="queryParams.pageSize"
+ show-size-changer
+ @change="getList"
+ />
+ </div>
+#end
+ </Card>
+#if ($table.templateType == 11) ## erp鎯呭喌
+ <Card>
+ <!-- 瀛愯〃鐨勮〃鍗� -->
+ <Tabs v-model:active-key="subTabsName">
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+ <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
+ <${subSimpleClassName}List :${subJoinColumn_strikeCase}="select${simpleClassName}?.id" />
+ </TabPane>
+ #end
+ </Tabs>
+ </Card>
+#end
+ </Page>
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_erp.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_erp.vue.vm
new file mode 100644
index 0000000..0cb89f4
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_erp.vue.vm
@@ -0,0 +1,213 @@
+#set ($subTable = $subTables.get($subIndex))##褰撳墠琛�
+#set ($subColumns = $subColumnsList.get($subIndex))##褰撳墠瀛楁鏁扮粍
+#set ($subJoinColumn = $subJoinColumns.get($subIndex))##褰撳墠 join 瀛楁
+#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
+<script lang="ts" setup>
+import type { Rule } from 'antdv-next/es/form';
+import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
+
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { DICT_TYPE } from '@vben/constants';
+import { getDictOptions } from '@vben/hooks';
+import { Tinymce as RichTextarea } from '#/components/tinymce';
+import { ImageUpload, FileUpload } from "#/components/upload";
+import { message, Tabs, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'antdv-next';
+
+import { $t } from '#/locales';
+
+import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+const emit = defineEmits(['success']);
+const getTitle = computed(() => {
+ return formData.value?.id
+ ? $t('ui.actionTitle.edit', ['${subTable.classComment}'])
+ : $t('ui.actionTitle.create', ['${subTable.classComment}']);
+});
+
+const formRef = ref();
+const formData = ref<Partial<${simpleClassName}Api.${subSimpleClassName}>>({
+ #foreach ($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if ($column.htmlType == "checkbox")
+ $column.javaField: [],
+ #else
+ $column.javaField: undefined,
+ #end
+ #end
+ #end
+});
+const rules: Record<string, Rule[]> = {
+ #foreach ($column in $subColumns)
+ #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 鍒涘缓鎴栬�呮洿鏂版搷浣� && 瑕佹眰闈炵┖ && 闈炰富閿�
+ #set($comment=$column.columnComment)
+ $column.javaField: [{ required: true, message: '${comment}涓嶈兘涓虹┖', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
+ #end
+ #end
+};
+
+const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ await formRef.value?.validate();
+
+ modalApi.lock();
+ // 鎻愪氦琛ㄥ崟
+ const data = formData.value as ${simpleClassName}Api.${subSimpleClassName};
+ try {
+ await (formData.value?.id ? update${subSimpleClassName}(data) : create${subSimpleClassName}(data));
+ // 鍏抽棴骞舵彁绀�
+ await modalApi.close();
+ emit('success');
+ message.success({
+ content: $t('ui.actionMessage.operationSuccess'),
+ });
+ } finally {
+ modalApi.unlock();
+ }
+ },
+ async onOpenChange(isOpen: boolean) {
+ if (!isOpen) {
+ resetForm()
+ return;
+ }
+
+ // 鍔犺浇鏁版嵁
+ let data = modalApi.getData<${simpleClassName}Api.${subSimpleClassName}>();
+ if (!data) {
+ return;
+ }
+ if (data.id) {
+ modalApi.lock();
+ try {
+ data = await get${subSimpleClassName}(data.id);
+ } finally {
+ modalApi.unlock();
+ }
+ }
+ // 璁剧疆鍒� values
+ formData.value = data;
+ },
+});
+
+/** 閲嶇疆琛ㄥ崟 */
+function resetForm(){
+ formData.value = {
+ #foreach ($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if ($column.htmlType == "checkbox")
+ $column.javaField: [],
+ #else
+ $column.javaField: undefined,
+ #end
+ #end
+ #end
+ };
+ formRef.value?.resetFields();
+}
+</script>
+
+<template>
+ <Modal :title="getTitle">
+ <Form
+ ref="formRef"
+ :model="formData"
+ :rules="rules"
+ :label-col="{ span: 5 }"
+ :wrapper-col="{ span: 18 }"
+ >
+ #foreach($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($javaType = $column.javaType)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ #if ($column.htmlType == "input" && !$column.primaryKey)## 蹇界暐涓婚敭锛屼笉鐢ㄥ湪琛ㄥ崟閲�
+ <Form.Item label="${comment}" name="${javaField}">
+ <Input v-model:value="formData.${javaField}" placeholder="璇疯緭鍏�${comment}" />
+ </Form.Item>
+ #elseif($column.htmlType == "imageUpload")## 鍥剧墖涓婁紶
+ <Form.Item label="${comment}" name="${javaField}">
+ <ImageUpload v-model:value="formData.${javaField}" />
+ </Form.Item>
+ #elseif($column.htmlType == "fileUpload")## 鏂囦欢涓婁紶
+ <Form.Item label="${comment}" name="${javaField}">
+ <FileUpload v-model:value="formData.${javaField}" />
+ </Form.Item>
+ #elseif($column.htmlType == "editor")## 鏂囨湰缂栬緫鍣�
+ <Form.Item label="${comment}" name="${javaField}">
+ <RichTextarea v-model="formData.${javaField}" height="500px" />
+ </Form.Item>
+ #elseif($column.htmlType == "select")## 涓嬫媺妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <Select v-model:value="formData.${javaField}" placeholder="璇烽�夋嫨${comment}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <SelectOption
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </SelectOption>
+ #else##娌℃暟鎹瓧鍏�
+ <SelectOption label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ #end
+ </Select>
+ </Form.Item>
+ #elseif($column.htmlType == "checkbox")## 澶氶�夋
+ <Form.Item label="${comment}" name="${javaField}">
+ <CheckboxGroup v-model:value="formData.${javaField}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <Checkbox
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </Checkbox>
+ #else##娌℃暟鎹瓧鍏�
+ <Checkbox label="璇烽�夋嫨瀛楀吀鐢熸垚" />
+ #end
+ </CheckboxGroup>
+ </Form.Item>
+ #elseif($column.htmlType == "radio")## 鍗曢�夋
+ <Form.Item label="${comment}" name="${javaField}">
+ <RadioGroup v-model:value="formData.${javaField}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <Radio
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </Radio>
+ #else##娌℃暟鎹瓧鍏�
+ <Radio value="1">璇烽�夋嫨瀛楀吀鐢熸垚</Radio>
+ #end
+ </RadioGroup>
+ </Form.Item>
+ #elseif($column.htmlType == "datetime")## 鏃堕棿妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <DatePicker
+ v-model:value="formData.${javaField}"
+ valueFormat="x"
+ placeholder="閫夋嫨${comment}"
+ />
+ </Form.Item>
+ #elseif($column.htmlType == "textarea")## 鏂囨湰妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <TextArea v-model:value="formData.${javaField}" placeholder="璇疯緭鍏�${comment}" />
+ </Form.Item>
+ #end
+ #end
+ #end
+ </Form>
+ </Modal>
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_inner.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_inner.vue.vm
new file mode 100644
index 0000000..7f0ec3a
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_inner.vue.vm
@@ -0,0 +1,2 @@
+## 涓昏〃鐨� normal 鍜� inner 浣跨敤鐩稿悓鐨� form 琛ㄥ崟
+#parse("codegen/vue3_vben5_antd/general/views/modules/form_sub_normal.vue.vm")
\ No newline at end of file
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_normal.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_normal.vue.vm
new file mode 100644
index 0000000..e788e4c
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_normal.vue.vm
@@ -0,0 +1,347 @@
+#set ($subTable = $subTables.get($subIndex))##褰撳墠琛�
+#set ($subColumns = $subColumnsList.get($subIndex))##褰撳墠瀛楁鏁扮粍
+#set ($subJoinColumn = $subJoinColumns.get($subIndex))##褰撳墠 join 瀛楁
+#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
+#set ($subClassNameVar = $subClassNameVars.get($subIndex))
+#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##棣栧瓧姣嶅ぇ鍐�
+<script lang="ts" setup>
+import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
+
+import { computed, ref, h, onMounted, watch, nextTick } from 'vue';
+
+import { DICT_TYPE } from '@vben/constants';
+import { getDictOptions } from '@vben/hooks';
+
+import { message, Tabs, Form, Input, TextArea, Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'antdv-next';
+import { $t } from '#/locales';
+
+#if ($subTable.subJoinMany) ## 涓�瀵瑰
+import type { VxeTableInstance } from '#/adapter/vxe-table';
+import { Plus } from "@vben/icons";
+import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
+import { ImageUpload, FileUpload } from "#/components/upload";
+import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
+#else
+import type { Rule } from 'antdv-next/es/form';
+import { Tinymce as RichTextarea } from '#/components/tinymce';
+import { ImageUpload, FileUpload } from "#/components/upload";
+import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
+#end
+
+const props = defineProps<{
+ ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}锛堜富琛ㄧ殑鍏宠仈瀛楁锛�
+}>()
+
+#if ($subTable.subJoinMany) ## 涓�瀵瑰
+const list = ref<${simpleClassName}Api.${subSimpleClassName}[]>([]) // 鍒楄〃鐨勬暟鎹�
+const tableRef = ref<VxeTableInstance>();
+
+/** 娣诲姞${subTable.classComment} */
+async function handleAdd() {
+ await tableRef.value?.insertAt({} as ${simpleClassName}Api.${subSimpleClassName}, -1);
+}
+
+/** 鍒犻櫎${subTable.classComment} */
+async function handleDelete(row: ${simpleClassName}Api.${subSimpleClassName}) {
+ await tableRef.value?.remove(row);
+}
+
+/** 鎻愪緵鑾峰彇琛ㄦ牸鏁版嵁鐨勬柟娉曚緵鐖剁粍浠惰皟鐢� */
+defineExpose({
+ getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => {
+ const data = list.value as ${simpleClassName}Api.${subSimpleClassName}[];
+ const removeRecords = tableRef.value?.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
+ const insertRecords = tableRef.value?.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
+ return [
+ ...data.filter(
+ (row) => !removeRecords.some((removed) => removed.id === row.id),
+ ),
+ ...insertRecords.map((row: any) => ({ ...row, id: undefined })),
+ ];
+ },
+});
+
+/** 鐩戝惉涓昏〃鐨勫叧鑱斿瓧娈电殑鍙樺寲锛屽姞杞藉搴旂殑瀛愯〃鏁版嵁 */
+watch(
+ () => props.${subJoinColumn.javaField},
+ async (val) => {
+ if (!val) {
+ return;
+ }
+ list.value = await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
+ },
+ { immediate: true },
+);
+#else
+const formRef = ref();
+const formData = ref<Partial<${simpleClassName}Api.${subSimpleClassName}>>({
+ #foreach ($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if ($column.htmlType == "checkbox")
+ $column.javaField: [],
+ #else
+ $column.javaField: undefined,
+ #end
+ #end
+ #end
+});
+const rules: Record<string, Rule[]> = {
+ #foreach ($column in $subColumns)
+ #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 鍒涘缓鎴栬�呮洿鏂版搷浣� && 瑕佹眰闈炵┖ && 闈炰富閿�
+ #set($comment=$column.columnComment)
+ $column.javaField: [{ required: true, message: '${comment}涓嶈兘涓虹┖', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
+ #end
+ #end
+};
+/** 鏆撮湶鍑鸿〃鍗曟牎楠屾柟娉曞拰琛ㄥ崟鍊艰幏鍙栨柟娉� */
+defineExpose({
+ validate: async () => await formRef.value?.validate(),
+ getValues: ()=> formData.value,
+});
+
+/** 鐩戝惉涓昏〃鐨勫叧鑱斿瓧娈电殑鍙樺寲锛屽姞杞藉搴旂殑瀛愯〃鏁版嵁 */
+watch(
+ () => props.${subJoinColumn.javaField},
+ async (val) => {
+ if (!val) {
+ return;
+ }
+ await nextTick();
+ formData.value = await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
+ },
+ { immediate: true },
+);
+#end
+</script>
+
+<template>
+#if ($subTable.subJoinMany) ## 涓�瀵瑰
+ <VxeTable ref="tableRef" :data="list" show-overflow class="mx-4">
+ #foreach($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #set ($comment = $column.columnComment)
+ #set ($javaField = $column.javaField)
+ #set ($javaType = $column.javaType)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ #if ( $column.id == $subJoinColumn.id) ## 鐗规畩锛氬拷鐣ヤ富瀛愯〃鐨� join 瀛楁锛屼笉鐢ㄥ~鍐�
+ #elseif ($column.htmlType == "input" && !$column.primaryKey)## 蹇界暐涓婚敭锛屼笉鐢ㄥ湪琛ㄥ崟閲�
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{ row }">
+ <Input v-model:value="row.${javaField}" />
+ </template>
+ </VxeColumn>
+ #elseif($column.htmlType == "imageUpload")## 鍥剧墖涓婁紶
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{ row }">
+ <ImageUpload v-model:value="row.${javaField}" />
+ </template>
+ </VxeColumn>
+ #elseif($column.htmlType == "fileUpload")## 鏂囦欢涓婁紶
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{ row }">
+ <FileUpload v-model:value="row.${javaField}" />
+ </template>
+ </VxeColumn>
+ #elseif($column.htmlType == "select")## 涓嬫媺妗�
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{ row }">
+ <Select v-model:value="row.${javaField}" placeholder="璇烽�夋嫨${comment}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <SelectOption
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </SelectOption>
+ #else##娌℃暟鎹瓧鍏�
+ <SelectOption label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ #end
+ </Select>
+ </template>
+ </VxeColumn>
+ #elseif($column.htmlType == "checkbox")## 澶氶�夋
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{ row }">
+ <CheckboxGroup v-model:value="row.${javaField}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <Checkbox
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </Checkbox>
+ #else##娌℃暟鎹瓧鍏�
+ <Checkbox label="璇烽�夋嫨瀛楀吀鐢熸垚" />
+ #end
+ </CheckboxGroup>
+ </template>
+ </VxeColumn>
+ #elseif($column.htmlType == "radio")## 鍗曢�夋
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{ row }">
+ <RadioGroup v-model:value="row.${javaField}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <Radio
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </Radio>
+ #else##娌℃暟鎹瓧鍏�
+ <Radio value="1">璇烽�夋嫨瀛楀吀鐢熸垚</Radio>
+ #end
+ </RadioGroup>
+ </template>
+ </VxeColumn>
+ #elseif($column.htmlType == "datetime")## 鏃堕棿妗�
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{ row }">
+ <DatePicker
+ v-model:value="row.${javaField}"
+ :showTime="true"
+ format="YYYY-MM-DD HH:mm:ss"
+ valueFormat='x'
+ />
+ </template>
+ </VxeColumn>
+ #elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 鏂囨湰妗�
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{ row }">
+ <TextArea v-model:value="row.${javaField}" />
+ </template>
+ </VxeColumn>
+ #end
+ #end
+ #end
+ <VxeColumn field="operation" title="鎿嶄綔" align="center">
+ <template #default="{ row }">
+ <Button
+ size="small"
+ type="link"
+ danger
+ @click="handleDelete(row)"
+ v-access:code="['${permissionPrefix}:delete']"
+ >
+ {{ $t('ui.actionTitle.delete') }}
+ </Button>
+ </template>
+ </VxeColumn>
+ </VxeTable>
+ <div class="flex justify-center mt-4">
+ <Button :icon="h(Plus)" type="primary" ghost @click="handleAdd" v-access:code="['${permissionPrefix}:create']">
+ {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
+ </Button>
+ </div>
+#else
+ <Form
+ ref="formRef"
+ class="mx-4"
+ :model="formData"
+ :rules="rules"
+ :label-col="{ span: 5 }"
+ :wrapper-col="{ span: 18 }"
+ >
+ #foreach($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($javaType = $column.javaType)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ #if ($column.htmlType == "input" && !$column.primaryKey)## 蹇界暐涓婚敭锛屼笉鐢ㄥ湪琛ㄥ崟閲�
+ <Form.Item label="${comment}" name="${javaField}">
+ <Input v-model:value="formData.${javaField}" placeholder="璇疯緭鍏�${comment}" />
+ </Form.Item>
+ #elseif($column.htmlType == "imageUpload")## 鍥剧墖涓婁紶
+ <Form.Item label="${comment}" name="${javaField}">
+ <ImageUpload v-model:value="formData.${javaField}" />
+ </Form.Item>
+ #elseif($column.htmlType == "fileUpload")## 鏂囦欢涓婁紶
+ <Form.Item label="${comment}" name="${javaField}">
+ <FileUpload v-model:value="formData.${javaField}" />
+ </Form.Item>
+ #elseif($column.htmlType == "editor")## 鏂囨湰缂栬緫鍣�
+ <Form.Item label="${comment}" name="${javaField}">
+ <RichTextarea v-model="formData.${javaField}" height="500px" />
+ </Form.Item>
+ #elseif($column.htmlType == "select")## 涓嬫媺妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <Select v-model:value="formData.${javaField}" placeholder="璇烽�夋嫨${comment}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <SelectOption
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </SelectOption>
+ #else##娌℃暟鎹瓧鍏�
+ <SelectOption label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ #end
+ </Select>
+ </Form.Item>
+ #elseif($column.htmlType == "checkbox")## 澶氶�夋
+ <Form.Item label="${comment}" name="${javaField}">
+ <CheckboxGroup v-model:value="formData.${javaField}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <Checkbox
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </Checkbox>
+ #else##娌℃暟鎹瓧鍏�
+ <Checkbox label="璇烽�夋嫨瀛楀吀鐢熸垚" />
+ #end
+ </CheckboxGroup>
+ </Form.Item>
+ #elseif($column.htmlType == "radio")## 鍗曢�夋
+ <Form.Item label="${comment}" name="${javaField}">
+ <RadioGroup v-model:value="formData.${javaField}">
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ <Radio
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </Radio>
+ #else##娌℃暟鎹瓧鍏�
+ <Radio value="1">璇烽�夋嫨瀛楀吀鐢熸垚</Radio>
+ #end
+ </RadioGroup>
+ </Form.Item>
+ #elseif($column.htmlType == "datetime")## 鏃堕棿妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <DatePicker
+ v-model:value="formData.${javaField}"
+ valueFormat="x"
+ placeholder="閫夋嫨${comment}"
+ />
+ </Form.Item>
+ #elseif($column.htmlType == "textarea")## 鏂囨湰妗�
+ <Form.Item label="${comment}" name="${javaField}">
+ <TextArea v-model:value="formData.${javaField}" placeholder="璇疯緭鍏�${comment}" />
+ </Form.Item>
+ #end
+ #end
+ #end
+ </Form>
+#end
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_erp.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_erp.vue.vm
new file mode 100644
index 0000000..239aa26
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_erp.vue.vm
@@ -0,0 +1,424 @@
+#set ($subTable = $subTables.get($subIndex))##褰撳墠琛�
+#set ($subColumns = $subColumnsList.get($subIndex))##褰撳墠瀛楁鏁扮粍
+#set ($subJoinColumn = $subJoinColumns.get($subIndex))##褰撳墠 join 瀛楁
+#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
+#set ($subJoinColumn = $subJoinColumns.get($subIndex))##褰撳墠 join 瀛楁
+#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex))
+#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##棣栧瓧姣嶅ぇ鍐�
+<script lang="ts" setup>
+import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
+import type { VxeTableInstance } from '#/adapter/vxe-table';
+
+import { reactive, ref, h, nextTick, watch, onMounted } from 'vue';
+
+import { DICT_TYPE } from '@vben/constants';
+import { getDictOptions } from '@vben/hooks';
+
+import { DictTag } from '#/components/dict-tag';
+import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
+import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
+import { formatDateTime } from '@vben/utils';
+
+#if ($table.templateType == 11) ## erp
+import { useVbenModal } from '@vben/common-ui';
+import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table';
+import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
+import { Tinymce as RichTextarea } from '#/components/tinymce';
+import { ImageUpload, FileUpload } from "#/components/upload";
+import { message, Button, Card, Tabs, Pagination, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, RangePicker, DatePicker, TreeSelect } from 'antdv-next';
+import { Plus, Trash2 } from '@vben/icons';
+import { $t } from '#/locales';
+#end
+
+#if ($table.templateType == 11) ## erp
+import { delete${subSimpleClassName},#if ($deleteBatchEnable) delete${subSimpleClassName}List,#end get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${table.businessName}';
+import { isEmpty, cloneDeep } from '@vben/utils';
+#else
+#if ($subTable.subJoinMany) ## 涓�瀵瑰
+import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
+#else
+import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
+#end
+#end
+
+const props = defineProps<{
+ ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}锛堜富琛ㄧ殑鍏宠仈瀛楁锛�
+}>()
+
+#if ($table.templateType == 11) ## erp
+const [FormModal, formModalApi] = useVbenModal({
+ connectedComponent: ${subSimpleClassName}Form,
+ destroyOnClose: true,
+});
+
+/** 鍒涘缓${subTable.classComment} */
+function handleCreate() {
+ if (!props.${subJoinColumn.javaField}){
+ message.warning("璇峰厛閫夋嫨涓�涓�${table.classComment}!")
+ return
+ }
+ formModalApi.setData({${subJoinColumn.javaField}: props.${subJoinColumn.javaField}}).open();
+}
+
+/** 缂栬緫${subTable.classComment} */
+function handleEdit(row: ${simpleClassName}Api.${subSimpleClassName}) {
+ formModalApi.setData(row).open();
+}
+
+/** 鍒犻櫎${subTable.classComment} */
+async function handleDelete(row: ${simpleClassName}Api.${subSimpleClassName}) {
+ const hideLoading = message.loading({
+ content: $t('ui.actionMessage.deleting', [row.id]),
+ duration: 0,
+ });
+ try {
+ await delete${subSimpleClassName}(row.id!);
+ message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
+ await getList();
+ } finally {
+ hideLoading();
+ }
+}
+
+#if ($deleteBatchEnable)
+/** 鎵归噺鍒犻櫎${subTable.classComment} */
+async function handleDeleteBatch() {
+ const hideLoading = message.loading({
+ content: $t('ui.actionMessage.deleting'),
+ duration: 0,
+ });
+ try {
+ await delete${subSimpleClassName}List(checkedIds.value);
+ checkedIds.value = [];
+ message.success($t('ui.actionMessage.deleteSuccess'));
+ await getList();
+ } finally {
+ hideLoading();
+ }
+}
+
+const checkedIds = ref<number[]>([])
+function handleRowCheckboxChange({
+ records,
+}: {
+ records: ${simpleClassName}Api.${subSimpleClassName}[];
+}) {
+ checkedIds.value = records.map((item) => item.id!);
+}
+#end
+#end
+
+const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑
+const list = ref<${simpleClassName}Api.${subSimpleClassName}[]>([]) // 鍒楄〃鐨勬暟鎹�
+#if ($table.templateType == 11) ## erp
+const total = ref(0) // 鍒楄〃鐨勬�婚〉鏁�
+#end
+#if ($table.templateType == 11) ## erp
+const queryFormRef = ref() // 鎼滅储鐨勮〃鍗�
+const queryParams = reactive({
+ pageNo: 1,
+ pageSize: 10,
+ #foreach ($column in $subColumns)
+ #if ($column.listOperation)
+ #if ($column.listOperationCondition != 'BETWEEN')
+ $column.javaField: undefined,
+ #end
+ #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
+ $column.javaField: undefined,
+ #end
+ #end
+ #end
+})
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery() {
+ queryParams.pageNo = 1
+ getList()
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function resetQuery() {
+ queryFormRef.value.resetFields()
+ handleQuery()
+}
+#end
+ /** 鏌ヨ鍒楄〃 */
+async function getList() {
+ loading.value = true
+ try {
+ if (!props.${subJoinColumn.javaField}){
+ return []
+ }
+ ## 鐗规畩锛氭爲琛ㄤ笓灞為�昏緫锛堟爲涓嶉渶瑕佸垎椤垫帴鍙o級
+ #if ($table.templateType == 11) ## erp
+ const params = cloneDeep(queryParams) as any;
+ #foreach ($column in $columns)
+ #if ($column.listOperation)
+ #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
+ if (params.${column.javaField} && Array.isArray(params.${column.javaField})) {
+ params.${column.javaField} = (params.${column.javaField} as string[]).join(',');
+ }
+ #end
+ #end
+ #end
+ params.${subJoinColumn.javaField} = props.${subJoinColumn.javaField};
+ const data = await get${subSimpleClassName}Page(params)
+ list.value = data.list
+ total.value = data.total
+ #else
+ #if ($subTable.subJoinMany) ## 涓�瀵瑰
+ list.value = await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
+ #else
+ list.value = [await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)];
+ #end
+ #end
+ } finally {
+ loading.value = false
+ }
+}
+
+/** 鐩戝惉涓昏〃鐨勫叧鑱斿瓧娈电殑鍙樺寲锛屽姞杞藉搴旂殑瀛愯〃鏁版嵁 */
+watch(
+ () => props.${subJoinColumn.javaField},
+ async (val) => {
+ if (!val) {
+ return;
+ }
+ await nextTick();
+ await getList()
+ },
+ { immediate: true },
+);
+
+#if ($table.templateType == 11) ## erp
+/** 鍒濆鍖� */
+const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
+onMounted(() => {
+ getList();
+});
+#end
+</script>
+
+<template>
+ #if ($table.templateType == 11) ## erp
+ <FormModal @success="getList" />
+ <div class="h-[600px]">
+ <Card v-if="!hiddenSearchBar" class="mb-4">
+ <!-- 鎼滅储宸ヤ綔鏍� -->
+ <Form
+ :model="queryParams"
+ ref="queryFormRef"
+ layout="inline"
+ >
+ #foreach($column in $subColumns)
+ #if ($column.listOperation)
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($javaType = $column.javaType)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ #if ($column.htmlType == "input")
+ <Form.Item label="${comment}" name="${javaField}">
+ <Input
+ v-model:value="queryParams.${javaField}"
+ placeholder="璇疯緭鍏�${comment}"
+ allowClear
+ @pressEnter="handleQuery"
+ class="w-full"
+ />
+ </Form.Item>
+ #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")
+ <Form.Item label="${comment}" name="${javaField}">
+ <Select
+ v-model:value="queryParams.${javaField}"
+ placeholder="璇烽�夋嫨${comment}"
+ allowClear
+ class="w-full"
+ >
+ #if ("" != $dictType)## 璁剧疆浜� dictType 鏁版嵁瀛楀吀鐨勬儏鍐�
+ <SelectOption
+ v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </SelectOption>
+ #else## 鏈缃� dictType 鏁版嵁瀛楀吀鐨勬儏鍐�
+ <SelectOption label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ #end
+ </Select>
+ </Form.Item>
+ #elseif($column.htmlType == "datetime")
+ #if ($column.listOperationCondition != "BETWEEN")## 闈炶寖鍥�
+ <Form.Item label="${comment}" name="${javaField}">
+ <DatePicker
+ v-model:value="queryParams.${javaField}"
+ valueFormat="YYYY-MM-DD"
+ placeholder="閫夋嫨${comment}"
+ allowClear
+ class="w-full"
+ />
+ </Form.Item>
+ #else## 鑼冨洿
+ <Form.Item label="${comment}" name="${javaField}">
+ <RangePicker
+ v-model:value="queryParams.${javaField}"
+ v-bind="getRangePickerDefaultProps()"
+ class="w-full"
+ />
+ </Form.Item>
+ #end
+ #end
+ #end
+ #end
+ <Form.Item>
+ <Button class="ml-2" @click="resetQuery"> 閲嶇疆 </Button>
+ <Button class="ml-2" @click="handleQuery" type="primary">
+ 鎼滅储
+ </Button>
+ </Form.Item>
+ </Form>
+ </Card>
+
+ <!-- 鍒楄〃 -->
+ <Card title="${table.classComment}">
+ <template #extra>
+ <VbenVxeTableToolbar
+ ref="tableToolbarRef"
+ v-model:hidden-search="hiddenSearchBar"
+ >
+ <Button
+ class="ml-2"
+ :icon="h(Plus)"
+ type="primary"
+ @click="handleCreate"
+ v-access:code="['${permissionPrefix}:create']"
+ >
+ {{ $t('ui.actionTitle.create', ['${table.classComment}']) }}
+ </Button>
+ #if ($deleteBatchEnable)
+ <Button
+ :icon="h(Trash2)"
+ type="primary"
+ danger
+ class="ml-2"
+ :disabled="isEmpty(checkedIds)"
+ @click="handleDeleteBatch"
+ v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:delete']"
+ >
+ 鎵归噺鍒犻櫎
+ </Button>
+ #end
+ </VbenVxeTableToolbar>
+ </template>
+ <VxeTable
+ ref="tableRef"
+ :data="list"
+ show-overflow
+ :loading="loading"
+ #if ($deleteBatchEnable)
+ @checkboxAll="handleRowCheckboxChange"
+ @checkboxChange="handleRowCheckboxChange"
+ #end
+ >
+ #if ($deleteBatchEnable)
+ <VxeColumn type="checkbox" width="40" />
+ #end
+ #foreach($column in $subColumns)
+ #if ($column.listOperationResult)
+ #set ($dictType=$column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($comment=$column.columnComment)
+ #if ($column.javaType == "LocalDateTime")## 鏃堕棿绫诲瀷
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{row}">
+ {{formatDateTime(row.${javaField})}}
+ </template>
+ </VxeColumn>
+ #elseif($column.dictType && "" != $column.dictType)## 鏁版嵁瀛楀吀
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{row}">
+ <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
+ </template>
+ </VxeColumn>
+ #elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField)
+ <VxeColumn field="${javaField}" title="${comment}" align="center" tree-node/>
+ #else
+ <VxeColumn field="${javaField}" title="${comment}" align="center" />
+ #end
+ #end
+ #end
+ <VxeColumn field="operation" title="鎿嶄綔" align="center">
+ <template #default="{row}">
+ <Button
+ size="small"
+ type="link"
+ @click="handleEdit(row)"
+ v-access:code="['${permissionPrefix}:update']"
+ >
+ {{ $t('ui.actionTitle.edit') }}
+ </Button>
+ <Button
+ size="small"
+ type="link"
+ danger
+ class="ml-2"
+ @click="handleDelete(row)"
+ v-access:code="['${permissionPrefix}:delete']"
+ >
+ {{ $t('ui.actionTitle.delete') }}
+ </Button>
+ </template>
+ </VxeColumn>
+ </VxeTable>
+ <!-- 鍒嗛〉 -->
+ <div class="mt-2 flex justify-end">
+ <Pagination
+ :total="total"
+ v-model:current="queryParams.pageNo"
+ v-model:page-size="queryParams.pageSize"
+ show-size-changer
+ @change="getList"
+ />
+ </div>
+ </Card>
+ </div>
+ #else
+ <Card title="${subTable.classComment}鍒楄〃">
+ <VxeTable
+ :data="list"
+ show-overflow
+ :loading="loading"
+ >
+ #foreach($column in $subColumns)
+ #if ($column.listOperationResult)
+ #set ($dictType=$column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($comment=$column.columnComment)
+ #if ($column.javaType == "LocalDateTime")## 鏃堕棿绫诲瀷
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{row}">
+ {{formatDateTime(row.${javaField})}}
+ </template>
+ </VxeColumn>
+ #elseif($column.dictType && "" != $column.dictType)## 鏁版嵁瀛楀吀
+ <VxeColumn field="${javaField}" title="${comment}" align="center">
+ <template #default="{row}">
+ <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
+ </template>
+ </VxeColumn>
+ #else
+ <VxeColumn field="${javaField}" title="${comment}" align="center" />
+ #end
+ #end
+ #end
+ </VxeTable>
+ </Card>
+ #end
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_inner.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_inner.vue.vm
new file mode 100644
index 0000000..d46037b
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_inner.vue.vm
@@ -0,0 +1,4 @@
+## 瀛愯〃鐨� erp 鍜� inner 浣跨敤鐩镐技鐨� list 鍒楄〃锛屽樊寮備富瑕佷袱鐐癸細
+## 1锛塱nner 浣跨敤 list 涓嶅垎椤碉紝erp 浣跨敤 page 鍒嗛〉
+## 2锛塭rp 鏀寔鍗曚釜瀛愯〃鐨勬柊澧炪�佷慨鏀广�佸垹闄わ紝inner 涓嶆敮鎸�
+#parse("codegen/vue3_vben5_antd/general/views/modules/list_sub_erp.vue.vm")
\ No newline at end of file
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/api/api.ts.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/api/api.ts.vm
new file mode 100644
index 0000000..5419e52
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/api/api.ts.vm
@@ -0,0 +1 @@
+#parse("codegen/vue3_vben5_ele/schema/api/api.ts.vm")
\ No newline at end of file
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/data.ts.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/data.ts.vm
new file mode 100644
index 0000000..34883d4
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/data.ts.vm
@@ -0,0 +1,616 @@
+#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
+import type { VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+import { DICT_TYPE } from '@vben/constants';
+import { getDictOptions } from '@vben/hooks';
+#if(${table.templateType} == 2)## 鏍戣〃闇�瑕佸鍏ヨ繖浜�
+import { get${simpleClassName}List } from '#/api/${table.moduleName}/${table.businessName}';
+import { handleTree } from '@vben/utils';
+#end
+
+import { getRangePickerDefaultProps } from '#/utils';
+
+/** 鏂板/淇敼鐨勮〃鍗� */
+export function useFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'id',
+ component: 'Input',
+ dependencies: {
+ triggerFields: [''],
+ show: () => false,
+ },
+ },
+#if(${table.templateType} == 2)## 鏍戣〃鐗规湁瀛楁锛氫笂绾�
+ {
+ fieldName: '${treeParentColumn.javaField}',
+ label: '涓婄骇${table.classComment}',
+ component: 'ApiTreeSelect',
+ componentProps: {
+ allowClear: true,
+ api: async () => {
+ const data = await get${simpleClassName}List({});
+ data.unshift({
+ id: 0,
+ ${treeNameColumn.javaField}: '椤剁骇${table.classComment}',
+ });
+ return handleTree(data);
+ },
+ labelField: '${treeNameColumn.javaField}',
+ valueField: 'id',
+ childrenField: 'children',
+ placeholder: '璇烽�夋嫨涓婄骇${table.classComment}',
+ treeDefaultExpandAll: true,
+ },
+ rules: 'selectRequired',
+ },
+#end
+#foreach($column in $columns)
+#if ($column.createOperation || $column.updateOperation)
+#if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 鏍戣〃涓凡缁忔坊鍔犱簡鐖禝D瀛楁锛岃繖閲屾帓闄�
+ #set ($dictType = $column.dictType)
+ #set ($javaType = $column.javaType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ {
+ fieldName: '${javaField}',
+ label: '${comment}',
+ #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 鍒涘缓鎴栬�呮洿鏂版搷浣� && 瑕佹眰闈炵┖ && 闈炰富閿�
+ rules: 'required',
+ #end
+ #if ($column.htmlType == "input")
+ component: 'Input',
+ componentProps: {
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #elseif($column.htmlType == "imageUpload")## 鍥剧墖涓婁紶
+ component: 'ImageUpload',
+ #elseif($column.htmlType == "fileUpload")## 鏂囦欢涓婁紶
+ component: 'FileUpload',
+ #elseif($column.htmlType == "editor")## 鏂囨湰缂栬緫鍣�
+ component: 'RichTextarea',
+ #elseif($column.htmlType == "select")## 涓嬫媺妗�
+ component: 'Select',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ placeholder: '璇烽�夋嫨${comment}',
+ },
+ #elseif($column.htmlType == "checkbox")## 澶氶�夋
+ component: 'Checkbox',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ },
+ #elseif($column.htmlType == "radio")## 鍗曢�夋
+ component: 'RadioGroup',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ buttonStyle: 'solid',
+ optionType: 'button',
+ },
+ #elseif($column.htmlType == "datetime")## 鏃堕棿妗�
+ component: 'DatePicker',
+ componentProps: {
+ showTime: true,
+ format: 'YYYY-MM-DD HH:mm:ss',
+ valueFormat: 'x',
+ },
+ #elseif($column.htmlType == "textarea")## 鏂囨湰鍩�
+ component: 'TextArea',
+ componentProps: {
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #elseif($column.htmlType == "inputNumber")## 鏁板瓧杈撳叆妗�
+ component: 'InputNumber',
+ componentProps: {
+ min: 0,
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #end
+ },
+#end
+#end
+#end
+ ];
+}
+
+#if ($importEnable)
+/** 瀵煎叆鐨勮〃鍗� */
+export function useImportFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'file',
+ label: '${table.classComment}鏁版嵁',
+ component: 'Upload',
+ rules: 'required',
+ help: '浠呭厑璁稿鍏� xls銆亁lsx 鏍煎紡鏂囦欢',
+ },
+ ];
+}
+
+#end
+/** 鍒楄〃鐨勬悳绱㈣〃鍗� */
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+#foreach($column in $columns)
+#if ($column.listOperation)
+ #set ($dictType = $column.dictType)
+ #set ($javaType = $column.javaType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ {
+ fieldName: '${javaField}',
+ label: '${comment}',
+ #if ($column.htmlType == "input" || $column.htmlType == "textarea" || $column.htmlType == "editor")
+ component: 'Input',
+ componentProps: {
+ allowClear: true,
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
+ component: 'Select',
+ componentProps: {
+ allowClear: true,
+ #if ("" != $dictType)## 璁剧疆浜� dictType 鏁版嵁瀛楀吀鐨勬儏鍐�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else## 鏈缃� dictType 鏁版嵁瀛楀吀鐨勬儏鍐�
+ options: [],
+ #end
+ placeholder: '璇烽�夋嫨${comment}',
+ },
+ #elseif($column.htmlType == "datetime")
+ component: 'RangePicker',
+ componentProps: {
+ ...getRangePickerDefaultProps(),
+ allowClear: true,
+ },
+ #end
+ },
+#end
+#end
+ ];
+}
+
+/** 鍒楄〃鐨勫瓧娈� */
+export function useGridColumns(): VxeTableGridOptions<${apiName}.${simpleClassName}>['columns'] {
+ return [
+#if ($table.templateType != 2 && $deleteBatchEnable)
+ { type: 'checkbox', width: 40 },
+#end
+#if ($table.templateType == 12) ## 鍐呭祵鎯呭喌
+ { type: 'expand', width: 80, slots: { content: 'expand_content' } },
+#end
+#foreach($column in $columns)
+#if ($column.listOperationResult)
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ {
+ field: '${javaField}',
+ title: '${comment}',
+ minWidth: 120,
+ #if ($column.javaType == "LocalDateTime")## 鏃堕棿绫诲瀷
+ formatter: 'formatDateTime',
+ #elseif("" != $dictType)## 鏁版嵁瀛楀吀
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.$dictType.toUpperCase() },
+ },
+ #end
+ #if (${table.templateType} == 2 && $column.id == $treeNameColumn.id)## 鏍戣〃鐗规湁:鏍囪鏍戣妭鐐瑰垪
+ treeNode: true,
+ #end
+ },
+#end
+#end
+ {
+ title: '鎿嶄綔',
+ width: 200,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
+
+## 鏍囧噯妯″紡鍜屽唴宓屾ā寮忔椂锛屼富瀛愬叧绯讳竴瀵逛竴鍒欑敓鎴愯〃鍗晄chema,涓�瀵瑰鍒欑敓鎴愬垪琛╯chema锛堝唴宓屾ā寮忔椂琛ㄥ崟schema涔熻鐢熸垚锛夈�俥rp 妯″紡鏃堕兘鐢熸垚
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subColumns = $subColumnsList.get($index))##褰撳墠瀛楁鏁扮粍
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subJoinColumn = $subJoinColumns.get($index))##褰撳墠 join 瀛楁
+ #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
+// ==================== 瀛愯〃锛�$subTable.classComment锛� ====================
+
+#if ($table.templateType == 11) ## erp 鎯呭喌
+/** 鏂板/淇敼鐨勮〃鍗� */
+export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'id',
+ component: 'Input',
+ dependencies: {
+ triggerFields: [''],
+ show: () => false,
+ },
+ },
+ #foreach($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 鏍戣〃涓凡缁忔坊鍔犱簡鐖禝D瀛楁锛岃繖閲屾帓闄�
+ #set ($dictType = $column.dictType)
+ #set ($javaType = $column.javaType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ #if ( $column.id == $subJoinColumn.id) ## 鐗规畩锛氬拷鐣ヤ富瀛愯〃鐨� join 瀛楁锛屼笉鐢ㄥ~鍐�
+ #else
+ {
+ fieldName: '${javaField}',
+ label: '${comment}',
+ #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 鍒涘缓鎴栬�呮洿鏂版搷浣� && 瑕佹眰闈炵┖ && 闈炰富閿�
+ rules: 'required',
+ #end
+ #if ($column.htmlType == "input")
+ component: 'Input',
+ componentProps: {
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #elseif($column.htmlType == "imageUpload")## 鍥剧墖涓婁紶
+ component: 'ImageUpload',
+ #elseif($column.htmlType == "fileUpload")## 鏂囦欢涓婁紶
+ component: 'FileUpload',
+ #elseif($column.htmlType == "editor")## 鏂囨湰缂栬緫鍣�
+ component: 'RichTextarea',
+ #elseif($column.htmlType == "select")## 涓嬫媺妗�
+ component: 'Select',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ placeholder: '璇烽�夋嫨${comment}',
+ },
+ #elseif($column.htmlType == "checkbox")## 澶氶�夋
+ component: 'Checkbox',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ },
+ #elseif($column.htmlType == "radio")## 鍗曢�夋
+ component: 'RadioGroup',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ buttonStyle: 'solid',
+ optionType: 'button',
+ },
+ #elseif($column.htmlType == "datetime")## 鏃堕棿妗�
+ component: 'DatePicker',
+ componentProps: {
+ showTime: true,
+ format: 'YYYY-MM-DD HH:mm:ss',
+ valueFormat: 'x',
+ },
+ #elseif($column.htmlType == "textarea")## 鏂囨湰鍩�
+ component: 'TextArea',
+ componentProps: {
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #elseif($column.htmlType == "inputNumber")## 鏁板瓧杈撳叆妗�
+ component: 'InputNumber',
+ componentProps: {
+ min: 0,
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #end
+ },
+ #end
+ #end
+ #end
+ #end
+ ];
+}
+
+/** 鍒楄〃鐨勬悳绱㈣〃鍗� */
+export function use${subSimpleClassName}GridFormSchema(): VbenFormSchema[] {
+ return [
+ #foreach($column in $subColumns)
+ #if ($column.listOperation)
+ #set ($dictType = $column.dictType)
+ #set ($javaType = $column.javaType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ {
+ fieldName: '${javaField}',
+ label: '${comment}',
+ #if ($column.htmlType == "input" || $column.htmlType == "textarea" || $column.htmlType == "editor")
+ component: 'Input',
+ componentProps: {
+ allowClear: true,
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
+ component: 'Select',
+ componentProps: {
+ allowClear: true,
+ #if ("" != $dictType)## 璁剧疆浜� dictType 鏁版嵁瀛楀吀鐨勬儏鍐�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else## 鏈缃� dictType 鏁版嵁瀛楀吀鐨勬儏鍐�
+ options: [],
+ #end
+ placeholder: '璇烽�夋嫨${comment}',
+ },
+ #elseif($column.htmlType == "datetime")
+ component: 'RangePicker',
+ componentProps: {
+ ...getRangePickerDefaultProps(),
+ allowClear: true,
+ },
+ #end
+ },
+ #end
+ #end
+ ];
+}
+
+/** 鍒楄〃鐨勫瓧娈� */
+export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${apiName}.${subSimpleClassName}>['columns'] {
+ return [
+ #if ($table.templateType != 2 && $deleteBatchEnable)
+ { type: 'checkbox', width: 40 },
+ #end
+ #foreach($column in $subColumns)
+ #if ($column.listOperationResult)
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ {
+ field: '${javaField}',
+ title: '${comment}',
+ minWidth: 120,
+ #if ($column.javaType == "LocalDateTime")## 鏃堕棿绫诲瀷
+ formatter: 'formatDateTime',
+ #elseif("" != $dictType)## 鏁版嵁瀛楀吀
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.$dictType.toUpperCase() },
+ },
+ #end
+ },
+ #end
+ #end
+ {
+ title: '鎿嶄綔',
+ width: 200,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
+
+#else
+ #if ($subTable.subJoinMany) ## 涓�瀵瑰
+ /** 鏂板/淇敼鍒楄〃鐨勫瓧娈� */
+ export function use${subSimpleClassName}GridEditColumns(): VxeTableGridOptions<${apiName}.${subSimpleClassName}>['columns'] {
+ return [
+ #foreach($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if (!$column.primaryKey && $column.listOperationResult && $column.id != $subJoinColumn.id) ## 鐗规畩锛氬拷鐣ヤ富瀛愯〃鐨� join 瀛楁锛屼笉鐢ㄥ~鍐�
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ {
+ field: '${javaField}',
+ title: '${comment}',
+ minWidth: 120,
+ slots: { default: '${javaField}' },
+ #if ($column.htmlType == "select" || $column.htmlType == "checkbox" || $column.htmlType == "radio")
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ params: {
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ },
+ #else
+ params: {
+ options: [],
+ },
+ #end
+ #end
+ },
+ #end
+ #end
+ #end
+ {
+ title: '鎿嶄綔',
+ width: 200,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+ }
+
+ #else
+ /** 鏂板/淇敼鐨勮〃鍗� */
+ export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'id',
+ component: 'Input',
+ dependencies: {
+ triggerFields: [''],
+ show: () => false,
+ },
+ },
+ #foreach($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 鏍戣〃涓凡缁忔坊鍔犱簡鐖禝D瀛楁锛岃繖閲屾帓闄�
+ #set ($dictType = $column.dictType)
+ #set ($javaType = $column.javaType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+ #set ($dictMethod = "number")
+ #elseif ($javaType == "String")
+ #set ($dictMethod = "string")
+ #elseif ($javaType == "Boolean")
+ #set ($dictMethod = "boolean")
+ #end
+ #if ( $column.id == $subJoinColumn.id) ## 鐗规畩锛氬拷鐣ヤ富瀛愯〃鐨� join 瀛楁锛屼笉鐢ㄥ~鍐�
+ #else
+ {
+ fieldName: '${javaField}',
+ label: '${comment}',
+ #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 鍒涘缓鎴栬�呮洿鏂版搷浣� && 瑕佹眰闈炵┖ && 闈炰富閿�
+ rules: 'required',
+ #end
+ #if ($column.htmlType == "input")
+ component: 'Input',
+ componentProps: {
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #elseif($column.htmlType == "imageUpload")## 鍥剧墖涓婁紶
+ component: 'ImageUpload',
+ #elseif($column.htmlType == "fileUpload")## 鏂囦欢涓婁紶
+ component: 'FileUpload',
+ #elseif($column.htmlType == "editor")## 鏂囨湰缂栬緫鍣�
+ component: 'RichTextarea',
+ #elseif($column.htmlType == "select")## 涓嬫媺妗�
+ component: 'Select',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ placeholder: '璇烽�夋嫨${comment}',
+ },
+ #elseif($column.htmlType == "checkbox")## 澶氶�夋
+ component: 'Checkbox',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ },
+ #elseif($column.htmlType == "radio")## 鍗曢�夋
+ component: 'RadioGroup',
+ componentProps: {
+ #if ("" != $dictType)## 鏈夋暟鎹瓧鍏�
+ options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
+ #else##娌℃暟鎹瓧鍏�
+ options: [],
+ #end
+ buttonStyle: 'solid',
+ optionType: 'button',
+ },
+ #elseif($column.htmlType == "datetime")## 鏃堕棿妗�
+ component: 'DatePicker',
+ componentProps: {
+ showTime: true,
+ format: 'YYYY-MM-DD HH:mm:ss',
+ valueFormat: 'x',
+ },
+ #elseif($column.htmlType == "textarea")## 鏂囨湰鍩�
+ component: 'TextArea',
+ componentProps: {
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #elseif($column.htmlType == "inputNumber")## 鏁板瓧杈撳叆妗�
+ component: 'InputNumber',
+ componentProps: {
+ min: 0,
+ placeholder: '璇疯緭鍏�${comment}',
+ },
+ #end
+ },
+ #end
+ #end
+ #end
+ #end
+ ];
+ }
+
+ #end
+ #if ($table.templateType == 12) ## 鍐呭祵鎯呭喌
+ /** 鍒楄〃鐨勫瓧娈� */
+ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] {
+ return [
+ #foreach($column in $subColumns)
+ #if ($column.listOperationResult)
+ #set ($dictType = $column.dictType)
+ #set ($javaField = $column.javaField)
+ #set ($comment = $column.columnComment)
+ {
+ field: '${javaField}',
+ title: '${comment}',
+ minWidth: 120,
+ #if ($column.javaType == "LocalDateTime")## 鏃堕棿绫诲瀷
+ formatter: 'formatDateTime',
+ #elseif("" != $dictType)## 鏁版嵁瀛楀吀
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.$dictType.toUpperCase() },
+ },
+ #end
+ },
+ #end
+ #end
+ ];
+ }
+ #end
+#end
+#end
\ No newline at end of file
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/form.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/form.vue.vm
new file mode 100644
index 0000000..d140f23
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/form.vue.vm
@@ -0,0 +1,157 @@
+#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
+<script lang="ts" setup>
+import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+
+import { message#if ($table.templateType == 11), Tabs#end } from 'antdv-next';
+
+import { useVbenForm } from '#/adapter/form';
+import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
+import { $t } from '#/locales';
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+ #foreach ($subSimpleClassName in $subSimpleClassNames)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
+ import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
+ #end
+#end
+
+import { useFormSchema } from '../data';
+
+const emit = defineEmits(['success']);
+const formData = ref<${apiName}.${simpleClassName}>();
+const getTitle = computed(() => {
+ return formData.value?.id
+ ? $t('ui.actionTitle.edit', ['${table.classComment}'])
+ : $t('ui.actionTitle.create', ['${table.classComment}']);
+});
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+ #if ( $subTables && $subTables.size() > 0 )
+
+ /** 瀛愯〃鐨勮〃鍗� */
+ const subTabsName = ref('$subClassNameVars.get(0)')
+ #foreach ($subClassNameVar in $subClassNameVars)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ const ${subClassNameVar}FormRef = ref<InstanceType<typeof ${subSimpleClassName}Form>>()
+ #end
+ #end
+#end
+
+const [Form, formApi] = useVbenForm({
+ commonConfig: {
+ componentProps: {
+ class: 'w-full',
+ },
+ formItemClass: 'col-span-2',
+ labelWidth: 80,
+ },
+ layout: 'horizontal',
+ schema: useFormSchema(),
+ showDefaultActions: false,
+});
+
+const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ const { valid } = await formApi.validate();
+ if (!valid) {
+ return;
+ }
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+ #if ( $subTables && $subTables.size() > 0 )
+ // 鏍¢獙瀛愯〃鍗�
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #if ($subTable.subJoinMany) ## 涓�瀵瑰
+ ## TODO 鍒楄〃鍊兼牎楠岋紵
+ #else
+ const ${subClassNameVar}Valid = await ${subClassNameVar}FormRef.value?.validate();
+ if (!${subClassNameVar}Valid) {
+ subTabsName.value = '${subClassNameVar}';
+ return;
+ }
+ #end
+ #end
+ #end
+#end
+ modalApi.lock();
+ // 鎻愪氦琛ㄥ崟
+ const data = (await formApi.getValues()) as ${apiName}.${simpleClassName};
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+ #if ( $subTables && $subTables.size() > 0 )
+ // 鎷兼帴瀛愯〃鐨勬暟鎹�
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #if ($subTable.subJoinMany)
+ data.${subClassNameVar}s = ${subClassNameVar}FormRef.value?.getData();
+ #else
+ data.${subClassNameVar} = await ${subClassNameVar}FormRef.value?.getValues();
+ #end
+ #end
+ #end
+#end
+ try {
+ await (formData.value?.id ? update${simpleClassName}(data) : create${simpleClassName}(data));
+ // 鍏抽棴骞舵彁绀�
+ await modalApi.close();
+ emit('success');
+ message.success($t('ui.actionMessage.operationSuccess'));
+ } finally {
+ modalApi.unlock();
+ }
+ },
+ async onOpenChange(isOpen: boolean) {
+ if (!isOpen) {
+ formData.value = undefined;
+ return;
+ }
+ // 鍔犺浇鏁版嵁
+ const data = modalApi.getData<${apiName}.${simpleClassName}>();
+ if (!data || !data.id) {
+#if (${table.templateType} == 2)## 鏍戣〃鐗规湁
+ // 璁剧疆涓婄骇
+ await formApi.setValues(data);
+#end
+ return;
+ }
+ modalApi.lock();
+ try {
+ formData.value = await get${simpleClassName}(data.id);
+ // 璁剧疆鍒� values
+ await formApi.setValues(formData.value);
+ } finally {
+ modalApi.unlock();
+ }
+ },
+});
+</script>
+
+<template>
+ <Modal :title="getTitle">
+ <Form class="mx-4" />
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+ <!-- 瀛愯〃鐨勮〃鍗� -->
+ <Tabs v-model:active-key="subTabsName">
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+ <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
+ <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData?.id" />
+ </TabPane>
+ #end
+ </Tabs>
+#end
+ </Modal>
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/import.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/import.vue.vm
new file mode 100644
index 0000000..e8f90fd
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/import.vue.vm
@@ -0,0 +1,82 @@
+<script lang="ts" setup>
+import type { FileType } from 'antdv-next/es/upload/interface';
+
+import { useVbenModal } from '@vben/common-ui';
+import { downloadFileFromBlobPart } from '@vben/utils';
+
+import { Button, message, Upload } from 'antdv-next';
+
+import { useVbenForm } from '#/adapter/form';
+import { import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}';
+import { $t } from '#/locales';
+
+import { useImportFormSchema } from '../data';
+
+const emit = defineEmits(['success']);
+
+const [Form, formApi] = useVbenForm({
+ commonConfig: {
+ formItemClass: 'col-span-2',
+ labelWidth: 120,
+ },
+ layout: 'horizontal',
+ schema: useImportFormSchema(),
+ showDefaultActions: false,
+});
+
+const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ const { valid } = await formApi.validate();
+ if (!valid) {
+ return;
+ }
+ modalApi.lock();
+ // 鎻愪氦琛ㄥ崟
+ const data = await formApi.getValues();
+ try {
+ await import${simpleClassName}(data.file);
+ // 鍏抽棴骞舵彁绀�
+ await modalApi.close();
+ emit('success');
+ message.success($t('ui.actionMessage.operationSuccess'));
+ } finally {
+ modalApi.unlock();
+ }
+ },
+});
+
+/** 涓婁紶鍓� */
+function beforeUpload(file: FileType) {
+ formApi.setFieldValue('file', file);
+ return false;
+}
+
+/** 涓嬭浇妯℃澘 */
+async function handleDownload() {
+ const data = await import${simpleClassName}Template();
+ downloadFileFromBlobPart({ fileName: '${table.classComment}瀵煎叆妯℃澘.xls', source: data });
+}
+</script>
+
+<template>
+ <Modal title="瀵煎叆${table.classComment}" class="w-1/3">
+ <Form class="mx-4">
+ <template #file>
+ <div class="w-full">
+ <Upload
+ :max-count="1"
+ accept=".xls,.xlsx"
+ :before-upload="beforeUpload"
+ >
+ <Button type="primary"> 閫夋嫨 Excel 鏂囦欢 </Button>
+ </Upload>
+ </div>
+ </template>
+ </Form>
+ <template #prepend-footer>
+ <div class="flex flex-auto items-center">
+ <Button @click="handleDownload"> 涓嬭浇瀵煎叆妯℃澘 </Button>
+ </div>
+ </template>
+ </Modal>
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/index.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/index.vue.vm
new file mode 100644
index 0000000..071ecd1
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/index.vue.vm
@@ -0,0 +1,347 @@
+#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
+<script lang="ts" setup>
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+import { ref } from 'vue';
+
+import {#if ($table.templateType != 2 && $deleteBatchEnable) confirm,#end Page, useVbenModal } from '@vben/common-ui';
+import { downloadFileFromBlobPart#if ($table.templateType != 2 && $deleteBatchEnable), isEmpty#end } from '@vben/utils';
+
+import { message#if ($table.templateType == 11), Tabs#end } from 'antdv-next';
+
+import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
+#if (${table.templateType} == 2)## 鏍戣〃鎺ュ彛
+import {
+ delete${simpleClassName},
+ export${simpleClassName},
+ get${simpleClassName}List,
+} from '#/api/${table.moduleName}/${table.businessName}';
+#else## 鏍囧噯琛ㄦ帴鍙�
+import {
+ delete${simpleClassName},#if ($deleteBatchEnable)
+
+ delete${simpleClassName}List,#end
+ export${simpleClassName},
+ get${simpleClassName}Page,
+} from '#/api/${table.moduleName}/${table.businessName}';
+#end
+#if ($importEnable)
+import ${simpleClassName}Import from './modules/import-form.vue';
+#end
+import { $t } from '#/locales';
+
+import { useGridColumns, useGridFormSchema } from './data';
+import Form from './modules/form.vue';
+## 鐗规畩锛氫富瀛愯〃涓撳睘閫昏緫
+#if ( $table.templateType == 11 || $table.templateType == 12 )
+ #foreach ($subSimpleClassName in $subSimpleClassNames)
+ #set ($index = $foreach.count - 1)
+ #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
+import ${subSimpleClassName}List from './modules/${subSimpleClassName_strikeCase}-list.vue';
+ #end
+#end
+
+#if ($table.templateType == 12 || $table.templateType == 11) ## 鍐呭祵鍜宔rp鎯呭喌
+/** 瀛愯〃鐨勫垪琛� */
+const subTabsName = ref('$subClassNameVars.get(0)')
+#if ($table.templateType == 11)
+const select${simpleClassName} = ref<${apiName}.${simpleClassName}>();
+#end
+#end
+const [FormModal, formModalApi] = useVbenModal({
+ connectedComponent: Form,
+ destroyOnClose: true,
+});
+#if ($importEnable)
+const [ImportFormModal, importFormModalApi] = useVbenModal({
+ connectedComponent: ${simpleClassName}Import,
+ destroyOnClose: true,
+});
+
+/** 瀵煎叆${table.classComment} */
+function handleImport() {
+ importFormModalApi.open();
+}
+#end
+#if (${table.templateType} == 2)## 鏍戣〃鐗规湁锛氭帶鍒惰〃鏍煎睍寮�鏀剁缉
+
+/** 鍒囨崲鏍戝舰灞曞紑/鏀剁缉鐘舵�� */
+const isExpanded = ref(true);
+function handleExpand() {
+ isExpanded.value = !isExpanded.value;
+ gridApi.grid.setAllTreeExpand(isExpanded.value);
+}
+#end
+
+/** 鍒锋柊琛ㄦ牸 */
+function handleRefresh() {
+#if ($table.templateType == 12) ## 鍐呭祵鎯呭喌
+ gridApi.reload();
+#else
+ gridApi.query();
+#end
+}
+
+/** 鍒涘缓${table.classComment} */
+function handleCreate() {
+ formModalApi.setData(null).open();
+}
+#if (${table.templateType} == 2)## 鏍戣〃鐗规湁锛氭柊澧炰笅绾�
+
+/** 娣诲姞涓嬬骇${table.classComment} */
+function handleAppend(row: ${apiName}.${simpleClassName}) {
+ formModalApi.setData({ ${treeParentColumn.javaField}: row.id }).open();
+}
+#end
+
+/** 缂栬緫${table.classComment} */
+function handleEdit(row: ${apiName}.${simpleClassName}) {
+ formModalApi.setData(row).open();
+}
+
+/** 鍒犻櫎${table.classComment} */
+async function handleDelete(row: ${apiName}.${simpleClassName}) {
+ const hideLoading = message.loading({
+ content: $t('ui.actionMessage.deleting', [row.id]),
+ duration: 0,
+ });
+ try {
+ await delete${simpleClassName}(row.id!);
+ message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
+ handleRefresh();
+ } finally {
+ hideLoading();
+ }
+}
+
+#if ($table.templateType != 2 && $deleteBatchEnable)
+/** 鎵归噺鍒犻櫎${table.classComment} */
+async function handleDeleteBatch() {
+ await confirm($t('ui.actionMessage.deleteBatchConfirm'));
+ const hideLoading = message.loading({
+ content: $t('ui.actionMessage.deletingBatch'),
+ duration: 0,
+ });
+ try {
+ await delete${simpleClassName}List(checkedIds.value);
+ checkedIds.value = [];
+ message.success($t('ui.actionMessage.deleteSuccess'));
+ handleRefresh();
+ } finally {
+ hideLoading();
+ }
+}
+
+const checkedIds = ref<number[]>([]);
+function handleRowCheckboxChange({
+ records,
+}: {
+ records: ${apiName}.${simpleClassName}[];
+}) {
+ checkedIds.value = records.map((item) => item.id!);
+}
+#end
+
+/** 瀵煎嚭琛ㄦ牸 */
+async function handleExport() {
+ const data = await export${simpleClassName}(await gridApi.formApi.getValues());
+ downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data });
+}
+
+
+const [Grid, gridApi] = useVbenVxeGrid({
+ formOptions: {
+ schema: useGridFormSchema(),
+ },
+ gridOptions: {
+ columns: useGridColumns(),
+#if (${table.templateType} == 11)
+ height: '600px',
+#else
+ height: 'auto',
+#end
+#if (${table.templateType} == 2)## 鏍戣〃璁剧疆
+ pagerConfig: {
+ enabled: false,
+ },
+#else## 鏍囧噯琛ㄨ缃�
+ keepSource: true,
+#end
+ proxyConfig: {
+ ajax: {
+#if (${table.templateType} == 2)## 鏍戣〃鏁版嵁鍔犺浇
+ query: async (_, formValues) => {
+ return await get${simpleClassName}List(formValues);
+ },
+#else## 鏍囧噯琛ㄦ暟鎹姞杞�
+ query: async ({ page }, formValues) => {
+ return await get${simpleClassName}Page({
+ pageNo: page.currentPage,
+ pageSize: page.pageSize,
+ ...formValues,
+ });
+ },
+#end
+ },
+ },
+ rowConfig: {
+ keyField: 'id',
+ isHover: true,
+#if (${table.templateType} == 11)
+ isCurrent: true,
+#end
+ },
+ toolbarConfig: {
+ refresh: true,
+ search: true,
+ },
+#if (${table.templateType} == 2)## 鏍戣〃璁剧疆
+ treeConfig: {
+ parentField: '${treeParentColumn.javaField}',
+ rowField: 'id',
+ transform: true,
+ expandAll: true,
+ reserve: true,
+ },
+#end
+ } as VxeTableGridOptions<${apiName}.${simpleClassName}>,
+#if (${table.templateType} == 11 || (${table.templateType} != 2 && $deleteBatchEnable))
+ gridEvents: {
+ #if(${table.templateType} == 11)
+ cellClick: ({ row }: { row: ${apiName}.${simpleClassName}}) => {
+ select${simpleClassName}.value = row;
+ },
+ #end
+ #if (${table.templateType} != 2 && $deleteBatchEnable)
+ checkboxAll: handleRowCheckboxChange,
+ checkboxChange: handleRowCheckboxChange,
+ #end
+ },
+#end
+});
+</script>
+
+<template>
+ <Page auto-content-height>
+ <FormModal @success="handleRefresh" />
+#if ($importEnable)
+ <ImportFormModal @success="handleRefresh" />
+#end
+#if ($table.templateType == 11) ## erp鎯呭喌
+ <div>
+#end
+ <Grid table-title="${table.classComment}鍒楄〃">
+ #if ($table.templateType == 12) ## 鍐呭祵鎯呭喌
+ <template #expand_content="{ row }">
+ <!-- 瀛愯〃鐨勮〃鍗� -->
+ <Tabs v-model:active-key="subTabsName" class="mx-8">
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+ <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
+ <${subSimpleClassName}List :${subJoinColumn_strikeCase}="row?.id" />
+ </TabPane>
+ #end
+ </Tabs>
+ </template>
+ #end
+ <template #toolbar-tools>
+ <TableAction
+ :actions="[
+ {
+ label: $t('ui.actionTitle.create', ['${table.classComment}']),
+ type: 'primary',
+ icon: ACTION_ICON.ADD,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
+ onClick: handleCreate,
+ },
+ #if (${table.templateType} == 2)## 鏍戣〃鐗规湁锛氬睍寮�/鏀剁缉鎸夐挳
+ {
+ label: isExpanded ? '鏀剁缉' : '灞曞紑',
+ type: 'primary',
+ onClick: handleExpand,
+ },
+ #end
+#if ($importEnable)
+ {
+ label: '瀵煎叆',
+ type: 'primary',
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:import'],
+ onClick: handleImport,
+ },
+#end
+ {
+ label: $t('ui.actionTitle.export'),
+ type: 'primary',
+ icon: ACTION_ICON.DOWNLOAD,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:export'],
+ onClick: handleExport,
+ },
+ #if ($table.templateType != 2 && $deleteBatchEnable)
+ {
+ label: $t('ui.actionTitle.deleteBatch'),
+ type: 'primary',
+ danger: true,
+ icon: ACTION_ICON.DELETE,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
+ disabled: isEmpty(checkedIds),
+ onClick: handleDeleteBatch,
+ },
+ #end
+ ]"
+ />
+ </template>
+ <template #actions="{ row }">
+ <TableAction
+ :actions="[
+ #if (${table.templateType} == 2)## 鏍戣〃鐗规湁锛氭柊澧炰笅绾�
+ {
+ label: '鏂板涓嬬骇',
+ type: 'link',
+ icon: ACTION_ICON.ADD,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
+ onClick: handleAppend.bind(null, row),
+ },
+ #end
+ {
+ label: $t('common.edit'),
+ type: 'link',
+ icon: ACTION_ICON.EDIT,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:update'],
+ onClick: handleEdit.bind(null, row),
+ },
+ {
+ label: $t('common.delete'),
+ type: 'link',
+ danger: true,
+ icon: ACTION_ICON.DELETE,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
+ popConfirm: {
+ title: $t('ui.actionMessage.deleteConfirm', [row.id]),
+ confirm: handleDelete.bind(null, row),
+ },
+ },
+ ]"
+ />
+ </template>
+ </Grid>
+#if ($table.templateType == 11) ## erp鎯呭喌
+ <!-- 瀛愯〃鐨勮〃鍗� -->
+ <Tabs v-model:active-key="subTabsName" class="mt-2">
+ #foreach ($subTable in $subTables)
+ #set ($index = $foreach.count - 1)
+ #set ($subClassNameVar = $subClassNameVars.get($index))
+ #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+ #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+ <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
+ <${subSimpleClassName}List :${subJoinColumn_strikeCase}="select${simpleClassName}?.id" />
+ </TabPane>
+ #end
+ </Tabs>
+ </div>
+#end
+ </Page>
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_erp.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_erp.vue.vm
new file mode 100644
index 0000000..fefa965
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_erp.vue.vm
@@ -0,0 +1,89 @@
+#set ($subTable = $subTables.get($subIndex))##褰撳墠琛�
+#set ($subColumns = $subColumnsList.get($subIndex))##褰撳墠瀛楁鏁扮粍
+#set ($subJoinColumn = $subJoinColumns.get($subIndex))##褰撳墠 join 瀛楁
+#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
+#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
+<script lang="ts" setup>
+ import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+ import { useVbenModal } from '@vben/common-ui';
+ import { message } from 'antdv-next';
+
+ import { computed, ref } from 'vue';
+ import { $t } from '#/locales';
+ import { useVbenForm } from '#/adapter/form';
+ import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+ import { use${subSimpleClassName}FormSchema } from '../data';
+
+ const emit = defineEmits(['success']);
+ const formData = ref<${apiName}.${subSimpleClassName}>();
+ const getTitle = computed(() => {
+ return formData.value?.id
+ ? $t('ui.actionTitle.edit', ['${subTable.classComment}'])
+ : $t('ui.actionTitle.create', ['${subTable.classComment}']);
+ });
+
+ const [Form, formApi] = useVbenForm({
+ commonConfig: {
+ componentProps: {
+ class: 'w-full',
+ },
+ formItemClass: 'col-span-2',
+ labelWidth: 80,
+ },
+ layout: 'horizontal',
+ schema: use${subSimpleClassName}FormSchema(),
+ showDefaultActions: false
+ });
+
+ const [Modal, modalApi] = useVbenModal({
+ async onConfirm() {
+ const { valid } = await formApi.validate();
+ if (!valid) {
+ return;
+ }
+ modalApi.lock();
+ // 鎻愪氦琛ㄥ崟
+ const data = (await formApi.getValues()) as ${apiName}.${subSimpleClassName};
+ data.${subJoinColumn.javaField} = formData.value?.${subJoinColumn.javaField};
+ try {
+ await (formData.value?.id ? update${subSimpleClassName}(data) : create${subSimpleClassName}(data));
+ // 鍏抽棴骞舵彁绀�
+ await modalApi.close();
+ emit('success');
+ message.success( $t('ui.actionMessage.operationSuccess') );
+ } finally {
+ modalApi.unlock();
+ }
+ },
+ async onOpenChange(isOpen: boolean) {
+ if (!isOpen) {
+ formData.value = undefined;
+ return;
+ }
+ // 鍔犺浇鏁版嵁
+ let data = modalApi.getData<${apiName}.${subSimpleClassName}>();
+ if (!data) {
+ return;
+ }
+ if (data.id) {
+ modalApi.lock();
+ try {
+ data = await get${subSimpleClassName}(data.id);
+ } finally {
+ modalApi.unlock();
+ }
+ }
+ // 璁剧疆鍒� values
+ formData.value = data;
+ await formApi.setValues(formData.value);
+ },
+ });
+</script>
+
+<template>
+ <Modal :title="getTitle">
+ <Form class="mx-4" />
+ </Modal>
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_inner.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_inner.vue.vm
new file mode 100644
index 0000000..2c59695
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_inner.vue.vm
@@ -0,0 +1,2 @@
+## 涓昏〃鐨� normal 鍜� inner 浣跨敤鐩稿悓鐨� form 琛ㄥ崟
+#parse("codegen/vue3_vben5_antd/schema/views/modules/form_sub_normal.vue.vm")
\ No newline at end of file
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_normal.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_normal.vue.vm
new file mode 100644
index 0000000..f74b03c
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_normal.vue.vm
@@ -0,0 +1,195 @@
+#set ($subTable = $subTables.get($subIndex))##褰撳墠琛�
+#set ($subColumns = $subColumnsList.get($subIndex))##褰撳墠瀛楁鏁扮粍
+#set ($subJoinColumn = $subJoinColumns.get($subIndex))##褰撳墠 join 瀛楁
+#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
+#set ($subClassNameVar = $subClassNameVars.get($subIndex))
+#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##棣栧瓧姣嶅ぇ鍐�
+#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
+<script lang="ts" setup>
+ import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+ import { computed, ref, h, onMounted, watch, nextTick } from 'vue';
+
+ import { $t } from '#/locales';
+
+#if ($subTable.subJoinMany) ## 涓�瀵瑰
+import { Plus } from "@vben/icons";
+import { Button, Tabs, Checkbox, Input, TextArea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'antdv-next';
+import { ImageUpload, FileUpload } from "#/components/upload";
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { use${subSimpleClassName}GridEditColumns } from '../data';
+import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
+#else
+import { useVbenForm } from '#/adapter/form';
+import { use${subSimpleClassName}FormSchema } from '../data';
+import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
+#end
+
+const props = defineProps<{
+ ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}锛堜富琛ㄧ殑鍏宠仈瀛楁锛�
+}>()
+
+#if ($subTable.subJoinMany) ## 涓�瀵瑰
+const [Grid, gridApi] = useVbenVxeGrid({
+gridOptions: {
+ columns: use${subSimpleClassName}GridEditColumns(),
+ border: true,
+ showOverflow: true,
+ autoResize: true,
+ keepSource: true,
+ rowConfig: {
+ keyField: 'id',
+ },
+ pagerConfig: {
+ enabled: false,
+ },
+ toolbarConfig: {
+ enabled: false,
+ },
+},
+});
+
+/** 娣诲姞${subTable.classComment} */
+const handleAdd = async () => {
+ await gridApi.grid.insertAt({} as ${apiName}.${subSimpleClassName}, -1);
+}
+
+/** 鍒犻櫎${subTable.classComment} */
+const handleDelete = async (row: ${apiName}.${subSimpleClassName}) => {
+ await gridApi.grid.remove(row);
+}
+
+/** 鎻愪緵鑾峰彇琛ㄦ牸鏁版嵁鐨勬柟娉曚緵鐖剁粍浠惰皟鐢� */
+defineExpose({
+ getData: (): ${apiName}.${subSimpleClassName}[] => {
+ const data = gridApi.grid.getData() as ${apiName}.${subSimpleClassName}[];
+ const removeRecords = gridApi.grid.getRemoveRecords() as ${apiName}.${subSimpleClassName}[];
+ const insertRecords = gridApi.grid.getInsertRecords() as ${apiName}.${subSimpleClassName}[];
+ return data
+ .filter((row) => !removeRecords.some((removed) => removed.id === row.id))
+ .concat(insertRecords.map((row: any) => ({ ...row, id: undefined })));
+ },
+});
+
+/** 鐩戝惉涓昏〃鐨勫叧鑱斿瓧娈电殑鍙樺寲锛屽姞杞藉搴旂殑瀛愯〃鏁版嵁 */
+watch(
+ () => props.${subJoinColumn.javaField},
+ async (val) => {
+ if (!val) {
+ return;
+ }
+ await nextTick();
+ await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
+ },
+ { immediate: true },
+);
+#else
+const [Form, formApi] = useVbenForm({
+ commonConfig: {
+ componentProps: {
+ class: 'w-full',
+ },
+ formItemClass: 'col-span-2',
+ labelWidth: 80,
+ },
+ layout: 'horizontal',
+ schema: use${subSimpleClassName}FormSchema(),
+ showDefaultActions: false
+});
+
+/** 鏆撮湶鍑鸿〃鍗曟牎楠屾柟娉曞拰琛ㄥ崟鍊艰幏鍙栨柟娉� */
+defineExpose({
+ validate: async () => {
+ const { valid } = await formApi.validate();
+ return valid;
+ },
+ getValues: formApi.getValues,
+});
+
+/** 鐩戝惉涓昏〃鐨勫叧鑱斿瓧娈电殑鍙樺寲锛屽姞杞藉搴旂殑瀛愯〃鏁版嵁 */
+watch(
+ () => props.${subJoinColumn.javaField},
+ async (val) => {
+ if (!val) {
+ return;
+ }
+ await nextTick();
+ await formApi.setValues(await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
+ },
+ { immediate: true },
+);
+#end
+</script>
+
+<template>
+#if ($subTable.subJoinMany) ## 涓�瀵瑰
+ <Grid class="mx-4">
+ #foreach($column in $subColumns)
+ #if ($column.createOperation || $column.updateOperation)
+ #set ($javaField = $column.javaField)
+ #if ( $column.id == $subJoinColumn.id) ## 鐗规畩锛氬拷鐣ヤ富瀛愯〃鐨� join 瀛楁锛屼笉鐢ㄥ~鍐�
+ #elseif ($column.htmlType == "input" && !$column.primaryKey)## 蹇界暐涓婚敭锛屼笉鐢ㄥ湪琛ㄥ崟閲�
+ <template #${javaField}="{ row }">
+ <Input v-model:value="row.${javaField}" />
+ </template>
+ #elseif($column.htmlType == "imageUpload")## 鍥剧墖涓婁紶
+ <template #${javaField}="{ row }">
+ <ImageUpload v-model:value="row.${javaField}" />
+ </template>
+ #elseif($column.htmlType == "fileUpload")## 鏂囦欢涓婁紶
+ <template #${javaField}="{ row }">
+ <FileUpload v-model:value="row.${javaField}" />
+ </template>
+ #elseif($column.htmlType == "select")## 涓嬫媺妗�
+ <template #${javaField}="{ row, column }">
+ <Select v-model:value="row.${javaField}" class="w-full">
+ <SelectOption v-for="option in column.params.options" :key="option.value" :value="option.value">
+ {{ option.label }}
+ </SelectOption>
+ </Select>
+ </template>
+ #elseif($column.htmlType == "checkbox")## 澶氶�夋
+ <template #${javaField}="{ row, column }">
+ <CheckboxGroup v-model:value="row.${javaField}" :options="column.params.options" />
+ </template>
+ #elseif($column.htmlType == "radio")## 鍗曢�夋
+ <template #${javaField}="{ row, column }">
+ <RadioGroup v-model:value="row.${javaField}" :options="column.params.options" />
+ </template>
+ #elseif($column.htmlType == "datetime")## 鏃堕棿妗�
+ <template #${javaField}="{ row }">
+ <DatePicker
+ v-model:value="row.${javaField}"
+ :showTime="true"
+ format="YYYY-MM-DD HH:mm:ss"
+ valueFormat='x'
+ />
+ </template>
+ #elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 鏂囨湰妗�
+ <template #${javaField}="{ row }">
+ <TextArea v-model:value="row.${javaField}" />
+ </template>
+ #end
+ #end
+ #end
+ <template #actions="{ row }">
+ <Button
+ size="small"
+ type="link"
+ danger
+ @click="handleDelete(row)"
+ v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:delete']"
+ >
+ {{ $t('ui.actionTitle.delete') }}
+ </Button>
+ </template>
+ </Grid>
+ <div class="flex justify-center -mt-4">
+ <Button :icon="h(Plus)" type="primary" ghost @click="handleAdd" v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:create']">
+ {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
+ </Button>
+ </div>
+#else
+ <Form class="mx-4" />
+#end
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_erp.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_erp.vue.vm
new file mode 100644
index 0000000..e85700d
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_erp.vue.vm
@@ -0,0 +1,240 @@
+#set ($subTable = $subTables.get($subIndex))##褰撳墠琛�
+#set ($subColumns = $subColumnsList.get($subIndex))##褰撳墠瀛楁鏁扮粍
+#set ($subJoinColumn = $subJoinColumns.get($subIndex))##褰撳墠 join 瀛楁
+#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
+#set ($subJoinColumn = $subJoinColumns.get($subIndex))##褰撳墠 join 瀛楁
+#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex))
+#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##棣栧瓧姣嶅ぇ鍐�
+#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
+<script lang="ts" setup>
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
+
+#if ($table.templateType == 11) ## erp
+import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
+#end
+import { confirm, useVbenModal } from '@vben/common-ui';
+import { message } from 'antdv-next';
+import { ref, computed, nextTick,watch } from 'vue';
+import { $t } from '#/locales';
+import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
+
+#if ($table.templateType == 11) ## erp
+import { delete${subSimpleClassName},#if ($deleteBatchEnable) delete${subSimpleClassName}List,#end get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${table.businessName}';
+import { use${subSimpleClassName}GridFormSchema, use${subSimpleClassName}GridColumns } from '../data';
+import { isEmpty } from '@vben/utils';
+#else
+#if ($subTable.subJoinMany) ## 涓�瀵瑰
+import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
+#else
+import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
+#end
+import { use${subSimpleClassName}GridColumns } from '../data';
+#end
+
+const props = defineProps<{
+ ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}锛堜富琛ㄧ殑鍏宠仈瀛楁锛�
+}>()
+
+#if ($table.templateType == 11) ## erp
+const [FormModal, formModalApi] = useVbenModal({
+ connectedComponent: ${subSimpleClassName}Form,
+ destroyOnClose: true,
+});
+
+/** 鍒涘缓${subTable.classComment} */
+function handleCreate() {
+ if (!props.${subJoinColumn.javaField}){
+ message.warning("璇峰厛閫夋嫨涓�涓�${table.classComment}!")
+ return
+ }
+ formModalApi.setData({${subJoinColumn.javaField}: props.${subJoinColumn.javaField}}).open();
+}
+
+/** 缂栬緫${subTable.classComment} */
+function handleEdit(row: ${apiName}.${subSimpleClassName}) {
+ formModalApi.setData(row).open();
+}
+
+/** 鍒犻櫎${subTable.classComment} */
+async function handleDelete(row: ${apiName}.${subSimpleClassName}) {
+ const hideLoading = message.loading({
+ content: $t('ui.actionMessage.deleting', [row.id]),
+ duration: 0,
+ });
+ try {
+ await delete${subSimpleClassName}(row.id!);
+ message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
+ handleRefresh();
+ } finally {
+ hideLoading();
+ }
+}
+
+#if ($deleteBatchEnable)
+/** 鎵归噺鍒犻櫎${subTable.classComment} */
+async function handleDeleteBatch() {
+ await confirm($t('ui.actionMessage.deleteBatchConfirm'));
+ const hideLoading = message.loading({
+ content: $t('ui.actionMessage.deletingBatch'),
+ duration: 0,
+ });
+ try {
+ await delete${subSimpleClassName}List(checkedIds.value);
+ checkedIds.value = [];
+ message.success($t('ui.actionMessage.deleteSuccess'));
+ handleRefresh();
+ } finally {
+ hideLoading();
+ }
+}
+
+const checkedIds = ref<number[]>([])
+function handleRowCheckboxChange({
+ records,
+}: {
+ records: ${apiName}.${subSimpleClassName}[];
+}) {
+ checkedIds.value = records.map((item) => item.id!);
+}
+#end
+
+#end
+const [Grid, gridApi] = useVbenVxeGrid({
+#if ($table.templateType == 11)
+ formOptions: {
+ schema: use${subSimpleClassName}GridFormSchema(),
+ },
+#end
+ gridOptions: {
+#if ($table.templateType == 11)
+ columns: use${subSimpleClassName}GridColumns(),
+ proxyConfig: {
+ ajax: {
+ query: async ({ page }, formValues) => {
+ if (!props.${subJoinColumn.javaField}){
+ return []
+ }
+ return await get${subSimpleClassName}Page({
+ pageNo: page.currentPage,
+ pageSize: page.pageSize,
+ ${subJoinColumn.javaField}: props.${subJoinColumn.javaField},
+ ...formValues,
+ });
+ },
+ },
+ },
+ pagerConfig: {
+ enabled: true,
+ },
+ toolbarConfig: {
+ refresh: true,
+ search: true,
+ },
+#else
+ columns: use${subSimpleClassName}GridColumns(),
+ pagerConfig: {
+ enabled: false,
+ },
+ toolbarConfig: {
+ enabled: false,
+ },
+#end
+ height: '600px',
+ rowConfig: {
+ keyField: 'id',
+ isHover: true,
+ },
+ } as VxeTableGridOptions<${apiName}.${subSimpleClassName}>,
+ #if (${table.templateType} == 11 && $deleteBatchEnable)
+ gridEvents:{
+ checkboxAll: handleRowCheckboxChange,
+ checkboxChange: handleRowCheckboxChange,
+ }
+ #end
+});
+
+/** 鍒锋柊琛ㄦ牸 */
+async function handleRefresh() {
+#if ($table.templateType == 11) ## erp
+ await gridApi.query();
+#else
+ #if ($subTable.subJoinMany) ## 涓�瀵瑰
+ await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
+ #else
+ await gridApi.grid.loadData([await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)]);
+ #end
+#end
+}
+
+/** 鐩戝惉涓昏〃鐨勫叧鑱斿瓧娈电殑鍙樺寲锛屽姞杞藉搴旂殑瀛愯〃鏁版嵁 */
+watch(
+ () => props.${subJoinColumn.javaField},
+ async (val) => {
+ if (!val) {
+ return;
+ }
+ await nextTick();
+ await handleRefresh()
+ },
+ { immediate: true },
+);
+</script>
+
+<template>
+ #if ($table.templateType == 11) ## erp
+ <FormModal @success="handleRefresh" />
+ <Grid table-title="${subTable.classComment}鍒楄〃">
+ <template #toolbar-tools>
+ <TableAction
+ :actions="[
+ {
+ label: $t('ui.actionTitle.create', ['${table.classComment}']),
+ type: 'primary',
+ icon: ACTION_ICON.ADD,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
+ onClick: handleCreate,
+ },
+ #if ($table.templateType == 11 && $deleteBatchEnable)
+ {
+ label: $t('ui.actionTitle.deleteBatch'),
+ type: 'primary',
+ danger: true,
+ icon: ACTION_ICON.DELETE,
+ disabled: isEmpty(checkedIds),
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
+ onClick: handleDeleteBatch,
+ },
+ #end
+ ]"
+ />
+ </template>
+ <template #actions="{ row }">
+ <TableAction
+ :actions="[
+ {
+ label: $t('common.edit'),
+ type: 'link',
+ icon: ACTION_ICON.EDIT,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:update'],
+ onClick: handleEdit.bind(null, row),
+ },
+ {
+ label: $t('common.delete'),
+ type: 'link',
+ danger: true,
+ icon: ACTION_ICON.DELETE,
+ auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
+ popConfirm: {
+ title: $t('ui.actionMessage.deleteConfirm', [row.id]),
+ confirm: handleDelete.bind(null, row),
+ },
+ },
+ ]"
+ />
+ </template>
+ </Grid>
+ #else
+ <Grid table-title="${subTable.classComment}鍒楄〃" />
+ #end
+</template>
diff --git a/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_inner.vue.vm b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_inner.vue.vm
new file mode 100644
index 0000000..2d8aa20
--- /dev/null
+++ b/yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_inner.vue.vm
@@ -0,0 +1,4 @@
+## 瀛愯〃鐨� erp 鍜� inner 浣跨敤鐩镐技鐨� list 鍒楄〃锛屽樊寮備富瑕佷袱鐐癸細
+## 1锛塱nner 浣跨敤 list 涓嶅垎椤碉紝erp 浣跨敤 page 鍒嗛〉
+## 2锛塭rp 鏀寔鍗曚釜瀛愯〃鐨勬柊澧炪�佷慨鏀广�佸垹闄わ紝inner 涓嶆敮鎸�
+#parse("codegen/vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm")
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java
index 6bc8c7b..f7681f7 100644
--- a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java
+++ b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java
@@ -1,15 +1,71 @@
package cn.iocoder.yudao.module.infra.framework.file.core.local;
+import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.IdUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClient;
import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
+import static org.junit.jupiter.api.Assertions.*;
public class LocalFileClientTest {
+
+ @TempDir
+ public File tempDir;
+
+ @Test
+ public void testUpload_success() {
+ // 鍑嗗鍙傛暟
+ LocalFileClient client = createClient();
+ byte[] content = "test".getBytes(StandardCharsets.UTF_8);
+ String path = "avatar/test.txt";
+
+ // 璋冪敤
+ String url = client.upload(content, path, "text/plain");
+
+ // 鏂█
+ assertEquals("http://127.0.0.1:48080/admin-api/infra/file/0/get/avatar/test.txt", url);
+ assertArrayEquals(content, FileUtil.readBytes(new File(tempDir, path)));
+ assertArrayEquals(content, client.getContent(path));
+
+ // 鍒犻櫎
+ client.delete(path);
+ assertFalse(FileUtil.exist(new File(tempDir, path)));
+ }
+
+ @Test
+ public void testUpload_encodeUrlPath() {
+ // 鍑嗗鍙傛暟
+ LocalFileClient client = createClient();
+ byte[] content = "test".getBytes(StandardCharsets.UTF_8);
+ String path = "avatar/涓枃 100%+鏂囦欢.txt";
+
+ // 璋冪敤
+ String url = client.upload(content, path, "text/plain");
+
+ // 鏂█
+ assertEquals("http://127.0.0.1:48080/admin-api/infra/file/0/get/avatar/%E4%B8%AD%E6%96%87%20100%25+%E6%96%87%E4%BB%B6.txt", url);
+ assertArrayEquals(content, FileUtil.readBytes(new File(tempDir, path)));
+ }
+
+ @Test
+ public void testUpload_pathInvalid() {
+ // 鍑嗗鍙傛暟
+ LocalFileClient client = createClient();
+ byte[] content = "test".getBytes(StandardCharsets.UTF_8);
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertThrows(ServiceException.class, () -> client.upload(content, "../test.txt", "text/plain"));
+ assertFalse(FileUtil.exist(new File(tempDir.getParentFile(), "test.txt")));
+ }
@Test
@Disabled
@@ -42,4 +98,13 @@
System.out.println();
}
+ private LocalFileClient createClient() {
+ LocalFileClientConfig config = new LocalFileClientConfig();
+ config.setDomain("http://127.0.0.1:48080");
+ config.setBasePath(tempDir.getAbsolutePath());
+ LocalFileClient client = new LocalFileClient(0L, config);
+ client.init();
+ return client;
+ }
+
}
diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java
index 981971b..8a3e2cd 100644
--- a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java
+++ b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java
@@ -9,10 +9,67 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
@SuppressWarnings("resource")
public class S3FileClientTest {
@Test
+ public void testPresignGetUrl_publicAccess_encodeUrlPath() {
+ // 鍑嗗鍙傛暟
+ S3FileClientConfig config = new S3FileClientConfig();
+ config.setDomain("https://static.iocoder.cn");
+ config.setEnablePublicAccess(true);
+ S3FileClient client = new S3FileClient(0L, config);
+
+ // 璋冪敤
+ String result = client.presignGetUrl("avatar/涓枃 100%+鏂囦欢.jpg", 300);
+
+ // 鏂█
+ assertEquals("https://static.iocoder.cn/avatar/%E4%B8%AD%E6%96%87%20100%25+%E6%96%87%E4%BB%B6.jpg", result);
+ }
+
+ @Test
+ public void testPresignGetUrl_publicAccess_decodeDomainUrl() {
+ // 鍑嗗鍙傛暟
+ S3FileClientConfig config = new S3FileClientConfig();
+ config.setDomain("https://static.iocoder.cn");
+ config.setEnablePublicAccess(true);
+ S3FileClient client = new S3FileClient(0L, config);
+
+ // 璋冪敤
+ String result = client.presignGetUrl("https://static.iocoder.cn/avatar/%E4%B8%AD%E6%96%87%20100%25+%E6%96%87%E4%BB%B6.jpg?token=1", 300);
+
+ // 鏂█
+ assertEquals("https://static.iocoder.cn/avatar/%E4%B8%AD%E6%96%87%20100%25+%E6%96%87%E4%BB%B6.jpg", result);
+ }
+
+ @Test
+ public void testPresignGetUrl_privateAccess_rawPath() {
+ // 鍑嗗鍙傛暟
+ S3FileClientConfig config = new S3FileClientConfig();
+ config.setAccessKey("admin");
+ config.setAccessSecret("password");
+ config.setBucket("yudao");
+ config.setDomain("http://127.0.0.1:9000/yudao");
+ config.setEndpoint("http://127.0.0.1:9000");
+ config.setEnablePathStyleAccess(true);
+ config.setEnablePublicAccess(false);
+ S3FileClient client = new S3FileClient(0L, config);
+ client.init();
+
+ // 璋冪敤
+ String result = client.presignGetUrl("avatar/涓枃 100%+鏂囦欢.jpg", 300);
+
+ // 鏂█
+ assertTrue(result.contains("/yudao/avatar/%E4%B8%AD%E6%96%87%20100%25"));
+ assertTrue(result.contains("%E6%96%87%E4%BB%B6.jpg"));
+ assertFalse(result.contains("%25E4%25B8%25AD"));
+ }
+
+ @Test
@Disabled // MinIO锛屽鏋滆闆嗘垚娴嬭瘯锛屽彲浠ユ敞閲婃湰琛�
public void testMinIO() throws Exception {
S3FileClientConfig config = new S3FileClientConfig();
diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtilsTest.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtilsTest.java
new file mode 100644
index 0000000..d13884b
--- /dev/null
+++ b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtilsTest.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.infra.framework.file.core.utils;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * {@link FileTypeUtils} 鐨勫崟鍏冩祴璇�
+ */
+public class FileTypeUtilsTest {
+
+ @Test
+ public void testWriteAttachment_contentDispositionEncodeFilename() throws Exception {
+ // 鍑嗗鍙傛暟
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ byte[] content = "test".getBytes(StandardCharsets.UTF_8);
+
+ // 璋冪敤
+ FileTypeUtils.writeAttachment(response, "涓枃 100%+鏂囦欢.txt", content);
+
+ // 鏂█
+ assertEquals("attachment;filename=\"__ 100%+__.txt\";"
+ + "filename*=UTF-8''%E4%B8%AD%E6%96%87%20100%25+%E6%96%87%E4%BB%B6.txt",
+ response.getHeader("Content-Disposition"));
+ assertArrayEquals(content, response.getContentAsByteArray());
+ }
+
+}
diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java
index 7d1be13..ba0850a 100644
--- a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java
+++ b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java
@@ -108,12 +108,21 @@
asserts.forEach(assertMap -> {
String contentPath = (String) assertMap.get("contentPath");
String filePath = (String) assertMap.get("filePath");
- String expected = ResourceUtil.readUtf8Str("codegen/" + path + "/" + contentPath)
- .replace("\r\n", "\n");
+ String expected = normalizeLineEndings(ResourceUtil.readUtf8Str("codegen/" + path + "/" + contentPath));
String actual = result.get(filePath);
- assertEquals(expected, actual == null ? null : actual.replace("\r\n", "\n"),
- filePath + "锛氫笉鍖归厤");
+ assertEquals(expected, normalizeLineEndings(actual), filePath + "锛氫笉鍖归厤");
});
+ }
+
+ /**
+ * 缁熶竴鎹㈣绗﹀苟蹇界暐鏂囦欢鏈熬鎹㈣锛岄伩鍏� Windows/Unix 钀界洏宸紓瀵艰嚧蹇収鏂█澶辫触
+ */
+ private static String normalizeLineEndings(String content) {
+ if (content == null) {
+ return null;
+ }
+ content = content.replace("\r\n", "\n").replace('\r', '\n');
+ return content.replaceAll("\\n+\\z", "");
}
// ==================== 璋冭瘯涓撶敤 ====================
@@ -143,10 +152,21 @@
protected void writeResult(Map<String, String> result, String basePath) {
// 鍐欏叆鏂囦欢鍐呭
List<Map<String, String>> asserts = new ArrayList<>();
+ Set<String> usedContentPaths = new LinkedHashSet<>();
result.forEach((filePath, fileContent) -> {
String lastFilePath = StrUtil.subAfter(filePath, '/', true);
- String contentPath = StrUtil.subAfter(lastFilePath, '.', true)
- + '/' + StrUtil.subBefore(lastFilePath, '.', true);
+ String ext = StrUtil.subAfter(lastFilePath, '.', true);
+ String name = StrUtil.subBefore(lastFilePath, '.', true);
+ String contentPath = ext + '/' + name;
+ // 鍚屽悕鏂囦欢锛堝 index.vue 鍚屾椂鍑虹幇鍦� 鍒楄〃/form/detail锛変細鎾炲悕锛屾挒鍚嶆椂鍓嶇紑琛ヤ笂绾х洰褰曞尯鍒嗭紱浠嶆挒鍒欏姞搴忓彿鍏滃簳锛岄伩鍏嶅揩鐓т簰鐩歌鐩�
+ if (usedContentPaths.contains(contentPath)) {
+ String parentDir = StrUtil.subAfter(StrUtil.subBefore(filePath, '/' + lastFilePath, true), '/', true);
+ contentPath = ext + '/' + parentDir + '/' + name;
+ for (int i = 2; usedContentPaths.contains(contentPath); i++) {
+ contentPath = ext + '/' + parentDir + '/' + name + '-' + i;
+ }
+ }
+ usedContentPaths.add(contentPath);
asserts.add(MapUtil.<String, String>builder().put("filePath", filePath)
.put("contentPath", contentPath).build());
FileUtil.writeUtf8String(fileContent, basePath + "/" + contentPath);
diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineUniappTest.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineUniappTest.java
new file mode 100644
index 0000000..763e66f
--- /dev/null
+++ b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineUniappTest.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.infra.service.codegen.inner;
+
+import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
+import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
+import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
+import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
+import com.baomidou.mybatisplus.annotation.DbType;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link CodegenEngine} 鐨� Vue3 Admin Uniapp + Wot UI 鍗曞厓娴嬭瘯
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class CodegenEngineUniappTest extends CodegenEngineAbstractTest {
+
+ @Test
+ public void testExecute_one() {
+ // 鍑嗗鍙傛暟
+ CodegenTableDO table = getTable("student")
+ .setFrontType(CodegenFrontTypeEnum.VUE3_ADMIN_UNIAPP_WOT.getType())
+ .setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
+ List<CodegenColumnDO> columns = getColumnList("student");
+
+ // 璋冪敤
+ Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null);
+ // 鏂█
+ assertResult(result, "/vue3_admin_uniapp_one");
+ }
+
+}
diff --git a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java
index 8cd8fe7..4b14aec 100644
--- a/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java
+++ b/yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImplTest.java
@@ -5,6 +5,7 @@
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
+import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileCreateReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
@@ -22,6 +23,7 @@
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS;
+import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_PATH_INVALID;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.*;
@@ -173,6 +175,16 @@
}
@Test
+ public void testDeleteFile_pathInvalid() {
+ // mock 鏁版嵁
+ FileDO dbFile = randomPojo(FileDO.class, o -> o.setConfigId(10L).setPath("../tudou.jpg"));
+ fileMapper.insert(dbFile);
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> fileService.deleteFile(dbFile.getId()), FILE_PATH_INVALID);
+ }
+
+ @Test
public void testGetFileContent() throws Exception {
// 鍑嗗鍙傛暟
Long configId = 10L;
@@ -187,6 +199,76 @@
byte[] result = fileService.getFileContent(configId, path);
// 鏂█
assertSame(result, content);
+ }
+
+ @Test
+ public void testGetFileContent_pathInvalid() {
+ // 鍑嗗鍙傛暟
+ Long configId = 10L;
+ String path = "../tudou.jpg";
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> fileService.getFileContent(configId, path), FILE_PATH_INVALID);
+ }
+
+ @Test
+ public void testGetFileByConfigIdAndPath() {
+ // mock 鏁版嵁
+ FileDO dbFile = randomPojo(FileDO.class, o -> o.setConfigId(10L).setPath("avatar/涓枃 100%+鏂囦欢.jpg"));
+ fileMapper.insert(dbFile);
+ FileDO latestFile = ObjectUtils.cloneIgnoreId(dbFile, o -> o.setName("鏈�鏂版枃浠跺悕.jpg"));
+ fileMapper.insert(latestFile);
+ fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("avatar/other.jpg")));
+ fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setConfigId(20L)));
+
+ // 璋冪敤
+ FileDO result = fileService.getFileByConfigIdAndPath(10L, "avatar/涓枃 100%+鏂囦欢.jpg");
+
+ // 鏂█
+ AssertUtils.assertPojoEquals(latestFile, result);
+ }
+
+ @Test
+ public void testCreateFileByPresignedPath_success() {
+ // 鍑嗗鍙傛暟
+ FileCreateReqVO reqVO = randomPojo(FileCreateReqVO.class, o -> {
+ o.setPath("avatar/test.jpg");
+ o.setName("test.jpg");
+ o.setUrl("https://www.iocoder.cn/test.jpg?token=123");
+ });
+
+ // 璋冪敤
+ Long fileId = fileService.createFile(reqVO);
+
+ // 鏂█
+ FileDO file = fileMapper.selectById(fileId);
+ assertEquals("avatar/test.jpg", file.getPath());
+ assertEquals("test.jpg", file.getName());
+ assertEquals("https://www.iocoder.cn/test.jpg", file.getUrl());
+ }
+
+ @Test
+ public void testCreateFileByPresignedPath_nameInvalid() {
+ // 鍑嗗鍙傛暟
+ FileCreateReqVO reqVO = randomPojo(FileCreateReqVO.class, o -> {
+ o.setPath("avatar/test.jpg");
+ o.setName("../test.jpg");
+ });
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> fileService.createFile(reqVO), FILE_PATH_INVALID);
+ }
+
+ @Test
+ public void testCreateFileByPresignedPath_pathInvalid() {
+ // 鍑嗗鍙傛暟
+ FileCreateReqVO reqVO = randomPojo(FileCreateReqVO.class, o -> {
+ o.setPath("../test.jpg");
+ o.setName("test.jpg");
+ });
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> fileService.createFile(reqVO), FILE_PATH_INVALID);
}
@Test
@@ -343,6 +425,28 @@
}
@Test
+ public void testGenerateUploadPath_FileNameInvalid() {
+ // 鍑嗗鍙傛暟
+ String name = "../test.jpg";
+ String directory = "avatar";
+ FileServiceImpl.PATH_PREFIX_DATE_ENABLE = false;
+ FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = false;
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> fileService.generateUploadPath(name, directory), FILE_PATH_INVALID);
+ }
+
+ @Test
+ public void testGenerateUploadPath_DirectoryInvalid() {
+ // 鍑嗗鍙傛暟
+ String name = "test.jpg";
+ String directory = "../avatar";
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> fileService.generateUploadPath(name, directory), FILE_PATH_INVALID);
+ }
+
+ @Test
public void testGenerateUploadPath_DirectoryEmpty() {
// 鍑嗗鍙傛暟
String name = "test.jpg";
diff --git a/yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vue2_master_inner/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vue2_master_inner/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vue2_master_inner/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vue2_master_inner/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vue2_master_normal/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vue2_master_normal/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vue2_master_normal/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vue2_master_normal/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/assert.json b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/assert.json
new file mode 100644
index 0000000..dab3f92
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/assert.json
@@ -0,0 +1,55 @@
+[ {
+ "contentPath" : "java/InfraStudentPageReqVO",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
+}, {
+ "contentPath" : "java/InfraStudentRespVO",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
+}, {
+ "contentPath" : "java/InfraStudentSaveReqVO",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
+}, {
+ "contentPath" : "java/InfraStudentController",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
+}, {
+ "contentPath" : "java/InfraStudentDO",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
+}, {
+ "contentPath" : "java/InfraStudentMapper",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
+}, {
+ "contentPath" : "xml/InfraStudentMapper",
+ "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
+}, {
+ "contentPath" : "java/InfraStudentServiceImpl",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
+}, {
+ "contentPath" : "java/InfraStudentService",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
+}, {
+ "contentPath" : "java/InfraStudentServiceImplTest",
+ "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
+}, {
+ "contentPath" : "java/ErrorCodeConstants_鎵嬪姩鎿嶄綔",
+ "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_鎵嬪姩鎿嶄綔.java"
+}, {
+ "contentPath" : "sql/sql",
+ "filePath" : "sql/sql.sql"
+}, {
+ "contentPath" : "sql/h2",
+ "filePath" : "sql/h2.sql"
+}, {
+ "contentPath" : "ts/index",
+ "filePath" : "yudao-ui-admin-uniapp/src/api/infra/demo/index.ts"
+}, {
+ "contentPath" : "vue/index",
+ "filePath" : "yudao-ui-admin-uniapp/src/pages-infra/demo/index.vue"
+}, {
+ "contentPath" : "vue/search-form",
+ "filePath" : "yudao-ui-admin-uniapp/src/pages-infra/demo/components/search-form.vue"
+}, {
+ "contentPath" : "vue/form/index",
+ "filePath" : "yudao-ui-admin-uniapp/src/pages-infra/demo/form/index.vue"
+}, {
+ "contentPath" : "vue/detail/index",
+ "filePath" : "yudao-ui-admin-uniapp/src/pages-infra/demo/detail/index.vue"
+} ]
\ No newline at end of file
diff --git "a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/ErrorCodeConstants_\346\211\213\345\212\250\346\223\215\344\275\234" "b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/ErrorCodeConstants_\346\211\213\345\212\250\346\223\215\344\275\234"
new file mode 100644
index 0000000..a4df7d2
--- /dev/null
+++ "b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/ErrorCodeConstants_\346\211\213\345\212\250\346\223\215\344\275\234"
@@ -0,0 +1,3 @@
+// TODO 寰呭姙锛氳灏嗕笅闈㈢殑閿欒鐮佸鍒跺埌 yudao-module-infra 妯″潡鐨� ErrorCodeConstants 绫讳腑銆傛敞鎰忥紝璇风粰鈥淭ODO 琛ュ厖缂栧彿鈥濊缃竴涓敊璇爜缂栧彿锛侊紒锛�
+// ========== 瀛︾敓 TODO 琛ュ厖缂栧彿 ==========
+ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 琛ュ厖缂栧彿, "瀛︾敓涓嶅瓨鍦�");
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentController b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentController
new file mode 100644
index 0000000..cb35199
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentController
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.infra.controller.admin.demo;
+
+import org.springframework.web.bind.annotation.*;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import jakarta.validation.constraints.*;
+import jakarta.validation.*;
+import jakarta.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
+import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
+import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
+
+@Tag(name = "绠$悊鍚庡彴 - 瀛︾敓")
+@RestController
+@RequestMapping("/infra/student")
+@Validated
+public class InfraStudentController {
+
+ @Resource
+ private InfraStudentService studentService;
+
+ @PostMapping("/create")
+ @Operation(summary = "鍒涘缓瀛︾敓")
+ @PreAuthorize("@ss.hasPermission('infra:student:create')")
+ public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
+ return success(studentService.createStudent(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "鏇存柊瀛︾敓")
+ @PreAuthorize("@ss.hasPermission('infra:student:update')")
+ public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
+ studentService.updateStudent(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎瀛︾敓")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('infra:student:delete')")
+ public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
+ studentService.deleteStudent(id);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete-list")
+ @Parameter(name = "ids", description = "缂栧彿", required = true)
+ @Operation(summary = "鎵归噺鍒犻櫎瀛︾敓")
+ @PreAuthorize("@ss.hasPermission('infra:student:delete')")
+ public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
+ studentService.deleteStudentListByIds(ids);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱瀛︾敓")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('infra:student:query')")
+ public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
+ InfraStudentDO student = studentService.getStudent(id);
+ return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱瀛︾敓鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('infra:student:query')")
+ public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
+ PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "瀵煎嚭瀛︾敓 Excel")
+ @PreAuthorize("@ss.hasPermission('infra:student:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
+ // 瀵煎嚭 Excel
+ ExcelUtils.write(response, "瀛︾敓.xls", "鏁版嵁", InfraStudentRespVO.class,
+ BeanUtils.toBean(list, InfraStudentRespVO.class));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentDO b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentDO
new file mode 100644
index 0000000..f39fef2
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentDO
@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 瀛︾敓 DO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@TableName("infra_student")
+@KeySequence("infra_student_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷銆傚鏋滄槸 MySQL 绛夋暟鎹簱锛屽彲涓嶅啓銆�
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class InfraStudentDO extends BaseDO {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 鍚嶅瓧
+ */
+ private String name;
+ /**
+ * 绠�浠�
+ */
+ private String description;
+ /**
+ * 鍑虹敓鏃ユ湡
+ */
+ private LocalDateTime birthday;
+ /**
+ * 鎬у埆
+ *
+ * 鏋氫妇 {@link TODO system_user_sex 瀵瑰簲鐨勭被}
+ */
+ private Integer sex;
+ /**
+ * 鏄惁鏈夋晥
+ *
+ * 鏋氫妇 {@link TODO infra_boolean_string 瀵瑰簲鐨勭被}
+ */
+ private Boolean enabled;
+ /**
+ * 澶村儚
+ */
+ private String avatar;
+ /**
+ * 闄勪欢
+ */
+ private String video;
+ /**
+ * 澶囨敞
+ */
+ private String memo;
+
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentMapper b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentMapper
new file mode 100644
index 0000000..34e70a0
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentMapper
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.infra.dal.mysql.demo;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
+
+/**
+ * 瀛︾敓 Mapper
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Mapper
+public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
+
+ default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
+ .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
+ .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
+ .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
+ .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
+ .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(InfraStudentDO::getId));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentPageReqVO b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentPageReqVO
new file mode 100644
index 0000000..52d7a23
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentPageReqVO
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - 瀛︾敓鍒嗛〉 Request VO")
+@Data
+public class InfraStudentPageReqVO extends PageParam {
+
+ @Schema(description = "鍚嶅瓧", example = "鑺嬪ご")
+ private String name;
+
+ @Schema(description = "鍑虹敓鏃ユ湡")
+ private LocalDateTime birthday;
+
+ @Schema(description = "鎬у埆", example = "1")
+ private Integer sex;
+
+ @Schema(description = "鏄惁鏈夋晥", example = "true")
+ private Boolean enabled;
+
+ @Schema(description = "鍒涘缓鏃堕棿")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentRespVO b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentRespVO
new file mode 100644
index 0000000..12166f4
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentRespVO
@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import cn.idev.excel.annotation.*;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+
+@Schema(description = "绠$悊鍚庡彴 - 瀛︾敓 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class InfraStudentRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @ExcelProperty("缂栧彿")
+ private Long id;
+
+ @Schema(description = "鍚嶅瓧", requiredMode = Schema.RequiredMode.REQUIRED, example = "鑺嬪ご")
+ @ExcelProperty("鍚嶅瓧")
+ private String name;
+
+ @Schema(description = "绠�浠�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎴戞槸浠嬬粛")
+ @ExcelProperty("绠�浠�")
+ private String description;
+
+ @Schema(description = "鍑虹敓鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("鍑虹敓鏃ユ湡")
+ private LocalDateTime birthday;
+
+ @Schema(description = "鎬у埆", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @ExcelProperty(value = "鎬у埆", converter = DictConvert.class)
+ @DictFormat("system_user_sex") // TODO 浠g爜浼樺寲锛氬缓璁缃埌瀵瑰簲鐨� DictTypeConstants 鏋氫妇绫讳腑
+ private Integer sex;
+
+ @Schema(description = "鏄惁鏈夋晥", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+ @ExcelProperty(value = "鏄惁鏈夋晥", converter = DictConvert.class)
+ @DictFormat("infra_boolean_string") // TODO 浠g爜浼樺寲锛氬缓璁缃埌瀵瑰簲鐨� DictTypeConstants 鏋氫妇绫讳腑
+ private Boolean enabled;
+
+ @Schema(description = "澶村儚", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
+ @ExcelProperty("澶村儚")
+ private String avatar;
+
+ @Schema(description = "闄勪欢", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
+ @ExcelProperty("闄勪欢")
+ private String video;
+
+ @Schema(description = "澶囨敞", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎴戞槸澶囨敞")
+ @ExcelProperty("澶囨敞")
+ private String memo;
+
+ @Schema(description = "鍒涘缓鏃堕棿")
+ @ExcelProperty("鍒涘缓鏃堕棿")
+ private LocalDateTime createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentSaveReqVO b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentSaveReqVO
new file mode 100644
index 0000000..cdb6e92
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentSaveReqVO
@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 瀛︾敓鏂板/淇敼 Request VO")
+@Data
+public class InfraStudentSaveReqVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鍚嶅瓧", requiredMode = Schema.RequiredMode.REQUIRED, example = "鑺嬪ご")
+ @NotEmpty(message = "鍚嶅瓧涓嶈兘涓虹┖")
+ private String name;
+
+ @Schema(description = "绠�浠�", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎴戞槸浠嬬粛")
+ @NotEmpty(message = "绠�浠嬩笉鑳戒负绌�")
+ private String description;
+
+ @Schema(description = "鍑虹敓鏃ユ湡", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "鍑虹敓鏃ユ湡涓嶈兘涓虹┖")
+ private LocalDateTime birthday;
+
+ @Schema(description = "鎬у埆", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "鎬у埆涓嶈兘涓虹┖")
+ private Integer sex;
+
+ @Schema(description = "鏄惁鏈夋晥", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+ @NotNull(message = "鏄惁鏈夋晥涓嶈兘涓虹┖")
+ private Boolean enabled;
+
+ @Schema(description = "澶村儚", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
+ @NotEmpty(message = "澶村儚涓嶈兘涓虹┖")
+ private String avatar;
+
+ @Schema(description = "闄勪欢", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
+ @NotEmpty(message = "闄勪欢涓嶈兘涓虹┖")
+ private String video;
+
+ @Schema(description = "澶囨敞", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎴戞槸澶囨敞")
+ @NotEmpty(message = "澶囨敞涓嶈兘涓虹┖")
+ private String memo;
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentService b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentService
new file mode 100644
index 0000000..cab590e
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentService
@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.infra.service.demo;
+
+import java.util.*;
+import jakarta.validation.*;
+import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
+import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+
+/**
+ * 瀛︾敓 Service 鎺ュ彛
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public interface InfraStudentService {
+
+ /**
+ * 鍒涘缓瀛︾敓
+ *
+ * @param createReqVO 鍒涘缓淇℃伅
+ * @return 缂栧彿
+ */
+ Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
+
+ /**
+ * 鏇存柊瀛︾敓
+ *
+ * @param updateReqVO 鏇存柊淇℃伅
+ */
+ void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
+
+ /**
+ * 鍒犻櫎瀛︾敓
+ *
+ * @param id 缂栧彿
+ */
+ void deleteStudent(Long id);
+
+ /**
+ * 鎵归噺鍒犻櫎瀛︾敓
+ *
+ * @param ids 缂栧彿
+ */
+ void deleteStudentListByIds(List<Long> ids);
+
+ /**
+ * 鑾峰緱瀛︾敓
+ *
+ * @param id 缂栧彿
+ * @return 瀛︾敓
+ */
+ InfraStudentDO getStudent(Long id);
+
+ /**
+ * 鑾峰緱瀛︾敓鍒嗛〉
+ *
+ * @param pageReqVO 鍒嗛〉鏌ヨ
+ * @return 瀛︾敓鍒嗛〉
+ */
+ PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentServiceImpl
new file mode 100644
index 0000000..38b346a
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentServiceImpl
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.infra.service.demo;
+
+import cn.hutool.core.collection.CollUtil;
+import org.springframework.stereotype.Service;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
+import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
+import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
+
+/**
+ * 瀛︾敓 Service 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Service
+@Validated
+public class InfraStudentServiceImpl implements InfraStudentService {
+
+ @Resource
+ private InfraStudentMapper studentMapper;
+
+ @Override
+ public Long createStudent(InfraStudentSaveReqVO createReqVO) {
+ // 鎻掑叆
+ InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
+ studentMapper.insert(student);
+
+ // 杩斿洖
+ return student.getId();
+ }
+
+ @Override
+ public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
+ // 鏍¢獙瀛樺湪
+ validateStudentExists(updateReqVO.getId());
+ // 鏇存柊
+ InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
+ studentMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteStudent(Long id) {
+ // 鏍¢獙瀛樺湪
+ validateStudentExists(id);
+ // 鍒犻櫎
+ studentMapper.deleteById(id);
+ }
+
+ @Override
+ public void deleteStudentListByIds(List<Long> ids) {
+ // 鍒犻櫎
+ studentMapper.deleteByIds(ids);
+ }
+
+
+ private void validateStudentExists(Long id) {
+ if (studentMapper.selectById(id) == null) {
+ throw exception(STUDENT_NOT_EXISTS);
+ }
+ }
+
+ @Override
+ public InfraStudentDO getStudent(Long id) {
+ return studentMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
+ return studentMapper.selectPage(pageReqVO);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentServiceImplTest b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentServiceImplTest
new file mode 100644
index 0000000..f1d3bb9
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/java/InfraStudentServiceImplTest
@@ -0,0 +1,145 @@
+package cn.iocoder.yudao.module.infra.service.demo;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import jakarta.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
+import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
+import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+import java.time.LocalDateTime;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link InfraStudentServiceImpl} 鐨勫崟鍏冩祴璇曠被
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Import(InfraStudentServiceImpl.class)
+public class InfraStudentServiceImplTest extends BaseDbUnitTest {
+
+ @Resource
+ private InfraStudentServiceImpl studentService;
+
+ @Resource
+ private InfraStudentMapper studentMapper;
+
+ @Test
+ public void testCreateStudent_success() {
+ // 鍑嗗鍙傛暟
+ InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
+
+ // 璋冪敤
+ Long studentId = studentService.createStudent(createReqVO);
+ // 鏂█
+ assertNotNull(studentId);
+ // 鏍¢獙璁板綍鐨勫睘鎬ф槸鍚︽纭�
+ InfraStudentDO student = studentMapper.selectById(studentId);
+ assertPojoEquals(createReqVO, student, "id");
+ }
+
+ @Test
+ public void testUpdateStudent_success() {
+ // mock 鏁版嵁
+ InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
+ studentMapper.insert(dbStudent);// @Sql: 鍏堟彃鍏ュ嚭涓�鏉″瓨鍦ㄧ殑鏁版嵁
+ // 鍑嗗鍙傛暟
+ InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
+ o.setId(dbStudent.getId()); // 璁剧疆鏇存柊鐨� ID
+ });
+
+ // 璋冪敤
+ studentService.updateStudent(updateReqVO);
+ // 鏍¢獙鏄惁鏇存柊姝g‘
+ InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 鑾峰彇鏈�鏂扮殑
+ assertPojoEquals(updateReqVO, student);
+ }
+
+ @Test
+ public void testUpdateStudent_notExists() {
+ // 鍑嗗鍙傛暟
+ InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
+
+ // 璋冪敤, 骞舵柇瑷�寮傚父
+ assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
+ }
+
+ @Test
+ public void testDeleteStudent_success() {
+ // mock 鏁版嵁
+ InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
+ studentMapper.insert(dbStudent);// @Sql: 鍏堟彃鍏ュ嚭涓�鏉″瓨鍦ㄧ殑鏁版嵁
+ // 鍑嗗鍙傛暟
+ Long id = dbStudent.getId();
+
+ // 璋冪敤
+ studentService.deleteStudent(id);
+ // 鏍¢獙鏁版嵁涓嶅瓨鍦ㄤ簡
+ assertNull(studentMapper.selectById(id));
+ }
+
+ @Test
+ public void testDeleteStudent_notExists() {
+ // 鍑嗗鍙傛暟
+ Long id = randomLongId();
+
+ // 璋冪敤, 骞舵柇瑷�寮傚父
+ assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
+ }
+
+ @Test
+ @Disabled // TODO 璇蜂慨鏀� null 涓洪渶瑕佺殑鍊硷紝鐒跺悗鍒犻櫎 @Disabled 娉ㄨВ
+ public void testGetStudentPage() {
+ // mock 鏁版嵁
+ InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 绛変細鏌ヨ鍒�
+ o.setName(null);
+ o.setBirthday(null);
+ o.setSex(null);
+ o.setEnabled(null);
+ o.setCreateTime(null);
+ });
+ studentMapper.insert(dbStudent);
+ // 娴嬭瘯 name 涓嶅尮閰�
+ studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
+ // 娴嬭瘯 birthday 涓嶅尮閰�
+ studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
+ // 娴嬭瘯 sex 涓嶅尮閰�
+ studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
+ // 娴嬭瘯 enabled 涓嶅尮閰�
+ studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
+ // 娴嬭瘯 createTime 涓嶅尮閰�
+ studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
+ // 鍑嗗鍙傛暟
+ InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
+ reqVO.setName(null);
+ reqVO.setBirthday(null);
+ reqVO.setSex(null);
+ reqVO.setEnabled(null);
+ reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+
+ // 璋冪敤
+ PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
+ // 鏂█
+ assertEquals(1, pageResult.getTotal());
+ assertEquals(1, pageResult.getList().size());
+ assertPojoEquals(dbStudent, pageResult.getList().get(0));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/sql/h2 b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/sql/h2
new file mode 100644
index 0000000..6c1875f
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/sql/h2
@@ -0,0 +1,17 @@
+-- 灏嗚寤鸿〃 SQL 璇彞锛屾坊鍔犲埌 yudao-module-infra-biz 妯″潡鐨� test/resources/sql/create_tables.sql 鏂囦欢閲�
+CREATE TABLE IF NOT EXISTS "infra_student" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+ "name" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "birthday" varchar NOT NULL,
+ "sex" int NOT NULL,
+ "enabled" bit NOT NULL,
+ "avatar" varchar NOT NULL,
+ "video" varchar NOT NULL,
+ "memo" varchar NOT NULL,
+ "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY ("id")
+) COMMENT '瀛︾敓琛�';
+
+-- 灏嗚鍒犺〃 SQL 璇彞锛屾坊鍔犲埌 yudao-module-infra-biz 妯″潡鐨� test/resources/sql/clean.sql 鏂囦欢閲�
+DELETE FROM "infra_student";
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/sql/sql b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/sql/sql
new file mode 100644
index 0000000..c0e5f74
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/sql/sql
@@ -0,0 +1,54 @@
+-- 鑿滃崟 SQL
+INSERT INTO system_menu(
+ name, permission, type, sort, parent_id,
+ path, icon, component, status, component_name
+)
+VALUES (
+ '瀛︾敓绠$悊', '', 2, 0, 888,
+ 'student', '', 'infra/demo/index', 0, 'InfraStudent'
+);
+
+-- 鎸夐挳鐖惰彍鍗旾D
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 鎸夐挳 SQL
+INSERT INTO system_menu(
+ name, permission, type, sort, parent_id,
+ path, icon, component, status
+)
+VALUES (
+ '瀛︾敓鏌ヨ', 'infra:student:query', 3, 1, @parentId,
+ '', '', '', 0
+);
+INSERT INTO system_menu(
+ name, permission, type, sort, parent_id,
+ path, icon, component, status
+)
+VALUES (
+ '瀛︾敓鍒涘缓', 'infra:student:create', 3, 2, @parentId,
+ '', '', '', 0
+);
+INSERT INTO system_menu(
+ name, permission, type, sort, parent_id,
+ path, icon, component, status
+)
+VALUES (
+ '瀛︾敓鏇存柊', 'infra:student:update', 3, 3, @parentId,
+ '', '', '', 0
+);
+INSERT INTO system_menu(
+ name, permission, type, sort, parent_id,
+ path, icon, component, status
+)
+VALUES (
+ '瀛︾敓鍒犻櫎', 'infra:student:delete', 3, 4, @parentId,
+ '', '', '', 0
+);
+INSERT INTO system_menu(
+ name, permission, type, sort, parent_id,
+ path, icon, component, status
+)
+VALUES (
+ '瀛︾敓瀵煎嚭', 'infra:student:export', 3, 5, @parentId,
+ '', '', '', 0
+);
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/ts/index b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/ts/index
new file mode 100644
index 0000000..da8643a
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/ts/index
@@ -0,0 +1,41 @@
+import type { PageParam, PageResult } from '@/http/types'
+import { http } from '@/http/http'
+
+/** 瀛︾敓淇℃伅 */
+export interface Student {
+ id?: number
+ name: string
+ description: string
+ birthday: Date
+ sex: number
+ enabled: boolean
+ avatar: string
+ video: string
+ memo: string
+ createTime?: Date
+}
+
+/** 鑾峰彇瀛︾敓鍒嗛〉鍒楄〃 */
+export function getStudentPage(params: PageParam) {
+ return http.get<PageResult<Student>>('/infra/student/page', params)
+}
+
+/** 鑾峰彇瀛︾敓璇︽儏 */
+export function getStudent(id: number) {
+ return http.get<Student>(`/infra/student/get?id=${id}`)
+}
+
+/** 鍒涘缓瀛︾敓 */
+export function createStudent(data: Student) {
+ return http.post<number>('/infra/student/create', data)
+}
+
+/** 鏇存柊瀛︾敓 */
+export function updateStudent(data: Student) {
+ return http.put<boolean>('/infra/student/update', data)
+}
+
+/** 鍒犻櫎瀛︾敓 */
+export function deleteStudent(id: number) {
+ return http.delete<boolean>(`/infra/student/delete?id=${id}`)
+}
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/detail/index b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/detail/index
new file mode 100644
index 0000000..d6972ec
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/detail/index
@@ -0,0 +1,140 @@
+<template>
+ <view class="yd-page-container">
+ <!-- 椤堕儴瀵艰埅鏍� -->
+ <wd-navbar
+ title="瀛︾敓璇︽儏"
+ left-arrow placeholder safe-area-inset-top fixed
+ @click-left="handleBack"
+ />
+
+ <!-- 璇︽儏鍐呭 -->
+ <view>
+ <wd-cell-group border>
+ <wd-cell title="缂栧彿" :value="formData?.id ?? '-'" />
+ <wd-cell title="鍚嶅瓧" :value="formData?.name ?? '-'" />
+ <wd-cell title="绠�浠�" :value="formData?.description ?? '-'" />
+ <wd-cell title="鍑虹敓鏃ユ湡" :value="formatDateTime(formData?.birthday) || '-'" />
+ <wd-cell title="鎬у埆">
+ <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="formData?.sex" />
+ </wd-cell>
+ <wd-cell title="鏄惁鏈夋晥">
+ <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="formData?.enabled" />
+ </wd-cell>
+ <wd-cell title="澶村儚" :value="formData?.avatar ?? '-'" />
+ <wd-cell title="闄勪欢" :value="formData?.video ?? '-'" />
+ <wd-cell title="澶囨敞" :value="formData?.memo ?? '-'" />
+ <wd-cell title="鍒涘缓鏃堕棿" :value="formatDateTime(formData?.createTime) || '-'" />
+ </wd-cell-group>
+ </view>
+
+ <!-- 搴曢儴鎿嶄綔鎸夐挳 -->
+ <view class="yd-detail-footer">
+ <view class="yd-detail-footer-actions">
+ <wd-button
+ v-if="hasAccessByCodes(['infra:student:update'])"
+ class="flex-1" type="warning" @click="handleEdit"
+ >
+ 缂栬緫
+ </wd-button>
+ <wd-button
+ v-if="hasAccessByCodes(['infra:student:delete'])"
+ class="flex-1" type="error" :loading="deleting" @click="handleDelete"
+ >
+ 鍒犻櫎
+ </wd-button>
+ </view>
+ </view>
+ </view>
+</template>
+
+<script lang="ts" setup>
+import type { Student } from '@/api/infra/demo'
+import { onUnload } from '@dcloudio/uni-app'
+import { onMounted, ref } from 'vue'
+import { useToast } from '@wot-ui/ui/components/wd-toast'
+import { deleteStudent, getStudent } from '@/api/infra/demo'
+import { useAccess } from '@/hooks/useAccess'
+import { delay, navigateBackPlus } from '@/utils'
+import { DICT_TYPE } from '@/utils/constants'
+import { formatDateTime } from '@/utils/date'
+
+const props = defineProps<{
+ id?: number | any
+}>()
+
+definePage({
+ style: {
+ navigationBarTitleText: '',
+ navigationStyle: 'custom',
+ },
+})
+
+const { hasAccessByCodes } = useAccess()
+const toast = useToast()
+const formData = ref<Student>() // 璇︽儏鏁版嵁
+const deleting = ref(false) // 鍒犻櫎鐘舵��
+
+/** 杩斿洖涓婁竴椤� */
+function handleBack() {
+ navigateBackPlus('/pages-infra/demo/index')
+}
+
+/** 鍔犺浇瀛︾敓璇︽儏 */
+async function getDetail() {
+ if (!props.id || deleting.value) {
+ return
+ }
+ try {
+ toast.loading('鍔犺浇涓�...')
+ formData.value = await getStudent(props.id)
+ } finally {
+ toast.close()
+ }
+}
+
+/** 缂栬緫瀛︾敓 */
+function handleEdit() {
+ uni.navigateTo({
+ url: `/pages-infra/demo/form/index?id=${props.id}`,
+ })
+}
+
+/** 鍒犻櫎瀛︾敓 */
+function handleDelete() {
+ if (!props.id) {
+ return
+ }
+ uni.showModal({
+ title: '鎻愮ず',
+ content: '纭畾瑕佸垹闄よ瀛︾敓鍚楋紵',
+ success: async (res) => {
+ if (!res.confirm) {
+ return
+ }
+ deleting.value = true
+ try {
+ await deleteStudent(props.id)
+ toast.success('鍒犻櫎鎴愬姛')
+ uni.$emit('infra:demo:reload')
+ delay(handleBack)
+ } finally {
+ deleting.value = false
+ }
+ },
+ })
+}
+
+/** 鍒濆鍖� */
+onMounted(() => {
+ uni.$on('infra:demo:reload', getDetail)
+ getDetail()
+})
+
+/** 鍗歌浇 */
+onUnload(() => {
+ uni.$off('infra:demo:reload', getDetail)
+})
+</script>
+
+<style lang="scss" scoped>
+</style>
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/form/index b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/form/index
new file mode 100644
index 0000000..06e1a54
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/form/index
@@ -0,0 +1,187 @@
+<template>
+ <view class="yd-page-container">
+ <!-- 椤堕儴瀵艰埅鏍� -->
+ <wd-navbar
+ :title="getTitle"
+ left-arrow placeholder safe-area-inset-top fixed
+ @click-left="handleBack"
+ />
+
+ <!-- 琛ㄥ崟鍖哄煙 -->
+ <view>
+ <wd-form ref="formRef" :model="formData" :schema="formSchema">
+ <wd-cell-group border>
+ <wd-form-item title="鍚嶅瓧" title-width="180rpx" prop="name">
+ <wd-input
+ v-model="formData.name"
+ clearable
+ placeholder="璇疯緭鍏ュ悕瀛�"
+ />
+ </wd-form-item>
+ <wd-form-item title="绠�浠�" title-width="180rpx" prop="description">
+ <wd-textarea
+ v-model="formData.description"
+ clearable
+ placeholder="璇疯緭鍏ョ畝浠�"
+ :maxlength="200"
+ show-word-limit
+ />
+ </wd-form-item>
+ <wd-form-item
+ title="鍑虹敓鏃ユ湡"
+ title-width="180rpx"
+ prop="birthday"
+ is-link
+ :value="formatDateTime(formData.birthday)"
+ placeholder="璇烽�夋嫨鍑虹敓鏃ユ湡"
+ @click="birthdayVisible = true"
+ />
+ <wd-datetime-picker
+ v-model="formData.birthday"
+ v-model:visible="birthdayVisible"
+ type="datetime"
+ />
+ <yd-form-picker
+ v-model="formData.sex"
+ label="鎬у埆"
+ label-width="180rpx"
+ prop="sex"
+ :dict-type="DICT_TYPE.SYSTEM_USER_SEX"
+ placeholder="璇烽�夋嫨鎬у埆"
+ />
+ <wd-form-item title="鏄惁鏈夋晥" title-width="180rpx" prop="enabled" center>
+ <wd-radio-group v-model="formData.enabled" type="button">
+ <wd-radio
+ v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </wd-form-item>
+ <wd-form-item title="澶村儚" title-width="180rpx" prop="avatar">
+ <yd-upload-img v-model="formData.avatar" directory="infra/demo" />
+ </wd-form-item>
+ <wd-form-item title="闄勪欢" title-width="180rpx" prop="video">
+ <yd-upload-file v-model="formData.video" directory="infra/demo" />
+ </wd-form-item>
+ <wd-form-item title="澶囨敞" title-width="180rpx" prop="memo">
+ <wd-input
+ v-model="formData.memo"
+ clearable
+ placeholder="璇疯緭鍏ュ娉�"
+ />
+ </wd-form-item>
+ </wd-cell-group>
+ </wd-form>
+ </view>
+
+ <!-- 搴曢儴淇濆瓨鎸夐挳 -->
+ <view class="yd-detail-footer">
+ <wd-button
+ type="primary"
+ block
+ :loading="formLoading"
+ @click="handleSubmit"
+ >
+ 淇濆瓨
+ </wd-button>
+ </view>
+ </view>
+</template>
+
+<script lang="ts" setup>
+import type { FormInstance } from '@wot-ui/ui/components/wd-form/types'
+import type { Student } from '@/api/infra/demo'
+import { computed, onMounted, ref } from 'vue'
+import { useToast } from '@wot-ui/ui/components/wd-toast'
+import { createStudent, getStudent, updateStudent } from '@/api/infra/demo'
+import { getBoolDictOptions } from '@/hooks/useDict'
+import { delay, navigateBackPlus } from '@/utils'
+import { DICT_TYPE } from '@/utils/constants'
+import { formatDateTime } from '@/utils/date'
+import { createFormSchema } from '@/utils/wot'
+
+const props = defineProps<{
+ id?: number | any
+}>()
+
+definePage({
+ style: {
+ navigationBarTitleText: '',
+ navigationStyle: 'custom',
+ },
+})
+
+const toast = useToast()
+const getTitle = computed(() => props.id ? '缂栬緫瀛︾敓' : '鏂板瀛︾敓')
+const formLoading = ref(false) // 琛ㄥ崟鎻愪氦鐘舵��
+const formData = ref<Student>({
+ id: undefined,
+ name: '',
+ description: '',
+ birthday: undefined,
+ sex: 0,
+ enabled: false,
+ avatar: '',
+ video: '',
+ memo: '',
+}) // 琛ㄥ崟鏁版嵁
+const birthdayVisible = ref(false) // 鍑虹敓鏃ユ湡閫夋嫨鍣ㄧ姸鎬�
+const formSchema = createFormSchema({
+ name: [{ required: true, message: '鍚嶅瓧涓嶈兘涓虹┖' }],
+ description: [{ required: true, message: '绠�浠嬩笉鑳戒负绌�' }],
+ birthday: [{ required: true, message: '鍑虹敓鏃ユ湡涓嶈兘涓虹┖' }],
+ sex: [{ required: true, message: '鎬у埆涓嶈兘涓虹┖' }],
+ enabled: [{ required: true, message: '鏄惁鏈夋晥涓嶈兘涓虹┖' }],
+ avatar: [{ required: true, message: '澶村儚涓嶈兘涓虹┖' }],
+ video: [{ required: true, message: '闄勪欢涓嶈兘涓虹┖' }],
+ memo: [{ required: true, message: '澶囨敞涓嶈兘涓虹┖' }],
+}) // 琛ㄥ崟鏍¢獙瑙勫垯
+const formRef = ref<FormInstance>() // 琛ㄥ崟缁勪欢寮曠敤
+
+/** 杩斿洖涓婁竴椤� */
+function handleBack() {
+ navigateBackPlus('/pages-infra/demo/index')
+}
+
+/** 鍔犺浇瀛︾敓璇︽儏 */
+async function getDetail() {
+ if (!props.id) {
+ return
+ }
+ formData.value = await getStudent(props.id)
+}
+
+/** 鎻愪氦琛ㄥ崟 */
+async function handleSubmit() {
+ const { valid } = await formRef.value.validate()
+ if (!valid) {
+ return
+ }
+
+ formLoading.value = true
+ try {
+ if (props.id) {
+ await updateStudent(formData.value)
+ toast.success('淇敼鎴愬姛')
+ } else {
+ await createStudent(formData.value)
+ toast.success('鏂板鎴愬姛')
+ }
+ uni.$emit('infra:demo:reload')
+ delay(handleBack)
+ } finally {
+ formLoading.value = false
+ }
+}
+
+/** 鍒濆鍖� */
+onMounted(() => {
+ getDetail()
+})
+</script>
+
+<style lang="scss" scoped>
+</style>
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/index b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/index
new file mode 100644
index 0000000..acb1b87
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/index
@@ -0,0 +1,169 @@
+<template>
+ <view class="yd-page-container yd-page-container-paging">
+ <!-- 椤堕儴瀵艰埅鏍� -->
+ <wd-navbar
+ title="瀛︾敓绠$悊"
+ left-arrow placeholder safe-area-inset-top fixed
+ @click-left="handleBack"
+ />
+
+ <!-- 鎼滅储缁勪欢 -->
+ <SearchForm @search="handleQuery" @reset="handleReset" />
+
+ <!-- 瀛︾敓鍒楄〃 -->
+ <z-paging
+ ref="pagingRef"
+ v-model="list"
+ :fixed="false"
+ class="min-h-0 flex-1"
+ :default-page-size="10"
+ :refresher-enabled="true"
+ :inside-more="true"
+ :loading-more-default-as-loading="true"
+ empty-view-text="鏆傛棤瀛︾敓鏁版嵁"
+ @query="queryList"
+ >
+ <view class="p-24rpx">
+ <view
+ v-for="item in list"
+ :key="item.id"
+ class="mb-24rpx overflow-hidden rounded-12rpx bg-white shadow-sm"
+ @click="handleDetail(item)"
+ >
+ <view class="p-24rpx">
+ <view class="mb-16rpx flex items-center justify-between">
+ <view class="text-32rpx text-[#333] font-semibold">
+ {{ item.name }}
+ </view>
+ <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="item.sex" />
+ </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">绠�浠嬶細</text>
+ <text class="line-clamp-1">{{ item.description }}</text>
+ </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">鍑虹敓鏃ユ湡锛�</text>
+ <text class="line-clamp-1">{{ formatDateTime(item.birthday) || '-' }}</text>
+ </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">鏄惁鏈夋晥锛�</text>
+ <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="item.enabled" />
+ </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">澶村儚锛�</text>
+ <text class="line-clamp-1">{{ item.avatar }}</text>
+ </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">闄勪欢锛�</text>
+ <text class="line-clamp-1">{{ item.video }}</text>
+ </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">澶囨敞锛�</text>
+ <text class="line-clamp-1">{{ item.memo }}</text>
+ </view>
+ <view class="mb-12rpx flex items-center text-28rpx text-[#666]">
+ <text class="mr-8rpx text-[#999]">鍒涘缓鏃堕棿锛�</text>
+ <text class="line-clamp-1">{{ formatDateTime(item.createTime) || '-' }}</text>
+ </view>
+ </view>
+ </view>
+ </view>
+ </z-paging>
+
+ <!-- 鏂板鎸夐挳 -->
+ <wd-fab
+ v-if="hasAccessByCodes(['infra:student:create'])"
+ position="right-bottom"
+ type="primary"
+ :expandable="false"
+ @click="handleAdd"
+ />
+ </view>
+</template>
+
+<script lang="ts" setup>
+import type { Student } from '@/api/infra/demo'
+import { onUnload } from '@dcloudio/uni-app'
+import { onMounted, ref } from 'vue'
+import { getStudentPage } from '@/api/infra/demo'
+import { useAccess } from '@/hooks/useAccess'
+import { navigateBackPlus } from '@/utils'
+import { DICT_TYPE } from '@/utils/constants'
+import { formatDateTime } from '@/utils/date'
+import SearchForm from './components/search-form.vue'
+
+definePage({
+ style: {
+ navigationBarTitleText: '',
+ navigationStyle: 'custom',
+ },
+})
+
+const { hasAccessByCodes } = useAccess()
+const list = ref<Student[]>([]) // 鍒楄〃鏁版嵁
+const pagingRef = ref<any>() // 鍒嗛〉缁勪欢寮曠敤
+const queryParams = ref<Record<string, any>>({}) // 鏌ヨ鍙傛暟
+
+/** 杩斿洖涓婁竴椤� */
+function handleBack() {
+ navigateBackPlus()
+}
+
+/** 鏌ヨ瀛︾敓鍒楄〃 */
+async function queryList(pageNo: number, pageSize: number) {
+ try {
+ const params = {
+ ...queryParams.value,
+ pageNo,
+ pageSize,
+ }
+ const data = await getStudentPage(params)
+ pagingRef.value?.completeByTotal(data.list, data.total)
+ } catch {
+ pagingRef.value?.complete(false)
+ }
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery(data?: Record<string, any>) {
+ queryParams.value = { ...data }
+ reload()
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function handleReset() {
+ handleQuery()
+}
+
+/** 閲嶆柊鍔犺浇 */
+function reload() {
+ pagingRef.value?.reload()
+}
+
+/** 鏂板瀛︾敓 */
+function handleAdd() {
+ uni.navigateTo({
+ url: '/pages-infra/demo/form/index',
+ })
+}
+
+/** 鏌ョ湅璇︽儏 */
+function handleDetail(item: Student) {
+ uni.navigateTo({
+ url: `/pages-infra/demo/detail/index?id=${item.id}`,
+ })
+}
+
+/** 鍒濆鍖� */
+onMounted(() => {
+ uni.$on('infra:demo:reload', reload)
+})
+
+/** 鍗歌浇 */
+onUnload(() => {
+ uni.$off('infra:demo:reload', reload)
+})
+</script>
+
+<style lang="scss" scoped>
+</style>
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/search-form b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/search-form
new file mode 100644
index 0000000..9571c6e
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/search-form
@@ -0,0 +1,140 @@
+<template>
+ <!-- 鎼滅储妗嗗叆鍙� -->
+ <view @click="visible = true">
+ <wd-search :placeholder="placeholder" hide-cancel disabled />
+ </view>
+
+ <!-- 鎼滅储寮圭獥 -->
+ <wd-popup v-model="visible" position="top" @close="visible = false">
+ <view class="yd-search-form-container" :style="{ paddingTop: `${getNavbarHeight()}px` }">
+ <view class="yd-search-form-item">
+ <view class="yd-search-form-label">
+ 鍚嶅瓧
+ </view>
+ <wd-input
+ v-model="formData.name"
+ placeholder="璇疯緭鍏ュ悕瀛�"
+ clearable
+ />
+ </view>
+ <view class="yd-search-form-item">
+ <view class="yd-search-form-label">
+ 鍑虹敓鏃ユ湡
+ </view>
+ <wd-input
+ v-model="formData.birthday"
+ placeholder="璇疯緭鍏ュ嚭鐢熸棩鏈�"
+ clearable
+ />
+ </view>
+ <view class="yd-search-form-item">
+ <view class="yd-search-form-label">
+ 鎬у埆
+ </view>
+ <wd-radio-group v-model="formData.sex" type="button">
+ <wd-radio :value="-1">
+ 鍏ㄩ儴
+ </wd-radio>
+ <wd-radio
+ v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </view>
+ <view class="yd-search-form-item">
+ <view class="yd-search-form-label">
+ 鏄惁鏈夋晥
+ </view>
+ <wd-radio-group v-model="formData.enabled" type="button">
+ <wd-radio :value="-1">
+ 鍏ㄩ儴
+ </wd-radio>
+ <wd-radio
+ v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
+ :key="dict.value"
+ :value="dict.value"
+ >
+ {{ dict.label }}
+ </wd-radio>
+ </wd-radio-group>
+ </view>
+ <yd-search-date-range v-model="formData.createTime" label="鍒涘缓鏃堕棿" />
+ <view class="yd-search-form-actions">
+ <wd-button class="flex-1" plain @click="handleReset">
+ 閲嶇疆
+ </wd-button>
+ <wd-button class="flex-1" type="primary" @click="handleSearch">
+ 鎼滅储
+ </wd-button>
+ </view>
+ </view>
+ </wd-popup>
+</template>
+
+<script lang="ts" setup>
+import { computed, reactive, ref } from 'vue'
+import { getNavbarHeight } from '@/utils'
+import { formatDate, formatDateRange } from '@/utils/date'
+import { getDictLabel, getIntDictOptions, getBoolDictOptions } from '@/hooks/useDict'
+import { DICT_TYPE } from '@/utils/constants'
+
+const emit = defineEmits<{
+ search: [data: Record<string, any>]
+ reset: []
+}>()
+
+const visible = ref(false) // 鎼滅储寮圭獥鏄剧ず鐘舵��
+const formData = reactive({
+ name: undefined as string | undefined,
+ birthday: undefined as string | undefined,
+ sex: -1, // -1 琛ㄧず鍏ㄩ儴
+ enabled: -1 as -1 | boolean, // -1 琛ㄧず鍏ㄩ儴
+ createTime: [undefined, undefined] as [number | undefined, number | undefined],
+}) // 鎼滅储琛ㄥ崟鏁版嵁
+
+/** 鎼滅储鏉′欢 placeholder 鎷兼帴 */
+const placeholder = computed(() => {
+ const conditions: string[] = []
+ if (formData.name) {
+ conditions.push(`鍚嶅瓧:${formData.name}`)
+ }
+ if (formData.birthday) {
+ conditions.push(`鍑虹敓鏃ユ湡:${formData.birthday}`)
+ }
+ if (formData.sex !== -1) {
+ conditions.push(`鎬у埆:${getDictLabel(DICT_TYPE.SYSTEM_USER_SEX, formData.sex)}`)
+ }
+ if (formData.enabled !== -1) {
+ conditions.push(`鏄惁鏈夋晥:${getDictLabel(DICT_TYPE.INFRA_BOOLEAN_STRING, formData.enabled)}`)
+ }
+ if (formData.createTime?.[0] && formData.createTime?.[1]) {
+ conditions.push(`鍒涘缓鏃堕棿:${formatDate(formData.createTime[0])}~${formatDate(formData.createTime[1])}`)
+ }
+ return conditions.length > 0 ? conditions.join(' | ') : '鎼滅储瀛︾敓'
+})
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleSearch() {
+ visible.value = false
+ emit('search', {
+ ...formData,
+ sex: formData.sex === -1 ? undefined : formData.sex,
+ enabled: formData.enabled === -1 ? undefined : formData.enabled,
+ createTime: formatDateRange(formData.createTime),
+ })
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function handleReset() {
+ formData.name = undefined
+ formData.birthday = undefined
+ formData.sex = -1
+ formData.enabled = -1
+ formData.createTime = [undefined, undefined]
+ visible.value = false
+ emit('reset')
+}
+</script>
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/xml/InfraStudentMapper b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/xml/InfraStudentMapper
new file mode 100644
index 0000000..155aa5c
--- /dev/null
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/xml/InfraStudentMapper
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
+
+ <!--
+ 涓�鑸儏鍐典笅锛屽敖鍙兘浣跨敤 Mapper 杩涜 CRUD 澧炲垹鏀规煡鍗冲彲銆�
+ 鏃犳硶婊¤冻鐨勫満鏅紝渚嬪璇村琛ㄥ叧鑱旀煡璇紝鎵嶄娇鐢� XML 缂栧啓 SQL銆�
+ 浠g爜鐢熸垚鍣ㄦ殏鏃跺彧鐢熸垚 Mapper XML 鏂囦欢鏈韩锛屾洿澶氭帹鑽� MybatisX 蹇�熷紑鍙戞彃浠舵潵鐢熸垚鏌ヨ銆�
+ 鏂囨。鍙锛歨ttps://www.iocoder.cn/MyBatis/x-plugins/
+ -->
+
+</mapper>
\ No newline at end of file
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_master_inner/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vue3_master_inner/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vue3_master_inner/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_master_inner/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-infra/src/test/resources/codegen/vue3_master_normal/java/InfraStudentServiceImpl b/yudao-module-infra/src/test/resources/codegen/vue3_master_normal/java/InfraStudentServiceImpl
index 2b485a4..31d689e 100644
--- a/yudao-module-infra/src/test/resources/codegen/vue3_master_normal/java/InfraStudentServiceImpl
+++ b/yudao-module-infra/src/test/resources/codegen/vue3_master_normal/java/InfraStudentServiceImpl
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.infra.service.demo;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml
index 75cdd32..83b4640 100644
--- a/yudao-module-iot/yudao-module-iot-biz/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml
@@ -99,8 +99,8 @@
<!-- <optional>true</optional>-->
</dependency>
<dependency>
- <groupId>org.springframework.kafka</groupId>
- <artifactId>spring-kafka</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-kafka</artifactId>
<optional>true</optional>
</dependency>
<dependency>
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java
index 7922eb1..08b8cb3 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java
@@ -94,6 +94,9 @@
// 2. 缁勮杩斿洖缁撴灉
Set<Long> deviceIds = convertSet(configList, IotDeviceModbusConfigDO::getDeviceId);
Map<Long, IotDeviceDO> deviceMap = deviceService.getDeviceMap(deviceIds);
+ if (CollUtil.isEmpty(deviceMap)) {
+ return success(new ArrayList<>());
+ }
Map<Long, List<IotDeviceModbusPointDO>> pointMap = modbusPointService.getEnabledDeviceModbusPointMapByDeviceIds(deviceIds);
Map<Long, IotProductDO> productMap = productService.getProductMap(convertSet(deviceMap.values(), IotDeviceDO::getProductId));
List<IotModbusDeviceConfigRespDTO> result = new ArrayList<>(configList.size());
@@ -139,4 +142,4 @@
return success(deviceService.registerSubDevices(reqDTO));
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java
index e68a7b7..6b11c61 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java
@@ -37,6 +37,15 @@
@Schema(description = "鎺ユ敹鐨勭被鍨嬫暟缁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
private List<Integer> receiveTypes;
+ @Schema(description = "鐭俊妯℃澘缂栧彿", example = "iot_alert_sms")
+ private String smsTemplateCode;
+
+ @Schema(description = "閭欢妯℃澘缂栧彿", example = "iot_alert_mail")
+ private String mailTemplateCode;
+
+ @Schema(description = "绔欏唴淇℃ā鏉跨紪鍙�", example = "iot_alert_notify")
+ private String notifyTemplateCode;
+
@Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java
index 694e8bf..e83e255 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java
@@ -44,4 +44,12 @@
@NotEmpty(message = "鎺ユ敹鐨勭被鍨嬫暟缁勪笉鑳戒负绌�")
private List<Integer> receiveTypes;
+ @Schema(description = "鐭俊妯℃澘缂栧彿", example = "iot_alert_sms")
+ private String smsTemplateCode;
+
+ @Schema(description = "閭欢妯℃澘缂栧彿", example = "iot_alert_mail")
+ private String mailTemplateCode;
+
+ @Schema(description = "绔欏唴淇℃ā鏉跨紪鍙�", example = "iot_alert_notify")
+ private String notifyTemplateCode;
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java
index 835ef62..e3f732b 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java
@@ -29,6 +29,9 @@
@Schema(description = "鎵ц鍣ㄦ暟缁�", requiredMode = Schema.RequiredMode.REQUIRED)
private List<IotSceneRuleDO.Action> actions;
+ @Schema(description = "鏈�鍚庤Е鍙戞椂闂�")
+ private LocalDateTime lastTriggerTime;
+
@Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java
index 69f466b..792bb81 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java
@@ -81,4 +81,22 @@
@TableField(typeHandler = IntegerListTypeHandler.class)
private List<Integer> receiveTypes;
+ /**
+ * 鐭俊妯℃澘缂栧彿
+ *
+ * 鍏宠仈 SmsTemplateDO 鐨� code 灞炴��
+ */
+ private String smsTemplateCode;
+ /**
+ * 閭欢妯℃澘缂栧彿
+ *
+ * 鍏宠仈 MailTemplateDO 鐨� code 灞炴��
+ */
+ private String mailTemplateCode;
+ /**
+ * 绔欏唴淇℃ā鏉跨紪鍙�
+ *
+ * 鍏宠仈 NotifyTemplateDO 鐨� code 灞炴��
+ */
+ private String notifyTemplateCode;
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java
index 52b0d36..330e105 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java
@@ -33,7 +33,7 @@
default List<IotAlertConfigDO> selectListBySceneRuleIdAndStatus(Long sceneRuleId, Integer status) {
return selectList(new LambdaQueryWrapperX<IotAlertConfigDO>()
.eq(IotAlertConfigDO::getStatus, status)
- .apply(MyBatisUtils.findInSet("scene_rule_ids", sceneRuleId)));
+ .apply(MyBatisUtils.findInSet("scene_rule_ids"), sceneRuleId));
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
index 1e3fb2e..84c2d99 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
@@ -4,6 +4,7 @@
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.iot.controller.admin.device.vo.device.IotDevicePageReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
@@ -34,7 +35,7 @@
.likeIfPresent(IotDeviceDO::getNickname, reqVO.getNickname())
.eqIfPresent(IotDeviceDO::getState, reqVO.getStatus())
.eqIfPresent(IotDeviceDO::getGatewayId, reqVO.getGatewayId())
- .apply(ObjectUtil.isNotNull(reqVO.getGroupId()), "FIND_IN_SET(" + reqVO.getGroupId() + ",group_ids) > 0")
+ .apply(ObjectUtil.isNotNull(reqVO.getGroupId()), MyBatisUtils.findInSet("group_ids"), reqVO.getGroupId())
.orderByDesc(IotDeviceDO::getId));
}
@@ -72,7 +73,7 @@
default Long selectCountByGroupId(Long groupId) {
return selectCount(new LambdaQueryWrapperX<IotDeviceDO>()
- .apply("FIND_IN_SET(" + groupId + ",group_ids) > 0"));
+ .apply(MyBatisUtils.findInSet("group_ids"), groupId));
}
default Long selectCountByCreateTime(@Nullable LocalDateTime createTime) {
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java
index ce2eeb0..579b62e 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java
@@ -28,7 +28,7 @@
default List<IotDataRuleDO> selectListBySinkId(Long sinkId) {
return selectList(new LambdaQueryWrapperX<IotDataRuleDO>()
- .apply(MyBatisUtils.findInSet("sink_ids", sinkId)));
+ .apply(MyBatisUtils.findInSet("sink_ids"), sinkId));
}
default List<IotDataRuleDO> selectListByStatus(Integer status) {
@@ -39,4 +39,4 @@
return selectOne(IotDataRuleDO::getName, name);
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
index 065eb2d..2829bdf 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -98,6 +98,9 @@
// ========== IoT 鍛婅閰嶇疆 1-050-013-000 ==========
ErrorCode ALERT_CONFIG_NOT_EXISTS = new ErrorCode(1_050_013_000, "IoT 鍛婅閰嶇疆涓嶅瓨鍦�");
+ ErrorCode ALERT_CONFIG_SMS_TEMPLATE_REQUIRED = new ErrorCode(1_050_013_001, "宸查�夋嫨鐭俊鎺ユ敹鏂瑰紡锛岀煭淇℃ā鏉夸笉鑳戒负绌�");
+ ErrorCode ALERT_CONFIG_MAIL_TEMPLATE_REQUIRED = new ErrorCode(1_050_013_002, "宸查�夋嫨閭欢鎺ユ敹鏂瑰紡锛岄偖浠舵ā鏉夸笉鑳戒负绌�");
+ ErrorCode ALERT_CONFIG_NOTIFY_TEMPLATE_REQUIRED = new ErrorCode(1_050_013_003, "宸查�夋嫨绔欏唴淇℃帴鏀舵柟寮忥紝绔欏唴淇℃ā鏉夸笉鑳戒负绌�");
// ========== IoT 鍛婅璁板綍 1-050-014-000 ==========
ErrorCode ALERT_RECORD_NOT_EXISTS = new ErrorCode(1_050_014_000, "IoT 鍛婅璁板綍涓嶅瓨鍦�");
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java
index 48c3142..010e369 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java
@@ -1,8 +1,11 @@
package cn.iocoder.yudao.module.iot.framework.tdengine.core;
+import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
+
+import java.util.Locale;
/**
* TDEngine 琛ㄥ瓧娈�
@@ -61,4 +64,15 @@
this.type = type;
}
+ /**
+ * 鏋勫缓瀛楁鍚嶏細TDengine 榛樿浼氬皢瀛楁鍚嶈浆涓哄皬鍐欙紝闇�瑕佸拰寤鸿〃銆佸啓鍏ャ�佹煡璇繚鎸佷竴鑷淬��
+ * 渚嬪锛歅T -> pt锛孭fT -> pf_t銆�
+ */
+ public static String buildFieldName(String field) {
+ if (StrUtil.isBlank(field)) {
+ return field;
+ }
+ return StrUtil.toUnderlineCase(field).toLowerCase(Locale.ROOT);
+ }
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java
index aa93787..bd422b7 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java
@@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.iot.service.alert;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigPageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO;
import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertConfigMapper;
+import cn.iocoder.yudao.module.iot.enums.alert.IotAlertReceiveTypeEnum;
import cn.iocoder.yudao.module.iot.service.rule.scene.IotSceneRuleService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
@@ -16,7 +19,10 @@
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_CONFIG_MAIL_TEMPLATE_REQUIRED;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_CONFIG_NOT_EXISTS;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_CONFIG_NOTIFY_TEMPLATE_REQUIRED;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_CONFIG_SMS_TEMPLATE_REQUIRED;
/**
* IoT 鍛婅閰嶇疆 Service 瀹炵幇绫�
@@ -42,6 +48,7 @@
// 鏍¢獙鍏宠仈鏁版嵁鏄惁瀛樺湪
sceneRuleService.validateSceneRuleList(createReqVO.getSceneRuleIds());
adminUserApi.validateUserList(createReqVO.getReceiveUserIds());
+ validateReceiveTemplates(createReqVO);
// 鎻掑叆
IotAlertConfigDO alertConfig = BeanUtils.toBean(createReqVO, IotAlertConfigDO.class);
@@ -56,6 +63,7 @@
// 鏍¢獙鍏宠仈鏁版嵁鏄惁瀛樺湪
sceneRuleService.validateSceneRuleList(updateReqVO.getSceneRuleIds());
adminUserApi.validateUserList(updateReqVO.getReceiveUserIds());
+ validateReceiveTemplates(updateReqVO);
// 鏇存柊
IotAlertConfigDO updateObj = BeanUtils.toBean(updateReqVO, IotAlertConfigDO.class);
@@ -76,6 +84,24 @@
}
}
+ private void validateReceiveTemplates(IotAlertConfigSaveReqVO reqVO) {
+ if (CollUtil.isEmpty(reqVO.getReceiveTypes())) {
+ return;
+ }
+ if (reqVO.getReceiveTypes().contains(IotAlertReceiveTypeEnum.SMS.getType())
+ && StrUtil.isBlank(reqVO.getSmsTemplateCode())) {
+ throw exception(ALERT_CONFIG_SMS_TEMPLATE_REQUIRED);
+ }
+ if (reqVO.getReceiveTypes().contains(IotAlertReceiveTypeEnum.MAIL.getType())
+ && StrUtil.isBlank(reqVO.getMailTemplateCode())) {
+ throw exception(ALERT_CONFIG_MAIL_TEMPLATE_REQUIRED);
+ }
+ if (reqVO.getReceiveTypes().contains(IotAlertReceiveTypeEnum.NOTIFY.getType())
+ && StrUtil.isBlank(reqVO.getNotifyTemplateCode())) {
+ throw exception(ALERT_CONFIG_NOTIFY_TEMPLATE_REQUIRED);
+ }
+ }
+
@Override
public IotAlertConfigDO getAlertConfig(Long id) {
return alertConfigMapper.selectById(id);
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java
index 93c73f5..77db754 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java
@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.iot.service.device.property;
import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
@@ -119,7 +118,7 @@
private List<TDengineTableField> buildTableFieldList(List<IotThingModelDO> thingModels) {
return convertList(thingModels, thingModel -> {
TDengineTableField field = new TDengineTableField(
- StrUtil.toUnderlineCase(thingModel.getIdentifier()), // TDengine 瀛楁榛樿閮芥槸灏忓啓
+ TDengineTableField.buildFieldName(thingModel.getIdentifier()),
TYPE_MAPPING.get(thingModel.getProperty().getDataType()));
String dataType = thingModel.getProperty().getDataType();
if (Objects.equals(dataType, IotDataSpecsDataTypeEnum.TEXT.getDataType())) {
@@ -148,8 +147,16 @@
// 1. 鏍规嵁鐗╂ā鍨嬶紝鎷兼帴鍚堟硶鐨勫睘鎬�
// TODO @鑺嬭壙锛氥�愬緟瀹� 004銆戣祴鑳藉悗锛屽睘鎬у埌搴曚互 thingModel 涓哄噯锛坕k锛夛紝杩樻槸 db 鐨勮〃缁撴瀯涓哄噯锛坱l锛夛紵
List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductIdFromCache(device.getProductId());
- Map<String, Object> properties = new HashMap<>();
+ Map<String, Object> properties = new LinkedHashMap<>();
params.forEach((key, value) -> {
+ if (!(key instanceof CharSequence)) {
+ log.error("[saveDeviceProperty][娑堟伅({}) 鐨勫睘鎬� key({}) 绫诲瀷涓嶆纭甝", message, key);
+ return;
+ }
+ if (value == null) {
+ log.warn("[saveDeviceProperty][娑堟伅({}) 鐨勫睘鎬�({}) 鍊间负绌猴紝璺宠繃]", message, key);
+ return;
+ }
// 蹇界暐澶у皬鍐欏尮閰嶇墿妯″瀷锛岄伩鍏嶈澶囦笂鎶ョ殑 key 涓� identifier 澶у皬鍐欎笉涓�鑷村鑷翠涪澶�
IotThingModelDO thingModel = CollUtil.findOne(thingModels,
o -> StrUtil.equalsIgnoreCase(o.getIdentifier(), (CharSequence) key));
@@ -158,21 +165,9 @@
return;
}
String identifier = thingModel.getIdentifier(); // 缁熶竴浠ョ墿妯″瀷 identifier 浣滀负 key锛岄伩鍏嶅ぇ灏忓啓闂
- String dataType = thingModel.getProperty().getDataType();
- if (ObjectUtils.equalsAny(dataType,
- IotDataSpecsDataTypeEnum.STRUCT.getDataType(), IotDataSpecsDataTypeEnum.ARRAY.getDataType())) {
- // 鐗规畩锛歋TRUCT 鍜� ARRAY 绫诲瀷锛屽湪 TDengine 閲岋紝鏈夋病瀵瑰簲鏁版嵁绫诲瀷锛屽彧鑳介�氳繃 JSON 鏉ュ瓨鍌�
- properties.put(identifier, JsonUtils.toJsonString(value));
- } else if (IotDataSpecsDataTypeEnum.INT.getDataType().equals(dataType)) {
- properties.put(identifier, Convert.toInt(value));
- } else if (IotDataSpecsDataTypeEnum.FLOAT.getDataType().equals(dataType)) {
- properties.put(identifier, Convert.toFloat(value));
- } else if (IotDataSpecsDataTypeEnum.DOUBLE.getDataType().equals(dataType)) {
- properties.put(identifier, Convert.toDouble(value));
- } else if (IotDataSpecsDataTypeEnum.BOOL.getDataType().equals(dataType)) {
- properties.put(identifier, Convert.toBool(value, false) ? (byte) 1 : (byte) 0);
- } else {
- properties.put(identifier, value);
+ Object convertedValue = convertPropertyValue(message, thingModel, value);
+ if (convertedValue != null) {
+ properties.put(identifier, convertedValue);
}
});
if (CollUtil.isEmpty(properties)) {
@@ -192,6 +187,23 @@
// 2.3 鎻愬彇 GeoLocation 骞舵洿鏂拌澶囧畾浣�
// 涓轰粈涔� properties 涓虹┖锛屼篃瑕佹墽琛屽畾浣嶆洿鏂帮紵鍥犱负鍙兘涓婃姤鐨勫睘鎬ч噷锛屾病鏈夊悎娉曞睘鎬э紝浣嗘槸鍖呭惈 GeoLocation 瀹氫綅灞炴��
extractAndUpdateDeviceLocation(device, (Map<?, ?>) message.getParams());
+ }
+
+ private Object convertPropertyValue(IotDeviceMessage message, IotThingModelDO thingModel, Object value) {
+ String identifier = thingModel.getIdentifier();
+ String dataType = thingModel.getProperty().getDataType();
+ try {
+ Object convertedValue = thingModelService.convertThingModelPropertyValue(thingModel, value);
+ if (convertedValue == null) {
+ log.warn("[saveDeviceProperty][娑堟伅({}) 鐨勫睘鎬�({}) 鍊�({}) 鏃犳硶杞崲涓虹被鍨�({})锛岃烦杩嘳",
+ message, identifier, value, dataType);
+ }
+ return convertedValue;
+ } catch (Exception e) {
+ log.error("[saveDeviceProperty][娑堟伅({}) 鐨勫睘鎬�({}) 鍊�({}) 杞崲涓虹被鍨�({}) 寮傚父锛岃烦杩嘳",
+ message, identifier, value, dataType, e);
+ return null;
+ }
}
@Override
@@ -310,4 +322,4 @@
return new BigDecimal[]{longitude, latitude};
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java
index 01ddd57..238e030 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java
@@ -3,6 +3,7 @@
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharPool;
import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher;
import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator;
@@ -11,7 +12,6 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
-import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
@@ -73,7 +73,7 @@
LocalDateTime now = LocalDateTime.now();
if (isDateTimeOperator(operatorEnum)) {
// 鏃ユ湡鏃堕棿鍖归厤锛堟椂闂存埑锛岀绾э級
- long currentTimestamp = now.atZone(ZoneId.systemDefault()).toEpochSecond();
+ long currentTimestamp = LocalDateTimeUtils.toEpochSecond(now);
return matchDateTime(currentTimestamp, operatorEnum, param);
} else {
// 褰撴棩鏃堕棿鍖归厤锛圚H:mm:ss锛�
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java
index bc26436..937b8f6 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.rule.scene.action;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@@ -79,30 +80,38 @@
}
Map<String, Object> templateParams = buildTemplateParams(config, deviceMessage, device);
config.getReceiveUserIds().forEach(userId ->
- config.getReceiveTypes().forEach(receiveType -> sendAlertMessageToUser(userId, receiveType, templateParams)));
+ config.getReceiveTypes().forEach(receiveType ->
+ sendAlertMessageToUser(userId, receiveType, config, templateParams)));
}
/**
* 鎸夋寚瀹氭帴鏀舵柟寮忥紝缁欏崟涓敤鎴峰彂閫佸憡璀︽秷鎭�
*/
- private void sendAlertMessageToUser(Long userId, Integer receiveType, Map<String, Object> templateParams) {
+ private void sendAlertMessageToUser(Long userId, Integer receiveType, IotAlertConfigDO config,
+ Map<String, Object> templateParams) {
IotAlertReceiveTypeEnum typeEnum = IotAlertReceiveTypeEnum.of(receiveType);
if (typeEnum == null) {
return;
+ }
+ String templateCode = resolveTemplateCode(config, typeEnum);
+ if (StrUtil.isBlank(templateCode)) {//涓轰簡鍏煎鑰佺殑缁撴瀯
+ templateCode=typeEnum.getTemplateCode();
+ log.warn("[sendAlertMessageToUser][閰嶇疆({}) 鐢ㄦ埛({}) 鎺ユ敹鏂瑰紡({}) 鏈厤缃ā鏉匡紝浣跨敤榛樿妯℃澘锛坽}锛塢",
+ config.getId(), userId, typeEnum,templateCode);
}
try {
switch (typeEnum) {
case SMS:
smsSendApi.sendSingleSmsToAdmin(new SmsSendSingleToUserReqDTO().setUserId(userId)
- .setTemplateCode(typeEnum.getTemplateCode()).setTemplateParams(templateParams));
+ .setTemplateCode(templateCode).setTemplateParams(templateParams));
break;
case MAIL:
mailSendApi.sendSingleMailToAdmin(new MailSendSingleToUserReqDTO().setUserId(userId)
- .setTemplateCode(typeEnum.getTemplateCode()).setTemplateParams(templateParams));
+ .setTemplateCode(templateCode).setTemplateParams(templateParams));
break;
case NOTIFY:
notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO().setUserId(userId)
- .setTemplateCode(typeEnum.getTemplateCode()).setTemplateParams(templateParams));
+ .setTemplateCode(templateCode).setTemplateParams(templateParams));
break;
}
} catch (Exception ex) {
@@ -111,6 +120,24 @@
}
}
+ private String resolveTemplateCode(IotAlertConfigDO config, IotAlertReceiveTypeEnum typeEnum) {
+ String templateCode = null;
+ switch (typeEnum) {
+ case SMS:
+ templateCode = config.getSmsTemplateCode();
+ break;
+ case MAIL:
+ templateCode = config.getMailTemplateCode();
+ break;
+ case NOTIFY:
+ templateCode = config.getNotifyTemplateCode();
+ break;
+ default:
+ break;
+ }
+ return StrUtil.blankToDefault(templateCode, typeEnum.getTemplateCode());
+ }
+
private Map<String, Object> buildTemplateParams(IotAlertConfigDO config,
@Nullable IotDeviceMessage deviceMessage,
@Nullable IotDeviceDO device) {
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java
index 5d62bab..84cbbf9 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/IotSceneRuleMatcherHelper.java
@@ -2,13 +2,17 @@
import cn.hutool.core.text.CharPool;
import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
+import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
@@ -248,4 +252,26 @@
return StrUtil.isNotBlank(expectedIdentifier) && expectedIdentifier.equals(actualIdentifier);
}
+ /**
+ * 鏍¢獙鍖归厤鍣ㄤ腑鐨勪骇鍝佸拰璁惧鏄惁涓�鑷�
+ *
+ * @param message 娑堟伅
+ * @param productId 浜у搧缂栧彿
+ * @param deviceId 璁惧缂栧彿
+ * @return 鏍¢獙缁撴灉
+ */
+ public static boolean productAndDeviceNotMatched(IotDeviceMessage message, Long productId, Long deviceId) {
+ if (message == null || message.getDeviceId() == null) {
+ return false;
+ }
+ if (deviceId != null && !IotDeviceDO.DEVICE_ID_ALL.equals(deviceId)) {
+ return ObjectUtil.notEqual(message.getDeviceId(), deviceId);
+ }
+ if (productId == null) {
+ return false;
+ }
+ IotDeviceDO device = SpringUtils.getBean(IotDeviceService.class).getDeviceFromCache(message.getDeviceId());
+ return device == null || ObjectUtil.notEqual(device.getProductId(), productId);
+ }
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotCurrentTimeConditionMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotCurrentTimeConditionMatcher.java
index a54785a..3b41f57 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotCurrentTimeConditionMatcher.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotCurrentTimeConditionMatcher.java
@@ -31,13 +31,19 @@
return false;
}
- // 1.2 妫�鏌ユ搷浣滅鍜屽弬鏁版槸鍚︽湁鏁�
+ // 1.2 淇鏉′欢鍖归厤涓拷鐣ヤ簡浜у搧鍜岃澶囩殑涓�鑷存�ч獙璇侊紝2025.05.25 by panda
+ if (IotSceneRuleMatcherHelper.productAndDeviceNotMatched(message, condition.getProductId(),condition.getDeviceId())){
+ IotSceneRuleMatcherHelper.logConditionMatchFailure(message,condition,"鏉′欢鍖归厤鍣ㄤ腑浜у搧鎴栬澶囦笉鍖归厤");
+ return false;
+ }
+
+ // 1.3 妫�鏌ユ搷浣滅鍜屽弬鏁版槸鍚︽湁鏁�
if (!IotSceneRuleMatcherHelper.isConditionOperatorAndParamValid(condition)) {
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "鎿嶄綔绗︽垨鍙傛暟鏃犳晥");
return false;
}
- // 1.3 楠岃瘉鎿嶄綔绗︽槸鍚︿负鏀寔鐨勬椂闂存搷浣滅
+ // 1.4 楠岃瘉鎿嶄綔绗︽槸鍚︿负鏀寔鐨勬椂闂存搷浣滅
String operator = condition.getOperator();
IotSceneRuleConditionOperatorEnum operatorEnum = IotSceneRuleConditionOperatorEnum.operatorOf(operator);
if (operatorEnum == null) {
@@ -45,6 +51,7 @@
return false;
}
+ // 1.5 楠岃瘉鎿嶄綔绗︽槸鍚︿负鏃堕棿鐩稿叧鐨勬搷浣滅
if (IotSceneRuleTimeHelper.isTimeOperator(operatorEnum)) {
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "涓嶆敮鎸佺殑鏃堕棿鎿嶄綔绗�: " + operator);
return false;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDevicePropertyConditionMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDevicePropertyConditionMatcher.java
index 5741b95..f2c92ae 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDevicePropertyConditionMatcher.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDevicePropertyConditionMatcher.java
@@ -30,14 +30,20 @@
return false;
}
- // 1.2 妫�鏌ユ秷鎭腑鏄惁鍖呭惈鏉′欢鎸囧畾鐨勫睘鎬ф爣璇嗙
+ // 1.2 淇鏉′欢鍖归厤涓拷鐣ヤ簡浜у搧鍜岃澶囩殑涓�鑷存�ч獙璇侊紝2025.05.25 by panda
+ if (IotSceneRuleMatcherHelper.productAndDeviceNotMatched(message, condition.getProductId(),condition.getDeviceId())){
+ IotSceneRuleMatcherHelper.logConditionMatchFailure(message,condition,"鏉′欢鍖归厤鍣ㄤ腑浜у搧鎴栬澶囦笉鍖归厤");
+ return false;
+ }
+
+ // 1.3 妫�鏌ユ秷鎭腑鏄惁鍖呭惈鏉′欢鎸囧畾鐨勫睘鎬ф爣璇嗙
// 娉ㄦ剰锛氬睘鎬т笂鎶ュ彲鑳藉悓鏃朵笂鎶ュ涓睘鎬э紝鎵�浠ラ渶瑕佸垽鏂� condition.getIdentifier() 鏄惁鍦� message 鐨� params 涓�
if (IotDeviceMessageUtils.notContainsIdentifier(message, condition.getIdentifier())) {
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "娑堟伅涓笉鍖呭惈灞炴��: " + condition.getIdentifier());
return false;
}
- // 1.3 妫�鏌ユ搷浣滅鍜屽弬鏁版槸鍚︽湁鏁�
+ // 1.4 妫�鏌ユ搷浣滅鍜屽弬鏁版槸鍚︽湁鏁�
if (!IotSceneRuleMatcherHelper.isConditionOperatorAndParamValid(condition)) {
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "鎿嶄綔绗︽垨鍙傛暟鏃犳晥");
return false;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDeviceStateConditionMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDeviceStateConditionMatcher.java
index 2328122..15dcbbd 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDeviceStateConditionMatcher.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/condition/IotDeviceStateConditionMatcher.java
@@ -27,8 +27,13 @@
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "鏉′欢鍩虹鍙傛暟鏃犳晥");
return false;
}
+ // 1.2 淇鏉′欢鍖归厤涓拷鐣ヤ簡浜у搧鍜岃澶囩殑涓�鑷存�ч獙璇侊紝2025.05.25 by panda
+ if (IotSceneRuleMatcherHelper.productAndDeviceNotMatched(message, condition.getProductId(),condition.getDeviceId())){
+ IotSceneRuleMatcherHelper.logConditionMatchFailure(message,condition,"鏉′欢鍖归厤鍣ㄤ腑浜у搧鎴栬澶囦笉鍖归厤");
+ return false;
+ }
- // 1.2 妫�鏌ユ搷浣滅鍜屽弬鏁版槸鍚︽湁鏁�
+ // 1.3 妫�鏌ユ搷浣滅鍜屽弬鏁版槸鍚︽湁鏁�
if (!IotSceneRuleMatcherHelper.isConditionOperatorAndParamValid(condition)) {
IotSceneRuleMatcherHelper.logConditionMatchFailure(message, condition, "鎿嶄綔绗︽垨鍙傛暟鏃犳晥");
return false;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceEventPostTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceEventPostTriggerMatcher.java
index d997e46..2d54ff0 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceEventPostTriggerMatcher.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceEventPostTriggerMatcher.java
@@ -43,7 +43,13 @@
return false;
}
- // 1.3 妫�鏌ユ爣璇嗙鏄惁鍖归厤
+ // 1.3 淇瑙﹀彂鍣ㄤ腑蹇界暐浜嗕骇鍝佸拰璁惧鐨勪竴鑷存�ч獙璇侊紝2025.05.25 by panda
+ if (IotSceneRuleMatcherHelper.productAndDeviceNotMatched(message, trigger.getProductId(),trigger.getDeviceId())){
+ IotSceneRuleMatcherHelper.logTriggerMatchFailure(message,trigger,"瑙﹀彂鍣ㄤ腑浜у搧鎴栬澶囦笉鍖归厤");
+ return false;
+ }
+
+ // 1.4 妫�鏌ユ爣璇嗙鏄惁鍖归厤
String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message);
if (!IotSceneRuleMatcherHelper.isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "鏍囪瘑绗︿笉鍖归厤锛屾湡鏈�: " +
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDevicePropertyPostTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDevicePropertyPostTriggerMatcher.java
index 1f019b5..ea89ce3 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDevicePropertyPostTriggerMatcher.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDevicePropertyPostTriggerMatcher.java
@@ -36,7 +36,13 @@
return false;
}
- // 1.3 妫�鏌ユ秷鎭腑鏄惁鍖呭惈瑙﹀彂鍣ㄦ寚瀹氱殑灞炴�ф爣璇嗙
+ // 1.3 淇瑙﹀彂鍣ㄤ腑蹇界暐浜嗕骇鍝佸拰璁惧鐨勪竴鑷存�ч獙璇侊紝2025.05.25 by panda
+ if (IotSceneRuleMatcherHelper.productAndDeviceNotMatched(message, trigger.getProductId(),trigger.getDeviceId())){
+ IotSceneRuleMatcherHelper.logTriggerMatchFailure(message,trigger,"瑙﹀彂鍣ㄤ腑浜у搧鎴栬澶囦笉鍖归厤");
+ return false;
+ }
+
+ // 1.4 妫�鏌ユ秷鎭腑鏄惁鍖呭惈瑙﹀彂鍣ㄦ寚瀹氱殑灞炴�ф爣璇嗙
// 娉ㄦ剰锛氬睘鎬т笂鎶ュ彲鑳藉悓鏃朵笂鎶ュ涓睘鎬э紝鎵�浠ラ渶瑕佸垽鏂� trigger.getIdentifier() 鏄惁鍦� message 鐨� params 涓�
if (IotDeviceMessageUtils.notContainsIdentifier(message, trigger.getIdentifier())) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "娑堟伅涓笉鍖呭惈灞炴��: " +
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java
index 842d081..5dcde66 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceServiceInvokeTriggerMatcher.java
@@ -7,7 +7,9 @@
import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper;
+import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.Map;
@@ -19,6 +21,9 @@
*/
@Component
public class IotDeviceServiceInvokeTriggerMatcher implements IotSceneRuleTriggerMatcher {
+
+ @Resource
+ private IotDeviceService iotDeviceService;
@Override
public IotSceneRuleTriggerTypeEnum getSupportedTriggerType() {
@@ -37,7 +42,12 @@
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "娑堟伅鏂规硶涓嶅尮閰嶏紝鏈熸湜: " + IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod() + ", 瀹為檯: " + message.getMethod());
return false;
}
- // 1.3 妫�鏌ユ爣璇嗙鏄惁鍖归厤
+ // 1.3 淇瑙﹀彂鍣ㄤ腑蹇界暐浜嗕骇鍝佸拰璁惧鐨勪竴鑷存�ч獙璇侊紝2025.05.25 by panda
+ if (IotSceneRuleMatcherHelper.productAndDeviceNotMatched(message, trigger.getProductId(),trigger.getDeviceId())){
+ IotSceneRuleMatcherHelper.logTriggerMatchFailure(message,trigger,"瑙﹀彂鍣ㄤ腑浜у搧鎴栬澶囦笉鍖归厤");
+ return false;
+ }
+ // 1.4 妫�鏌ユ爣璇嗙鏄惁鍖归厤
String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message);
if (!IotSceneRuleMatcherHelper.isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "鏍囪瘑绗︿笉鍖归厤锛屾湡鏈�: " + trigger.getIdentifier() + ", 瀹為檯: " + messageIdentifier);
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceStateUpdateTriggerMatcher.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceStateUpdateTriggerMatcher.java
index 6b8c73a..183442e 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceStateUpdateTriggerMatcher.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/matcher/trigger/IotDeviceStateUpdateTriggerMatcher.java
@@ -5,7 +5,9 @@
import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.IotSceneRuleMatcherHelper;
+import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
/**
@@ -15,6 +17,9 @@
*/
@Component
public class IotDeviceStateUpdateTriggerMatcher implements IotSceneRuleTriggerMatcher {
+
+ @Resource
+ private IotDeviceService iotDeviceService;
@Override
public IotSceneRuleTriggerTypeEnum getSupportedTriggerType() {
@@ -36,7 +41,13 @@
return false;
}
- // 1.3 妫�鏌ユ搷浣滅鍜屽�兼槸鍚︽湁鏁�
+ // 1.3 淇瑙﹀彂鍣ㄤ腑蹇界暐浜嗕骇鍝佸拰璁惧鐨勪竴鑷存�ч獙璇侊紝2025.05.25 by panda
+ if (IotSceneRuleMatcherHelper.productAndDeviceNotMatched(message, trigger.getProductId(),trigger.getDeviceId())){
+ IotSceneRuleMatcherHelper.logTriggerMatchFailure(message,trigger,"瑙﹀彂鍣ㄤ腑浜у搧鎴栬澶囦笉鍖归厤");
+ return false;
+ }
+
+ // 1.4 妫�鏌ユ搷浣滅鍜屽�兼槸鍚︽湁鏁�
if (!IotSceneRuleMatcherHelper.isTriggerOperatorAndValueValid(trigger)) {
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "鎿嶄綔绗︽垨鍊兼棤鏁�");
return false;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java
index b8c951b..5bdfd7c 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java
@@ -108,4 +108,13 @@
*/
void validateThingModelListExists(Long productId, Set<String> identifiers);
-}
\ No newline at end of file
+ /**
+ * 鎸夌墿妯″瀷灞炴�х殑鏁版嵁绫诲瀷杞崲璁惧涓婃姤鍊�
+ *
+ * @param thingModel 鐗╂ā鍨�
+ * @param value 璁惧涓婃姤鍊�
+ * @return 杞崲鍚庣殑鍊硷紱鏃犳硶杞崲鏃惰繑鍥� null
+ */
+ Object convertThingModelPropertyValue(IotThingModelDO thingModel, Object value);
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java
index 4a8b974..9029960 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java
@@ -1,10 +1,16 @@
package cn.iocoder.yudao.module.iot.service.thingmodel;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelListReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO;
@@ -12,9 +18,14 @@
import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelBoolOrEnumDataSpecs;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDataSpecs;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs;
import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotThingModelMapper;
import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
+import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
+import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceModbusPointService;
import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import jakarta.annotation.Resource;
@@ -26,7 +37,15 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZonedDateTime;
import java.util.Collection;
+import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -166,6 +185,239 @@
}
}
+ @Override
+ public Object convertThingModelPropertyValue(IotThingModelDO thingModel, Object value) {
+ if (thingModel == null || thingModel.getProperty() == null || value == null) {
+ return null;
+ }
+ String dataType = thingModel.getProperty().getDataType();
+ if (ObjectUtils.equalsAny(dataType,
+ IotDataSpecsDataTypeEnum.STRUCT.getDataType(), IotDataSpecsDataTypeEnum.ARRAY.getDataType())) {
+ // 鐗规畩锛歋TRUCT 鍜� ARRAY 绫诲瀷锛屽湪 TDengine 閲岋紝娌℃湁瀵瑰簲鏁版嵁绫诲瀷锛屽彧鑳介�氳繃 JSON 鏉ュ瓨鍌�
+ return convertToVarchar(JsonUtils.toJsonString(value), TDengineTableField.LENGTH_VARCHAR);
+ }
+ if (IotDataSpecsDataTypeEnum.INT.getDataType().equals(dataType)) {
+ return convertToInt(value);
+ }
+ if (IotDataSpecsDataTypeEnum.FLOAT.getDataType().equals(dataType)) {
+ return convertToFloat(value);
+ }
+ if (IotDataSpecsDataTypeEnum.DOUBLE.getDataType().equals(dataType)) {
+ return convertToDouble(value);
+ }
+ if (IotDataSpecsDataTypeEnum.ENUM.getDataType().equals(dataType)) {
+ return convertEnumToTinyInt(thingModel, value);
+ }
+ if (IotDataSpecsDataTypeEnum.BOOL.getDataType().equals(dataType)) {
+ return convertBoolToTinyInt(value);
+ }
+ if (IotDataSpecsDataTypeEnum.TEXT.getDataType().equals(dataType)) {
+ return convertToVarchar(Convert.toStr(value), getTextLength(thingModel));
+ }
+ if (IotDataSpecsDataTypeEnum.DATE.getDataType().equals(dataType)) {
+ return convertToTimestamp(value);
+ }
+ return null;
+ }
+
+ private Integer getTextLength(IotThingModelDO thingModel) {
+ ThingModelDataSpecs dataSpecs = thingModel.getProperty().getDataSpecs();
+ if (!(dataSpecs instanceof ThingModelDateOrTextDataSpecs)) {
+ return null;
+ }
+ return ((ThingModelDateOrTextDataSpecs) dataSpecs).getLength();
+ }
+
+ private String convertToVarchar(String value, Integer length) {
+ if (value == null) {
+ return null;
+ }
+ if (length != null && value.getBytes(StandardCharsets.UTF_8).length > length) {
+ return null;
+ }
+ return value;
+ }
+
+ private Integer convertToInt(Object value) {
+ BigDecimal decimal = convertToBigDecimal(value);
+ if (decimal == null) {
+ return null;
+ }
+ try {
+ return decimal.intValueExact();
+ } catch (ArithmeticException e) {
+ return null;
+ }
+ }
+
+ private Float convertToFloat(Object value) {
+ BigDecimal decimal = convertToBigDecimal(value);
+ if (decimal == null) {
+ return null;
+ }
+ float result = decimal.floatValue();
+ return Float.isFinite(result) ? result : null;
+ }
+
+ private Double convertToDouble(Object value) {
+ BigDecimal decimal = convertToBigDecimal(value);
+ if (decimal == null) {
+ return null;
+ }
+ double result = decimal.doubleValue();
+ return Double.isFinite(result) ? result : null;
+ }
+
+ private BigDecimal convertToBigDecimal(Object value) {
+ if (value instanceof Boolean) {
+ return null;
+ }
+ String text = Convert.toStr(value);
+ if (StrUtil.isBlank(text)) {
+ return null;
+ }
+ try {
+ return new BigDecimal(text);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+ private Byte convertEnumToTinyInt(IotThingModelDO thingModel, Object value) {
+ Integer intValue = convertToInt(value);
+ if (intValue == null && value instanceof CharSequence) {
+ intValue = getEnumValueByName(thingModel, value.toString());
+ }
+ if (intValue == null || !isTinyInt(intValue)) {
+ return null;
+ }
+ if (CollUtil.isNotEmpty(thingModel.getProperty().getDataSpecsList())
+ && getEnumDataSpecsByValue(thingModel, intValue) == null) {
+ return null;
+ }
+ return intValue.byteValue();
+ }
+
+ private Integer getEnumValueByName(IotThingModelDO thingModel, String name) {
+ ThingModelBoolOrEnumDataSpecs dataSpecs = getEnumDataSpecsByName(thingModel, name);
+ return dataSpecs != null ? dataSpecs.getValue() : null;
+ }
+
+ private ThingModelBoolOrEnumDataSpecs getEnumDataSpecsByName(IotThingModelDO thingModel, String name) {
+ if (CollUtil.isEmpty(thingModel.getProperty().getDataSpecsList())) {
+ return null;
+ }
+ for (ThingModelDataSpecs dataSpecs : thingModel.getProperty().getDataSpecsList()) {
+ if (!(dataSpecs instanceof ThingModelBoolOrEnumDataSpecs)) {
+ continue;
+ }
+ ThingModelBoolOrEnumDataSpecs enumDataSpecs = (ThingModelBoolOrEnumDataSpecs) dataSpecs;
+ if (StrUtil.equals(enumDataSpecs.getName(), name)) {
+ return enumDataSpecs;
+ }
+ }
+ return null;
+ }
+
+ private ThingModelBoolOrEnumDataSpecs getEnumDataSpecsByValue(IotThingModelDO thingModel, Integer value) {
+ if (CollUtil.isEmpty(thingModel.getProperty().getDataSpecsList())) {
+ return null;
+ }
+ for (ThingModelDataSpecs dataSpecs : thingModel.getProperty().getDataSpecsList()) {
+ if (!(dataSpecs instanceof ThingModelBoolOrEnumDataSpecs)) {
+ continue;
+ }
+ ThingModelBoolOrEnumDataSpecs enumDataSpecs = (ThingModelBoolOrEnumDataSpecs) dataSpecs;
+ if (Objects.equals(enumDataSpecs.getValue(), value)) {
+ return enumDataSpecs;
+ }
+ }
+ return null;
+ }
+
+ private Byte convertBoolToTinyInt(Object value) {
+ if (value instanceof Boolean) {
+ return (Boolean) value ? (byte) 1 : (byte) 0;
+ }
+ if (value instanceof CharSequence) {
+ String text = StrUtil.trim(value.toString());
+ if (StrUtil.equalsIgnoreCase(text, "true")) {
+ return (byte) 1;
+ }
+ if (StrUtil.equalsIgnoreCase(text, "false")) {
+ return (byte) 0;
+ }
+ }
+ Integer intValue = convertToInt(value);
+ if (intValue == null || (intValue != 0 && intValue != 1)) {
+ return null;
+ }
+ return intValue.byteValue();
+ }
+
+ private boolean isTinyInt(Integer value) {
+ return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE;
+ }
+
+ private Long convertToTimestamp(Object value) {
+ if (value instanceof LocalDateTime) {
+ return LocalDateTimeUtil.toEpochMilli((LocalDateTime) value);
+ }
+ if (value instanceof LocalDate) {
+ return LocalDateTimeUtil.toEpochMilli(((LocalDate) value).atStartOfDay());
+ }
+ if (value instanceof Instant) {
+ return ((Instant) value).toEpochMilli();
+ }
+ if (value instanceof OffsetDateTime) {
+ return ((OffsetDateTime) value).toInstant().toEpochMilli();
+ }
+ if (value instanceof ZonedDateTime) {
+ return ((ZonedDateTime) value).toInstant().toEpochMilli();
+ }
+ if (value instanceof Date) {
+ return ((Date) value).getTime();
+ }
+ Long timestamp = convertToLong(value);
+ if (timestamp != null) {
+ return timestamp;
+ }
+ if (!(value instanceof CharSequence)) {
+ return null;
+ }
+ String text = StrUtil.trim(value.toString());
+ if (StrUtil.isBlank(text)) {
+ return null;
+ }
+ try {
+ return OffsetDateTime.parse(text).toInstant().toEpochMilli();
+ } catch (Exception ignored) {
+ // 灏濊瘯鏈湴鏃堕棿鏍煎紡锛屼緥濡� yyyy-MM-dd HH:mm:ss
+ }
+ try {
+ return LocalDateTimeUtil.toEpochMilli(LocalDateTimeUtil.parse(text, DatePattern.NORM_DATETIME_PATTERN));
+ } catch (Exception ignored) {
+ // 灏濊瘯鍏跺畠 Hutool 鏀寔鐨勬湰鍦版椂闂存牸寮�
+ }
+ try {
+ return LocalDateTimeUtil.toEpochMilli(LocalDateTimeUtils.parse(text));
+ } catch (Exception ignored) {
+ return null;
+ }
+ }
+
+ private Long convertToLong(Object value) {
+ BigDecimal decimal = convertToBigDecimal(value);
+ if (decimal == null) {
+ return null;
+ }
+ try {
+ return decimal.longValueExact();
+ } catch (ArithmeticException e) {
+ return null;
+ }
+ }
+
private void validateProductThingModelMapperExists(Long id) {
if (thingModelMapper.selectById(id) == null) {
throw exception(THING_MODEL_NOT_EXISTS);
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml
index cc68ab8..c47c5a5 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml
@@ -51,7 +51,7 @@
TAGS ('${device.id}')
(ts, report_time,
<foreach item="key" collection="properties.keys" separator=",">
- ${@cn.hutool.core.util.StrUtil@toUnderlineCase(key)}
+ ${@cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField@buildFieldName(key)}
</foreach>
)
VALUES
@@ -68,12 +68,12 @@
<select id="selectListByHistory"
resultType="cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO">
- SELECT ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} AS `value`, ts AS update_time
+ SELECT ${@cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField@buildFieldName(reqVO.identifier)} AS `value`, ts AS update_time
FROM device_property_${reqVO.deviceId}
- WHERE ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} IS NOT NULL
+ WHERE ${@cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField@buildFieldName(reqVO.identifier)} IS NOT NULL
AND ts BETWEEN ${@cn.hutool.core.date.LocalDateTimeUtil@toEpochMilli(reqVO.times[0])}
AND ${@cn.hutool.core.date.LocalDateTimeUtil@toEpochMilli(reqVO.times[1])}
ORDER BY ts DESC
</select>
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableFieldTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableFieldTest.java
new file mode 100644
index 0000000..df2cb42
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableFieldTest.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.iot.framework.tdengine.core;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class TDengineTableFieldTest {
+
+ @Test
+ public void testBuildFieldName() {
+ assertEquals("ua", TDengineTableField.buildFieldName("Ua"));
+ assertEquals("pf_t", TDengineTableField.buildFieldName("PfT"));
+ assertEquals("pt", TDengineTableField.buildFieldName("PT"));
+ assertEquals("pa", TDengineTableField.buildFieldName("PA"));
+ assertEquals("geo_location", TDengineTableField.buildFieldName("GeoLocation"));
+ assertEquals("light_status", TDengineTableField.buildFieldName("LightStatus"));
+ }
+
+ @Test
+ public void testBuildFieldName_blank() {
+ assertNull(TDengineTableField.buildFieldName(null));
+ assertEquals("", TDengineTableField.buildFieldName(""));
+ assertEquals(" ", TDengineTableField.buildFieldName(" "));
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImplTest.java
index 8f87cb8..67be85e 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImplTest.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImplTest.java
@@ -5,11 +5,15 @@
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty;
import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO;
import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyMapper;
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
+import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
+import cn.iocoder.yudao.module.iot.framework.tdengine.core.TDengineTableField;
+import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@@ -17,8 +21,12 @@
import org.mockito.Mock;
import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.*;
@@ -38,6 +46,8 @@
@Mock
private IotThingModelService thingModelService;
@Mock
+ private IotProductService productService;
+ @Mock
private IotDevicePropertyMapper devicePropertyMapper;
@Mock
private DevicePropertyRedisDAO deviceDataRedisDAO;
@@ -54,6 +64,7 @@
// mock 琛屼负
when(thingModelService.getThingModelListByProductIdFromCache(device.getProductId()))
.thenReturn(singletonList(thingModel));
+ when(thingModelService.convertThingModelPropertyValue(thingModel, 100)).thenReturn(100);
// 璋冪敤
service.saveDeviceProperty(device, message);
@@ -91,64 +102,99 @@
}
@Test
- public void testSaveDeviceProperty_boolFromBooleanTrue() {
- // 鍑嗗鍙傛暟锛氱墿妯″瀷涓� BOOL锛岃澶囦笂鎶ュ師鐢� boolean true
- assertBoolValueConvertedToByte(true, (byte) 1);
- }
-
- @Test
- public void testSaveDeviceProperty_boolFromBooleanFalse() {
- // 鍑嗗鍙傛暟锛氱墿妯″瀷涓� BOOL锛岃澶囦笂鎶ュ師鐢� boolean false
- assertBoolValueConvertedToByte(false, (byte) 0);
- }
-
- @Test
- public void testSaveDeviceProperty_boolFromStringTrue() {
- // 鍑嗗鍙傛暟锛氱墿妯″瀷涓� BOOL锛岃澶囦笂鎶ュ瓧绗︿覆 "true"
- assertBoolValueConvertedToByte("true", (byte) 1);
- }
-
- @Test
- public void testSaveDeviceProperty_boolFromStringFalse() {
- // 鍑嗗鍙傛暟锛氱墿妯″瀷涓� BOOL锛岃澶囦笂鎶ュ瓧绗︿覆 "false"
- assertBoolValueConvertedToByte("false", (byte) 0);
- }
-
- @Test
- public void testSaveDeviceProperty_boolFromNumberOne() {
- // 鍑嗗鍙傛暟锛氱墿妯″瀷涓� BOOL锛岃澶囦笂鎶ユ暟瀛� 1
- assertBoolValueConvertedToByte(1, (byte) 1);
- }
-
- @Test
- public void testSaveDeviceProperty_boolFromNumberZero() {
- // 鍑嗗鍙傛暟锛氱墿妯″瀷涓� BOOL锛岃澶囦笂鎶ユ暟瀛� 0
- assertBoolValueConvertedToByte(0, (byte) 0);
- }
-
- /**
- * 鏍¢獙 BOOL 绫诲瀷灞炴�т笂鎶ュ悗锛屾渶缁堣惤鍒� properties Map 鐨勫�肩被鍨嬩笌鏁板��
- */
- private void assertBoolValueConvertedToByte(Object reportedValue, byte expected) {
- // 鍑嗗鍙傛暟
+ public void testSaveDeviceProperty_convertValueFailed() {
+ // 鍑嗗鍙傛暟锛氱墿妯″瀷瀛樺湪锛屼絾鏄睘鎬у�兼棤娉曟寜鐗╂ā鍨嬭浆鎹�
IotDeviceDO device = buildDevice();
- IotThingModelDO thingModel = buildThingModel("PowerSwitch", IotDataSpecsDataTypeEnum.BOOL.getDataType());
+ IotThingModelDO temperature = buildThingModel("Temperature", IotDataSpecsDataTypeEnum.INT.getDataType());
Map<String, Object> params = new HashMap<>();
- params.put("PowerSwitch", reportedValue);
+ params.put("Temperature", "abc");
IotDeviceMessage message = buildMessage(params);
- // mock 琛屼负
+ // mock 鏂规硶
+ when(thingModelService.getThingModelListByProductIdFromCache(device.getProductId()))
+ .thenReturn(singletonList(temperature));
+ when(thingModelService.convertThingModelPropertyValue(temperature, "abc")).thenReturn(null);
+
+ // 璋冪敤锛屽苟鏂█锛氫笉浼氭姏鍑哄紓甯�
+ assertDoesNotThrow(() -> service.saveDeviceProperty(device, message));
+
+ // 鏂█锛氭病鏈夊悎娉曞睘鎬э紝涓嶄細鍐欏叆 TDengine 涓� Redis
+ verify(devicePropertyMapper, never()).insert(any(), any(), anyLong(), anyLong());
+ verify(deviceDataRedisDAO, never()).putAll(anyLong(), any());
+ }
+
+ @Test
+ public void testSaveDeviceProperty_skipNullValue() {
+ // 鍑嗗鍙傛暟锛氬睘鎬у�间负绌猴紝涓嶈兘鍐欏叆 TDengine 涓� Redis
+ IotDeviceDO device = buildDevice();
+ IotThingModelDO thingModel = buildThingModel("Temperature", IotDataSpecsDataTypeEnum.INT.getDataType());
+ Map<String, Object> params = new HashMap<>();
+ params.put("Temperature", null);
+ IotDeviceMessage message = buildMessage(params);
+
+ // mock 鏂规硶
when(thingModelService.getThingModelListByProductIdFromCache(device.getProductId()))
.thenReturn(singletonList(thingModel));
- // 璋冪敤锛氫笉鑳芥姏寮傚父
+ // 璋冪敤锛屽苟鏂█锛氫笉浼氭姏鍑哄紓甯�
assertDoesNotThrow(() -> service.saveDeviceProperty(device, message));
- // 鏂█锛氬啓鍏ョ殑 value 鏄� byte 绫诲瀷锛屼笖鍊煎尮閰�
+ // 鏂█锛氳烦杩囩┖鍊硷紝涓嶄細杞崲灞炴�у�硷紝涔熶笉浼氬啓鍏� TDengine 涓� Redis
+ verify(thingModelService, never()).convertThingModelPropertyValue(any(), any());
+ verify(devicePropertyMapper, never()).insert(any(), any(), anyLong(), anyLong());
+ verify(deviceDataRedisDAO, never()).putAll(anyLong(), any());
+ }
+
+ @Test
+ public void testSaveDeviceProperty_skipInvalidKeyType() {
+ // 鍑嗗鍙傛暟锛歁ap 涓寘鍚潪瀛楃涓� key锛屼笉鑳藉洜涓哄己杞け璐ュ奖鍝嶅叾瀹冨悎娉曞睘鎬�
+ IotDeviceDO device = buildDevice();
+ IotThingModelDO thingModel = buildThingModel("PowerSwitch", IotDataSpecsDataTypeEnum.BOOL.getDataType());
+ Map<Object, Object> params = new HashMap<>();
+ params.put(123, 1);
+ params.put("PowerSwitch", true);
+ IotDeviceMessage message = buildMessage(params);
+
+ // mock 鏂规硶
+ when(thingModelService.getThingModelListByProductIdFromCache(device.getProductId()))
+ .thenReturn(singletonList(thingModel));
+ when(thingModelService.convertThingModelPropertyValue(thingModel, true)).thenReturn((byte) 1);
+
+ // 璋冪敤锛屽苟鏂█锛氶潪瀛楃涓� key 涓嶅奖鍝嶅叾瀹冨悎娉曞睘鎬�
+ assertDoesNotThrow(() -> service.saveDeviceProperty(device, message));
+
+ // 鏂█锛氬彧鍐欏叆鍚堟硶灞炴��
Map<String, Object> dbProperties = captureMapperInsertProperties();
- Object actual = dbProperties.get("PowerSwitch");
- assertTrue(actual instanceof Byte, "BOOL 灞炴�у簲琚浆涓� Byte 绫诲瀷锛屽疄闄呬负 " + (actual == null ? "null" : actual.getClass()));
- assertEquals(expected, actual);
+ assertEquals(1, dbProperties.size());
+ assertEquals((byte) 1, dbProperties.get("PowerSwitch"));
+ }
+
+ @Test
+ public void testDefineDevicePropertyData_fieldNameToLowerCase() {
+ // 鍑嗗鍙傛暟锛氬叏澶у啓缂╁啓鍜岄┘宄扮缉鍐欓兘闇�瑕佽浆鎹负 TDengine 瀹為檯鐨勫皬鍐欏瓧娈靛悕
+ Long productId = 2L;
+ IotProductDO product = IotProductDO.builder().id(productId).build();
+ List<IotThingModelDO> thingModels = Arrays.asList(
+ buildThingModel("Ua", IotDataSpecsDataTypeEnum.FLOAT.getDataType()),
+ buildThingModel("PfT", IotDataSpecsDataTypeEnum.FLOAT.getDataType()),
+ buildThingModel("PT", IotDataSpecsDataTypeEnum.FLOAT.getDataType()),
+ buildThingModel("PA", IotDataSpecsDataTypeEnum.FLOAT.getDataType()));
+ thingModels.forEach(thingModel -> thingModel.setType(IotThingModelTypeEnum.PROPERTY.getType()));
+
+ // mock 鏂规硶
+ when(productService.validateProductExists(productId)).thenReturn(product);
+ when(thingModelService.getThingModelListByProductId(productId)).thenReturn(thingModels);
+ when(devicePropertyMapper.getProductPropertySTableFieldList(productId)).thenReturn(Collections.emptyList());
+
+ // 璋冪敤
+ service.defineDevicePropertyData(productId);
+
+ // 鏂█锛氬瓧娈靛悕缁熶竴涓哄皬鍐欎笅鍒掔嚎锛岄伩鍏� PT 鍜屾暟鎹簱涓殑 pt 琚鍒や负涓嶅悓瀛楁
+ ArgumentCaptor<List<TDengineTableField>> captor = ArgumentCaptor.forClass(List.class);
+ verify(devicePropertyMapper).createProductPropertySTable(eq(productId), captor.capture());
+ assertEquals(Arrays.asList("ua", "pf_t", "pt", "pa"), captor.getValue().stream()
+ .map(TDengineTableField::getField)
+ .collect(Collectors.toList()));
}
// ========== 杈呭姪鏂规硶 ==========
@@ -173,7 +219,7 @@
/**
* 鏋勯�犱竴鏉″睘鎬т笂鎶ユ秷鎭�
*/
- private IotDeviceMessage buildMessage(Map<String, Object> params) {
+ private IotDeviceMessage buildMessage(Map<?, ?> params) {
IotDeviceMessage message = new IotDeviceMessage();
message.setMethod(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod());
message.setParams(params);
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimerConditionIntegrationTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimerConditionIntegrationTest.java
index 479ba40..a760bf7 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimerConditionIntegrationTest.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimerConditionIntegrationTest.java
@@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.iot.service.rule.scene;
import cn.hutool.core.collection.ListUtil;
+import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.iot.core.enums.device.IotDeviceStateEnum;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
@@ -21,6 +23,9 @@
import org.junit.jupiter.api.*;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.lang.reflect.Field;
import java.util.*;
@@ -43,8 +48,23 @@
*
* @author HUIHUI
*/
+@SpringJUnitConfig(classes = IotSceneRuleTimerConditionIntegrationTest.TestConfig.class)
public class IotSceneRuleTimerConditionIntegrationTest extends BaseMockitoUnitTest {
+ /**
+ * 娉ㄥ叆涓�涓� SpringUtil锛岃В鏋� EL 琛ㄨ揪寮忔椂闇�瑕�
+ * {@link SpringExpressionUtils#parseExpression}
+ */
+ @Configuration
+ static class TestConfig {
+
+ @Bean
+ public SpringUtil springUtil() {
+ return new SpringUtil();
+ }
+
+ }
+
@InjectMocks
private IotSceneRuleServiceImpl sceneRuleService;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleActionTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleActionTest.java
index 6bce069..5b2a4cb 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleActionTest.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleActionTest.java
@@ -106,6 +106,9 @@
IotAlertReceiveTypeEnum.SMS.getType(),
IotAlertReceiveTypeEnum.MAIL.getType(),
IotAlertReceiveTypeEnum.NOTIFY.getType()));
+ c.setSmsTemplateCode("custom_sms");
+ c.setMailTemplateCode("custom_mail");
+ c.setNotifyTemplateCode("custom_notify");
});
IotDeviceDO device = randomPojo(IotDeviceDO.class);
@@ -130,13 +133,13 @@
ArgumentCaptor<SmsSendSingleToUserReqDTO> smsCaptor = ArgumentCaptor.forClass(SmsSendSingleToUserReqDTO.class);
verify(smsSendApi, times(1)).sendSingleSmsToAdmin(smsCaptor.capture());
assertEquals(userId, smsCaptor.getValue().getUserId());
- assertEquals(IotAlertReceiveTypeEnum.SMS.getTemplateCode(), smsCaptor.getValue().getTemplateCode());
+ assertEquals("custom_sms", smsCaptor.getValue().getTemplateCode());
ArgumentCaptor<MailSendSingleToUserReqDTO> mailCaptor = ArgumentCaptor.forClass(MailSendSingleToUserReqDTO.class);
verify(mailSendApi, times(1)).sendSingleMailToAdmin(mailCaptor.capture());
- assertEquals(IotAlertReceiveTypeEnum.MAIL.getTemplateCode(), mailCaptor.getValue().getTemplateCode());
+ assertEquals("custom_mail", mailCaptor.getValue().getTemplateCode());
ArgumentCaptor<NotifySendSingleToUserReqDTO> notifyCaptor = ArgumentCaptor.forClass(NotifySendSingleToUserReqDTO.class);
verify(notifyMessageSendApi, times(1)).sendSingleMessageToAdmin(notifyCaptor.capture());
- assertEquals(IotAlertReceiveTypeEnum.NOTIFY.getTemplateCode(), notifyCaptor.getValue().getTemplateCode());
+ assertEquals("custom_notify", notifyCaptor.getValue().getTemplateCode());
}
@Test
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImplTest.java
new file mode 100644
index 0000000..2668c43
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImplTest.java
@@ -0,0 +1,201 @@
+package cn.iocoder.yudao.module.iot.service.thingmodel;
+
+import cn.hutool.core.date.LocalDateTimeUtil;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelBoolOrEnumDataSpecs;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs;
+import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceModbusPointService;
+import cn.iocoder.yudao.module.iot.service.product.IotProductService;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link IotThingModelServiceImpl} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Import(IotThingModelServiceImpl.class)
+public class IotThingModelServiceImplTest extends BaseDbUnitTest {
+
+ @Resource
+ private IotThingModelServiceImpl thingModelService;
+
+ @MockitoBean
+ private IotProductService productService;
+ @MockitoBean
+ private IotDeviceModbusPointService deviceModbusPointService;
+
+ @Test
+ public void testConvertThingModelPropertyValue_boolFromBooleanTrue() {
+ assertBoolValueConvertedToByte(true, (byte) 1);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_boolFromBooleanFalse() {
+ assertBoolValueConvertedToByte(false, (byte) 0);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_boolFromStringTrue() {
+ assertBoolValueConvertedToByte("true", (byte) 1);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_boolFromStringFalse() {
+ assertBoolValueConvertedToByte("false", (byte) 0);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_boolFromNumberOne() {
+ assertBoolValueConvertedToByte(1, (byte) 1);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_boolFromNumberZero() {
+ assertBoolValueConvertedToByte(0, (byte) 0);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_boolInvalid() {
+ IotThingModelDO thingModel = buildThingModel("PowerSwitch", IotDataSpecsDataTypeEnum.BOOL.getDataType());
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, "yes");
+
+ assertNull(result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_enumFromStringNumber() {
+ IotThingModelDO thingModel = buildEnumThingModel("WorkMode", enumSpec("Auto", 1), enumSpec("Manual", 2));
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, "1");
+
+ assertEquals((byte) 1, result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_enumFromSpecName() {
+ IotThingModelDO thingModel = buildEnumThingModel("WorkMode", enumSpec("Auto", 1), enumSpec("Manual", 2));
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, "Manual");
+
+ assertEquals((byte) 2, result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_enumInvalidSpecValue() {
+ IotThingModelDO thingModel = buildEnumThingModel("WorkMode", enumSpec("Auto", 1), enumSpec("Manual", 2));
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, 3);
+
+ assertNull(result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_enumOutOfTinyIntRange() {
+ IotThingModelDO thingModel = buildThingModel("WorkMode", IotDataSpecsDataTypeEnum.ENUM.getDataType());
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, 128);
+
+ assertNull(result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_dateFromLocalDateTime() {
+ IotThingModelDO thingModel = buildThingModel("CollectTime", IotDataSpecsDataTypeEnum.DATE.getDataType());
+ LocalDateTime collectTime = LocalDateTime.of(2025, 1, 2, 3, 4, 5);
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, collectTime);
+
+ assertEquals(LocalDateTimeUtil.toEpochMilli(collectTime), result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_dateFromString() {
+ IotThingModelDO thingModel = buildThingModel("CollectTime", IotDataSpecsDataTypeEnum.DATE.getDataType());
+ LocalDateTime collectTime = LocalDateTime.of(2025, 1, 2, 3, 4, 5);
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, "2025-01-02 03:04:05");
+
+ assertEquals(LocalDateTimeUtil.toEpochMilli(collectTime), result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_intInvalid() {
+ IotThingModelDO thingModel = buildThingModel("Temperature", IotDataSpecsDataTypeEnum.INT.getDataType());
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, "abc");
+
+ assertNull(result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_textOverLength() {
+ IotThingModelDO thingModel = buildTextThingModel("Remark", 3);
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, "abcd");
+
+ assertNull(result);
+ }
+
+ @Test
+ public void testConvertThingModelPropertyValue_structToJson() {
+ IotThingModelDO thingModel = buildThingModel("GeoLocation", IotDataSpecsDataTypeEnum.STRUCT.getDataType());
+ Map<String, Object> value = new HashMap<>();
+ value.put("Longitude", 120.1D);
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, value);
+
+ assertEquals(JsonUtils.toJsonString(value), result);
+ }
+
+ private void assertBoolValueConvertedToByte(Object reportedValue, byte expected) {
+ IotThingModelDO thingModel = buildThingModel("PowerSwitch", IotDataSpecsDataTypeEnum.BOOL.getDataType());
+
+ Object result = thingModelService.convertThingModelPropertyValue(thingModel, reportedValue);
+
+ assertEquals(expected, result);
+ }
+
+ private IotThingModelDO buildThingModel(String identifier, String dataType) {
+ ThingModelProperty property = new ThingModelProperty();
+ property.setIdentifier(identifier);
+ property.setDataType(dataType);
+ return IotThingModelDO.builder().identifier(identifier).property(property).build();
+ }
+
+ private IotThingModelDO buildEnumThingModel(String identifier, ThingModelBoolOrEnumDataSpecs... dataSpecsList) {
+ IotThingModelDO thingModel = buildThingModel(identifier, IotDataSpecsDataTypeEnum.ENUM.getDataType());
+ thingModel.getProperty().setDataSpecsList(Arrays.asList(dataSpecsList));
+ return thingModel;
+ }
+
+ private ThingModelBoolOrEnumDataSpecs enumSpec(String name, Integer value) {
+ ThingModelBoolOrEnumDataSpecs dataSpecs = new ThingModelBoolOrEnumDataSpecs();
+ dataSpecs.setName(name);
+ dataSpecs.setValue(value);
+ return dataSpecs;
+ }
+
+ private IotThingModelDO buildTextThingModel(String identifier, Integer length) {
+ IotThingModelDO thingModel = buildThingModel(identifier, IotDataSpecsDataTypeEnum.TEXT.getDataType());
+ ThingModelDateOrTextDataSpecs dataSpecs = new ThingModelDateOrTextDataSpecs();
+ dataSpecs.setLength(length);
+ thingModel.getProperty().setDataSpecs(dataSpecs);
+ return thingModel;
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-core/pom.xml b/yudao-module-iot/yudao-module-iot-core/pom.xml
index 30ebc2d..eae864d 100644
--- a/yudao-module-iot/yudao-module-iot-core/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-core/pom.xml
@@ -56,8 +56,8 @@
</dependency>
<dependency>
- <groupId>org.springframework.kafka</groupId>
- <artifactId>spring-kafka</artifactId>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-kafka</artifactId>
<optional>true</optional>
</dependency>
@@ -69,4 +69,4 @@
</dependency>
</dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java
index 67ae673..39f59f3 100644
--- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java
+++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusAutoConfiguration.java
@@ -6,7 +6,9 @@
import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessage;
import cn.iocoder.yudao.framework.mq.redis.core.stream.AbstractRedisStreamMessageListener;
import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
+import cn.iocoder.yudao.module.iot.core.messagebus.core.kafka.IotKafkaMessageBus;
import cn.iocoder.yudao.module.iot.core.messagebus.core.local.IotLocalMessageBus;
+import cn.iocoder.yudao.module.iot.core.messagebus.core.rabbitmq.IotRabbitMQMessageBus;
import cn.iocoder.yudao.module.iot.core.messagebus.core.redis.IotRedisMessageBus;
import cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq.IotRocketMQMessageBus;
import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
@@ -14,15 +16,20 @@
import org.apache.rocketmq.spring.autoconfigure.RocketMQProperties;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RedissonClient;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.kafka.autoconfigure.KafkaProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.kafka.core.KafkaTemplate;
import java.util.List;
@@ -73,6 +80,21 @@
}
+ // ==================== Kafka 瀹炵幇 ====================
+
+ @Configuration
+ @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "kafka")
+ @ConditionalOnClass(KafkaTemplate.class)
+ public static class IotKafkaMessageBusConfiguration {
+
+ @Bean
+ public IotKafkaMessageBus iotKafkaMessageBus(KafkaProperties kafkaProperties) {
+ log.info("[iotKafkaMessageBus][鍒涘缓 IoT Kafka 娑堟伅鎬荤嚎]");
+ return new IotKafkaMessageBus(kafkaProperties);
+ }
+
+ }
+
// ==================== Redis 瀹炵幇 ====================
/**
@@ -99,7 +121,8 @@
RedisMQTemplate redisTemplate,
RedissonClient redissonClient) {
List<AbstractRedisStreamMessageListener<?>> listeners = getListeners(messageBus);
- return new RedisPendingMessageResendJob(listeners, redisTemplate, redissonClient);
+ return new RedisPendingMessageResendJob(listeners, redisTemplate, redissonClient,
+ RedisPendingMessageResendJob.IOT_RESEND_LOCK_KEY);
}
/**
@@ -110,7 +133,8 @@
RedisMQTemplate redisTemplate,
RedissonClient redissonClient) {
List<AbstractRedisStreamMessageListener<?>> listeners = getListeners(messageBus);
- return new RedisStreamMessageCleanupJob(listeners, redisTemplate, redissonClient);
+ return new RedisStreamMessageCleanupJob(listeners, redisTemplate, redissonClient,
+ RedisStreamMessageCleanupJob.IOT_CLEANUP_LOCK_KEY);
}
private List<AbstractRedisStreamMessageListener<?>> getListeners(IotRedisMessageBus messageBus) {
@@ -126,4 +150,25 @@
}
-}
\ No newline at end of file
+ // ==================== RabbitMQ 瀹炵幇 ====================
+
+ @Configuration
+ @ConditionalOnProperty(prefix = "yudao.iot.message-bus", name = "type", havingValue = "rabbitmq")
+ @ConditionalOnClass(RabbitTemplate.class)
+ public static class IotRabbitMQMessageBusConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public RabbitAdmin rabbitAdmin(RabbitTemplate rabbitTemplate) {
+ return new RabbitAdmin(rabbitTemplate);
+ }
+
+ @Bean
+ public IotRabbitMQMessageBus iotRabbitMQMessageBus(RabbitTemplate rabbitTemplate, RabbitAdmin rabbitAdmin) {
+ log.info("[iotRabbitMQMessageBus][鍒涘缓 IoT RabbitMQ 娑堟伅鎬荤嚎]");
+ return new IotRabbitMQMessageBus(rabbitTemplate, rabbitAdmin);
+ }
+
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusProperties.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusProperties.java
index 501eb2b..607f2b8 100644
--- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusProperties.java
+++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/config/IotMessageBusProperties.java
@@ -20,9 +20,9 @@
/**
* 娑堟伅鎬荤嚎绫诲瀷
*
- * 鍙�夊�硷細local銆乺edis銆乺ocketmq銆乺abbitmq
+ * 鍙�夊�硷細local銆乺edis銆乺ocketmq銆乲afka銆乺abbitmq
*/
@NotNull(message = "IoT 娑堟伅鎬荤嚎绫诲瀷涓嶈兘涓虹┖")
private String type = "local";
-}
\ No newline at end of file
+}
diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/kafka/IotKafkaMessageBus.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/kafka/IotKafkaMessageBus.java
new file mode 100644
index 0000000..6644dcb
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/kafka/IotKafkaMessageBus.java
@@ -0,0 +1,127 @@
+package cn.iocoder.yudao.module.iot.core.messagebus.core.kafka;
+
+import cn.hutool.core.util.TypeUtil;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
+import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
+import jakarta.annotation.PreDestroy;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.serialization.StringDeserializer;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.boot.kafka.autoconfigure.KafkaProperties;
+import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.listener.AcknowledgingMessageListener;
+import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
+import org.springframework.kafka.listener.ContainerProperties;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * 鍩轰簬 Kafka 鐨� {@link IotMessageBus} 瀹炵幇绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+public class IotKafkaMessageBus implements IotMessageBus {
+
+ private final KafkaTemplate<String, String> kafkaTemplate;
+
+ private final KafkaProperties kafkaProperties;
+
+ @Getter
+ private final List<IotMessageSubscriber<?>> subscribers = new ArrayList<>();
+
+ private final List<ConcurrentMessageListenerContainer<String, String>> containers = new ArrayList<>();
+
+ public IotKafkaMessageBus(KafkaProperties kafkaProperties) {
+ this.kafkaProperties = kafkaProperties;
+ this.kafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory<>(buildProducerProperties(kafkaProperties)));
+ }
+
+ @Override
+ public void post(String topic, Object message) {
+ String messageJson = JsonUtils.toJsonString(message);
+ try {
+ kafkaTemplate.send(topic, messageJson).get();
+ log.info("[post][topic({}) 鍙戦�佹秷鎭�({})]", topic, message);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException(String.format("鍙戦�� Kafka 娑堟伅澶辫触锛宼opic(%s) message(%s)", topic, message), e);
+ } catch (ExecutionException e) {
+ throw new IllegalStateException(String.format("鍙戦�� Kafka 娑堟伅澶辫触锛宼opic(%s) message(%s)", topic, message), e);
+ }
+ }
+
+ @Override
+ public void register(IotMessageSubscriber<?> subscriber) {
+ Type type = TypeUtil.getTypeArgument(subscriber.getClass(), 0);
+ if (type == null) {
+ throw new IllegalStateException(String.format("绫诲瀷(%s) 闇�瑕佽缃秷鎭被鍨�", getClass().getName()));
+ }
+
+ // 1. 鍒涘缓娑堣垂瀹瑰櫒
+ ContainerProperties containerProperties = new ContainerProperties(subscriber.getTopic());
+ containerProperties.setGroupId(subscriber.getGroup());
+ containerProperties.setAckMode(ContainerProperties.AckMode.MANUAL_IMMEDIATE);
+ containerProperties.setMissingTopicsFatal(false);
+ containerProperties.setMessageListener((AcknowledgingMessageListener<String, String>) (message, acknowledgment) -> {
+ try {
+ subscriber.onMessage(JsonUtils.parseObject(message.value(), type));
+ acknowledgment.acknowledge();
+ } catch (Exception ex) {
+ log.error("[onMessage][topic({}/{}) message({}) 娑堣垂鑰�({}) 澶勭悊寮傚父]",
+ subscriber.getTopic(), subscriber.getGroup(), message, subscriber.getClass().getName(), ex);
+ throw ex;
+ }
+ });
+ ConcurrentMessageListenerContainer<String, String> container = new ConcurrentMessageListenerContainer<>(
+ new DefaultKafkaConsumerFactory<>(buildConsumerProperties(kafkaProperties, subscriber.getGroup())),
+ containerProperties);
+ container.start();
+
+ // 2. 淇濆瓨娑堣垂鑰呭紩鐢�
+ containers.add(container);
+ subscribers.add(subscriber);
+ }
+
+ @PreDestroy
+ public void destroy() {
+ for (ConcurrentMessageListenerContainer<String, String> container : containers) {
+ try {
+ container.stop();
+ log.info("[destroy][鍏抽棴 Kafka 娑堣垂鑰呭鍣ㄦ垚鍔焆");
+ } catch (Exception e) {
+ log.error("[destroy][鍏抽棴 Kafka 娑堣垂鑰呭鍣ㄥ紓甯竇", e);
+ }
+ }
+ kafkaTemplate.destroy();
+ }
+
+ private static Map<String, Object> buildProducerProperties(KafkaProperties kafkaProperties) {
+ Map<String, Object> properties = new HashMap<>(kafkaProperties.buildProducerProperties());
+ properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ return properties;
+ }
+
+ private static Map<String, Object> buildConsumerProperties(KafkaProperties kafkaProperties, String group) {
+ Map<String, Object> properties = new HashMap<>(kafkaProperties.buildConsumerProperties());
+ properties.put(ConsumerConfig.GROUP_ID_CONFIG, group);
+ properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+ properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+ properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
+ properties.putIfAbsent(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
+ return properties;
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rabbitmq/IotRabbitMQMessageBus.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rabbitmq/IotRabbitMQMessageBus.java
new file mode 100644
index 0000000..9ce1dfa
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rabbitmq/IotRabbitMQMessageBus.java
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.iot.core.messagebus.core.rabbitmq;
+
+import cn.hutool.core.util.TypeUtil;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
+import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
+import jakarta.annotation.PreDestroy;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.AcknowledgeMode;
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.MessageBuilder;
+import org.springframework.amqp.core.Queue;
+import org.springframework.amqp.core.TopicExchange;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
+import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鍩轰簬 RabbitMQ 鐨� {@link IotMessageBus} 瀹炵幇绫�
+ *
+ * @author ywc
+ */
+@RequiredArgsConstructor
+@Slf4j
+public class IotRabbitMQMessageBus implements IotMessageBus {
+
+ private static final String ROUTING_KEY = "#";
+
+ private final RabbitTemplate rabbitTemplate;
+
+ private final RabbitAdmin rabbitAdmin;
+
+ @Getter
+ private final List<IotMessageSubscriber<?>> subscribers = new ArrayList<>();
+
+ private final List<SimpleMessageListenerContainer> containers = new ArrayList<>();
+
+ @Override
+ public void post(String topic, Object message) {
+ rabbitTemplate.send(topic, ROUTING_KEY, MessageBuilder.withBody(JsonUtils.toJsonByte(message)).build());
+ log.info("[post][topic({}) 鍙戦�佹秷鎭�({})]", topic, message);
+ }
+
+ @Override
+ @SuppressWarnings("DataFlowIssue")
+ public void register(IotMessageSubscriber<?> subscriber) {
+ Type type = TypeUtil.getTypeArgument(subscriber.getClass(), 0);
+ if (type == null) {
+ throw new IllegalStateException(String.format("绫诲瀷(%s) 闇�瑕佽缃秷鎭被鍨�", getClass().getName()));
+ }
+
+ // 1.1 澹版槑浜ゆ崲鏈恒�侀槦鍒楀拰缁戝畾鍏崇郴
+ Queue queue = new Queue(subscriber.getGroup(), true, false, false);
+ rabbitAdmin.declareQueue(queue);
+ TopicExchange exchange = new TopicExchange(subscriber.getTopic());
+ rabbitAdmin.declareExchange(exchange);
+ Binding binding = BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY);
+ rabbitAdmin.declareBinding(binding);
+
+ // 1.2 鍒涘缓娑堣垂瀹瑰櫒
+ SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(rabbitTemplate.getConnectionFactory());
+ container.setQueues(queue);
+ container.setConcurrentConsumers(1);
+ container.setMaxConcurrentConsumers(10);
+ container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
+ container.setMessageListener((ChannelAwareMessageListener) (message, channel) -> {
+ try {
+ subscriber.onMessage(JsonUtils.parseObject(message.getBody(), type));
+ channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+ } catch (Exception ex) {
+ log.error("[onMessage][topic({}/{}) message({}) 娑堣垂鑰�({}) 澶勭悊寮傚父]",
+ subscriber.getTopic(), subscriber.getGroup(), message, subscriber.getClass().getName(), ex);
+ channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
+ }
+ });
+ container.start();
+
+ // 2. 淇濆瓨娑堣垂鑰呭紩鐢�
+ containers.add(container);
+ subscribers.add(subscriber);
+ }
+
+ @PreDestroy
+ public void destroy() {
+ for (SimpleMessageListenerContainer container : containers) {
+ try {
+ container.stop();
+ container.destroy();
+ log.info("[destroy][鍏抽棴 RabbitMQ 娑堣垂鑰呭鍣ㄦ垚鍔焆");
+ } catch (Exception e) {
+ log.error("[destroy][鍏抽棴 RabbitMQ 娑堣垂鑰呭鍣ㄥ紓甯竇", e);
+ }
+ }
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-gateway/pom.xml b/yudao-module-iot/yudao-module-iot-gateway/pom.xml
index 51e55c3..43fea45 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-gateway/pom.xml
@@ -27,17 +27,35 @@
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
-
- <!-- 娑堟伅闃熷垪鐩稿叧 -->
<dependency>
- <groupId>org.apache.rocketmq</groupId>
- <artifactId>rocketmq-spring-boot-starter</artifactId>
- <!-- TODO @鑺嬭壙锛氭秷鎭槦鍒楋紝鍚庣画鍙兘鍘绘帀锛岄粯璁や笉浣跨敤 rocketmq -->
- <optional>true</optional>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-restclient</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- 宸ュ叿绫荤浉鍏� -->
<dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+
+ <!-- 娑堟伅闃熷垪鐩稿叧 -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-kafka</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.rocketmq</groupId>
+ <artifactId>rocketmq-spring-boot-starter</artifactId>
+ <optional>true</optional>
+ </dependency>
+
+ <!-- Vert.x 鐩稿叧 -->
+ <dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
</dependency>
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/manager/AbstractIotModbusPollScheduler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/manager/AbstractIotModbusPollScheduler.java
index e62f85f..a41634b 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/manager/AbstractIotModbusPollScheduler.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/manager/AbstractIotModbusPollScheduler.java
@@ -12,6 +12,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
/**
@@ -19,6 +20,8 @@
* <p>
* 灏佽閫氱敤鐨勫畾鏃跺櫒绠$悊銆乸er-device 璇锋眰闃熷垪闄愰�熼�昏緫銆�
* 瀛愮被鍙渶瀹炵幇 {@link #pollPoint(Long, Long)} 瀹氫箟鍏蜂綋鐨勮疆璇㈠姩浣溿��
+ * 濡傞渶灏嗗涓偣浣嶅悎骞朵负涓�涓疆璇换鍔★紝鍙鐩� {@link #buildPollTasks(IotModbusDeviceConfigRespDTO)}
+ * 鍜� {@link #pollTask(Long, String)}銆�
* <p>
*
* @author 鑺嬮亾婧愮爜
@@ -38,9 +41,9 @@
private static final int MAX_QUEUE_SIZE = 1000;
/**
- * 璁惧鐐逛綅鐨勫畾鏃跺櫒鏄犲皠锛歞eviceId -> (pointId -> PointTimerInfo)
+ * 璁惧杞浠诲姟鐨勫畾鏃跺櫒鏄犲皠锛歞eviceId -> (taskKey -> PollTimerInfo)
*/
- private final Map<Long, Map<Long, PointTimerInfo>> devicePointTimers = new ConcurrentHashMap<>();
+ private final Map<Long, Map<String, PollTimerInfo>> devicePollTimers = new ConcurrentHashMap<>();
/**
* per-device 璇锋眰闃熷垪锛歞eviceId -> 寰呮墽琛岃姹傞槦鍒�
@@ -60,11 +63,29 @@
}
/**
- * 鐐逛綅瀹氭椂鍣ㄤ俊鎭�
+ * 杞浠诲姟淇℃伅
*/
@Data
@AllArgsConstructor
- private static class PointTimerInfo {
+ protected static class PollTask {
+
+ /**
+ * 浠诲姟鏍囪瘑
+ */
+ private String key;
+ /**
+ * 杞闂撮殧锛堢敤浜庡垽鏂槸鍚﹂渶瑕佹洿鏂板畾鏃跺櫒锛�
+ */
+ private Integer pollInterval;
+
+ }
+
+ /**
+ * 杞瀹氭椂鍣ㄤ俊鎭�
+ */
+ @Data
+ @AllArgsConstructor
+ private static class PollTimerInfo {
/**
* Vert.x 瀹氭椂鍣� ID
@@ -82,75 +103,84 @@
/**
* 鏇存柊杞浠诲姟锛堝閲忔洿鏂帮級
*
- * 1. 銆愬垹闄ゃ�戠偣浣嶏細鍋滄瀵瑰簲鐨勮疆璇㈠畾鏃跺櫒
- * 2. 銆愭柊澧炪�戠偣浣嶏細鍒涘缓瀵瑰簲鐨勮疆璇㈠畾鏃跺櫒
- * 3. 銆愪慨鏀广�戠偣浣嶏細pollInterval 鍙樺寲锛岄噸寤哄搴旂殑杞瀹氭椂鍣�
- * 銆愪慨鏀广�戝叾浠栧睘鎬у彉鍖栵細涓嶉渶瑕侀噸寤哄畾鏃跺櫒锛坧ollPoint 杩愯鏃朵粠 configCache 鍙栨渶鏂� point锛�
+ * 1. 銆愬垹闄ゃ�戜换鍔★細鍋滄瀵瑰簲鐨勮疆璇㈠畾鏃跺櫒
+ * 2. 銆愭柊澧炪�戜换鍔★細鍒涘缓瀵瑰簲鐨勮疆璇㈠畾鏃跺櫒
+ * 3. 銆愪慨鏀广�戜换鍔★細pollInterval 鍙樺寲锛岄噸寤哄搴旂殑杞瀹氭椂鍣�
+ * 銆愪慨鏀广�戝叾浠栧睘鎬у彉鍖栵細涓嶉渶瑕侀噸寤哄畾鏃跺櫒锛坧ollTask 杩愯鏃朵粠 configCache 鍙栨渶鏂伴厤缃級
*/
public void updatePolling(IotModbusDeviceConfigRespDTO config) {
Long deviceId = config.getDeviceId();
- List<IotModbusPointRespDTO> newPoints = config.getPoints();
- Map<Long, PointTimerInfo> currentTimers = devicePointTimers
+ List<PollTask> newTasks = buildPollTasks(config);
+ Map<String, PollTimerInfo> currentTimers = devicePollTimers
.computeIfAbsent(deviceId, k -> new ConcurrentHashMap<>());
- // 1.1 璁$畻鏂伴厤缃腑鐨勭偣浣� ID 闆嗗悎
- Set<Long> newPointIds = convertSet(newPoints, IotModbusPointRespDTO::getId);
- // 1.2 璁$畻鍒犻櫎鐨勭偣浣� ID 闆嗗悎
- Set<Long> removedPointIds = new HashSet<>(currentTimers.keySet());
- removedPointIds.removeAll(newPointIds);
+ // 1.1 璁$畻鏂伴厤缃腑鐨勪换鍔� Key 闆嗗悎
+ Set<String> newTaskKeys = convertSet(newTasks, PollTask::getKey);
+ // 1.2 璁$畻鍒犻櫎鐨勪换鍔� Key 闆嗗悎
+ Set<String> removedTaskKeys = new HashSet<>(currentTimers.keySet());
+ removedTaskKeys.removeAll(newTaskKeys);
- // 2. 澶勭悊鍒犻櫎鐨勭偣浣嶏細鍋滄涓嶅啀瀛樺湪鐨勫畾鏃跺櫒
- for (Long pointId : removedPointIds) {
- PointTimerInfo timerInfo = currentTimers.remove(pointId);
+ // 2. 澶勭悊鍒犻櫎鐨勪换鍔★細鍋滄涓嶅啀瀛樺湪鐨勫畾鏃跺櫒
+ for (String taskKey : removedTaskKeys) {
+ PollTimerInfo timerInfo = currentTimers.remove(taskKey);
if (timerInfo != null) {
vertx.cancelTimer(timerInfo.getTimerId());
- log.debug("[updatePolling][璁惧 {} 鐐逛綅 {} 瀹氭椂鍣ㄥ凡鍒犻櫎]", deviceId, pointId);
+ log.debug("[updatePolling][璁惧 {} 杞浠诲姟 {} 瀹氭椂鍣ㄥ凡鍒犻櫎]", deviceId, taskKey);
}
}
- // 3. 澶勭悊鏂板鍜屼慨鏀圭殑鐐逛綅
- if (CollUtil.isEmpty(newPoints)) {
+ // 3. 澶勭悊鏂板鍜屼慨鏀圭殑浠诲姟
+ if (CollUtil.isEmpty(newTasks)) {
return;
}
- for (IotModbusPointRespDTO point : newPoints) {
- Long pointId = point.getId();
- Integer newPollInterval = point.getPollInterval();
- PointTimerInfo existingTimer = currentTimers.get(pointId);
- // 3.1 鏂板鐐逛綅锛氬垱寤哄畾鏃跺櫒
+ for (PollTask task : newTasks) {
+ String taskKey = task.getKey();
+ Integer newPollInterval = task.getPollInterval();
+ PollTimerInfo existingTimer = currentTimers.get(taskKey);
+ // 3.1 鏂板浠诲姟锛氬垱寤哄畾鏃跺櫒
if (existingTimer == null) {
- Long timerId = createPollTimer(deviceId, pointId, newPollInterval);
+ Long timerId = createPollTimer(deviceId, taskKey, newPollInterval);
if (timerId != null) {
- currentTimers.put(pointId, new PointTimerInfo(timerId, newPollInterval));
- log.debug("[updatePolling][璁惧 {} 鐐逛綅 {} 瀹氭椂鍣ㄥ凡鍒涘缓, interval={}ms]",
- deviceId, pointId, newPollInterval);
+ currentTimers.put(taskKey, new PollTimerInfo(timerId, newPollInterval));
+ log.debug("[updatePolling][璁惧 {} 杞浠诲姟 {} 瀹氭椂鍣ㄥ凡鍒涘缓, interval={}ms]",
+ deviceId, taskKey, newPollInterval);
}
} else if (!Objects.equals(existingTimer.getPollInterval(), newPollInterval)) {
// 3.2 pollInterval 鍙樺寲锛氶噸寤哄畾鏃跺櫒
vertx.cancelTimer(existingTimer.getTimerId());
- Long timerId = createPollTimer(deviceId, pointId, newPollInterval);
+ Long timerId = createPollTimer(deviceId, taskKey, newPollInterval);
if (timerId != null) {
- currentTimers.put(pointId, new PointTimerInfo(timerId, newPollInterval));
- log.debug("[updatePolling][璁惧 {} 鐐逛綅 {} 瀹氭椂鍣ㄥ凡鏇存柊, interval={}ms -> {}ms]",
- deviceId, pointId, existingTimer.getPollInterval(), newPollInterval);
+ currentTimers.put(taskKey, new PollTimerInfo(timerId, newPollInterval));
+ log.debug("[updatePolling][璁惧 {} 杞浠诲姟 {} 瀹氭椂鍣ㄥ凡鏇存柊, interval={}ms -> {}ms]",
+ deviceId, taskKey, existingTimer.getPollInterval(), newPollInterval);
} else {
- currentTimers.remove(pointId);
+ currentTimers.remove(taskKey);
}
}
- // 3.3 鍏朵粬灞炴�у彉鍖栵細鏃犻渶閲嶅缓瀹氭椂鍣紝鍥犱负 pollPoint() 杩愯鏃朵粠 configCache 鑾峰彇鏈�鏂� point锛岃嚜鍔ㄤ娇鐢ㄦ柊閰嶇疆
+ // 3.3 鍏朵粬灞炴�у彉鍖栵細鏃犻渶閲嶅缓瀹氭椂鍣紝鍥犱负 pollTask() 杩愯鏃朵粠 configCache 鑾峰彇鏈�鏂伴厤缃�
}
+ }
+
+ /**
+ * 鏋勫缓杞浠诲姟鍒楄〃
+ *
+ * 榛樿姣忎釜鐐逛綅涓�涓疆璇换鍔°�俆CP Client 绛夊崗璁彲瑕嗙洊璇ユ柟娉曪紝灏嗗涓偣浣嶅悎骞朵负涓�涓壒閲忚鍙栦换鍔°��
+ */
+ protected List<PollTask> buildPollTasks(IotModbusDeviceConfigRespDTO config) {
+ return convertList(config.getPoints(), point -> new PollTask(String.valueOf(point.getId()), point.getPollInterval()));
}
/**
* 鍒涘缓杞瀹氭椂鍣�
*/
- private Long createPollTimer(Long deviceId, Long pointId, Integer pollInterval) {
+ private Long createPollTimer(Long deviceId, String taskKey, Integer pollInterval) {
if (pollInterval == null || pollInterval <= 0) {
return null;
}
return vertx.setPeriodic(pollInterval, timerId -> {
try {
- submitPollRequest(deviceId, pointId);
+ submitPollRequest(deviceId, taskKey);
} catch (Exception e) {
- log.error("[createPollTimer][杞鐐逛綅澶辫触, deviceId={}, pointId={}]", deviceId, pointId, e);
+ log.error("[createPollTimer][杞浠诲姟澶辫触, deviceId={}, taskKey={}]", deviceId, taskKey, e);
}
});
}
@@ -160,7 +190,7 @@
/**
* 鎻愪氦杞璇锋眰鍒拌澶囪姹傞槦鍒楋紙淇濊瘉鍚岃澶囪姹傞棿闅旓級
*/
- private void submitPollRequest(Long deviceId, Long pointId) {
+ private void submitPollRequest(Long deviceId, String taskKey) {
// 1. 銆愰噸瑕併�戝皢璇锋眰娣诲姞鍒拌澶囩殑璇锋眰闃熷垪
Queue<Runnable> queue = deviceRequestQueues.computeIfAbsent(deviceId, k -> new ConcurrentLinkedQueue<>());
while (queue.size() >= MAX_QUEUE_SIZE) {
@@ -168,7 +198,7 @@
queue.poll();
log.warn("[submitPollRequest][璁惧 {} 璇锋眰闃熷垪宸叉弧({}), 涓㈠純鏈�鏃ц姹俔", deviceId, MAX_QUEUE_SIZE);
}
- queue.offer(() -> pollPoint(deviceId, pointId));
+ queue.offer(() -> pollTask(deviceId, taskKey));
// 2. 澶勭悊璁惧璇锋眰闃熷垪锛堝鏋滄病鏈夊欢杩� timer 鍦ㄧ瓑寰咃級
processDeviceQueue(deviceId);
@@ -239,6 +269,15 @@
// ========== 杞鎵ц ==========
/**
+ * 杞浠诲姟
+ *
+ * 榛樿灏嗕换鍔℃爣璇嗕綔涓虹偣浣� ID锛屾墽琛屽崟鐐硅疆璇€��
+ */
+ protected void pollTask(Long deviceId, String taskKey) {
+ pollPoint(deviceId, Long.valueOf(taskKey));
+ }
+
+ /**
* 杞鍗曚釜鐐逛綅锛堝瓙绫诲疄鐜板叿浣撶殑璇诲彇閫昏緫锛�
*
* @param deviceId 璁惧 ID
@@ -252,25 +291,25 @@
* 鍋滄璁惧鐨勮疆璇�
*/
public void stopPolling(Long deviceId) {
- Map<Long, PointTimerInfo> timers = devicePointTimers.remove(deviceId);
- if (CollUtil.isEmpty(timers)) {
- return;
- }
- for (PointTimerInfo timerInfo : timers.values()) {
- vertx.cancelTimer(timerInfo.getTimerId());
+ Map<String, PollTimerInfo> timers = devicePollTimers.remove(deviceId);
+ if (CollUtil.isNotEmpty(timers)) {
+ for (PollTimerInfo timerInfo : timers.values()) {
+ vertx.cancelTimer(timerInfo.getTimerId());
+ }
}
// 娓呯悊璇锋眰闃熷垪
deviceRequestQueues.remove(deviceId);
deviceLastRequestTime.remove(deviceId);
deviceDelayTimerActive.remove(deviceId);
- log.debug("[stopPolling][璁惧 {} 鍋滄浜� {} 涓疆璇㈠畾鏃跺櫒]", deviceId, timers.size());
+ log.debug("[stopPolling][璁惧 {} 鍋滄浜� {} 涓疆璇㈠畾鏃跺櫒]", deviceId,
+ CollUtil.isEmpty(timers) ? 0 : timers.size());
}
/**
* 鍋滄鎵�鏈夎疆璇�
*/
public void stopAll() {
- for (Long deviceId : new ArrayList<>(devicePointTimers.keySet())) {
+ for (Long deviceId : new ArrayList<>(devicePollTimers.keySet())) {
stopPolling(deviceId);
}
}
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java
index 1324f3a..1d52f8d 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java
@@ -39,11 +39,38 @@
public static Future<int[]> read(IotModbusTcpClientConnectionManager.ModbusConnection connection,
Integer slaveId,
IotModbusPointRespDTO point) {
+ return read(connection, slaveId, point.getFunctionCode(),
+ point.getRegisterAddress(), point.getRegisterCount(), point.getIdentifier());
+ }
+
+ /**
+ * 璇诲彇 Modbus 鏁版嵁
+ *
+ * @param connection Modbus 杩炴帴
+ * @param slaveId 浠庣珯鍦板潃
+ * @param functionCode 鍔熻兘鐮�
+ * @param registerAddress 瀵勫瓨鍣ㄨ捣濮嬪湴鍧�
+ * @param registerCount 瀵勫瓨鍣ㄦ暟閲�
+ * @return 鍘熷鍊硷紙int 鏁扮粍锛�
+ */
+ public static Future<int[]> read(IotModbusTcpClientConnectionManager.ModbusConnection connection,
+ Integer slaveId,
+ Integer functionCode,
+ Integer registerAddress,
+ Integer registerCount) {
+ return read(connection, slaveId, functionCode, registerAddress, registerCount, null);
+ }
+
+ private static Future<int[]> read(IotModbusTcpClientConnectionManager.ModbusConnection connection,
+ Integer slaveId,
+ Integer functionCode,
+ Integer registerAddress,
+ Integer registerCount,
+ String identifier) {
return connection.executeBlocking(tcpConnection -> {
try {
// 1. 鍒涘缓璇锋眰
- ModbusRequest request = createReadRequest(point.getFunctionCode(),
- point.getRegisterAddress(), point.getRegisterCount());
+ ModbusRequest request = createReadRequest(functionCode, registerAddress, registerCount);
request.setUnitID(slaveId);
// 2. 鎵ц浜嬪姟锛堣姹傦級
@@ -53,10 +80,10 @@
// 3. 瑙f瀽鍝嶅簲
ModbusResponse response = transaction.getResponse();
- return extractValues(response, point.getFunctionCode());
+ return extractValues(response, functionCode);
} catch (Exception e) {
- throw new RuntimeException(String.format("Modbus 璇诲彇澶辫触 [slaveId=%d, identifier=%s, address=%d]",
- slaveId, point.getIdentifier(), point.getRegisterAddress()), e);
+ throw new RuntimeException(String.format("Modbus 璇诲彇澶辫触 [slaveId=%d, identifier=%s, functionCode=%d, address=%d, count=%d]",
+ slaveId, identifier, functionCode, registerAddress, registerCount), e);
}
});
}
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollScheduler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollScheduler.java
index 946937d..fba2f75 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollScheduler.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollScheduler.java
@@ -9,7 +9,15 @@
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusTcpClientUtils;
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.handler.upstream.IotModbusTcpClientUpstreamHandler;
import io.vertx.core.Vertx;
+import lombok.AllArgsConstructor;
+import lombok.Data;
import lombok.extern.slf4j.Slf4j;
+
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
/**
* IoT Modbus TCP Client 杞璋冨害鍣細绠$悊鐐逛綅鐨勮疆璇㈠畾鏃跺櫒锛岃皟搴﹁鍙栦换鍔″苟涓婃姤缁撴灉
@@ -34,6 +42,47 @@
}
// ========== 杞鎵ц ==========
+
+ @Override
+ protected List<PollTask> buildPollTasks(IotModbusDeviceConfigRespDTO config) {
+ return convertList(buildReadSegments(config), segment -> new PollTask(segment.getKey(), segment.getPollInterval()));
+ }
+
+ /**
+ * 杞璇诲彇娈�
+ */
+ @Override
+ protected void pollTask(Long deviceId, String taskKey) {
+ // 1.1 浠� configCache 鑾峰彇鏈�鏂伴厤缃�
+ IotModbusDeviceConfigRespDTO config = configCacheService.getConfig(deviceId);
+ if (config == null || CollUtil.isEmpty(config.getPoints())) {
+ log.warn("[pollTask][璁惧 {} 娌℃湁閰嶇疆]", deviceId);
+ return;
+ }
+ // 1.2 鏌ユ壘璇诲彇娈点�傞厤缃彉鍖栧悗锛屽鏋滃綋鍓� taskKey 宸蹭笉瀛樺湪锛岀洿鎺ヨ烦杩囩瓑寰呬笅涓�杞� updatePolling 娓呯悊 timer
+ ReadSegment segment = findReadSegment(config, taskKey);
+ if (segment == null) {
+ log.debug("[pollTask][璁惧 {} 璇诲彇娈� {} 鏈壘鍒帮紝璺宠繃闄堟棫杞浠诲姟]", deviceId, taskKey);
+ return;
+ }
+
+ // 2.1 鑾峰彇杩炴帴
+ IotModbusTcpClientConnectionManager.ModbusConnection connection = connectionManager.getConnection(deviceId);
+ if (connection == null) {
+ log.warn("[pollTask][璁惧 {} 娌℃湁杩炴帴]", deviceId);
+ return;
+ }
+ // 2.2 鑾峰彇 slave ID
+ Integer slaveId = connectionManager.getSlaveId(deviceId);
+ Assert.notNull(slaveId, "璁惧 {} 娌℃湁閰嶇疆 slaveId", deviceId);
+
+ // 3. 鎵ц Modbus 鎵归噺璇诲彇
+ IotModbusTcpClientUtils.read(connection, slaveId, segment.getFunctionCode(),
+ segment.getStartAddress(), segment.getRegisterCount())
+ .onSuccess(rawValues -> handleSegmentReadResult(config, segment, rawValues))
+ .onFailure(e -> log.error("[pollTask][璇诲彇鐐逛綅娈靛け璐�, deviceId={}, segment={}]",
+ deviceId, segment.getKey(), e));
+ }
/**
* 杞鍗曚釜鐐逛綅
@@ -70,4 +119,174 @@
deviceId, point.getIdentifier(), e));
}
+ private void handleSegmentReadResult(IotModbusDeviceConfigRespDTO config,
+ ReadSegment segment,
+ int[] rawValues) {
+ for (IotModbusPointRespDTO point : segment.getPoints()) {
+ // 鎵归噺璇诲彇杩斿洖鐨勬槸鏁翠釜杩炵画鍦板潃娈碉紝闇�瑕佹寜鐐逛綅鍦板潃鍒囩墖鍚庡啀澶嶇敤鍗曠偣涓婃姤閫昏緫
+ int[] pointRawValues = extractPointRawValues(rawValues, segment, point);
+ if (pointRawValues == null) {
+ log.warn("[handleSegmentReadResult][璇诲彇娈电粨鏋滈暱搴︿笉瓒�, deviceId={}, segment={}, identifier={}]",
+ config.getDeviceId(), segment.getKey(), point.getIdentifier());
+ continue;
+ }
+ upstreamHandler.handleReadResult(config, point, pointRawValues);
+ }
+ }
+
+ private ReadSegment findReadSegment(IotModbusDeviceConfigRespDTO config, String taskKey) {
+ return CollUtil.findOne(buildReadSegments(config), segment -> segment.getKey().equals(taskKey));
+ }
+
+ /**
+ * 鏋勫缓鎵归噺璇诲彇娈�
+ *
+ * <p>鍙悎骞跺姛鑳界爜銆佽疆璇㈤棿闅旂浉鍚岋紝涓斿湴鍧�杩炵画鎴栭噸鍙犵殑鐐逛綅锛涗笉璺ㄥ姛鑳界爜銆佷笉璺ㄨ疆璇㈤棿闅旓紝閬垮厤鏀瑰彉鍘熸湁杞璇箟銆�
+ * 鍚屾椂鎸� Modbus 鍗忚闄愬埗鎺у埗鍗曟璇诲彇闀垮害锛岃秴杩囬檺鍒舵椂鎷嗘垚澶氫釜璇诲彇娈点��
+ */
+ static List<ReadSegment> buildReadSegments(IotModbusDeviceConfigRespDTO config) {
+ if (config == null) {
+ return Collections.emptyList();
+ }
+
+ // 1. 鎸夊姛鑳界爜鍜岃疆璇㈤棿闅斿垎缁勶細涓よ�呬换涓�涓嶅悓锛岄兘涓嶈兘鍏辩敤鍚屼竴娆� Modbus 璇昏姹�
+ List<IotModbusPointRespDTO> validPoints = filterList(config.getPoints(), IotModbusTcpClientPollScheduler::isValidReadPoint);
+ if (CollUtil.isEmpty(validPoints)) {
+ return Collections.emptyList();
+ }
+ Map<SegmentGroupKey, List<IotModbusPointRespDTO>> pointsByGroup = convertMultiMap(validPoints,
+ point -> new SegmentGroupKey(point.getFunctionCode(), point.getPollInterval()));
+
+ // 2. 缁勫唴鎸夊湴鍧�鎺掑簭鍚庯紝鍚堝苟杩炵画鎴栭噸鍙犲尯闂达紝鐢熸垚瀹為檯杞鐨勮鍙栨
+ List<ReadSegment> segments = new ArrayList<>();
+ for (Map.Entry<SegmentGroupKey, List<IotModbusPointRespDTO>> entry : pointsByGroup.entrySet()) {
+ List<IotModbusPointRespDTO> points = entry.getValue();
+ points.sort(Comparator.comparing(IotModbusPointRespDTO::getRegisterAddress)
+ .thenComparing(IotModbusPointRespDTO::getRegisterCount)
+ .thenComparing(IotModbusPointRespDTO::getId));
+ buildReadSegments(entry.getKey(), points, segments);
+ }
+ // 3. 鍥哄畾鎺掑簭锛屼繚璇佺敓鎴愮殑 taskKey 绋冲畾锛屼究浜� updatePolling 鍋氬閲忔洿鏂�
+ segments.sort(Comparator.comparing(ReadSegment::getFunctionCode)
+ .thenComparing(ReadSegment::getPollInterval)
+ .thenComparing(ReadSegment::getStartAddress));
+ return segments;
+ }
+
+ private static void buildReadSegments(SegmentGroupKey groupKey,
+ List<IotModbusPointRespDTO> points,
+ List<ReadSegment> segments) {
+ ReadSegment current = null;
+ int maxRegisterCount = getMaxRegisterCount(groupKey.getFunctionCode());
+ // points 宸叉寜 registerAddress 鎺掑簭锛屽洜姝ゅ彲浠ョ嚎鎬у悎骞惰繛缁�/閲嶅彔鍦板潃娈�
+ for (IotModbusPointRespDTO point : points) {
+ int pointStartAddress = point.getRegisterAddress();
+ int pointEndAddress = pointStartAddress + point.getRegisterCount();
+ // 1. 褰撳墠鐐逛綅鏃犳硶鍚堝苟鏃讹紝鏂板缓涓�涓鍙栨
+ if (current == null || !canMerge(current, pointStartAddress, pointEndAddress, maxRegisterCount)) {
+ current = new ReadSegment(groupKey.getFunctionCode(), groupKey.getPollInterval(),
+ pointStartAddress, point.getRegisterCount(), new ArrayList<>());
+ segments.add(current);
+ } else {
+ // 2. 褰撳墠鐐逛綅鍙悎骞舵椂锛屾墿灞曡鍙栨瑕嗙洊鑼冨洿
+ current.setRegisterCount(Math.max(current.getEndAddress(), pointEndAddress) - current.getStartAddress());
+ }
+ // 3. 璁板綍璇诲彇娈靛寘鍚殑鐐逛綅锛岃鍙栨垚鍔熷悗鎸夌偣浣嶉�愪釜鍒囩墖涓婃姤
+ current.getPoints().add(point);
+ }
+ }
+
+ /**
+ * 鍒ゆ柇鐐逛綅鏄惁鍙互鍚堝苟鍒板綋鍓嶈鍙栨
+ *
+ * <p>浠呭悎骞惰繛缁垨閲嶅彔鍖洪棿锛屼笉鍚堝苟瀛樺湪鍦板潃绌烘礊鐨勫尯闂达紝閬垮厤棰濆璇诲彇鏃犲叧瀵勫瓨鍣ㄣ��
+ */
+ private static boolean canMerge(ReadSegment segment, int pointStartAddress, int pointEndAddress, int maxRegisterCount) {
+ if (pointStartAddress > segment.getEndAddress()) {
+ return false;
+ }
+ int mergedRegisterCount = Math.max(segment.getEndAddress(), pointEndAddress) - segment.getStartAddress();
+ return mergedRegisterCount <= maxRegisterCount;
+ }
+
+ /**
+ * 浠庢壒閲忚鍙栫粨鏋滀腑鎻愬彇鍗曚釜鐐逛綅鐨勫師濮嬪��
+ *
+ * <p>渚嬪璇诲彇娈典粠鍦板潃 10 寮�濮嬶紝鐐逛綅鍦板潃涓� 12銆佹暟閲忎负 2锛屽垯鍙� rawValues[2..4)銆�
+ */
+ static int[] extractPointRawValues(int[] rawValues, ReadSegment segment, IotModbusPointRespDTO point) {
+ if (rawValues == null) {
+ return null;
+ }
+ // 1. 璁$畻鐐逛綅鍦ㄦ壒閲忚鍙栫粨鏋滀腑鐨勭浉瀵瑰亸绉�
+ int offset = point.getRegisterAddress() - segment.getStartAddress();
+ int end = offset + point.getRegisterCount();
+ // 2. 闃插尽寮傚父鍝嶅簲闀垮害锛岄伩鍏嶈秺鐣屽奖鍝嶅悓涓�璇诲彇娈靛唴鍏跺畠鐐逛綅
+ if (offset < 0 || end > rawValues.length) {
+ return null;
+ }
+ // 3. 杩斿洖鍗曚釜鐐逛綅闇�瑕佺殑鍘熷瀵勫瓨鍣ㄥ��
+ return Arrays.copyOfRange(rawValues, offset, end);
+ }
+
+ private static boolean isValidReadPoint(IotModbusPointRespDTO point) {
+ return point != null
+ && point.getId() != null
+ && point.getFunctionCode() != null
+ && point.getRegisterAddress() != null
+ && point.getRegisterCount() != null
+ && point.getRegisterCount() > 0
+ && point.getPollInterval() != null
+ && point.getPollInterval() > 0;
+ }
+
+ @SuppressWarnings("EnhancedSwitchMigration")
+ private static int getMaxRegisterCount(Integer functionCode) {
+ switch (functionCode) {
+ case IotModbusCommonUtils.FC_READ_COILS:
+ case IotModbusCommonUtils.FC_READ_DISCRETE_INPUTS:
+ return 2000;
+ case IotModbusCommonUtils.FC_READ_HOLDING_REGISTERS:
+ case IotModbusCommonUtils.FC_READ_INPUT_REGISTERS:
+ return 125;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * 璇诲彇娈靛垎缁� Key
+ */
+ @Data
+ @AllArgsConstructor
+ static class SegmentGroupKey {
+
+ private Integer functionCode;
+ private Integer pollInterval;
+
+ }
+
+ /**
+ * 涓�娆� Modbus 鎵归噺璇昏姹傚搴旂殑杩炵画鍦板潃娈�
+ */
+ @Data
+ @AllArgsConstructor
+ static class ReadSegment {
+
+ private Integer functionCode;
+ private Integer pollInterval;
+ private Integer startAddress;
+ private Integer registerCount;
+ private List<IotModbusPointRespDTO> points;
+
+ String getKey() {
+ return functionCode + ":" + pollInterval + ":" + startAddress + ":" + registerCount;
+ }
+
+ int getEndAddress() {
+ return startAddress + registerCount;
+ }
+
+ }
+
}
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/IotModbusTcpServerProtocol.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/IotModbusTcpServerProtocol.java
index 80ce9ee..ea6e908 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/IotModbusTcpServerProtocol.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/IotModbusTcpServerProtocol.java
@@ -326,9 +326,27 @@
log.error("[refreshConfig][澶勭悊璁惧閰嶇疆澶辫触, deviceId={}]", config.getDeviceId(), e);
}
}
+
+ // 3. 娓呯悊鏈疆涓嶅啀杩斿洖閰嶇疆鐨勫凡杩炴帴璁惧锛岄伩鍏嶇户缁疆璇㈠凡鍒犻櫎璁惧鐨勬棫鐐逛綅
+ Set<Long> missingDeviceIds = configCacheService.cleanupMissingConfigs(connectedDeviceIds, configs);
+ for (Long deviceId : missingDeviceIds) {
+ cleanupMissingDevice(deviceId);
+ }
} catch (Exception e) {
log.error("[refreshConfig][鍒锋柊閰嶇疆澶辫触]", e);
}
}
+ private void cleanupMissingDevice(Long deviceId) {
+ try {
+ pollScheduler.stopPolling(deviceId);
+ pendingRequestManager.removeDevice(deviceId);
+ configCacheService.removeConfig(deviceId);
+ connectionManager.closeConnection(deviceId);
+ log.info("[cleanupMissingDevice][璁惧 {} 閰嶇疆宸插け鏁堬紝宸插仠姝㈣疆璇㈠苟娓呯悊杩炴帴]", deviceId);
+ } catch (Exception e) {
+ log.error("[cleanupMissingDevice][娓呯悊璁惧澶辫触, deviceId={}]", deviceId, e);
+ }
+ }
+
}
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConfigCacheService.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConfigCacheService.java
index 19ba6e9..f7df6b5 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConfigCacheService.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConfigCacheService.java
@@ -12,10 +12,13 @@
import lombok.extern.slf4j.Slf4j;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
/**
* IoT Modbus TCP Server 閰嶇疆缂撳瓨锛氳璇佹椂鎸夐渶鍔犺浇锛屾柇杩炴椂娓呯悊锛屽畾鏃跺埛鏂板凡杩炴帴璁惧
@@ -97,6 +100,27 @@
}
/**
+ * 娓呯悊鏈疆鍒锋柊鍚庝笉鍐嶆湁鏁堢殑璁惧閰嶇疆
+ *
+ * @param refreshedDeviceIds 鏈疆鍙備笌鍒锋柊鐨勮澶囩紪鍙�
+ * @param currentConfigs 鏈疆杩滅杩斿洖鐨勬湁鏁堥厤缃�
+ * @return 鏈疆宸蹭笉鍐嶆湁鏁堢殑璁惧缂栧彿
+ */
+ public Set<Long> cleanupMissingConfigs(Set<Long> refreshedDeviceIds,
+ List<IotModbusDeviceConfigRespDTO> currentConfigs) {
+ if (CollUtil.isEmpty(refreshedDeviceIds)) {
+ return Collections.emptySet();
+ }
+ Set<Long> currentDeviceIds = convertSet(currentConfigs, IotModbusDeviceConfigRespDTO::getDeviceId);
+ Set<Long> missingDeviceIds = new HashSet<>(refreshedDeviceIds);
+ missingDeviceIds.removeAll(currentDeviceIds);
+ for (Long deviceId : missingDeviceIds) {
+ configCache.remove(deviceId);
+ }
+ return missingDeviceIds;
+ }
+
+ /**
* 鑾峰彇璁惧閰嶇疆
*/
public IotModbusDeviceConfigRespDTO getConfig(Long deviceId) {
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConnectionManager.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConnectionManager.java
index 781d8ac..4c01f6a 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConnectionManager.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpserver/manager/IotModbusTcpServerConnectionManager.java
@@ -9,6 +9,7 @@
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -109,7 +110,7 @@
* 鑾峰彇鎵�鏈夊凡杩炴帴璁惧鐨� ID 闆嗗悎
*/
public Set<Long> getConnectedDeviceIds() {
- return deviceSocketMap.keySet();
+ return new HashSet<>(deviceSocketMap.keySet());
}
/**
@@ -131,6 +132,24 @@
}
/**
+ * 鍏抽棴鎸囧畾璁惧杩炴帴锛屽苟鍏堢Щ闄ゆ槧灏勶紝閬垮厤 closeHandler 鍐嶆寜姝e父鏂繛鍙戦�佷笅绾挎秷鎭�
+ */
+ public void closeConnection(Long deviceId) {
+ NetSocket socket = deviceSocketMap.remove(deviceId);
+ if (socket == null) {
+ return;
+ }
+ connectionMap.remove(socket);
+ try {
+ socket.close();
+ log.info("[closeConnection][璁惧 {} 杩炴帴宸插叧闂璢", deviceId);
+ } catch (Exception e) {
+ log.warn("[closeConnection][鍏抽棴璁惧杩炴帴澶辫触, deviceId={}, remoteAddress={}]",
+ deviceId, socket.remoteAddress(), e);
+ }
+ }
+
+ /**
* 鍙戦�佹暟鎹埌璁惧
*
* @return 鍙戦�佺粨鏋� Future
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java
index b8df7a6..7204162 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/remote/IotDeviceApiImpl.java
@@ -17,14 +17,13 @@
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
import java.util.List;
@@ -47,11 +46,11 @@
@PostConstruct
public void init() {
IotGatewayProperties.RpcProperties rpc = gatewayProperties.getRpc();
- SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
- requestFactory.setConnectTimeout(rpc.getConnectTimeout());
- requestFactory.setReadTimeout(rpc.getReadTimeout());
- restTemplate = new RestTemplate(requestFactory);
- restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(rpc.getUrl()));
+ restTemplate = new RestTemplateBuilder()
+ .baseUri(rpc.getUrl())
+ .readTimeout(rpc.getReadTimeout())
+ .connectTimeout(rpc.getConnectTimeout())
+ .build();
}
@Override
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml b/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml
index 71ee6f3..6ddecc3 100644
--- a/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml
@@ -12,6 +12,9 @@
database: 0 # Redis 鏁版嵁搴撶储寮�
# password: # Redis 瀵嗙爜锛屽鏋滄湁鐨勮瘽
timeout: 30000ms # 杩炴帴瓒呮椂鏃堕棿
+ # Kafka 閰嶇疆椤癸紝瀵瑰簲 KafkaProperties 閰嶇疆绫�
+ kafka:
+ bootstrap-servers: 127.0.0.1:9092 # 鎸囧畾 Kafka Broker 鍦板潃锛屽彲浠ヨ缃涓紝浠ラ�楀彿鍒嗛殧
--- #################### 娑堟伅闃熷垪鐩稿叧 ####################
diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollSchedulerTest.java b/yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollSchedulerTest.java
new file mode 100644
index 0000000..214db67
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/tcpclient/manager/IotModbusTcpClientPollSchedulerTest.java
@@ -0,0 +1,147 @@
+package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager;
+
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
+import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager.IotModbusTcpClientPollScheduler.ReadSegment;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils.FC_READ_COILS;
+import static cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils.FC_READ_HOLDING_REGISTERS;
+import static cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils.FC_READ_INPUT_REGISTERS;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link IotModbusTcpClientPollScheduler} 鐨勫崟鍏冩祴璇�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+public class IotModbusTcpClientPollSchedulerTest {
+
+ @Test
+ public void testBuildReadSegments_mergeContinuousPoints() {
+ // 鍑嗗鍙傛暟
+ IotModbusPointRespDTO point01 = randomPoint(1L, FC_READ_HOLDING_REGISTERS, 0, 1, 1000);
+ IotModbusPointRespDTO point02 = randomPoint(2L, FC_READ_HOLDING_REGISTERS, 1, 2, 1000);
+ IotModbusPointRespDTO point03 = randomPoint(3L, FC_READ_HOLDING_REGISTERS, 4, 1, 1000);
+ IotModbusDeviceConfigRespDTO config = randomConfig(point01, point02, point03);
+
+ // 璋冪敤
+ List<ReadSegment> segments = IotModbusTcpClientPollScheduler.buildReadSegments(config);
+
+ // 鏂█
+ assertEquals(2, segments.size());
+ assertEquals(0, segments.get(0).getStartAddress());
+ assertEquals(3, segments.get(0).getRegisterCount());
+ assertIterableEquals(Arrays.asList(point01, point02), segments.get(0).getPoints());
+ assertEquals(4, segments.get(1).getStartAddress());
+ assertEquals(1, segments.get(1).getRegisterCount());
+ assertIterableEquals(Collections.singletonList(point03), segments.get(1).getPoints());
+ }
+
+ @Test
+ public void testBuildReadSegments_mergeOverlappingPoints() {
+ // 鍑嗗鍙傛暟
+ IotModbusPointRespDTO point01 = randomPoint(1L, FC_READ_HOLDING_REGISTERS, 0, 2, 1000);
+ IotModbusPointRespDTO point02 = randomPoint(2L, FC_READ_HOLDING_REGISTERS, 1, 1, 1000);
+ IotModbusDeviceConfigRespDTO config = randomConfig(point01, point02);
+
+ // 璋冪敤
+ List<ReadSegment> segments = IotModbusTcpClientPollScheduler.buildReadSegments(config);
+
+ // 鏂█
+ assertEquals(1, segments.size());
+ assertEquals(0, segments.get(0).getStartAddress());
+ assertEquals(2, segments.get(0).getRegisterCount());
+ assertIterableEquals(Arrays.asList(point01, point02), segments.get(0).getPoints());
+ }
+
+ @Test
+ public void testBuildReadSegments_notMergeDifferentFunctionCodeOrPollInterval() {
+ // 鍑嗗鍙傛暟
+ IotModbusPointRespDTO point01 = randomPoint(1L, FC_READ_HOLDING_REGISTERS, 0, 1, 1000);
+ IotModbusPointRespDTO point02 = randomPoint(2L, FC_READ_INPUT_REGISTERS, 1, 1, 1000);
+ IotModbusPointRespDTO point03 = randomPoint(3L, FC_READ_HOLDING_REGISTERS, 1, 1, 2000);
+ IotModbusDeviceConfigRespDTO config = randomConfig(point01, point02, point03);
+
+ // 璋冪敤
+ List<ReadSegment> segments = IotModbusTcpClientPollScheduler.buildReadSegments(config);
+
+ // 鏂█
+ assertEquals(3, segments.size());
+ assertEquals(FC_READ_HOLDING_REGISTERS, segments.get(0).getFunctionCode());
+ assertEquals(1000, segments.get(0).getPollInterval());
+ assertEquals(FC_READ_HOLDING_REGISTERS, segments.get(1).getFunctionCode());
+ assertEquals(2000, segments.get(1).getPollInterval());
+ assertEquals(FC_READ_INPUT_REGISTERS, segments.get(2).getFunctionCode());
+ assertEquals(1000, segments.get(2).getPollInterval());
+ }
+
+ @Test
+ public void testBuildReadSegments_splitWhenExceedsMaxRegisterCount() {
+ // 鍑嗗鍙傛暟
+ IotModbusPointRespDTO point01 = randomPoint(1L, FC_READ_HOLDING_REGISTERS, 0, 100, 1000);
+ IotModbusPointRespDTO point02 = randomPoint(2L, FC_READ_HOLDING_REGISTERS, 100, 30, 1000);
+ IotModbusDeviceConfigRespDTO config = randomConfig(point01, point02);
+
+ // 璋冪敤
+ List<ReadSegment> segments = IotModbusTcpClientPollScheduler.buildReadSegments(config);
+
+ // 鏂█
+ assertEquals(2, segments.size());
+ assertEquals(0, segments.get(0).getStartAddress());
+ assertEquals(100, segments.get(0).getRegisterCount());
+ assertEquals(100, segments.get(1).getStartAddress());
+ assertEquals(30, segments.get(1).getRegisterCount());
+ }
+
+ @Test
+ public void testExtractPointRawValues() {
+ // 鍑嗗鍙傛暟
+ IotModbusPointRespDTO point = randomPoint(1L, FC_READ_HOLDING_REGISTERS, 12, 2, 1000);
+ ReadSegment segment = new ReadSegment(FC_READ_HOLDING_REGISTERS, 1000, 10, 4, Collections.singletonList(point));
+ int[] rawValues = new int[]{100, 200, 300, 400};
+
+ // 璋冪敤
+ int[] pointRawValues = IotModbusTcpClientPollScheduler.extractPointRawValues(rawValues, segment, point);
+
+ // 鏂█
+ assertArrayEquals(new int[]{300, 400}, pointRawValues);
+ }
+
+ @Test
+ public void testExtractPointRawValuesForCoils() {
+ // 鍑嗗鍙傛暟
+ IotModbusPointRespDTO point = randomPoint(1L, FC_READ_COILS, 3, 2, 1000);
+ ReadSegment segment = new ReadSegment(FC_READ_COILS, 1000, 0, 5, Collections.singletonList(point));
+ int[] rawValues = new int[]{1, 0, 1, 1, 0, 0, 0, 0}; // 绾垮湀鍝嶅簲鍙兘鎸夊瓧鑺傝ˉ榻�
+
+ // 璋冪敤
+ int[] pointRawValues = IotModbusTcpClientPollScheduler.extractPointRawValues(rawValues, segment, point);
+
+ // 鏂█
+ assertArrayEquals(new int[]{1, 0}, pointRawValues);
+ }
+
+ private static IotModbusDeviceConfigRespDTO randomConfig(IotModbusPointRespDTO... points) {
+ IotModbusDeviceConfigRespDTO config = new IotModbusDeviceConfigRespDTO();
+ config.setDeviceId(1L);
+ config.setPoints(Arrays.asList(points));
+ return config;
+ }
+
+ private static IotModbusPointRespDTO randomPoint(Long id, Integer functionCode, Integer registerAddress,
+ Integer registerCount, Integer pollInterval) {
+ IotModbusPointRespDTO point = new IotModbusPointRespDTO();
+ point.setId(id);
+ point.setFunctionCode(functionCode);
+ point.setRegisterAddress(registerAddress);
+ point.setRegisterCount(registerCount);
+ point.setPollInterval(pollInterval);
+ return point;
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java
index 3cac6d0..5055bb9 100644
--- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java
+++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java
@@ -7,6 +7,7 @@
import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@@ -34,6 +35,15 @@
return success(BeanUtils.toBean(pageResult, ProductCommentRespVO.class));
}
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱鍟嗗搧璇勪环")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('product:comment:query')")
+ public CommonResult<ProductCommentRespVO> getComment(@RequestParam("id") Long id) {
+ ProductCommentDO comment = productCommentService.getComment(id);
+ return success(BeanUtils.toBean(comment, ProductCommentRespVO.class));
+ }
+
@PutMapping("/update-visible")
@Operation(summary = "鏄剧ず / 闅愯棌璇勮")
@PreAuthorize("@ss.hasPermission('product:comment:update')")
diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
index 8e5ea71..bd9a9dc 100644
--- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
+++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
@@ -118,10 +118,10 @@
}
@GetMapping("/get-count")
- @Operation(summary = "鑾峰緱鍟嗗搧 SPU 鍒嗛〉 tab count")
+ @Operation(summary = "鑾峰緱鍟嗗搧 SPU 鍒嗛〉 tab count锛堟敮鎸佹寜 name/categoryId/createTime 绛涢�夛級")
@PreAuthorize("@ss.hasPermission('product:spu:query')")
- public CommonResult<Map<Integer, Long>> getSpuCount() {
- return success(productSpuService.getTabsCount());
+ public CommonResult<Map<Integer, Long>> getSpuCount(ProductSpuPageReqVO reqVO) {
+ return success(productSpuService.getTabsCount(reqVO));
}
@GetMapping("/export-excel")
diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
index 993889c..e243a3c 100644
--- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
+++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java
@@ -147,6 +147,22 @@
}
/**
+ * 鎸夌瓫閫夋潯浠� + Tab 缁熻鍟嗗搧 SPU 鏁伴噺锛堢敤浜庡甫绛涢�夌殑 tab count锛�
+ *
+ * @param reqVO 绛涢�夋潯浠讹紙name/categoryId/createTime锛�
+ * @param tabType Tab 鏍囩绫诲瀷
+ * @return 鏁伴噺
+ */
+ default Long selectCountByTab(ProductSpuPageReqVO reqVO, Integer tabType) {
+ LambdaQueryWrapperX<ProductSpuDO> queryWrapper = new LambdaQueryWrapperX<ProductSpuDO>()
+ .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
+ .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
+ .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime());
+ appendTabQuery(tabType, queryWrapper);
+ return selectCount(queryWrapper);
+ }
+
+ /**
* 鏇存柊鍟嗗搧 SPU 娴忚閲�
*
* @param id 鍟嗗搧 SPU 缂栧彿
diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java
index b54e219..b940340 100644
--- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java
+++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java
@@ -53,6 +53,14 @@
void replyComment(ProductCommentReplyReqVO replyVO, Long userId);
/**
+ * 銆愮鐞嗗憳銆戣幏寰楀晢鍝佽瘎浠�
+ *
+ * @param id 璇勪环缂栧彿
+ * @return 鍟嗗搧璇勪环
+ */
+ ProductCommentDO getComment(Long id);
+
+ /**
* 銆愮鐞嗗憳銆戣幏寰楀晢鍝佽瘎浠峰垎椤�
*
* @param pageReqVO 鍒嗛〉鏌ヨ
diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java
index 34b0766..e6cc2f6 100644
--- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java
+++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java
@@ -140,6 +140,11 @@
}
@Override
+ public ProductCommentDO getComment(Long id) {
+ return validateCommentExists(id);
+ }
+
+ @Override
public PageResult<ProductCommentDO> getCommentPage(ProductCommentPageReqVO pageReqVO) {
return productCommentMapper.selectPage(pageReqVO);
}
diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
index 6ed9460..8329775 100644
--- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
+++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
@@ -118,11 +118,12 @@
void updateSpuStatus(ProductSpuUpdateStatusReqVO updateReqVO);
/**
- * 鑾峰彇 SPU 鍒楄〃鏍囩瀵瑰簲鐨� Count 鏁伴噺
+ * 鑾峰彇 SPU 鍒楄〃鏍囩瀵瑰簲鐨� Count 鏁伴噺锛堟敮鎸佹寜 name/categoryId/createTime 绛涢�夛級
*
+ * @param reqVO 绛涢�夋潯浠�
* @return Count 鏁伴噺
*/
- Map<Integer, Long> getTabsCount();
+ Map<Integer, Long> getTabsCount(ProductSpuPageReqVO reqVO);
/**
* 閫氳繃鍒嗙被 categoryId 鏌ヨ SPU 涓暟
diff --git a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
index b7b9057..a36a746 100644
--- a/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
+++ b/yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
@@ -256,23 +256,19 @@
}
@Override
- public Map<Integer, Long> getTabsCount() {
+ public Map<Integer, Long> getTabsCount(ProductSpuPageReqVO reqVO) {
Map<Integer, Long> counts = Maps.newLinkedHashMapWithExpectedSize(5);
- // 鏌ヨ閿�鍞腑鐨勫晢鍝佹暟閲�
+ // 姣忎釜 tab 鐨勬暟閲� = 绛涢�夋潯浠讹紙name/categoryId/createTime锛�+ 璇� tab 鐨勭姸鎬�/搴撳瓨鏉′欢
counts.put(ProductSpuPageReqVO.FOR_SALE,
- productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()));
- // 鏌ヨ浠撳簱涓殑鍟嗗搧鏁伴噺
+ productSpuMapper.selectCountByTab(reqVO, ProductSpuPageReqVO.FOR_SALE));
counts.put(ProductSpuPageReqVO.IN_WAREHOUSE,
- productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.DISABLE.getStatus()));
- // 鏌ヨ鍞┖鐨勫晢鍝佹暟閲�
+ productSpuMapper.selectCountByTab(reqVO, ProductSpuPageReqVO.IN_WAREHOUSE));
counts.put(ProductSpuPageReqVO.SOLD_OUT,
- productSpuMapper.selectCount(ProductSpuDO::getStock, 0));
- // 鏌ヨ瑙﹀彂璀︽垝搴撳瓨鐨勫晢鍝佹暟閲�
+ productSpuMapper.selectCountByTab(reqVO, ProductSpuPageReqVO.SOLD_OUT));
counts.put(ProductSpuPageReqVO.ALERT_STOCK,
- productSpuMapper.selectCount());
- // 鏌ヨ鍥炴敹绔欎腑鐨勫晢鍝佹暟閲�
+ productSpuMapper.selectCountByTab(reqVO, ProductSpuPageReqVO.ALERT_STOCK));
counts.put(ProductSpuPageReqVO.RECYCLE_BIN,
- productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()));
+ productSpuMapper.selectCountByTab(reqVO, ProductSpuPageReqVO.RECYCLE_BIN));
return counts;
}
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java
index 8dfc99a..fb124c5 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java
@@ -4,10 +4,12 @@
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponSendReqVO;
import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
@@ -63,6 +65,15 @@
return success(pageResulVO);
}
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱浼樻儬鍔�")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('promotion:coupon:query')")
+ public CommonResult<CouponRespVO> getCoupon(@RequestParam("id") Long id) {
+ CouponDO coupon = couponService.getCoupon(id);
+ return success(BeanUtils.toBean(coupon, CouponRespVO.class));
+ }
+
@PostMapping("/send")
@Operation(summary = "鍙戦�佷紭鎯犲姷")
@PreAuthorize("@ss.hasPermission('promotion:coupon:send')")
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
index 68693e0..fdadd68 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
@@ -5,6 +5,7 @@
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.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
@@ -34,7 +35,7 @@
.eqIfPresent(CouponTemplateDO::getDiscountType, reqVO.getDiscountType())
.betweenIfPresent(CouponTemplateDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(CouponTemplateDO::getProductScope, reqVO.getProductScope())
- .and(reqVO.getProductScopeValue() != null, w -> w.apply("FIND_IN_SET({0}, product_scope_values)",
+ .and(reqVO.getProductScopeValue() != null, w -> w.apply(MyBatisUtils.findInSet("product_scope_values"),
reqVO.getProductScopeValue()))
.and(canTakeConsumer != null, canTakeConsumer)
.orderByDesc(CouponTemplateDO::getId));
@@ -61,7 +62,7 @@
Consumer<LambdaQueryWrapper<CouponTemplateDO>> canTakeConsumer = buildCanTakeQueryConsumer(canTakeTypes);
return selectList(new LambdaQueryWrapperX<CouponTemplateDO>()
.eqIfPresent(CouponTemplateDO::getProductScope, productScope)
- .and(productScopeValue != null, w -> w.apply("FIND_IN_SET({0}, product_scope_values)",
+ .and(productScopeValue != null, w -> w.apply(MyBatisUtils.findInSet("product_scope_values"),
productScopeValue))
.and(canTakeConsumer != null, canTakeConsumer)
.last(" LIMIT " + count)
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java
index 6d8e9c6..831ad0d 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java
@@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.reward;
-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.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
@@ -14,6 +14,7 @@
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* 婊″噺閫佹椿鍔� Mapper
@@ -34,18 +35,18 @@
Collection<Long> categoryIds,
Integer status) {
LocalDateTime now = LocalDateTime.now();
- Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream()
- .map(id -> StrUtil.format("FIND_IN_SET({}, product_scope_values) ", id))
+ Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> IntStream.range(0, ids.size())
+ .mapToObj(index -> MyBatisUtils.findInSetWithParamIndex("product_scope_values", index))
.collect(Collectors.joining(" OR "));
return selectList(new LambdaQueryWrapperX<RewardActivityDO>()
.eq(RewardActivityDO::getStatus, status)
.lt(RewardActivityDO::getStartTime, now)
.gt(RewardActivityDO::getEndTime, now)
.and(i -> i.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.SPU.getScope())
- .and(i1 -> i1.apply(productScopeValuesFindInSetFunc.apply(spuIds)))
+ .and(i1 -> i1.apply(productScopeValuesFindInSetFunc.apply(spuIds), spuIds.toArray()))
.or(i1 -> i1.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.ALL.getScope()))
.or(i1 -> i1.eq(RewardActivityDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope())
- .and(i2 -> i2.apply(productScopeValuesFindInSetFunc.apply(categoryIds)))))
+ .and(i2 -> i2.apply(productScopeValuesFindInSetFunc.apply(categoryIds), categoryIds.toArray()))))
.orderByDesc(RewardActivityDO::getId)
);
}
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
index 34e50f1..7f0c07d 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
@@ -5,6 +5,7 @@
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.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
@@ -27,7 +28,7 @@
.likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
.eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
.betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime())
- .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ", config_ids) > 0")
+ .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), MyBatisUtils.findInSet("config_ids"), reqVO.getConfigId())
.orderByDesc(SeckillActivityDO::getId));
}
@@ -70,7 +71,7 @@
.eqIfPresent(SeckillActivityDO::getStatus, status)
.lt(SeckillActivityDO::getStartTime, dateTime)
.gt(SeckillActivityDO::getEndTime, dateTime)// 寮�濮嬫椂闂� < 鎸囧畾鏃堕棿 < 缁撴潫鏃堕棿锛屼篃灏辨槸璇磋幏鍙栨寚瀹氭椂闂存鐨勬椿鍔�
- .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0"));
+ .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), MyBatisUtils.findInSet("config_ids"), pageReqVO.getConfigId()));
}
default SeckillActivityDO selectBySpuIdAndStatusAndNow(Long spuId, Integer status) {
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
index 862e130..ab215f6 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
@@ -77,7 +77,6 @@
@Resource
public SocialClientApi socialClientApi;
- // TODO @鑺嬭壙锛氬湪璇︾粏棰勮涓嬶紱
@Override
public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(
Long userId, Long activityId, Long headId, Long skuId, Integer count) {
@@ -97,7 +96,7 @@
}
// 2. 鐖舵嫾鍥㈡槸鍚﹀瓨鍦�,鏄惁宸茬粡婊′簡
- if (headId != null) {
+ if (isJoinCombination(headId)) {
// 2.1. 鏌ヨ杩涜涓殑鐖舵嫾鍥�
CombinationRecordDO record = combinationRecordMapper.selectByHeadId(headId, CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
if (record == null) {
@@ -129,7 +128,7 @@
throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
}
// 4.3 鏍¢獙搴撳瓨鏄惁鍏呰冻
- if (count >= sku.getStock()) {
+ if (count > sku.getStock()) {
throw exception(COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL);
}
@@ -153,6 +152,16 @@
return new KeyValue<>(activity, product);
}
+ /**
+ * 鏄惁鍔犲叆宸叉湁鎷煎洟銆�
+ *
+ * 鍓嶇寮�鍥㈡椂鍙兘涓嶄紶 headId锛屼篃鍙兘浼� {@link CombinationRecordDO#HEAD_ID_GROUP}锛岄兘搴旇涓烘柊寮�鍥紱
+ * 鍙湁浼犲叆鐪熷疄鍥㈤暱璁板綍缂栧彿鏃讹紝鎵嶉渶瑕佹寜鍙傚洟鏍¢獙鐖舵嫾鍥€��
+ */
+ private static boolean isJoinCombination(Long headId) {
+ return headId != null && ObjUtil.notEqual(headId, CombinationRecordDO.HEAD_ID_GROUP);
+ }
+
@Override
@Transactional(rollbackFor = Exception.class)
public CombinationRecordDO createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
@@ -166,7 +175,7 @@
ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO, keyValue.getKey(), user, spu, sku);
// 2.1. 濡傛灉鏄洟闀块渶瑕佽缃� headId 涓� CombinationRecordDO#HEAD_ID_GROUP
- if (record.getHeadId() == null) {
+ if (!isJoinCombination(record.getHeadId())) {
record.setStartTime(LocalDateTime.now())
.setExpireTime(LocalDateTime.now().plusHours(keyValue.getKey().getLimitDuration()))
.setHeadId(CombinationRecordDO.HEAD_ID_GROUP);
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
index c24cf3a..f6b464d 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
@@ -160,7 +160,7 @@
Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<CouponTemplateDO> templates);
/**
- * 鑾峰緱浼樻儬鍔�
+ * 銆愪細鍛樸�戣幏寰椾紭鎯犲姷
*
* @param userId 鐢ㄦ埛缂栧彿
* @param id 缂栧彿
@@ -168,4 +168,12 @@
*/
CouponDO getCoupon(Long userId, Long id);
+ /**
+ * 銆愮鐞嗗憳銆戣幏寰椾紭鎯犲姷
+ *
+ * @param id 缂栧彿
+ * @return 浼樻儬鍔�
+ */
+ CouponDO getCoupon(Long id);
+
}
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
index c3aa766..dd433f3 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
@@ -378,6 +378,11 @@
return couponMapper.selectByIdAndUserId(id, userId);
}
+ @Override
+ public CouponDO getCoupon(Long id) {
+ return couponMapper.selectById(id);
+ }
+
private CouponDO validateCouponExists(Long id) {
CouponDO coupon = couponMapper.selectById(id);
if (coupon == null) {
diff --git a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
index 8c25cb8..d4323c6 100644
--- a/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
+++ b/yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
@@ -52,6 +52,9 @@
@Override
public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) {
+ // 鏍¢獙鍙戞斁鏁伴噺涓嶈兘灏忎簬姣忎汉闄愰鏁伴噺锛堜粎鍦� CouponTakeTypeEnum.USER 鐢ㄦ埛棰嗗彇鏃讹級
+ validateTotalCountNotLessThanTakeLimitCount(createReqVO.getTakeType(), createReqVO.getTotalCount(),
+ createReqVO.getTakeLimitCount());
// 鏍¢獙鍟嗗搧鑼冨洿
validateProductScope(createReqVO.getProductScope(), createReqVO.getProductScopeValues());
// 鎻掑叆
@@ -66,8 +69,11 @@
public void updateCouponTemplate(CouponTemplateUpdateReqVO updateReqVO) {
// 鏍¢獙瀛樺湪
CouponTemplateDO couponTemplate = validateCouponTemplateExists(updateReqVO.getId());
+ // 鏍¢獙鍙戞斁鏁伴噺涓嶈兘灏忎簬姣忎汉闄愰鏁伴噺锛堜粎鍦� CouponTakeTypeEnum.USER 鐢ㄦ埛棰嗗彇鏃讹級
+ validateTotalCountNotLessThanTakeLimitCount(updateReqVO.getTakeType(), updateReqVO.getTotalCount(),
+ updateReqVO.getTakeLimitCount());
// 鏍¢獙鍙戞斁鏁伴噺涓嶈兘杩囧皬锛堜粎鍦� CouponTakeTypeEnum.USER 鐢ㄦ埛棰嗗彇鏃讹級
- if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeType())
+ if (CouponTakeTypeEnum.isUser(updateReqVO.getTakeType())
&& !isTotalCountUnlimited(updateReqVO.getTotalCount()) // 闈炰笉闄愬埗鎬诲彂鏀炬暟閲�
&& updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) {
throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount());
@@ -104,6 +110,16 @@
return couponTemplate;
}
+ private void validateTotalCountNotLessThanTakeLimitCount(Integer takeType, Integer totalCount, Integer takeLimitCount) {
+ // 淇 https://gitee.com/yudaocode/yudao-mall-uniapp/issues/IJLP6Q 鍙嶉
+ if (CouponTakeTypeEnum.isUser(takeType)
+ && !isTakeLimitCountUnlimited(takeLimitCount)
+ && !isTotalCountUnlimited(totalCount)
+ && takeLimitCount > totalCount) {
+ throw exception(COUPON_TEMPLATE_NOT_ENOUGH);
+ }
+ }
+
private void validateProductScope(Integer productScope, List<Long> productScopeValues) {
if (Objects.equals(PromotionProductScopeEnum.SPU.getScope(), productScope)) {
productSpuApi.validateSpuList(productScopeValues);
diff --git a/yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImplTest.java b/yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImplTest.java
new file mode 100644
index 0000000..5a07773
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImplTest.java
@@ -0,0 +1,325 @@
+package cn.iocoder.yudao.module.promotion.service.combination;
+
+import cn.iocoder.yudao.framework.common.core.KeyValue;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
+import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
+import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
+import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
+import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.function.Consumer;
+
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link CombinationRecordServiceImpl} 鐨勫崟鍏冩祴璇曠被
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Import(CombinationRecordServiceImpl.class)
+public class CombinationRecordServiceImplTest extends BaseDbUnitTest {
+
+ private static final Long USER_ID = 100L;
+ private static final Long ACTIVITY_ID = 200L;
+ private static final Long SPU_ID = 300L;
+ private static final Long SKU_ID = 400L;
+ private static final Long HEAD_ID = 500L;
+ private static final Long ORDER_ID = 600L;
+
+ @Resource
+ private CombinationRecordServiceImpl combinationRecordService;
+ @Resource
+ private CombinationRecordMapper combinationRecordMapper;
+
+ @MockitoBean
+ private CombinationActivityService combinationActivityService;
+ @MockitoBean
+ private MemberUserApi memberUserApi;
+ @MockitoBean
+ private ProductSpuApi productSpuApi;
+ @MockitoBean
+ private ProductSkuApi productSkuApi;
+ @MockitoBean
+ private TradeOrderApi tradeOrderApi;
+ @MockitoBean
+ private SocialClientApi socialClientApi;
+
+ @Test
+ public void testValidateCombinationRecord_headIdNullAsNewGroup() {
+ // mock 鏁版嵁
+ CombinationActivityDO activity = mockValidateContext(10);
+
+ // 璋冪敤
+ KeyValue<CombinationActivityDO, CombinationProductDO> result = combinationRecordService
+ .validateCombinationRecord(USER_ID, ACTIVITY_ID, null, SKU_ID, 1);
+
+ // 鏂█
+ assertSame(activity, result.getKey());
+ assertEquals(SKU_ID, result.getValue().getSkuId());
+ }
+
+ @Test
+ public void testValidateCombinationRecord_headIdGroupAsNewGroup() {
+ // mock 鏁版嵁锛歨eadId 涓� 0 鏃讹紝涔熶唬琛ㄦ柊寮�鍥�
+ CombinationActivityDO activity = mockValidateContext(10);
+
+ // 璋冪敤
+ KeyValue<CombinationActivityDO, CombinationProductDO> result = combinationRecordService
+ .validateCombinationRecord(USER_ID, ACTIVITY_ID, CombinationRecordDO.HEAD_ID_GROUP, SKU_ID, 1);
+
+ // 鏂█
+ assertSame(activity, result.getKey());
+ assertEquals(SKU_ID, result.getValue().getSkuId());
+ }
+
+ @Test
+ public void testValidateCombinationRecord_realHeadIdAsJoinGroup() {
+ // mock 鏁版嵁锛氱湡瀹� headId 鏃讹紝鎸夊弬鍥㈡牎楠岀埗鎷煎洟
+ CombinationActivityDO activity = mockValidateContext(10);
+ combinationRecordMapper.insert(randomRecord(o -> {
+ o.setId(HEAD_ID);
+ o.setHeadId(CombinationRecordDO.HEAD_ID_GROUP);
+ o.setUserId(101L);
+ o.setOrderId(601L);
+ }));
+
+ // 璋冪敤
+ KeyValue<CombinationActivityDO, CombinationProductDO> result = combinationRecordService
+ .validateCombinationRecord(USER_ID, ACTIVITY_ID, HEAD_ID, SKU_ID, 1);
+
+ // 鏂█
+ assertSame(activity, result.getKey());
+ assertEquals(SKU_ID, result.getValue().getSkuId());
+ }
+
+ @Test
+ public void testValidateCombinationRecord_realHeadIdNotExists() {
+ // mock 鏁版嵁锛氭嫾鍥㈡椿鍔ㄦ甯革紝浣嗙埗鎷煎洟涓嶅瓨鍦�
+ mockActivity();
+
+ // 璋冪敤锛屽苟鏂█
+ assertServiceException(() -> combinationRecordService.validateCombinationRecord(
+ USER_ID, ACTIVITY_ID, HEAD_ID, SKU_ID, 1), COMBINATION_RECORD_HEAD_NOT_EXISTS);
+ }
+
+ @Test
+ public void testValidateCombinationRecord_countEqualsStock() {
+ // mock 鏁版嵁锛氬簱瀛樺垰濂界瓑浜庤喘涔版暟閲�
+ mockValidateContext(10);
+
+ // 璋冪敤
+ KeyValue<CombinationActivityDO, CombinationProductDO> result = combinationRecordService
+ .validateCombinationRecord(USER_ID, ACTIVITY_ID, null, SKU_ID, 10);
+
+ // 鏂█
+ assertNotNull(result);
+ }
+
+ @Test
+ public void testValidateCombinationRecord_countGreaterThanStock() {
+ // mock 鏁版嵁锛氬簱瀛樹笉瓒�
+ mockValidateContext(10);
+
+ // 璋冪敤锛屽苟鏂█
+ assertServiceException(() -> combinationRecordService.validateCombinationRecord(
+ USER_ID, ACTIVITY_ID, null, SKU_ID, 11), COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL);
+ }
+
+ @Test
+ public void testValidateCombinationRecord_haveJoined() {
+ // mock 鏁版嵁锛氱敤鎴峰瓨鍦ㄨ繘琛屼腑鐨勬嫾鍥㈣褰�
+ mockValidateContext(10);
+ combinationRecordMapper.insert(randomRecord(o -> {
+ o.setStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
+ o.setCount(1);
+ }));
+
+ // 璋冪敤锛屽苟鏂█
+ assertServiceException(() -> combinationRecordService.validateCombinationRecord(
+ USER_ID, ACTIVITY_ID, null, SKU_ID, 1), COMBINATION_RECORD_FAILED_HAVE_JOINED);
+ }
+
+ @Test
+ public void testValidateCombinationRecord_totalLimitCountExceed() {
+ // mock 鏁版嵁锛氱敤鎴峰巻鍙茶喘涔版暟閲忓姞鏈鏁伴噺瓒呰繃鎬婚檺璐�
+ CombinationActivityDO activity = mockValidateContext(10);
+ activity.setTotalLimitCount(5);
+ combinationRecordMapper.insert(randomRecord(o -> {
+ o.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
+ o.setCount(3);
+ }));
+
+ // 璋冪敤锛屽苟鏂█
+ assertServiceException(() -> combinationRecordService.validateCombinationRecord(
+ USER_ID, ACTIVITY_ID, null, SKU_ID, 3), COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
+ }
+
+ @Test
+ public void testCreateCombinationRecord_headIdGroupAsNewGroup() {
+ // mock 鏁版嵁锛氬紑鍥㈠弬鏁颁腑 headId 涓� 0
+ mockValidateContext(10);
+ mockCreateContext();
+ CombinationRecordCreateReqDTO reqDTO = randomCreateReqDTO(CombinationRecordDO.HEAD_ID_GROUP);
+
+ // 璋冪敤
+ CombinationRecordDO record = combinationRecordService.createCombinationRecord(reqDTO);
+
+ // 鏂█锛氫粛鐒舵寜寮�鍥㈠鐞嗭紝涓嶆洿鏂板叾瀹冨洟璁板綍
+ assertNotNull(record.getId());
+ assertEquals(CombinationRecordDO.HEAD_ID_GROUP, record.getHeadId());
+ assertEquals(CombinationRecordStatusEnum.IN_PROGRESS.getStatus(), record.getStatus());
+ assertEquals(1, record.getUserCount());
+ assertFalse(record.getVirtualGroup());
+ assertNotNull(record.getStartTime());
+ assertNotNull(record.getExpireTime());
+ assertEquals(1L, combinationRecordMapper.selectCount());
+ assertEquals(CombinationRecordDO.HEAD_ID_GROUP,
+ combinationRecordMapper.selectById(record.getId()).getHeadId());
+ }
+
+ @Test
+ public void testHandleExpireRecord_cancelOrders() {
+ // mock 鏁版嵁锛氳繃鏈熷洟闀垮拰涓�涓洟鍛�
+ CombinationRecordDO headRecord = randomRecord(o -> {
+ o.setId(HEAD_ID);
+ o.setHeadId(CombinationRecordDO.HEAD_ID_GROUP);
+ o.setUserId(USER_ID);
+ o.setOrderId(ORDER_ID);
+ });
+ CombinationRecordDO memberRecord = randomRecord(o -> {
+ o.setId(501L);
+ o.setHeadId(HEAD_ID);
+ o.setUserId(101L);
+ o.setOrderId(601L);
+ });
+ combinationRecordMapper.insert(headRecord);
+ combinationRecordMapper.insert(memberRecord);
+
+ // 璋冪敤
+ combinationRecordService.handleExpireRecord(headRecord);
+
+ // 鏂█锛氭暣鍥㈣褰曟爣璁颁负澶辫触锛屽苟鍙栨秷宸叉敮浠樿鍗�
+ List<CombinationRecordDO> records = combinationRecordMapper.selectList();
+ assertEquals(2, records.size());
+ assertTrue(records.stream().allMatch(item ->
+ CombinationRecordStatusEnum.FAILED.getStatus().equals(item.getStatus())));
+ assertTrue(records.stream().allMatch(item -> item.getEndTime() != null));
+ verify(tradeOrderApi).cancelPaidOrder(USER_ID, ORDER_ID, TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getType());
+ verify(tradeOrderApi).cancelPaidOrder(101L, 601L, TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getType());
+ }
+
+ private CombinationActivityDO mockValidateContext(Integer stock) {
+ CombinationActivityDO activity = mockActivity();
+ CombinationProductDO product = randomPojo(CombinationProductDO.class, o -> {
+ o.setActivityId(ACTIVITY_ID);
+ o.setSpuId(SPU_ID);
+ o.setSkuId(SKU_ID);
+ o.setCombinationPrice(100);
+ });
+ ProductSkuRespDTO sku = randomPojo(ProductSkuRespDTO.class, o -> {
+ o.setId(SKU_ID);
+ o.setSpuId(SPU_ID);
+ o.setStock(stock);
+ o.setPicUrl("https://www.iocoder.cn/sku.png");
+ });
+ when(combinationActivityService.selectByActivityIdAndSkuId(ACTIVITY_ID, SKU_ID)).thenReturn(product);
+ when(productSkuApi.getSku(SKU_ID)).thenReturn(sku);
+ return activity;
+ }
+
+ private CombinationActivityDO mockActivity() {
+ CombinationActivityDO activity = randomPojo(CombinationActivityDO.class, o -> {
+ o.setId(ACTIVITY_ID);
+ o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+ o.setStartTime(LocalDateTime.now().minusHours(1));
+ o.setEndTime(LocalDateTime.now().plusHours(1));
+ o.setSingleLimitCount(100);
+ o.setTotalLimitCount(100);
+ o.setUserSize(3);
+ o.setVirtualGroup(false);
+ o.setLimitDuration(24);
+ });
+ when(combinationActivityService.validateCombinationActivityExists(ACTIVITY_ID)).thenReturn(activity);
+ return activity;
+ }
+
+ private void mockCreateContext() {
+ MemberUserRespDTO user = randomPojo(MemberUserRespDTO.class, o -> {
+ o.setId(USER_ID);
+ o.setNickname("鑺嬮亾婧愮爜");
+ o.setAvatar("https://www.iocoder.cn/avatar.png");
+ });
+ when(memberUserApi.getUser(USER_ID)).thenReturn(user);
+ ProductSpuRespDTO spu = randomPojo(ProductSpuRespDTO.class, o -> {
+ o.setId(SPU_ID);
+ o.setName("娴嬭瘯鍟嗗搧");
+ o.setPicUrl("https://www.iocoder.cn/spu.png");
+ });
+ when(productSpuApi.getSpu(SPU_ID)).thenReturn(spu);
+ }
+
+ private static CombinationRecordCreateReqDTO randomCreateReqDTO(Long headId) {
+ return randomPojo(CombinationRecordCreateReqDTO.class, o -> {
+ o.setActivityId(ACTIVITY_ID);
+ o.setSpuId(SPU_ID);
+ o.setSkuId(SKU_ID);
+ o.setCount(1);
+ o.setOrderId(ORDER_ID);
+ o.setUserId(USER_ID);
+ o.setHeadId(headId);
+ o.setCombinationPrice(100);
+ });
+ }
+
+ @SafeVarargs
+ private static CombinationRecordDO randomRecord(Consumer<CombinationRecordDO>... consumers) {
+ return randomPojo(CombinationRecordDO.class, o -> {
+ o.setActivityId(ACTIVITY_ID);
+ o.setCombinationPrice(100);
+ o.setSpuId(SPU_ID);
+ o.setSpuName("娴嬭瘯鍟嗗搧");
+ o.setPicUrl("https://www.iocoder.cn/spu.png");
+ o.setSkuId(SKU_ID);
+ o.setCount(1);
+ o.setUserId(USER_ID);
+ o.setNickname("鑺嬮亾婧愮爜");
+ o.setAvatar("https://www.iocoder.cn/avatar.png");
+ o.setHeadId(CombinationRecordDO.HEAD_ID_GROUP);
+ o.setStatus(CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
+ o.setOrderId(ORDER_ID);
+ o.setUserSize(3);
+ o.setUserCount(1);
+ o.setVirtualGroup(false);
+ o.setStartTime(LocalDateTime.now().minusMinutes(10));
+ o.setExpireTime(LocalDateTime.now().plusHours(1));
+ o.setEndTime(null);
+ for (Consumer<CombinationRecordDO> consumer : consumers) {
+ consumer.accept(o);
+ }
+ });
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java b/yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java
index 2f38628..1845be2 100644
--- a/yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java
+++ b/yudao-module-mall/yudao-module-promotion/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java
@@ -2,7 +2,10 @@
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
@@ -10,21 +13,23 @@
import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
+import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
+import java.util.function.Consumer;
-import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_ENOUGH;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*;
@@ -33,7 +38,6 @@
*
* @author 鑺嬮亾婧愮爜
*/
-@Disabled // TODO 鑺嬭壙锛氬悗缁� fix 琛ュ厖鐨勫崟娴�
@Import(CouponTemplateServiceImpl.class)
public class CouponTemplateServiceImplTest extends BaseDbUnitTest {
@@ -43,13 +47,26 @@
@Resource
private CouponTemplateMapper couponTemplateMapper;
+ @MockitoBean
+ private ProductCategoryApi productCategoryApi;
+ @MockitoBean
+ private ProductSpuApi productSpuApi;
+
@Test
public void testCreateCouponTemplate_success() {
// 鍑嗗鍙傛暟
- CouponTemplateCreateReqVO reqVO = randomPojo(CouponTemplateCreateReqVO.class,
- o -> o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope())
- .setValidityType(randomEle(CouponTemplateValidityTypeEnum.values()).getType())
- .setDiscountType(randomEle(PromotionDiscountTypeEnum.values()).getType()));
+ CouponTemplateCreateReqVO reqVO = randomPojo(CouponTemplateCreateReqVO.class, o -> {
+ o.setTotalCount(10);
+ o.setTakeLimitCount(2);
+ o.setTakeType(CouponTakeTypeEnum.USER.getType());
+ o.setProductScope(PromotionProductScopeEnum.ALL.getScope());
+ o.setProductScopeValues(null);
+ o.setValidityType(CouponTemplateValidityTypeEnum.TERM.getType());
+ o.setFixedStartTerm(0);
+ o.setFixedEndTerm(7);
+ o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType());
+ o.setDiscountPrice(100);
+ });
// 璋冪敤
Long couponTemplateId = couponTemplateService.createCouponTemplate(reqVO);
@@ -63,15 +80,21 @@
@Test
public void testUpdateCouponTemplate_success() {
// mock 鏁版嵁
- CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class);
+ CouponTemplateDO dbCouponTemplate = randomCouponTemplateDO();
couponTemplateMapper.insert(dbCouponTemplate);// @Sql: 鍏堟彃鍏ュ嚭涓�鏉″瓨鍦ㄧ殑鏁版嵁
// 鍑嗗鍙傛暟
CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> {
o.setId(dbCouponTemplate.getId()); // 璁剧疆鏇存柊鐨� ID
- // 鍏跺畠閫氱敤瀛楁
- o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope())
- .setValidityType(randomEle(CouponTemplateValidityTypeEnum.values()).getType())
- .setDiscountType(randomEle(PromotionDiscountTypeEnum.values()).getType());
+ o.setTotalCount(10);
+ o.setTakeLimitCount(2);
+ o.setTakeType(CouponTakeTypeEnum.USER.getType());
+ o.setProductScope(PromotionProductScopeEnum.ALL.getScope());
+ o.setProductScopeValues(null);
+ o.setValidityType(CouponTemplateValidityTypeEnum.TERM.getType());
+ o.setFixedStartTerm(0);
+ o.setFixedEndTerm(7);
+ o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType());
+ o.setDiscountPrice(100);
});
// 璋冪敤
@@ -84,16 +107,60 @@
@Test
public void testUpdateCouponTemplate_notExists() {
// 鍑嗗鍙傛暟
- CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class);
+ CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> o.setId(randomLongId()));
// 璋冪敤, 骞舵柇瑷�寮傚父
assertServiceException(() -> couponTemplateService.updateCouponTemplate(reqVO), COUPON_TEMPLATE_NOT_EXISTS);
}
@Test
+ public void testCreateCouponTemplate_takeLimitCountGreaterThanTotalCount() {
+ // 鍑嗗鍙傛暟
+ CouponTemplateCreateReqVO reqVO = randomPojo(CouponTemplateCreateReqVO.class, o -> {
+ o.setTotalCount(1);
+ o.setTakeLimitCount(2);
+ o.setTakeType(CouponTakeTypeEnum.USER.getType());
+ o.setProductScope(PromotionProductScopeEnum.ALL.getScope());
+ o.setProductScopeValues(null);
+ o.setValidityType(CouponTemplateValidityTypeEnum.TERM.getType());
+ o.setFixedStartTerm(0);
+ o.setFixedEndTerm(7);
+ o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType());
+ o.setDiscountPrice(100);
+ });
+
+ // 璋冪敤锛屽苟鏂█
+ assertServiceException(() -> couponTemplateService.createCouponTemplate(reqVO), COUPON_TEMPLATE_NOT_ENOUGH);
+ }
+
+ @Test
+ public void testUpdateCouponTemplate_takeLimitCountGreaterThanTotalCount() {
+ // mock 鏁版嵁
+ CouponTemplateDO couponTemplate = randomCouponTemplateDO();
+ couponTemplateMapper.insert(couponTemplate);
+ // 鍑嗗鍙傛暟
+ CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> {
+ o.setId(couponTemplate.getId()); // 璁剧疆鏇存柊鐨� ID
+ o.setTotalCount(1);
+ o.setTakeLimitCount(2);
+ o.setTakeType(CouponTakeTypeEnum.USER.getType());
+ o.setProductScope(PromotionProductScopeEnum.ALL.getScope());
+ o.setProductScopeValues(null);
+ o.setValidityType(CouponTemplateValidityTypeEnum.TERM.getType());
+ o.setFixedStartTerm(0);
+ o.setFixedEndTerm(7);
+ o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType());
+ o.setDiscountPrice(100);
+ });
+
+ // 璋冪敤锛屽苟鏂█
+ assertServiceException(() -> couponTemplateService.updateCouponTemplate(reqVO), COUPON_TEMPLATE_NOT_ENOUGH);
+ }
+
+ @Test
public void testDeleteCouponTemplate_success() {
// mock 鏁版嵁
- CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class);
+ CouponTemplateDO dbCouponTemplate = randomCouponTemplateDO();
couponTemplateMapper.insert(dbCouponTemplate);// @Sql: 鍏堟彃鍏ュ嚭涓�鏉″瓨鍦ㄧ殑鏁版嵁
// 鍑嗗鍙傛暟
Long id = dbCouponTemplate.getId();
@@ -146,4 +213,25 @@
assertPojoEquals(dbCouponTemplate, pageResult.getList().get(0));
}
+ @SafeVarargs
+ private static CouponTemplateDO randomCouponTemplateDO(Consumer<CouponTemplateDO>... consumers) {
+ Consumer<CouponTemplateDO> consumer = o -> {
+ o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+ o.setTotalCount(10);
+ o.setTakeLimitCount(1);
+ o.setTakeType(CouponTakeTypeEnum.USER.getType());
+ o.setUsePrice(0);
+ o.setProductScope(PromotionProductScopeEnum.ALL.getScope());
+ o.setProductScopeValues(null);
+ o.setValidityType(CouponTemplateValidityTypeEnum.TERM.getType());
+ o.setFixedStartTerm(0);
+ o.setFixedEndTerm(7);
+ o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType());
+ o.setDiscountPrice(100);
+ o.setTakeCount(0);
+ o.setUseCount(0);
+ };
+ return randomPojo(CouponTemplateDO.class, ArrayUtils.append(consumer, consumers));
+ }
+
}
diff --git a/yudao-module-mall/yudao-module-promotion/src/test/resources/sql/clean.sql b/yudao-module-mall/yudao-module-promotion/src/test/resources/sql/clean.sql
index 6a1a242..54ec043 100644
--- a/yudao-module-mall/yudao-module-promotion/src/test/resources/sql/clean.sql
+++ b/yudao-module-mall/yudao-module-promotion/src/test/resources/sql/clean.sql
@@ -5,8 +5,9 @@
DELETE FROM "promotion_discount_activity";
DELETE FROM "promotion_discount_product";
DELETE FROM "promotion_seckill_config";
+DELETE FROM "promotion_combination_record";
DELETE FROM "promotion_combination_activity";
DELETE FROM "promotion_article_category";
DELETE FROM "promotion_article";
DELETE FROM "promotion_diy_template";
-DELETE FROM "promotion_diy_page";
\ No newline at end of file
+DELETE FROM "promotion_diy_page";
diff --git a/yudao-module-mall/yudao-module-promotion/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-promotion/src/test/resources/sql/create_tables.sql
index 00ac3f9..fae2e52 100644
--- a/yudao-module-mall/yudao-module-promotion/src/test/resources/sql/create_tables.sql
+++ b/yudao-module-mall/yudao-module-promotion/src/test/resources/sql/create_tables.sql
@@ -23,13 +23,14 @@
(
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar NOT NULL,
+ "description" varchar,
"status" int NOT NULL,
"total_count" int NOT NULL,
"take_limit_count" int NOT NULL,
"take_type" int NOT NULL,
"use_price" int NOT NULL,
"product_scope" int NOT NULL,
- "product_spu_ids" varchar,
+ "product_scope_values" varchar,
"validity_type" int NOT NULL,
"valid_start_time" datetime,
"valid_end_time" datetime,
@@ -57,11 +58,11 @@
"status" int NOT NULL,
"user_id" bigint NOT NULL,
"take_type" int NOT NULL,
- "useprice" int NOT NULL,
+ "use_price" int NOT NULL,
"valid_start_time" datetime NOT NULL,
"valid_end_time" datetime NOT NULL,
"product_scope" int NOT NULL,
- "product_spu_ids" varchar,
+ "product_scope_values" varchar,
"discount_type" int NOT NULL,
"discount_percent" int,
"discount_price" int,
@@ -111,6 +112,27 @@
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '闄愭椂鎶樻墸娲诲姩';
+
+CREATE TABLE IF NOT EXISTS "promotion_discount_product"
+(
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+ "activity_id" bigint NOT NULL,
+ "spu_id" bigint NOT NULL,
+ "sku_id" bigint NOT NULL,
+ "discount_type" int NOT NULL,
+ "discount_percent" int,
+ "discount_price" int,
+ "activity_name" varchar NOT NULL,
+ "activity_status" int NOT NULL,
+ "activity_start_time" datetime NOT NULL,
+ "activity_end_time" datetime NOT NULL,
+ "creator" varchar DEFAULT '',
+ "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar DEFAULT '',
+ "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ PRIMARY KEY ("id")
+) COMMENT '闄愭椂鎶樻墸鍟嗗搧';
CREATE TABLE IF NOT EXISTS "promotion_seckill_activity"
(
@@ -180,6 +202,36 @@
"tenant_id" bigint NOT NULL,
PRIMARY KEY ("id")
) COMMENT '鎷煎洟娲诲姩';
+
+CREATE TABLE IF NOT EXISTS "promotion_combination_record"
+(
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+ "activity_id" bigint NOT NULL,
+ "combination_price" int NOT NULL,
+ "spu_id" bigint NOT NULL,
+ "spu_name" varchar NOT NULL,
+ "pic_url" varchar,
+ "sku_id" bigint NOT NULL,
+ "count" int NOT NULL,
+ "user_id" bigint NOT NULL,
+ "nickname" varchar,
+ "avatar" varchar,
+ "head_id" bigint NOT NULL,
+ "status" int NOT NULL,
+ "order_id" bigint NOT NULL,
+ "user_size" int NOT NULL,
+ "user_count" int NOT NULL,
+ "virtual_group" bit NOT NULL,
+ "expire_time" datetime,
+ "start_time" datetime,
+ "end_time" datetime,
+ "creator" varchar DEFAULT '',
+ "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar DEFAULT '',
+ "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ PRIMARY KEY ("id")
+) COMMENT '鎷煎洟璁板綍';
CREATE TABLE IF NOT EXISTS "promotion_article_category"
(
@@ -253,4 +305,4 @@
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL,
PRIMARY KEY ("id")
-) COMMENT '瑁呬慨椤甸潰';
\ No newline at end of file
+) COMMENT '瑁呬慨椤甸潰';
diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java
index 904c246..c81047b 100644
--- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java
+++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java
@@ -73,7 +73,7 @@
}
List<AdminUserRespDTO> verifyUsers = CollUtil.isNotEmpty(deliveryPickUpStore.getVerifyUserIds()) ?
adminUserApi.getUserList(deliveryPickUpStore.getVerifyUserIds()) : null;
- return success(BeanUtils.toBean(deliveryPickUpStore, DeliveryPickUpStoreRespVO.class)
+ return success(DeliveryPickUpStoreConvert.INSTANCE.convert01(deliveryPickUpStore)
.setVerifyUsers(BeanUtils.toBean(verifyUsers, UserSimpleBaseVO.class)));
}
diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java
index fdf39a4..3c1233a 100644
--- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java
+++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java
@@ -21,6 +21,9 @@
@Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
+ @Schema(description = "鍦板尯鍚嶇О", example = "涓婃捣涓婃捣甯傛櫘闄�鍖�")
+ private String areaName;
+
@Schema(description = "鏍搁攢鐢ㄦ埛鏁扮粍", requiredMode = Schema.RequiredMode.REQUIRED)
private List<UserSimpleBaseVO> verifyUsers;
diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java
index 46495c0..310028d 100644
--- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java
+++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java
@@ -13,6 +13,7 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -47,13 +48,13 @@
@PostMapping(value = "/create")
@Operation(summary = "鐢宠鍞悗")
- public CommonResult<Long> createAfterSale(@RequestBody AppAfterSaleCreateReqVO createReqVO) {
+ public CommonResult<Long> createAfterSale(@Valid @RequestBody AppAfterSaleCreateReqVO createReqVO) {
return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO));
}
@PutMapping(value = "/delivery")
@Operation(summary = "閫�鍥炶揣鐗�")
- public CommonResult<Boolean> deliveryAfterSale(@RequestBody AppAfterSaleDeliveryReqVO deliveryReqVO) {
+ public CommonResult<Boolean> deliveryAfterSale(@Valid @RequestBody AppAfterSaleDeliveryReqVO deliveryReqVO) {
afterSaleService.deliveryAfterSale(getLoginUserId(), deliveryReqVO);
return success(true);
}
diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryPickUpStoreConvert.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryPickUpStoreConvert.java
index 05d8a8f..560e7fe 100644
--- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryPickUpStoreConvert.java
+++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryPickUpStoreConvert.java
@@ -30,6 +30,9 @@
PageResult<DeliveryPickUpStoreRespVO> convertPage(PageResult<DeliveryPickUpStoreDO> page);
+ @Mapping(source = "areaId", target = "areaName", qualifiedByName = "convertAreaIdToAreaName")
+ DeliveryPickUpStoreRespVO convert01(DeliveryPickUpStoreDO bean);
+
List<DeliveryPickUpStoreSimpleRespVO> convertList1(List<DeliveryPickUpStoreDO> list);
@Mapping(source = "areaId", target = "areaName", qualifiedByName = "convertAreaIdToAreaName")
DeliveryPickUpStoreSimpleRespVO convert02(DeliveryPickUpStoreDO bean);
diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
index 0e2380a..3842bb4 100644
--- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
+++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.trade.convert.order;
import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -268,8 +269,8 @@
.setTitle(StrUtil.format("{}鎴愬姛璐拱{}", user.getNickname(), item.getSpuName()));
if (BooleanUtil.isTrue(spu.getSubCommissionType())) {
// 鐗规畩锛氬崟鐙缃殑浣i噾闇�瑕佷箻浠ヨ喘涔版暟閲忋�傚叧鑱� https://gitee.com/yudaocode/yudao-mall-uniapp/issues/ICY7SJ
- bo.setFirstFixedPrice(sku.getFirstBrokeragePrice() * item.getCount())
- .setSecondFixedPrice(sku.getSecondBrokeragePrice() * item.getCount());
+ bo.setFirstFixedPrice(ObjectUtil.defaultIfNull(sku.getFirstBrokeragePrice(), 0) * item.getCount())
+ .setSecondFixedPrice(ObjectUtil.defaultIfNull(sku.getSecondBrokeragePrice(), 0) * item.getCount());
}
return bo;
}
diff --git a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java
index ed314c3..845fea7 100644
--- a/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java
+++ b/yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImpl.java
@@ -38,7 +38,6 @@
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMinValue;
-import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.BROKERAGE_WITHDRAW_USER_BALANCE_NOT_ENOUGH;
/**
@@ -143,7 +142,7 @@
int calculatePrice(Integer basePrice, Integer percent, Integer fixedPrice) {
// 1. 浼樺厛浣跨敤鍥哄畾浣i噾
if (fixedPrice != null && fixedPrice >= 0) {
- return ObjectUtil.defaultIfNull(fixedPrice, 0);
+ return fixedPrice;
}
// 2. 鏍规嵁姣斾緥璁$畻浣i噾
if (basePrice != null && basePrice > 0 && percent != null && percent > 0) {
@@ -329,7 +328,7 @@
return respVO;
}
// 2.2 鏍¢獙鐢ㄦ埛鏄惁鏈夊垎閿�璧勬牸
- respVO.setEnabled(brokerageUserService.getUserBrokerageEnabled(getLoginUserId()));
+ respVO.setEnabled(brokerageUserService.getUserBrokerageEnabled(userId));
if (BooleanUtil.isFalse(respVO.getEnabled())) {
return respVO;
}
@@ -339,22 +338,24 @@
return respVO;
}
- // 3.1 鍟嗗搧鍗曠嫭鍒嗕剑妯″紡
- Integer fixedMinPrice = 0;
- Integer fixedMaxPrice = 0;
- Integer spuMinPrice = 0;
- Integer spuMaxPrice = 0;
+ // 3.1 鑾峰彇鍟嗗搧 SKU 鍒楄〃
List<ProductSkuRespDTO> skuList = productSkuApi.getSkuListBySpuId(ListUtil.of(spuId));
if (BooleanUtil.isTrue(spu.getSubCommissionType())) {
- fixedMinPrice = getMinValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice);
- fixedMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getFirstBrokeragePrice);
- // 3.2 鍏ㄥ眬鍒嗕剑妯″紡锛堟牴鎹晢鍝佷环鏍兼瘮渚嬭绠楋級
+ // 3.2.1 鍟嗗搧鐙珛鍒嗛攢妯″紡锛氱洿鎺ュ彇 SKU 鍥哄畾浣i噾
+ // 娉ㄦ剰锛氬浐瀹氫剑閲戝厑璁镐负 0锛岃〃绀哄晢瀹朵富鍔ㄨ涓洪浂浣i噾锛涗负绌烘椂锛屼篃鎸� 0 澶勭悊
+ Integer fixedMinPrice = getMinValue(skuList,
+ sku -> ObjectUtil.defaultIfNull(sku.getFirstBrokeragePrice(), 0));
+ Integer fixedMaxPrice = getMaxValue(skuList,
+ sku -> ObjectUtil.defaultIfNull(sku.getFirstBrokeragePrice(), 0));
+ respVO.setBrokerageMinPrice(calculatePrice(null, tradeConfig.getBrokerageFirstPercent(), fixedMinPrice))
+ .setBrokerageMaxPrice(calculatePrice(null, tradeConfig.getBrokerageFirstPercent(), fixedMaxPrice));
} else {
- spuMinPrice = getMinValue(skuList, ProductSkuRespDTO::getPrice);
- spuMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getPrice);
+ // 3.2.2 鍏ㄥ眬姣斾緥妯″紡锛氬浐瀹氫剑閲戜紶 null锛岄伩鍏嶈榛樿鍊� 0 鎻愬墠鎷︽埅
+ Integer spuMinPrice = getMinValue(skuList, ProductSkuRespDTO::getPrice);
+ Integer spuMaxPrice = getMaxValue(skuList, ProductSkuRespDTO::getPrice);
+ respVO.setBrokerageMinPrice(calculatePrice(spuMinPrice, tradeConfig.getBrokerageFirstPercent(), null))
+ .setBrokerageMaxPrice(calculatePrice(spuMaxPrice, tradeConfig.getBrokerageFirstPercent(), null));
}
- respVO.setBrokerageMinPrice(calculatePrice(spuMinPrice, tradeConfig.getBrokerageFirstPercent(), fixedMinPrice));
- respVO.setBrokerageMaxPrice(calculatePrice(spuMaxPrice, tradeConfig.getBrokerageFirstPercent(), fixedMaxPrice));
return respVO;
}
diff --git a/yudao-module-mall/yudao-module-trade/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml b/yudao-module-mall/yudao-module-trade/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml
index 066f75d..69ee4ed 100644
--- a/yudao-module-mall/yudao-module-trade/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml
+++ b/yudao-module-mall/yudao-module-trade/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml
@@ -2,9 +2,19 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageUserMapper">
+ <sql id="OrderDirection">
+ <choose>
+ <when test="@cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils@isAscOrder(sortingField.order)">
+ ASC
+ </when>
+ <otherwise>
+ DESC
+ </otherwise>
+ </choose>
+ </sql>
+
<select id="selectSummaryPageByUserId"
resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
-
SELECT bu.id, bu.bind_user_time AS brokerageTime,
(SELECT SUM(price) FROM trade_brokerage_record r
WHERE r.user_id = bu.id AND biz_type = #{bizType} AND r.status = #{status} AND r.deleted = FALSE) AS brokeragePrice,
@@ -23,14 +33,17 @@
</if>
</where>
<choose>
- <when test="sortingField.field == 'userCount'">
- ORDER BY brokerageUserCount ${sortingField.order}
+ <when test="sortingField != null and sortingField.field == 'userCount'">
+ ORDER BY brokerageUserCount
+ <include refid="OrderDirection"/>
</when>
- <when test="sortingField.field == 'orderCount'">
- ORDER BY brokerageOrderCount ${sortingField.order}
+ <when test="sortingField != null and sortingField.field == 'orderCount'">
+ ORDER BY brokerageOrderCount
+ <include refid="OrderDirection"/>
</when>
- <when test="sortingField.field == 'price'">
- ORDER BY brokeragePrice ${sortingField.order}
+ <when test="sortingField != null and sortingField.field == 'price'">
+ ORDER BY brokeragePrice
+ <include refid="OrderDirection"/>
</when>
<otherwise>
ORDER BY bu.bind_user_time DESC
diff --git a/yudao-module-mall/yudao-module-trade/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java b/yudao-module-mall/yudao-module-trade/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java
index 141e865..abdd4e8 100644
--- a/yudao-module-mall/yudao-module-trade/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java
+++ b/yudao-module-mall/yudao-module-trade/src/test/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageRecordServiceImplTest.java
@@ -1,36 +1,42 @@
package cn.iocoder.yudao.module.trade.service.brokerage;
+import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO;
+import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageRecordMapper;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
import jakarta.annotation.Resource;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import java.math.RoundingMode;
-import static cn.hutool.core.util.RandomUtil.randomEle;
-import static cn.hutool.core.util.RandomUtil.randomInt;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
-import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomInteger;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
-// TODO @鑺嬭壙锛氬崟娴嬪悗缁湅鐪�
/**
* {@link BrokerageRecordServiceImpl} 鐨勫崟鍏冩祴璇曠被
*
* @author owen
*/
-@Disabled // TODO 鑺嬭壙锛氬悗缁� fix 琛ュ厖鐨勫崟娴�
@Import(BrokerageRecordServiceImpl.class)
public class BrokerageRecordServiceImplTest extends BaseDbUnitTest {
@@ -43,31 +49,43 @@
private TradeConfigService tradeConfigService;
@MockitoBean
private BrokerageUserService brokerageUserService;
+ @MockitoBean
+ private ProductSpuApi productSpuApi;
+ @MockitoBean
+ private ProductSkuApi productSkuApi;
@Test
- @Disabled // TODO 璇蜂慨鏀� null 涓洪渶瑕佺殑鍊硷紝鐒跺悗鍒犻櫎 @Disabled 娉ㄨВ
public void testGetBrokerageRecordPage() {
// mock 鏁版嵁
BrokerageRecordDO dbBrokerageRecord = randomPojo(BrokerageRecordDO.class, o -> { // 绛変細鏌ヨ鍒�
- o.setUserId(null);
- o.setBizType(null);
- o.setStatus(null);
- o.setCreateTime(null);
+ o.setUserId(1L);
+ o.setBizType(BrokerageRecordBizTypeEnum.ORDER.getType());
+ o.setStatus(BrokerageRecordStatusEnum.SETTLEMENT.getStatus());
+ o.setSourceUserLevel(1);
+ o.setSourceUserId(100L);
+ o.setCreateTime(buildTime(2023, 2, 10));
+ o.setDeleted(false);
});
brokerageRecordMapper.insert(dbBrokerageRecord);
// 娴嬭瘯 userId 涓嶅尮閰�
- brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setUserId(null)));
+ brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setUserId(2L)));
// 娴嬭瘯 bizType 涓嶅尮閰�
- brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setBizType(null)));
+ brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord,
+ o -> o.setBizType(BrokerageRecordBizTypeEnum.WITHDRAW.getType())));
// 娴嬭瘯 status 涓嶅尮閰�
- brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setStatus(null)));
+ brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord,
+ o -> o.setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus())));
+ // 娴嬭瘯 sourceUserLevel 涓嶅尮閰�
+ brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setSourceUserLevel(2)));
// 娴嬭瘯 createTime 涓嶅尮閰�
- brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord, o -> o.setCreateTime(null)));
+ brokerageRecordMapper.insert(cloneIgnoreId(dbBrokerageRecord,
+ o -> o.setCreateTime(buildTime(2023, 3, 1))));
// 鍑嗗鍙傛暟
BrokerageRecordPageReqVO reqVO = new BrokerageRecordPageReqVO();
- reqVO.setUserId(null);
- reqVO.setBizType(null);
- reqVO.setStatus(null);
+ reqVO.setUserId(1L);
+ reqVO.setBizType(BrokerageRecordBizTypeEnum.ORDER.getType());
+ reqVO.setStatus(BrokerageRecordStatusEnum.SETTLEMENT.getStatus());
+ reqVO.setSourceUserLevel(1);
reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
// 璋冪敤
@@ -81,37 +99,159 @@
@Test
public void testCalculatePrice_useFixedPrice() {
// mock 鏁版嵁
- Integer payPrice = randomInteger();
- Integer percent = randomInt(1, 101);
- Integer fixedPrice = randomInt();
+ Integer payPrice = 1000;
+ Integer percent = 10;
+ Integer fixedPrice = 88;
// 璋冪敤
int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice);
// 鏂█
- assertEquals(brokerage, fixedPrice);
+ assertEquals(fixedPrice, brokerage);
}
@Test
public void testCalculatePrice_usePercent() {
- // mock 鏁版嵁
- Integer payPrice = randomInteger();
- Integer percent = randomInt(1, 101);
- Integer fixedPrice = randomEle(new Integer[]{0, null});
- System.out.println("fixedPrice=" + fixedPrice);
+ // mock 鏁版嵁锛歠ixedPrice 涓� null 鏃讹紝鎸夋瘮渚嬭绠椾剑閲�
+ Integer payPrice = 1000;
+ Integer percent = 10;
+ Integer fixedPrice = null;
// 璋冪敤
int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice);
// 鏂█
- assertEquals(brokerage, NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0, RoundingMode.DOWN).intValue());
+ assertEquals(NumberUtil.div(NumberUtil.mul(payPrice, percent), 100, 0,
+ RoundingMode.DOWN).intValue(), brokerage);
+ }
+
+ @Test
+ public void testCalculatePrice_fixedPriceIsZero() {
+ // mock 鏁版嵁锛歠ixedPrice 涓� 0 鏃讹紝浠嶄娇鐢ㄥ浐瀹氫剑閲戯紝涓嶅洖閫�鍒版瘮渚嬭绠�
+ Integer payPrice = 1000;
+ Integer percent = 10;
+ Integer fixedPrice = 0;
+ // 璋冪敤
+ int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice);
+ // 鏂█
+ assertEquals(0, brokerage);
}
@Test
public void testCalculatePrice_equalsZero() {
- // mock 鏁版嵁
+ // mock 鏁版嵁锛氫笁涓弬鏁板潎鏃犳晥鏃讹紝杩斿洖 0
Integer payPrice = null;
Integer percent = null;
Integer fixedPrice = null;
// 璋冪敤
int brokerage = brokerageRecordService.calculatePrice(payPrice, percent, fixedPrice);
// 鏂█
- assertEquals(brokerage, 0);
+ assertEquals(0, brokerage);
+ }
+
+ @Test
+ public void testCalculateProductBrokeragePrice_globalPercent() {
+ // mock锛氬垎閿�鍔熻兘宸插紑鍚紝姣斾緥 10%锛屽綋鍓嶇敤鎴锋湁鍒嗛攢璧勬牸
+ TradeConfigDO tradeConfig = new TradeConfigDO();
+ tradeConfig.setBrokerageEnabled(true);
+ tradeConfig.setBrokerageFirstPercent(10);
+ when(tradeConfigService.getTradeConfig()).thenReturn(tradeConfig);
+ when(brokerageUserService.getUserBrokerageEnabled(100L)).thenReturn(true);
+
+ // mock锛氬晢鍝佹湭寮�鍚嫭绔嬪垎閿�锛坰ubCommissionType = false锛夛紝SKU 鍞环 1000 鍒�
+ ProductSpuRespDTO spu = new ProductSpuRespDTO();
+ spu.setSubCommissionType(false);
+ when(productSpuApi.getSpu(1L)).thenReturn(spu);
+
+ ProductSkuRespDTO sku = new ProductSkuRespDTO();
+ sku.setPrice(1000);
+ when(productSkuApi.getSkuListBySpuId(ListUtil.of(1L))).thenReturn(ListUtil.of(sku));
+
+ // 璋冪敤
+ AppBrokerageProductPriceRespVO result = brokerageRecordService.calculateProductBrokeragePrice(100L, 1L);
+
+ // 鏂█锛氭寜 10% 姣斾緥璁$畻锛�1000 * 10% = 100 鍒嗭紙鍚戜笅鍙栨暣锛�
+ assertTrue(result.getEnabled());
+ assertEquals(100, result.getBrokerageMinPrice());
+ assertEquals(100, result.getBrokerageMaxPrice());
+ }
+
+ @Test
+ public void testCalculateProductBrokeragePrice_subCommissionZeroFixed() {
+ // mock锛氬垎閿�鍔熻兘宸插紑鍚紝姣斾緥 10%锛屽綋鍓嶇敤鎴锋湁鍒嗛攢璧勬牸
+ TradeConfigDO tradeConfig = new TradeConfigDO();
+ tradeConfig.setBrokerageEnabled(true);
+ tradeConfig.setBrokerageFirstPercent(10);
+ when(tradeConfigService.getTradeConfig()).thenReturn(tradeConfig);
+ when(brokerageUserService.getUserBrokerageEnabled(100L)).thenReturn(true);
+
+ // mock锛氬晢鍝佸紑鍚嫭绔嬪垎閿�锛坰ubCommissionType = true锛夛紝SKU 鍥哄畾浣i噾涓� 0锛堝晢瀹朵富鍔ㄨ缃級
+ ProductSpuRespDTO spu = new ProductSpuRespDTO();
+ spu.setSubCommissionType(true);
+ when(productSpuApi.getSpu(2L)).thenReturn(spu);
+
+ ProductSkuRespDTO sku = new ProductSkuRespDTO();
+ sku.setPrice(1000);
+ sku.setFirstBrokeragePrice(0);
+ when(productSkuApi.getSkuListBySpuId(ListUtil.of(2L))).thenReturn(ListUtil.of(sku));
+
+ // 璋冪敤
+ AppBrokerageProductPriceRespVO result = brokerageRecordService.calculateProductBrokeragePrice(100L, 2L);
+
+ // 鏂█锛氱嫭绔嬪垎閿�鍥哄畾浣i噾涓� 0锛屽簲杩斿洖 0锛屼笉寰楀洖閫�鍒板叏灞�姣斾緥
+ assertTrue(result.getEnabled());
+ assertEquals(0, result.getBrokerageMinPrice());
+ assertEquals(0, result.getBrokerageMaxPrice());
+ }
+
+ @Test
+ public void testCalculateProductBrokeragePrice_subCommissionNullFixed() {
+ // mock锛氬垎閿�鍔熻兘宸插紑鍚紝姣斾緥 10%锛屽綋鍓嶇敤鎴锋湁鍒嗛攢璧勬牸
+ TradeConfigDO tradeConfig = new TradeConfigDO();
+ tradeConfig.setBrokerageEnabled(true);
+ tradeConfig.setBrokerageFirstPercent(10);
+ when(tradeConfigService.getTradeConfig()).thenReturn(tradeConfig);
+ when(brokerageUserService.getUserBrokerageEnabled(100L)).thenReturn(true);
+
+ // mock锛氬晢鍝佸紑鍚嫭绔嬪垎閿�锛屽叾涓竴涓� SKU 鍥哄畾浣i噾鏈厤缃�
+ ProductSpuRespDTO spu = new ProductSpuRespDTO();
+ spu.setSubCommissionType(true);
+ when(productSpuApi.getSpu(3L)).thenReturn(spu);
+
+ ProductSkuRespDTO nullBrokerageSku = new ProductSkuRespDTO();
+ nullBrokerageSku.setPrice(1000);
+ nullBrokerageSku.setFirstBrokeragePrice(null);
+ ProductSkuRespDTO fixedBrokerageSku = new ProductSkuRespDTO();
+ fixedBrokerageSku.setPrice(2000);
+ fixedBrokerageSku.setFirstBrokeragePrice(200);
+ when(productSkuApi.getSkuListBySpuId(ListUtil.of(3L))).thenReturn(ListUtil.of(nullBrokerageSku, fixedBrokerageSku));
+
+ // 璋冪敤
+ AppBrokerageProductPriceRespVO result = brokerageRecordService.calculateProductBrokeragePrice(100L, 3L);
+
+ // 鏂█锛氱嫭绔嬪垎閿�鍥哄畾浣i噾涓虹┖鏃舵寜 0 澶勭悊锛岄伩鍏嶆瘮杈冩渶灏�/鏈�澶т剑閲戞椂鎶ラ敊
+ assertTrue(result.getEnabled());
+ assertEquals(0, result.getBrokerageMinPrice());
+ assertEquals(200, result.getBrokerageMaxPrice());
+ }
+
+ @Test
+ public void testCalculateProductBrokeragePrice_subCommissionEmptySkuList() {
+ // mock锛氬垎閿�鍔熻兘宸插紑鍚紝姣斾緥 10%锛屽綋鍓嶇敤鎴锋湁鍒嗛攢璧勬牸
+ TradeConfigDO tradeConfig = new TradeConfigDO();
+ tradeConfig.setBrokerageEnabled(true);
+ tradeConfig.setBrokerageFirstPercent(10);
+ when(tradeConfigService.getTradeConfig()).thenReturn(tradeConfig);
+ when(brokerageUserService.getUserBrokerageEnabled(100L)).thenReturn(true);
+
+ // mock锛氬晢鍝佸紑鍚嫭绔嬪垎閿�锛屼絾鏌ヨ涓嶅埌 SKU 鍥哄畾浣i噾
+ ProductSpuRespDTO spu = new ProductSpuRespDTO();
+ spu.setSubCommissionType(true);
+ when(productSpuApi.getSpu(4L)).thenReturn(spu);
+ when(productSkuApi.getSkuListBySpuId(ListUtil.of(4L))).thenReturn(ListUtil.of());
+
+ // 璋冪敤
+ AppBrokerageProductPriceRespVO result = brokerageRecordService.calculateProductBrokeragePrice(100L, 4L);
+
+ // 鏂█锛氱嫭绔嬪垎閿�娌℃湁鍥哄畾浣i噾鏃讹紝涓嶅洖閫�鍒板叏灞�姣斾緥
+ assertTrue(result.getEnabled());
+ assertEquals(0, result.getBrokerageMinPrice());
+ assertEquals(0, result.getBrokerageMaxPrice());
}
}
diff --git a/yudao-module-mall/yudao-module-trade/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-trade/src/test/resources/sql/create_tables.sql
index 1d7ed24..61ed058 100644
--- a/yudao-module-mall/yudao-module-trade/src/test/resources/sql/create_tables.sql
+++ b/yudao-module-mall/yudao-module-trade/src/test/resources/sql/create_tables.sql
@@ -173,7 +173,7 @@
) COMMENT '鍒嗛攢鐢ㄦ埛';
CREATE TABLE IF NOT EXISTS "trade_brokerage_record"
(
- "id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint NOT NULL,
"biz_id" varchar NOT NULL,
"biz_type" varchar NOT NULL,
@@ -184,6 +184,8 @@
"status" varchar NOT NULL,
"frozen_days" int NOT NULL,
"unfreeze_time" varchar,
+ "source_user_level" int,
+ "source_user_id" bigint,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
@@ -232,4 +234,4 @@
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
-) COMMENT '浣i噾鎻愮幇';
\ No newline at end of file
+) COMMENT '浣i噾鎻愮幇';
diff --git a/yudao-module-mdm-api/pom.xml b/yudao-module-mdm-api/pom.xml
deleted file mode 100644
index ccd7c49..0000000
--- a/yudao-module-mdm-api/pom.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao</artifactId>
- <version>${revision}</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>yudao-module-mdm-api</artifactId>
- <packaging>jar</packaging>
-
- <name>${project.artifactId}</name>
- <description>
- mdm 妯″潡涓嬶紝涓绘暟鎹鐞嗙殑 API 鎺ュ彛瀹氫箟锛屼緵鍏朵粬妯″潡寮曠敤
- </description>
-
- <dependencies>
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-common</artifactId>
- </dependency>
- </dependencies>
-
-</project>
\ No newline at end of file
diff --git a/yudao-module-mdm/pom.xml b/yudao-module-mdm/pom.xml
deleted file mode 100644
index 9190b17..0000000
--- a/yudao-module-mdm/pom.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao</artifactId>
- <version>${revision}</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>yudao-module-mdm</artifactId>
- <packaging>jar</packaging>
-
- <name>${project.artifactId}</name>
- <description>
- mdm 妯″潡涓嬶紝涓绘暟鎹鐞嗭紙Master Data Management锛夈��
- 渚嬪璇达細鐗╂枡銆佸垎绫汇�佸崟浣嶃�佸搧鐗屻�佷粨搴撶瓑涓绘暟鎹鐞�
- </description>
-
- <dependencies>
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-system</artifactId>
- <version>${revision}</version>
- </dependency>
-
- <!-- Web 鐩稿叧 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-security</artifactId>
- </dependency>
-
- <!-- DB 鐩稿叧 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
- </dependency>
-
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-redis</artifactId>
- </dependency>
-
- <!-- 宸ュ叿绫荤浉鍏� -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-excel</artifactId>
- </dependency>
-
- <!-- Test 娴嬭瘯鐩稿叧 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-spring-boot-starter-test</artifactId>
- </dependency>
-
- </dependencies>
-
-</project>
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/MdmBrandApi.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/MdmBrandApi.java
deleted file mode 100644
index 8b9ff0b..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/MdmBrandApi.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.brand;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.mdm.api.brand.dto.MdmBrandRespDTO;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 鍝佺墝 API 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmBrandApi {
-
- String PREFIX = "/rpc-api/mdm/brand";
-
- /**
- * 鑾峰彇鍝佺墝
- *
- * @param id 鍝佺墝缂栧彿
- * @return 鍝佺墝
- */
- CommonResult<MdmBrandRespDTO> getBrand(Long id);
-
- /**
- * 鑾峰彇鍝佺墝鍒楄〃
- *
- * @param ids 鍝佺墝缂栧彿鍒楄〃
- * @return 鍝佺墝鍒楄〃
- */
- CommonResult<List<MdmBrandRespDTO>> getBrandList(Collection<Long> ids);
-
- /**
- * 鏍¢獙鍝佺墝瀛樺湪
- *
- * @param id 鍝佺墝缂栧彿
- * @return 鍝佺墝
- */
- CommonResult<MdmBrandRespDTO> validateBrandExists(Long id);
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇鍝佺墝
- *
- * @param code 鍝佺墝缂栫爜
- * @return 鍝佺墝
- */
- CommonResult<MdmBrandRespDTO> getBrandByCode(String code);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/MdmBrandApiImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/MdmBrandApiImpl.java
deleted file mode 100644
index 70f54e1..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/MdmBrandApiImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.brand;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.api.brand.dto.MdmBrandRespDTO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.brand.MdmBrandDO;
-import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService;
-import jakarta.annotation.Resource;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collection;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * MDM 鍝佺墝 API 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@RestController
-@RequestMapping(MdmBrandApi.PREFIX)
-@Validated
-public class MdmBrandApiImpl implements MdmBrandApi {
-
- @Resource
- private MdmBrandService brandService;
-
- @Override
- public CommonResult<MdmBrandRespDTO> getBrand(Long id) {
- MdmBrandDO brand = brandService.getBrand(id);
- return success(BeanUtils.toBean(brand, MdmBrandRespDTO.class));
- }
-
- @Override
- public CommonResult<List<MdmBrandRespDTO>> getBrandList(Collection<Long> ids) {
- List<MdmBrandDO> list = brandService.getBrandList(ids);
- return success(BeanUtils.toBean(list, MdmBrandRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmBrandRespDTO> validateBrandExists(Long id) {
- MdmBrandDO brand = brandService.validateBrandExists(id);
- return success(BeanUtils.toBean(brand, MdmBrandRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmBrandRespDTO> getBrandByCode(String code) {
- MdmBrandDO brand = brandService.getBrandByCode(code);
- return success(BeanUtils.toBean(brand, MdmBrandRespDTO.class));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/dto/MdmBrandRespDTO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/dto/MdmBrandRespDTO.java
deleted file mode 100644
index 70779f8..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/brand/dto/MdmBrandRespDTO.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.brand.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Schema(description = "RPC 鏈嶅姟 - MDM 鍝佺墝 Response DTO")
-@Data
-public class MdmBrandRespDTO {
-
- @Schema(description = "鍝佺墝缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "鍝佺墝缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "BRAND001")
- private String code;
-
- @Schema(description = "鍝佺墝鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍝佺墝A")
- private String name;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/MdmItemCategoryApi.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/MdmItemCategoryApi.java
deleted file mode 100644
index 17f4686..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/MdmItemCategoryApi.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.category;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.mdm.api.category.dto.MdmItemCategoryRespDTO;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 鐗╂枡鍒嗙被 API 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmItemCategoryApi {
-
- String PREFIX = "/rpc-api/mdm/category";
-
- /**
- * 鑾峰彇鐗╂枡鍒嗙被
- *
- * @param id 鍒嗙被缂栧彿
- * @return 鐗╂枡鍒嗙被
- */
- CommonResult<MdmItemCategoryRespDTO> getItemCategory(Long id);
-
- /**
- * 鑾峰彇鐗╂枡鍒嗙被鍒楄〃
- *
- * @param ids 鍒嗙被缂栧彿鍒楄〃
- * @return 鐗╂枡鍒嗙被鍒楄〃
- */
- CommonResult<List<MdmItemCategoryRespDTO>> getItemCategoryList(Collection<Long> ids);
-
- /**
- * 鏍¢獙鐗╂枡鍒嗙被瀛樺湪
- *
- * @param id 鍒嗙被缂栧彿
- * @return 鐗╂枡鍒嗙被
- */
- CommonResult<MdmItemCategoryRespDTO> validateItemCategoryExists(Long id);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/MdmItemCategoryApiImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/MdmItemCategoryApiImpl.java
deleted file mode 100644
index 8f70f31..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/MdmItemCategoryApiImpl.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.category;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.api.category.dto.MdmItemCategoryRespDTO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
-import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService;
-import jakarta.annotation.Resource;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collection;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * MDM 鐗╂枡鍒嗙被 API 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@RestController
-@RequestMapping(MdmItemCategoryApi.PREFIX)
-@Validated
-public class MdmItemCategoryApiImpl implements MdmItemCategoryApi {
-
- @Resource
- private MdmItemCategoryService itemCategoryService;
-
- @Override
- public CommonResult<MdmItemCategoryRespDTO> getItemCategory(Long id) {
- MdmItemCategoryDO itemCategory = itemCategoryService.getItemCategory(id);
- return success(BeanUtils.toBean(itemCategory, MdmItemCategoryRespDTO.class));
- }
-
- @Override
- public CommonResult<List<MdmItemCategoryRespDTO>> getItemCategoryList(Collection<Long> ids) {
- List<MdmItemCategoryDO> list = itemCategoryService.getItemCategoryList(ids);
- return success(BeanUtils.toBean(list, MdmItemCategoryRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemCategoryRespDTO> validateItemCategoryExists(Long id) {
- MdmItemCategoryDO itemCategory = itemCategoryService.validateItemCategoryExists(id);
- return success(BeanUtils.toBean(itemCategory, MdmItemCategoryRespDTO.class));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/dto/MdmItemCategoryRespDTO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/dto/MdmItemCategoryRespDTO.java
deleted file mode 100644
index edc0135..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/category/dto/MdmItemCategoryRespDTO.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.category.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Schema(description = "RPC 鏈嶅姟 - MDM 鐗╂枡鍒嗙被 Response DTO")
-@Data
-public class MdmItemCategoryRespDTO {
-
- @Schema(description = "鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "鐖跺垎绫荤紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Long parentId;
-
- @Schema(description = "鍒嗙被缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "CAT001")
- private String code;
-
- @Schema(description = "鍒嗙被鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "浜旈噾閰嶄欢")
- private String name;
-
- @Schema(description = "鐗╂枡绫诲瀷", example = "1")
- private Integer itemType;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemApi.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemApi.java
deleted file mode 100644
index 597cf14..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemApi.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.item;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemCreateReqDTO;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemUpdateReqDTO;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-
-/**
- * MDM 鐗╂枡 API 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmItemApi {
-
- String PREFIX = "/rpc-api/mdm/item";
-
- /**
- * 鍒涘缓鐗╂枡
- *
- * @param createReqDTO 鍒涘缓淇℃伅
- * @return 鐗╂枡缂栧彿
- */
- CommonResult<Long> createItem(MdmItemCreateReqDTO createReqDTO);
-
- /**
- * 鏇存柊鐗╂枡
- *
- * @param updateReqDTO 鏇存柊淇℃伅
- * @return 鏄惁鎴愬姛
- */
- CommonResult<Boolean> updateItem(MdmItemUpdateReqDTO updateReqDTO);
-
- /**
- * 鑾峰彇鐗╂枡
- *
- * @param id 鐗╂枡缂栧彿
- * @return 鐗╂枡
- */
- CommonResult<MdmItemRespDTO> getItem(Long id);
-
- /**
- * 鑾峰彇鐗╂枡鍒楄〃
- *
- * @param ids 鐗╂枡缂栧彿鍒楄〃
- * @return 鐗╂枡鍒楄〃
- */
- CommonResult<List<MdmItemRespDTO>> getItemList(Collection<Long> ids);
-
- /**
- * 鑾峰彇鐗╂枡 Map
- *
- * @param ids 鐗╂枡缂栧彿鍒楄〃
- * @return 鐗╂枡 Map
- */
- default Map<Long, MdmItemRespDTO> getItemMap(Collection<Long> ids) {
- List<MdmItemRespDTO> list = getItemList(ids).getCheckedData();
- return convertMap(list, MdmItemRespDTO::getId);
- }
-
- /**
- * 鑾峰彇鐗╂枡鍒嗛〉
- *
- * @param itemType 鐗╂枡绫诲瀷
- * @param status 鐘舵��
- * @param pageNo 椤电爜
- * @param pageSize 姣忛〉鏁伴噺
- * @return 鐗╂枡鍒嗛〉
- */
- CommonResult<PageResult<MdmItemRespDTO>> getItemPage(Integer itemType, Integer status, Integer pageNo, Integer pageSize);
-
- /**
- * 鏍规嵁鐘舵�佽幏鍙栫墿鏂欏垪琛�
- *
- * @param status 鐘舵��
- * @return 鐗╂枡鍒楄〃
- */
- CommonResult<List<MdmItemRespDTO>> getItemListByStatus(Integer status);
-
- /**
- * 鏍¢獙鐗╂枡瀛樺湪
- *
- * @param id 鐗╂枡缂栧彿
- * @return 鐗╂枡
- */
- CommonResult<MdmItemRespDTO> validateItemExists(Long id);
-
- /**
- * 鏍¢獙鐗╂枡瀛樺湪涓斿惎鐢�
- *
- * @param id 鐗╂枡缂栧彿
- * @return 鐗╂枡
- */
- CommonResult<MdmItemRespDTO> validateItemExistsAndEnable(Long id);
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇鐗╂枡
- *
- * @param code 鐗╂枡缂栫爜
- * @return 鐗╂枡
- */
- CommonResult<MdmItemRespDTO> getItemByCode(String code);
-
- /**
- * 鏍规嵁鏉$爜鑾峰彇鐗╂枡
- *
- * @param barCode 鐗╂枡鏉$爜
- * @return 鐗╂枡
- */
- CommonResult<MdmItemRespDTO> getItemByBarCode(String barCode);
-
- /**
- * 鏍规嵁鍒嗙被缂栧彿缁熻鐗╂枡鏁伴噺
- *
- * @param categoryId 鍒嗙被缂栧彿
- * @return 鐗╂枡鏁伴噺
- */
- CommonResult<Long> getItemCountByCategoryId(Long categoryId);
-
- /**
- * 鏍规嵁鍗曚綅缂栧彿缁熻鐗╂枡鏁伴噺
- *
- * @param unitMeasureId 鍗曚綅缂栧彿
- * @return 鐗╂枡鏁伴噺
- */
- CommonResult<Long> getItemCountByUnitMeasureId(Long unitMeasureId);
-
- /**
- * 鏇存柊鐗╂枡鐘舵��
- *
- * @param id 鐗╂枡缂栧彿
- * @param status 鐘舵��
- * @return 鏄惁鎴愬姛
- */
- CommonResult<Boolean> updateItemStatus(Long id, Integer status);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemApiImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemApiImpl.java
deleted file mode 100644
index 9ec6300..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemApiImpl.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.item;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemCreateReqDTO;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemUpdateReqDTO;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
-import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper;
-import cn.iocoder.yudao.module.mdm.service.item.MdmItemService;
-import jakarta.annotation.Resource;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collection;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * MDM 鐗╂枡 API 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@RestController
-@RequestMapping(MdmItemApi.PREFIX)
-@Validated
-public class MdmItemApiImpl implements MdmItemApi {
-
- @Resource
- private MdmItemService itemService;
-
- @Resource
- private MdmItemMapper itemMapper;
-
- @Override
- public CommonResult<Long> createItem(MdmItemCreateReqDTO createReqDTO) {
- MdmItemSaveReqVO saveReqVO = BeanUtils.toBean(createReqDTO, MdmItemSaveReqVO.class);
- // 璁剧疆榛樿鐘舵��
- if (saveReqVO.getStatus() == null) {
- saveReqVO.setStatus(0);
- }
- return success(itemService.createItem(saveReqVO));
- }
-
- @Override
- public CommonResult<Boolean> updateItem(MdmItemUpdateReqDTO updateReqDTO) {
- MdmItemSaveReqVO saveReqVO = BeanUtils.toBean(updateReqDTO, MdmItemSaveReqVO.class);
- itemService.updateItem(saveReqVO);
- return success(true);
- }
-
- @Override
- public CommonResult<MdmItemRespDTO> getItem(Long id) {
- MdmItemDO item = itemService.getItem(id);
- return success(BeanUtils.toBean(item, MdmItemRespDTO.class));
- }
-
- @Override
- public CommonResult<List<MdmItemRespDTO>> getItemList(Collection<Long> ids) {
- List<MdmItemDO> list = itemService.getItemList(ids);
- return success(BeanUtils.toBean(list, MdmItemRespDTO.class));
- }
-
- @Override
- public CommonResult<PageResult<MdmItemRespDTO>> getItemPage(Integer itemType, Integer status, Integer pageNo, Integer pageSize) {
- MdmItemPageReqVO pageReqVO = new MdmItemPageReqVO();
- pageReqVO.setItemType(itemType);
- pageReqVO.setStatus(status);
- pageReqVO.setPageNo(pageNo);
- pageReqVO.setPageSize(pageSize);
- PageResult<MdmItemDO> pageResult = itemService.getItemPage(pageReqVO);
- return success(BeanUtils.toBean(pageResult, MdmItemRespDTO.class));
- }
-
- @Override
- public CommonResult<List<MdmItemRespDTO>> getItemListByStatus(Integer status) {
- MdmItemPageReqVO pageReqVO = new MdmItemPageReqVO();
- pageReqVO.setStatus(status);
- pageReqVO.setPageNo(1);
- pageReqVO.setPageSize(Integer.MAX_VALUE);
- PageResult<MdmItemDO> pageResult = itemService.getItemPage(pageReqVO);
- return success(BeanUtils.toBean(pageResult.getList(), MdmItemRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemRespDTO> validateItemExists(Long id) {
- MdmItemDO item = itemService.validateItemExists(id);
- return success(BeanUtils.toBean(item, MdmItemRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemRespDTO> validateItemExistsAndEnable(Long id) {
- MdmItemDO item = itemService.validateItemExistsAndEnable(id);
- return success(BeanUtils.toBean(item, MdmItemRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemRespDTO> getItemByCode(String code) {
- MdmItemDO item = itemService.getItemByCode(code);
- return success(BeanUtils.toBean(item, MdmItemRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemRespDTO> getItemByBarCode(String barCode) {
- MdmItemDO item = itemMapper.selectByBarCode(barCode);
- return success(BeanUtils.toBean(item, MdmItemRespDTO.class));
- }
-
- @Override
- public CommonResult<Long> getItemCountByCategoryId(Long categoryId) {
- return success(itemService.getItemCountByCategoryId(categoryId));
- }
-
- @Override
- public CommonResult<Long> getItemCountByUnitMeasureId(Long unitMeasureId) {
- return success(itemService.getItemCountByUnitMeasureId(unitMeasureId));
- }
-
- @Override
- public CommonResult<Boolean> updateItemStatus(Long id, Integer status) {
- itemService.updateItemStatus(id, status);
- return success(true);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemSkuApi.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemSkuApi.java
deleted file mode 100644
index d6f633e..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemSkuApi.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.item;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemSkuRespDTO;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-
-/**
- * MDM 鐗╂枡 SKU API 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmItemSkuApi {
-
- String PREFIX = "/rpc-api/mdm/item-sku";
-
- /**
- * 鑾峰彇 SKU
- *
- * @param id SKU 缂栧彿
- * @return SKU
- */
- CommonResult<MdmItemSkuRespDTO> getItemSku(Long id);
-
- /**
- * 鑾峰彇 SKU 鍒楄〃
- *
- * @param ids SKU 缂栧彿鍒楄〃
- * @return SKU 鍒楄〃
- */
- CommonResult<List<MdmItemSkuRespDTO>> getItemSkuList(Collection<Long> ids);
-
- /**
- * 鑾峰彇 SKU Map
- *
- * @param ids SKU 缂栧彿鍒楄〃
- * @return SKU Map
- */
- default Map<Long, MdmItemSkuRespDTO> getItemSkuMap(Collection<Long> ids) {
- List<MdmItemSkuRespDTO> list = getItemSkuList(ids).getCheckedData();
- return convertMap(list, MdmItemSkuRespDTO::getId);
- }
-
- /**
- * 鑾峰彇鐗╂枡鐨� SKU 鍒楄〃
- *
- * @param itemId 鐗╂枡缂栧彿
- * @return SKU 鍒楄〃
- */
- CommonResult<List<MdmItemSkuRespDTO>> getItemSkuListByItemId(Long itemId);
-
- /**
- * 鏍¢獙 SKU 瀛樺湪
- *
- * @param id SKU 缂栧彿
- * @return SKU
- */
- CommonResult<MdmItemSkuRespDTO> validateItemSkuExists(Long id);
-
- /**
- * 鏍¢獙 SKU 瀛樺湪涓斿惎鐢�
- *
- * @param id SKU 缂栧彿
- * @return SKU
- */
- CommonResult<MdmItemSkuRespDTO> validateItemSkuExistsAndEnable(Long id);
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇 SKU
- *
- * @param code SKU 缂栫爜
- * @return SKU
- */
- CommonResult<MdmItemSkuRespDTO> getItemSkuByCode(String code);
-
- /**
- * 鏍规嵁鏉$爜鑾峰彇 SKU
- *
- * @param barCode SKU 鏉$爜
- * @return SKU
- */
- CommonResult<MdmItemSkuRespDTO> getItemSkuByBarCode(String barCode);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemSkuApiImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemSkuApiImpl.java
deleted file mode 100644
index 7b0e0d9..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/MdmItemSkuApiImpl.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.item;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemSkuRespDTO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemSkuDO;
-import cn.iocoder.yudao.module.mdm.service.item.MdmItemSkuService;
-import jakarta.annotation.Resource;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collection;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * MDM 鐗╂枡 SKU API 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@RestController
-@RequestMapping(MdmItemSkuApi.PREFIX)
-@Validated
-public class MdmItemSkuApiImpl implements MdmItemSkuApi {
-
- @Resource
- private MdmItemSkuService itemSkuService;
-
- @Override
- public CommonResult<MdmItemSkuRespDTO> getItemSku(Long id) {
- MdmItemSkuDO sku = itemSkuService.getItemSku(id);
- return success(BeanUtils.toBean(sku, MdmItemSkuRespDTO.class));
- }
-
- @Override
- public CommonResult<List<MdmItemSkuRespDTO>> getItemSkuList(Collection<Long> ids) {
- List<MdmItemSkuDO> list = itemSkuService.getItemSkuList(ids);
- return success(BeanUtils.toBean(list, MdmItemSkuRespDTO.class));
- }
-
- @Override
- public CommonResult<List<MdmItemSkuRespDTO>> getItemSkuListByItemId(Long itemId) {
- List<MdmItemSkuDO> list = itemSkuService.getItemSkuListByItemId(itemId);
- return success(BeanUtils.toBean(list, MdmItemSkuRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemSkuRespDTO> validateItemSkuExists(Long id) {
- MdmItemSkuDO sku = itemSkuService.validateItemSkuExists(id);
- return success(BeanUtils.toBean(sku, MdmItemSkuRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemSkuRespDTO> validateItemSkuExistsAndEnable(Long id) {
- MdmItemSkuDO sku = itemSkuService.validateItemSkuExistsAndEnable(id);
- return success(BeanUtils.toBean(sku, MdmItemSkuRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemSkuRespDTO> getItemSkuByCode(String code) {
- MdmItemSkuDO sku = itemSkuService.getItemSkuByCode(code);
- return success(BeanUtils.toBean(sku, MdmItemSkuRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmItemSkuRespDTO> getItemSkuByBarCode(String barCode) {
- MdmItemSkuDO sku = itemSkuService.getItemSkuByBarCode(barCode);
- return success(BeanUtils.toBean(sku, MdmItemSkuRespDTO.class));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemCreateReqDTO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemCreateReqDTO.java
deleted file mode 100644
index 995cfe8..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemCreateReqDTO.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.item.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "RPC 鏈嶅姟 - MDM 鐗╂枡鍒涘缓 Request DTO")
-@Data
-public class MdmItemCreateReqDTO {
-
- @Schema(description = "鐗╂枡缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "ITEM001")
- private String code;
-
- @Schema(description = "鐗╂枡鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "铻轰笣")
- private String name;
-
- @Schema(description = "鐗╂枡鏉$爜", example = "12345678")
- private String barCode;
-
- @Schema(description = "瑙勬牸鍨嬪彿", example = "M8*20")
- private String specification;
-
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long categoryId;
-
- @Schema(description = "璁¢噺鍗曚綅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long unitMeasureId;
-
- @Schema(description = "鍝佺墝缂栧彿", example = "1")
- private Long brandId;
-
- @Schema(description = "鐗╂枡绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Integer itemType;
-
- @Schema(description = "鐘舵��", example = "0")
- private Integer status;
-
- @Schema(description = "閲囪喘浠锋牸", example = "10.00")
- private BigDecimal purchasePrice;
-
- @Schema(description = "閿�鍞环鏍�", example = "15.00")
- private BigDecimal salesPrice;
-
- @Schema(description = "鎴愭湰浠锋牸", example = "8.00")
- private BigDecimal costPrice;
-
- @Schema(description = "瀹夊叏搴撳瓨", example = "100")
- private BigDecimal safetyStock;
-
- @Schema(description = "淇濊川鏈熷ぉ鏁�", example = "365")
- private Integer expiryDay;
-
- @Schema(description = "鏄惁鎵规绠$悊", example = "false")
- private Boolean isBatchManaged;
-
- @Schema(description = "閲嶉噺(kg)", example = "0.5")
- private BigDecimal weight;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemRespDTO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemRespDTO.java
deleted file mode 100644
index 65364ca..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemRespDTO.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.item.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "RPC 鏈嶅姟 - MDM 鐗╂枡 Response DTO")
-@Data
-public class MdmItemRespDTO {
-
- @Schema(description = "鐗╂枡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "鐗╂枡缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "ITEM001")
- private String code;
-
- @Schema(description = "鐗╂枡鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "铻轰笣")
- private String name;
-
- @Schema(description = "鐗╂枡鏉$爜", example = "12345678")
- private String barCode;
-
- @Schema(description = "瑙勬牸鍨嬪彿", example = "M8*20")
- private String specification;
-
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long categoryId;
-
- @Schema(description = "璁¢噺鍗曚綅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long unitMeasureId;
-
- @Schema(description = "鍝佺墝缂栧彿", example = "1")
- private Long brandId;
-
- @Schema(description = "鐗╂枡绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Integer itemType;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "閲囪喘浠锋牸", example = "10.00")
- private BigDecimal purchasePrice;
-
- @Schema(description = "閿�鍞环鏍�", example = "15.00")
- private BigDecimal salesPrice;
-
- @Schema(description = "鎴愭湰浠锋牸", example = "8.00")
- private BigDecimal costPrice;
-
- @Schema(description = "瀹夊叏搴撳瓨", example = "100")
- private BigDecimal safetyStock;
-
- @Schema(description = "淇濊川鏈熷ぉ鏁�", example = "365")
- private Integer expiryDay;
-
- @Schema(description = "鏄惁鎵规绠$悊", example = "false")
- private Boolean isBatchManaged;
-
- @Schema(description = "鏄惁楂樺�肩墿鏂�", example = "false")
- private Boolean highValue;
-
- @Schema(description = "閲嶉噺", example = "0.5")
- private BigDecimal weight;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemSkuRespDTO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemSkuRespDTO.java
deleted file mode 100644
index 92264a4..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemSkuRespDTO.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.item.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "RPC 鏈嶅姟 - MDM 鐗╂枡 SKU Response DTO")
-@Data
-public class MdmItemSkuRespDTO {
-
- @Schema(description = "SKU 缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "鐗╂枡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long itemId;
-
- @Schema(description = "SKU 缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "SKU001")
- private String code;
-
- @Schema(description = "SKU 鍚嶇О", example = "瑙勬牸A")
- private String name;
-
- @Schema(description = "SKU 鏉$爜", example = "12345678")
- private String barCode;
-
- @Schema(description = "闀垮害锛坈m锛�", example = "10")
- private BigDecimal length;
-
- @Schema(description = "瀹藉害锛坈m锛�", example = "5")
- private BigDecimal width;
-
- @Schema(description = "楂樺害锛坈m锛�", example = "2")
- private BigDecimal height;
-
- @Schema(description = "姣涢噸锛坘g锛�", example = "0.5")
- private BigDecimal grossWeight;
-
- @Schema(description = "鍑�閲嶏紙kg锛�", example = "0.4")
- private BigDecimal netWeight;
-
- @Schema(description = "鎴愭湰浠�", example = "8.00")
- private BigDecimal costPrice;
-
- @Schema(description = "閿�鍞环", example = "15.00")
- private BigDecimal salePrice;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemUpdateReqDTO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemUpdateReqDTO.java
deleted file mode 100644
index 1f1fdf1..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/item/dto/MdmItemUpdateReqDTO.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.item.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "RPC 鏈嶅姟 - MDM 鐗╂枡鏇存柊 Request DTO")
-@Data
-public class MdmItemUpdateReqDTO {
-
- @Schema(description = "鐗╂枡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "鐗╂枡缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "ITEM001")
- private String code;
-
- @Schema(description = "鐗╂枡鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "铻轰笣")
- private String name;
-
- @Schema(description = "鐗╂枡鏉$爜", example = "12345678")
- private String barCode;
-
- @Schema(description = "瑙勬牸鍨嬪彿", example = "M8*20")
- private String specification;
-
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long categoryId;
-
- @Schema(description = "璁¢噺鍗曚綅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long unitMeasureId;
-
- @Schema(description = "鍝佺墝缂栧彿", example = "1")
- private Long brandId;
-
- @Schema(description = "鐗╂枡绫诲瀷", example = "1")
- private Integer itemType;
-
- @Schema(description = "鐘舵��", example = "0")
- private Integer status;
-
- @Schema(description = "閲囪喘浠锋牸", example = "10.00")
- private BigDecimal purchasePrice;
-
- @Schema(description = "閿�鍞环鏍�", example = "15.00")
- private BigDecimal salesPrice;
-
- @Schema(description = "鎴愭湰浠锋牸", example = "8.00")
- private BigDecimal costPrice;
-
- @Schema(description = "瀹夊叏搴撳瓨", example = "100")
- private BigDecimal safetyStock;
-
- @Schema(description = "淇濊川鏈熷ぉ鏁�", example = "365")
- private Integer expiryDay;
-
- @Schema(description = "鏄惁鎵规绠$悊", example = "false")
- private Boolean isBatchManaged;
-
- @Schema(description = "閲嶉噺(kg)", example = "0.5")
- private BigDecimal weight;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/MdmUnitMeasureApi.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/MdmUnitMeasureApi.java
deleted file mode 100644
index ab82a8a..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/MdmUnitMeasureApi.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.unit;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 璁¢噺鍗曚綅 API 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmUnitMeasureApi {
-
- String PREFIX = "/rpc-api/mdm/unit";
-
- /**
- * 鑾峰彇璁¢噺鍗曚綅
- *
- * @param id 鍗曚綅缂栧彿
- * @return 璁¢噺鍗曚綅
- */
- CommonResult<MdmUnitMeasureRespDTO> getUnitMeasure(Long id);
-
- /**
- * 鑾峰彇璁¢噺鍗曚綅鍒楄〃
- *
- * @param ids 鍗曚綅缂栧彿鍒楄〃
- * @return 璁¢噺鍗曚綅鍒楄〃
- */
- CommonResult<List<MdmUnitMeasureRespDTO>> getUnitMeasureList(Collection<Long> ids);
-
- /**
- * 鏍¢獙璁¢噺鍗曚綅瀛樺湪
- *
- * @param id 鍗曚綅缂栧彿
- * @return 璁¢噺鍗曚綅
- */
- CommonResult<MdmUnitMeasureRespDTO> validateUnitMeasureExists(Long id);
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇璁¢噺鍗曚綅
- *
- * @param code 鍗曚綅缂栫爜
- * @return 璁¢噺鍗曚綅
- */
- CommonResult<MdmUnitMeasureRespDTO> getUnitMeasureByCode(String code);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/MdmUnitMeasureApiImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/MdmUnitMeasureApiImpl.java
deleted file mode 100644
index 905db39..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/MdmUnitMeasureApiImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.unit;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
-import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService;
-import jakarta.annotation.Resource;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collection;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * MDM 璁¢噺鍗曚綅 API 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@RestController
-@RequestMapping(MdmUnitMeasureApi.PREFIX)
-@Validated
-public class MdmUnitMeasureApiImpl implements MdmUnitMeasureApi {
-
- @Resource
- private MdmUnitMeasureService unitMeasureService;
-
- @Override
- public CommonResult<MdmUnitMeasureRespDTO> getUnitMeasure(Long id) {
- MdmUnitMeasureDO unitMeasure = unitMeasureService.getUnitMeasure(id);
- return success(BeanUtils.toBean(unitMeasure, MdmUnitMeasureRespDTO.class));
- }
-
- @Override
- public CommonResult<List<MdmUnitMeasureRespDTO>> getUnitMeasureList(Collection<Long> ids) {
- List<MdmUnitMeasureDO> list = unitMeasureService.getUnitMeasureList(ids);
- return success(BeanUtils.toBean(list, MdmUnitMeasureRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmUnitMeasureRespDTO> validateUnitMeasureExists(Long id) {
- MdmUnitMeasureDO unitMeasure = unitMeasureService.validateUnitMeasureExists(id);
- return success(BeanUtils.toBean(unitMeasure, MdmUnitMeasureRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmUnitMeasureRespDTO> getUnitMeasureByCode(String code) {
- MdmUnitMeasureDO unitMeasure = unitMeasureService.getUnitMeasureByCode(code);
- return success(BeanUtils.toBean(unitMeasure, MdmUnitMeasureRespDTO.class));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/dto/MdmUnitMeasureRespDTO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/dto/MdmUnitMeasureRespDTO.java
deleted file mode 100644
index a9144f6..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/unit/dto/MdmUnitMeasureRespDTO.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.unit.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "RPC 鏈嶅姟 - MDM 璁¢噺鍗曚綅 Response DTO")
-@Data
-public class MdmUnitMeasureRespDTO {
-
- @Schema(description = "鍗曚綅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "鍗曚綅缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "PCS")
- private String code;
-
- @Schema(description = "鍗曚綅鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "涓�")
- private String name;
-
- @Schema(description = "鏄惁涓诲崟浣�", example = "true")
- private Boolean primaryFlag;
-
- @Schema(description = "涓诲崟浣嶇紪鍙�", example = "1")
- private Long primaryId;
-
- @Schema(description = "涓庝富鍗曚綅鎹㈢畻姣斾緥", example = "1.0")
- private BigDecimal changeRate;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/MdmWarehouseApi.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/MdmWarehouseApi.java
deleted file mode 100644
index d582986..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/MdmWarehouseApi.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.warehouse;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.mdm.api.warehouse.dto.MdmWarehouseRespDTO;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-
-/**
- * MDM 浠撳簱 API 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmWarehouseApi {
-
- String PREFIX = "/rpc-api/mdm/warehouse";
-
- /**
- * 鑾峰彇浠撳簱
- *
- * @param id 浠撳簱缂栧彿
- * @return 浠撳簱
- */
- CommonResult<MdmWarehouseRespDTO> getWarehouse(Long id);
-
- /**
- * 鑾峰彇浠撳簱鍒楄〃
- *
- * @param ids 浠撳簱缂栧彿鍒楄〃
- * @return 浠撳簱鍒楄〃
- */
- CommonResult<List<MdmWarehouseRespDTO>> getWarehouseList(Collection<Long> ids);
-
- /**
- * 鑾峰彇浠撳簱 Map
- *
- * @param ids 浠撳簱缂栧彿鍒楄〃
- * @return 浠撳簱 Map
- */
- default Map<Long, MdmWarehouseRespDTO> getWarehouseMap(Collection<Long> ids) {
- List<MdmWarehouseRespDTO> list = getWarehouseList(ids).getCheckedData();
- return convertMap(list, MdmWarehouseRespDTO::getId);
- }
-
- /**
- * 鏍¢獙浠撳簱瀛樺湪
- *
- * @param id 浠撳簱缂栧彿
- * @return 浠撳簱
- */
- CommonResult<MdmWarehouseRespDTO> validateWarehouseExists(Long id);
-
- /**
- * 鏍¢獙浠撳簱瀛樺湪涓斿惎鐢�
- *
- * @param id 浠撳簱缂栧彿
- * @return 浠撳簱
- */
- CommonResult<MdmWarehouseRespDTO> validateWarehouseExistsAndEnable(Long id);
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇浠撳簱
- *
- * @param code 浠撳簱缂栫爜
- * @return 浠撳簱
- */
- CommonResult<MdmWarehouseRespDTO> getWarehouseByCode(String code);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/MdmWarehouseApiImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/MdmWarehouseApiImpl.java
deleted file mode 100644
index 0e3a6a6..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/MdmWarehouseApiImpl.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.warehouse;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.api.warehouse.dto.MdmWarehouseRespDTO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.warehouse.MdmWarehouseDO;
-import cn.iocoder.yudao.module.mdm.service.warehouse.MdmWarehouseService;
-import jakarta.annotation.Resource;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collection;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * MDM 浠撳簱 API 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@RestController
-@RequestMapping(MdmWarehouseApi.PREFIX)
-@Validated
-public class MdmWarehouseApiImpl implements MdmWarehouseApi {
-
- @Resource
- private MdmWarehouseService warehouseService;
-
- @Override
- public CommonResult<MdmWarehouseRespDTO> getWarehouse(Long id) {
- MdmWarehouseDO warehouse = warehouseService.getWarehouse(id);
- return success(BeanUtils.toBean(warehouse, MdmWarehouseRespDTO.class));
- }
-
- @Override
- public CommonResult<List<MdmWarehouseRespDTO>> getWarehouseList(Collection<Long> ids) {
- List<MdmWarehouseDO> list = warehouseService.getWarehouseList(ids);
- return success(BeanUtils.toBean(list, MdmWarehouseRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmWarehouseRespDTO> validateWarehouseExists(Long id) {
- MdmWarehouseDO warehouse = warehouseService.validateWarehouseExists(id);
- return success(BeanUtils.toBean(warehouse, MdmWarehouseRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmWarehouseRespDTO> validateWarehouseExistsAndEnable(Long id) {
- MdmWarehouseDO warehouse = warehouseService.validateWarehouseExistsAndEnable(id);
- return success(BeanUtils.toBean(warehouse, MdmWarehouseRespDTO.class));
- }
-
- @Override
- public CommonResult<MdmWarehouseRespDTO> getWarehouseByCode(String code) {
- MdmWarehouseDO warehouse = warehouseService.getWarehouseByCode(code);
- return success(BeanUtils.toBean(warehouse, MdmWarehouseRespDTO.class));
- }
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/dto/MdmWarehouseRespDTO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/dto/MdmWarehouseRespDTO.java
deleted file mode 100644
index 6e13e64..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/api/warehouse/dto/MdmWarehouseRespDTO.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package cn.iocoder.yudao.module.mdm.api.warehouse.dto;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "RPC 鏈嶅姟 - MDM 浠撳簱 Response DTO")
-@Data
-public class MdmWarehouseRespDTO {
-
- @Schema(description = "浠撳簱缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "浠撳簱缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "WH001")
- private String code;
-
- @Schema(description = "浠撳簱鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍘熸枡浠�")
- private String name;
-
- @Schema(description = "浠撳簱鍦板潃", example = "涓婃捣甯傛郸涓滄柊鍖�")
- private String address;
-
- @Schema(description = "闈㈢Н锛堝钩鏂圭背锛�", example = "1000")
- private BigDecimal area;
-
- @Schema(description = "浠撳簱绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Integer type;
-
- @Schema(description = "璐熻矗浜虹敤鎴稩D", example = "1")
- private Long chargeUserId;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "鏄惁鍐荤粨", example = "false")
- private Boolean frozen;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/MdmBrandController.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/MdmBrandController.java
deleted file mode 100644
index f55edf0..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/MdmBrandController.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.brand;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mdm.controller.admin.brand.vo.MdmBrandPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.brand.vo.MdmBrandSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.brand.MdmBrandDO;
-import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "绠$悊鍚庡彴 - MDM 鍝佺墝")
-@RestController
-@RequestMapping("/mdm/brand")
-@Validated
-public class MdmBrandController {
-
- @Resource
- private MdmBrandService brandService;
-
- @PostMapping("/create")
- @Operation(summary = "鍒涘缓鍝佺墝")
- @PreAuthorize("@ss.hasPermission('mdm:brand:create')")
- public CommonResult<Long> createBrand(@Valid @RequestBody MdmBrandSaveReqVO createReqVO) {
- return success(brandService.createBrand(createReqVO));
- }
-
- @PutMapping("/update")
- @Operation(summary = "鏇存柊鍝佺墝")
- @PreAuthorize("@ss.hasPermission('mdm:brand:update')")
- public CommonResult<Boolean> updateBrand(@Valid @RequestBody MdmBrandSaveReqVO updateReqVO) {
- brandService.updateBrand(updateReqVO);
- return success(true);
- }
-
- @PutMapping("/update-status")
- @Operation(summary = "鏇存柊鍝佺墝鐘舵��")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @Parameter(name = "status", description = "鐘舵��", required = true, example = "0")
- @PreAuthorize("@ss.hasPermission('mdm:brand:update')")
- public CommonResult<Boolean> updateBrandStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) {
- brandService.updateBrandStatus(id, status);
- return success(true);
- }
-
- @DeleteMapping("/delete")
- @Operation(summary = "鍒犻櫎鍝佺墝")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('mdm:brand:delete')")
- public CommonResult<Boolean> deleteBrand(@RequestParam("id") Long id) {
- brandService.deleteBrand(id);
- return success(true);
- }
-
- @GetMapping("/get")
- @Operation(summary = "鑾峰緱鍝佺墝")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('mdm:brand:query')")
- public CommonResult<MdmBrandDO> getBrand(@RequestParam("id") Long id) {
- return success(brandService.getBrand(id));
- }
-
- @GetMapping("/page")
- @Operation(summary = "鑾峰緱鍝佺墝鍒嗛〉")
- @PreAuthorize("@ss.hasPermission('mdm:brand:query')")
- public CommonResult<PageResult<MdmBrandDO>> getBrandPage(@Valid MdmBrandPageReqVO pageReqVO) {
- return success(brandService.getBrandPage(pageReqVO));
- }
-
- @GetMapping("/list")
- @Operation(summary = "鑾峰緱鍝佺墝鍒楄〃")
- @PreAuthorize("@ss.hasPermission('mdm:brand:query')")
- public CommonResult<List<MdmBrandDO>> getBrandList() {
- return success(brandService.getBrandList(null));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/vo/MdmBrandPageReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/vo/MdmBrandPageReqVO.java
deleted file mode 100644
index 39f8b6a..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/vo/MdmBrandPageReqVO.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.brand.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 鍝佺墝鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class MdmBrandPageReqVO extends PageParam {
-
- @Schema(description = "鍝佺墝缂栫爜", example = "BRAND001")
- private String code;
-
- @Schema(description = "鍝佺墝鍚嶇О", example = "鍝佺墝A")
- private String name;
-
- @Schema(description = "鐘舵��", example = "0")
- private Integer status;
-
- @Schema(description = "鍒涘缓鏃堕棿")
- private LocalDateTime[] createTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/vo/MdmBrandSaveReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/vo/MdmBrandSaveReqVO.java
deleted file mode 100644
index 39761e2..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/brand/vo/MdmBrandSaveReqVO.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.brand.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 鍝佺墝鏂板/淇敼 Request VO")
-@Data
-public class MdmBrandSaveReqVO {
-
- @Schema(description = "鍝佺墝缂栧彿", example = "1")
- private Long id;
-
- @Schema(description = "鍝佺墝缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "BRAND001")
- private String code;
-
- @Schema(description = "鍝佺墝鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍝佺墝A")
- private String name;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/MdmItemCategoryController.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/MdmItemCategoryController.java
deleted file mode 100644
index 715ec5d..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/MdmItemCategoryController.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.category;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.category.vo.MdmItemCategoryPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.category.vo.MdmItemCategoryRespVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.category.vo.MdmItemCategorySaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
-import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "绠$悊鍚庡彴 - MDM 鐗╂枡鍒嗙被")
-@RestController
-@RequestMapping("/mdm/item-category")
-@Validated
-public class MdmItemCategoryController {
-
- @Resource
- private MdmItemCategoryService itemCategoryService;
-
- @PostMapping("/create")
- @Operation(summary = "鍒涘缓鐗╂枡鍒嗙被")
- @PreAuthorize("@ss.hasPermission('mdm:item-category:create')")
- public CommonResult<Long> createItemCategory(@Valid @RequestBody MdmItemCategorySaveReqVO createReqVO) {
- return success(itemCategoryService.createItemCategory(createReqVO));
- }
-
- @PutMapping("/update")
- @Operation(summary = "鏇存柊鐗╂枡鍒嗙被")
- @PreAuthorize("@ss.hasPermission('mdm:item-category:update')")
- public CommonResult<Boolean> updateItemCategory(@Valid @RequestBody MdmItemCategorySaveReqVO updateReqVO) {
- itemCategoryService.updateItemCategory(updateReqVO);
- return success(true);
- }
-
- @PutMapping("/update-status")
- @Operation(summary = "鏇存柊鐗╂枡鍒嗙被鐘舵��")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @Parameter(name = "status", description = "鐘舵��", required = true, example = "0")
- @PreAuthorize("@ss.hasPermission('mdm:item-category:update')")
- public CommonResult<Boolean> updateItemCategoryStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) {
- itemCategoryService.updateItemCategoryStatus(id, status);
- return success(true);
- }
-
- @DeleteMapping("/delete")
- @Operation(summary = "鍒犻櫎鐗╂枡鍒嗙被")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('mdm:item-category:delete')")
- public CommonResult<Boolean> deleteItemCategory(@RequestParam("id") Long id) {
- itemCategoryService.deleteItemCategory(id);
- return success(true);
- }
-
- @GetMapping("/get")
- @Operation(summary = "鑾峰緱鐗╂枡鍒嗙被")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('mdm:item-category:query')")
- public CommonResult<MdmItemCategoryRespVO> getItemCategory(@RequestParam("id") Long id) {
- MdmItemCategoryDO itemCategory = itemCategoryService.getItemCategory(id);
- return success(BeanUtils.toBean(itemCategory, MdmItemCategoryRespVO.class));
- }
-
- @GetMapping("/page")
- @Operation(summary = "鑾峰緱鐗╂枡鍒嗙被鍒嗛〉")
- @PreAuthorize("@ss.hasPermission('mdm:item-category:query')")
- public CommonResult<PageResult<MdmItemCategoryRespVO>> getItemCategoryPage(@Valid MdmItemCategoryPageReqVO pageReqVO) {
- PageResult<MdmItemCategoryDO> pageResult = itemCategoryService.getItemCategoryPage(pageReqVO);
- return success(BeanUtils.toBean(pageResult, MdmItemCategoryRespVO.class));
- }
-
- @GetMapping("/list")
- @Operation(summary = "鑾峰緱鐗╂枡鍒嗙被鍒楄〃")
- @PreAuthorize("@ss.hasPermission('mdm:item-category:query')")
- public CommonResult<List<MdmItemCategoryRespVO>> getItemCategoryList() {
- List<MdmItemCategoryDO> list = itemCategoryService.getItemCategoryList(null);
- return success(BeanUtils.toBean(list, MdmItemCategoryRespVO.class));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategoryPageReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategoryPageReqVO.java
deleted file mode 100644
index dcc1ede..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategoryPageReqVO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.category.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 鐗╂枡鍒嗙被鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class MdmItemCategoryPageReqVO extends PageParam {
-
- @Schema(description = "鍒嗙被缂栫爜", example = "CAT001")
- private String code;
-
- @Schema(description = "鍒嗙被鍚嶇О", example = "浜旈噾閰嶄欢")
- private String name;
-
- @Schema(description = "鐖跺垎绫荤紪鍙�", example = "0")
- private Long parentId;
-
- @Schema(description = "鐗╂枡绫诲瀷", example = "1")
- private Integer itemType;
-
- @Schema(description = "鐘舵��", example = "0")
- private Integer status;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategoryRespVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategoryRespVO.java
deleted file mode 100644
index ede6b3e..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategoryRespVO.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.category.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 鐗╂枡鍒嗙被 Response VO")
-@Data
-public class MdmItemCategoryRespVO {
-
- @Schema(description = "鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "鐖跺垎绫荤紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Long parentId;
-
- @Schema(description = "鍒嗙被缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "CAT001")
- private String code;
-
- @Schema(description = "鍒嗙被鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "浜旈噾閰嶄欢")
- private String name;
-
- @Schema(description = "鐗╂枡绫诲瀷", example = "1")
- private Integer itemType;
-
- @Schema(description = "鎺掑簭", example = "1")
- private Integer sort;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
- @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
- private LocalDateTime createTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategorySaveReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategorySaveReqVO.java
deleted file mode 100644
index 7df8691..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/category/vo/MdmItemCategorySaveReqVO.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.category.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 鐗╂枡鍒嗙被鏂板/淇敼 Request VO")
-@Data
-public class MdmItemCategorySaveReqVO {
-
- @Schema(description = "鍒嗙被缂栧彿", example = "1")
- private Long id;
-
- @Schema(description = "鐖跺垎绫荤紪鍙�", example = "0")
- private Long parentId;
-
- @Schema(description = "鍒嗙被缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "CAT001")
- private String code;
-
- @Schema(description = "鍒嗙被鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "浜旈噾閰嶄欢")
- private String name;
-
- @Schema(description = "鐗╂枡绫诲瀷", example = "1")
- private Integer itemType;
-
- @Schema(description = "鎺掑簭", example = "1")
- private Integer sort;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
deleted file mode 100644
index 736e3bd..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/MdmItemController.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.item;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemRespVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
-import cn.iocoder.yudao.module.mdm.service.item.MdmItemService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "绠$悊鍚庡彴 - MDM 鐗╂枡涓绘暟鎹�")
-@RestController
-@RequestMapping("/mdm/item")
-@Validated
-public class MdmItemController {
-
- @Resource
- private MdmItemService itemService;
-
- @PostMapping("/create")
- @Operation(summary = "鍒涘缓鐗╂枡")
- @PreAuthorize("@ss.hasPermission('mdm:item:create')")
- public CommonResult<Long> createItem(@Valid @RequestBody MdmItemSaveReqVO createReqVO) {
- return success(itemService.createItem(createReqVO));
- }
-
- @PutMapping("/update")
- @Operation(summary = "鏇存柊鐗╂枡")
- @PreAuthorize("@ss.hasPermission('mdm:item:update')")
- public CommonResult<Boolean> updateItem(@Valid @RequestBody MdmItemSaveReqVO updateReqVO) {
- itemService.updateItem(updateReqVO);
- return success(true);
- }
-
- @PutMapping("/update-status")
- @Operation(summary = "鏇存柊鐗╂枡鐘舵��")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @Parameter(name = "status", description = "鐘舵��", required = true, example = "0")
- @PreAuthorize("@ss.hasPermission('mdm:item:update')")
- public CommonResult<Boolean> updateItemStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) {
- itemService.updateItemStatus(id, status);
- return success(true);
- }
-
- @DeleteMapping("/delete")
- @Operation(summary = "鍒犻櫎鐗╂枡")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('mdm:item:delete')")
- public CommonResult<Boolean> deleteItem(@RequestParam("id") Long id) {
- itemService.deleteItem(id);
- return success(true);
- }
-
- @GetMapping("/get")
- @Operation(summary = "鑾峰緱鐗╂枡")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('mdm:item:query')")
- public CommonResult<MdmItemRespVO> getItem(@RequestParam("id") Long id) {
- MdmItemDO item = itemService.getItem(id);
- return success(BeanUtils.toBean(item, MdmItemRespVO.class));
- }
-
- @GetMapping("/page")
- @Operation(summary = "鑾峰緱鐗╂枡鍒嗛〉")
- @PreAuthorize("@ss.hasPermission('mdm:item:query')")
- public CommonResult<PageResult<MdmItemRespVO>> getItemPage(@Valid MdmItemPageReqVO pageReqVO) {
- PageResult<MdmItemDO> pageResult = itemService.getItemPage(pageReqVO);
- return success(BeanUtils.toBean(pageResult, MdmItemRespVO.class));
- }
-
- @GetMapping("/list-by-ids")
- @Operation(summary = "鑾峰緱鐗╂枡鍒楄〃")
- @Parameter(name = "ids", description = "缂栧彿鍒楄〃", required = true, example = "1,2,3")
- @PreAuthorize("@ss.hasPermission('mdm:item:query')")
- public CommonResult<List<MdmItemRespVO>> getItemList(@RequestParam("ids") List<Long> ids) {
- List<MdmItemDO> list = itemService.getItemList(ids);
- return success(BeanUtils.toBean(list, MdmItemRespVO.class));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemPageReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemPageReqVO.java
deleted file mode 100644
index 93e87b5..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemPageReqVO.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.item.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 鐗╂枡鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class MdmItemPageReqVO extends PageParam {
-
- @Schema(description = "鐗╂枡缂栫爜", example = "ITEM001")
- private String code;
-
- @Schema(description = "鐗╂枡鍚嶇О", example = "铻轰笣")
- private String name;
-
- @Schema(description = "鐗╂枡鏉$爜", example = "12345678")
- private String barCode;
-
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", example = "1")
- private Long categoryId;
-
- @Schema(description = "鐗╂枡绫诲瀷", example = "1")
- private Integer itemType;
-
- @Schema(description = "鐘舵��", example = "0")
- private Integer status;
-
- @Schema(description = "鍝佺墝缂栧彿", example = "1")
- private Long brandId;
-
- @Schema(description = "鍒涘缓鏃堕棿")
- private LocalDateTime[] createTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemRespVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemRespVO.java
deleted file mode 100644
index cc07aa9..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemRespVO.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.item.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 鐗╂枡 Response VO")
-@Data
-public class MdmItemRespVO {
-
- @Schema(description = "鐗╂枡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "鐗╂枡缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "ITEM001")
- private String code;
-
- @Schema(description = "鐗╂枡鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "铻轰笣")
- private String name;
-
- @Schema(description = "鐗╂枡鏉$爜", example = "12345678")
- private String barCode;
-
- @Schema(description = "瑙勬牸鍨嬪彿", example = "M8*20")
- private String specification;
-
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long categoryId;
-
- @Schema(description = "鐗╂枡鍒嗙被鍚嶇О", example = "浜旈噾閰嶄欢")
- private String categoryName;
-
- @Schema(description = "璁¢噺鍗曚綅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long unitMeasureId;
-
- @Schema(description = "璁¢噺鍗曚綅鍚嶇О", example = "涓�")
- private String unitMeasureName;
-
- @Schema(description = "鍝佺墝缂栧彿", example = "1")
- private Long brandId;
-
- @Schema(description = "鍝佺墝鍚嶇О", example = "鍝佺墝A")
- private String brandName;
-
- @Schema(description = "鐗╂枡绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Integer itemType;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "閲囪喘浠锋牸", example = "10.00")
- private BigDecimal purchasePrice;
-
- @Schema(description = "閿�鍞环鏍�", example = "15.00")
- private BigDecimal salesPrice;
-
- @Schema(description = "鎴愭湰浠锋牸", example = "8.00")
- private BigDecimal costPrice;
-
- @Schema(description = "瀹夊叏搴撳瓨", example = "100")
- private BigDecimal safetyStock;
-
- @Schema(description = "鏈�浣庡簱瀛�", example = "50")
- private BigDecimal minStock;
-
- @Schema(description = "鏈�楂樺簱瀛�", example = "500")
- private BigDecimal maxStock;
-
- @Schema(description = "淇濊川鏈熷ぉ鏁�", example = "365")
- private Integer expiryDays;
-
- @Schema(description = "鏄惁鎵规绠$悊", example = "false")
- private Boolean isBatchManaged;
-
- @Schema(description = "鏄惁楂樺�肩墿鏂�", example = "false")
- private Boolean isHighValue;
-
- @Schema(description = "閲嶉噺", example = "0.5")
- private BigDecimal weight;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
- @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
- private LocalDateTime createTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemSaveReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemSaveReqVO.java
deleted file mode 100644
index ede7f8c..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/item/vo/MdmItemSaveReqVO.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.item.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 鐗╂枡鏂板/淇敼 Request VO")
-@Data
-public class MdmItemSaveReqVO {
-
- @Schema(description = "鐗╂枡缂栧彿", example = "1")
- private Long id;
-
- @Schema(description = "鐗╂枡缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "ITEM001")
- private String code;
-
- @Schema(description = "鐗╂枡鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "铻轰笣")
- private String name;
-
- @Schema(description = "鐗╂枡鏉$爜", example = "12345678")
- private String barCode;
-
- @Schema(description = "瑙勬牸鍨嬪彿", example = "M8*20")
- private String specification;
-
- @Schema(description = "鐗╂枡鍒嗙被缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long categoryId;
-
- @Schema(description = "璁¢噺鍗曚綅缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long unitMeasureId;
-
- @Schema(description = "鍝佺墝缂栧彿", example = "1")
- private Long brandId;
-
- @Schema(description = "鐗╂枡绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Integer itemType;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "閲囪喘浠锋牸", example = "10.00")
- private BigDecimal purchasePrice;
-
- @Schema(description = "閿�鍞环鏍�", example = "15.00")
- private BigDecimal salesPrice;
-
- @Schema(description = "鎴愭湰浠锋牸", example = "8.00")
- private BigDecimal costPrice;
-
- @Schema(description = "瀹夊叏搴撳瓨", example = "100")
- private BigDecimal safetyStock;
-
- @Schema(description = "鏈�浣庡簱瀛�", example = "50")
- private BigDecimal minStock;
-
- @Schema(description = "鏈�楂樺簱瀛�", example = "500")
- private BigDecimal maxStock;
-
- @Schema(description = "淇濊川鏈熷ぉ鏁�", example = "365")
- private Integer expiryDay;
-
- @Schema(description = "鏄惁鎵规绠$悊", example = "false")
- private Boolean isBatchManaged;
-
- @Schema(description = "鏄惁楂樺�肩墿鏂�", example = "false")
- private Boolean isHighValue;
-
- @Schema(description = "閲嶉噺", example = "0.5")
- private BigDecimal weight;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/MdmUnitMeasureController.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/MdmUnitMeasureController.java
deleted file mode 100644
index 02335e9..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/MdmUnitMeasureController.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.unit;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.unit.vo.MdmUnitMeasurePageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.unit.vo.MdmUnitMeasureSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
-import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "绠$悊鍚庡彴 - MDM 璁¢噺鍗曚綅")
-@RestController
-@RequestMapping("/mdm/unit-measure")
-@Validated
-public class MdmUnitMeasureController {
-
- @Resource
- private MdmUnitMeasureService unitMeasureService;
-
- @PostMapping("/create")
- @Operation(summary = "鍒涘缓璁¢噺鍗曚綅")
- @PreAuthorize("@ss.hasPermission('mdm:unit-measure:create')")
- public CommonResult<Long> createUnitMeasure(@Valid @RequestBody MdmUnitMeasureSaveReqVO createReqVO) {
- return success(unitMeasureService.createUnitMeasure(createReqVO));
- }
-
- @PutMapping("/update")
- @Operation(summary = "鏇存柊璁¢噺鍗曚綅")
- @PreAuthorize("@ss.hasPermission('mdm:unit-measure:update')")
- public CommonResult<Boolean> updateUnitMeasure(@Valid @RequestBody MdmUnitMeasureSaveReqVO updateReqVO) {
- unitMeasureService.updateUnitMeasure(updateReqVO);
- return success(true);
- }
-
- @PutMapping("/update-status")
- @Operation(summary = "鏇存柊璁¢噺鍗曚綅鐘舵��")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @Parameter(name = "status", description = "鐘舵��", required = true, example = "0")
- @PreAuthorize("@ss.hasPermission('mdm:unit-measure:update')")
- public CommonResult<Boolean> updateUnitMeasureStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) {
- unitMeasureService.updateUnitMeasureStatus(id, status);
- return success(true);
- }
-
- @DeleteMapping("/delete")
- @Operation(summary = "鍒犻櫎璁¢噺鍗曚綅")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('mdm:unit-measure:delete')")
- public CommonResult<Boolean> deleteUnitMeasure(@RequestParam("id") Long id) {
- unitMeasureService.deleteUnitMeasure(id);
- return success(true);
- }
-
- @GetMapping("/get")
- @Operation(summary = "鑾峰緱璁¢噺鍗曚綅")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')")
- public CommonResult<MdmUnitMeasureDO> getUnitMeasure(@RequestParam("id") Long id) {
- return success(unitMeasureService.getUnitMeasure(id));
- }
-
- @GetMapping("/page")
- @Operation(summary = "鑾峰緱璁¢噺鍗曚綅鍒嗛〉")
- @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')")
- public CommonResult<PageResult<MdmUnitMeasureDO>> getUnitMeasurePage(@Valid MdmUnitMeasurePageReqVO pageReqVO) {
- return success(unitMeasureService.getUnitMeasurePage(pageReqVO));
- }
-
- @GetMapping("/list")
- @Operation(summary = "鑾峰緱璁¢噺鍗曚綅鍒楄〃")
- @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')")
- public CommonResult<List<MdmUnitMeasureDO>> getUnitMeasureList() {
- return success(unitMeasureService.getUnitMeasureList(null));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasurePageReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasurePageReqVO.java
deleted file mode 100644
index c7a8827..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasurePageReqVO.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.unit.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 璁¢噺鍗曚綅鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class MdmUnitMeasurePageReqVO extends PageParam {
-
- @Schema(description = "鍗曚綅缂栫爜", example = "PCS")
- private String code;
-
- @Schema(description = "鍗曚綅鍚嶇О", example = "涓�")
- private String name;
-
- @Schema(description = "鐘舵��", example = "0")
- private Integer status;
-
- @Schema(description = "鍒涘缓鏃堕棿")
- private LocalDateTime[] createTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureSaveReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureSaveReqVO.java
deleted file mode 100644
index 0d9455c..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/vo/MdmUnitMeasureSaveReqVO.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.unit.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 璁¢噺鍗曚綅鏂板/淇敼 Request VO")
-@Data
-public class MdmUnitMeasureSaveReqVO {
-
- @Schema(description = "鍗曚綅缂栧彿", example = "1")
- private Long id;
-
- @Schema(description = "鍗曚綅缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "PCS")
- private String code;
-
- @Schema(description = "鍗曚綅鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "涓�")
- private String name;
-
- @Schema(description = "鏄惁涓诲崟浣�", example = "true")
- private Boolean primaryFlag;
-
- @Schema(description = "涓诲崟浣嶇紪鍙�", example = "1")
- private Long primaryId;
-
- @Schema(description = "涓庝富鍗曚綅鎹㈢畻姣斾緥", example = "1.0")
- private BigDecimal changeRate;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/MdmWarehouseController.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/MdmWarehouseController.java
deleted file mode 100644
index 0c15cdf..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/MdmWarehouseController.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.warehouse;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.warehouse.vo.*;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.warehouse.MdmWarehouseDO;
-import cn.iocoder.yudao.module.mdm.service.warehouse.MdmWarehouseService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-@Tag(name = "绠$悊鍚庡彴 - MDM 浠撳簱")
-@RestController
-@RequestMapping("/mdm/warehouse")
-@Validated
-public class MdmWarehouseController {
-
- @Resource
- private MdmWarehouseService warehouseService;
-
- @PostMapping("/create")
- @Operation(summary = "鍒涘缓浠撳簱")
- @PreAuthorize("@ss.hasPermission('mdm:warehouse:create')")
- public CommonResult<Long> createWarehouse(@Valid @RequestBody MdmWarehouseSaveReqVO createReqVO) {
- return success(warehouseService.createWarehouse(createReqVO));
- }
-
- @PutMapping("/update")
- @Operation(summary = "鏇存柊浠撳簱")
- @PreAuthorize("@ss.hasPermission('mdm:warehouse:update')")
- public CommonResult<Boolean> updateWarehouse(@Valid @RequestBody MdmWarehouseSaveReqVO updateReqVO) {
- warehouseService.updateWarehouse(updateReqVO);
- return success(true);
- }
-
- @PutMapping("/update-status")
- @Operation(summary = "鏇存柊浠撳簱鐘舵��")
- @PreAuthorize("@ss.hasPermission('mdm:warehouse:update')")
- public CommonResult<Boolean> updateWarehouseStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) {
- warehouseService.updateWarehouseStatus(id, status);
- return success(true);
- }
-
- @DeleteMapping("/delete")
- @Operation(summary = "鍒犻櫎浠撳簱")
- @Parameter(name = "id", description = "缂栧彿", required = true)
- @PreAuthorize("@ss.hasPermission('mdm:warehouse:delete')")
- public CommonResult<Boolean> deleteWarehouse(@RequestParam("id") Long id) {
- warehouseService.deleteWarehouse(id);
- return success(true);
- }
-
- @GetMapping("/get")
- @Operation(summary = "鑾峰緱浠撳簱")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
- @PreAuthorize("@ss.hasPermission('mdm:warehouse:query')")
- public CommonResult<MdmWarehouseRespVO> getWarehouse(@RequestParam("id") Long id) {
- MdmWarehouseDO warehouse = warehouseService.getWarehouse(id);
- return success(BeanUtils.toBean(warehouse, MdmWarehouseRespVO.class));
- }
-
- @GetMapping("/page")
- @Operation(summary = "鑾峰緱浠撳簱鍒嗛〉")
- @PreAuthorize("@ss.hasPermission('mdm:warehouse:query')")
- public CommonResult<PageResult<MdmWarehouseRespVO>> getWarehousePage(@Valid MdmWarehousePageReqVO pageReqVO) {
- PageResult<MdmWarehouseDO> pageResult = warehouseService.getWarehousePage(pageReqVO);
- return success(BeanUtils.toBean(pageResult, MdmWarehouseRespVO.class));
- }
-
- @GetMapping("/list-by-ids")
- @Operation(summary = "鑾峰緱浠撳簱鍒楄〃")
- @Parameter(name = "ids", description = "缂栧彿鍒楄〃", required = true, example = "1,2,3")
- @PreAuthorize("@ss.hasPermission('mdm:warehouse:query')")
- public CommonResult<List<MdmWarehouseRespVO>> getWarehouseList(@RequestParam("ids") List<Long> ids) {
- List<MdmWarehouseDO> list = warehouseService.getWarehouseList(ids);
- return success(BeanUtils.toBean(list, MdmWarehouseRespVO.class));
- }
-
- @GetMapping("/list-all-simple")
- @Operation(summary = "鑾峰緱鍏ㄩ儴鍚敤鐨勪粨搴撳垪琛�")
- public CommonResult<List<MdmWarehouseRespVO>> getSimpleWarehouseList() {
- MdmWarehouseDO query = new MdmWarehouseDO();
- query.setStatus(0);
- List<MdmWarehouseDO> list = warehouseService.getWarehousePage(new MdmWarehousePageReqVO()).getList();
- return success(BeanUtils.toBean(list, MdmWarehouseRespVO.class));
- }
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehousePageReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehousePageReqVO.java
deleted file mode 100644
index eaa6853..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehousePageReqVO.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.warehouse.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 浠撳簱鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class MdmWarehousePageReqVO extends PageParam {
-
- @Schema(description = "浠撳簱缂栫爜", example = "WH001")
- private String code;
-
- @Schema(description = "浠撳簱鍚嶇О", example = "鎴愬搧浠撳簱")
- private String name;
-
- @Schema(description = "浠撳簱绫诲瀷", example = "1")
- private Integer type;
-
- @Schema(description = "鐘舵��", example = "0")
- private Integer status;
-
- @Schema(description = "鍒涘缓鏃堕棿")
- private LocalDateTime[] createTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehouseRespVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehouseRespVO.java
deleted file mode 100644
index a2287fe..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehouseRespVO.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.warehouse.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 浠撳簱 Response VO")
-@Data
-public class MdmWarehouseRespVO {
-
- @Schema(description = "浠撳簱缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "浠撳簱缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "WH001")
- private String code;
-
- @Schema(description = "浠撳簱鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎴愬搧浠撳簱")
- private String name;
-
- @Schema(description = "浠撳簱鍦板潃", example = "涓婃捣甯傛郸涓滄柊鍖�")
- private String address;
-
- @Schema(description = "闈㈢Н锛堝钩鏂圭背锛�", example = "1000.00")
- private BigDecimal area;
-
- @Schema(description = "浠撳簱绫诲瀷", example = "1")
- private Integer type;
-
- @Schema(description = "璐熻矗浜虹敤鎴稩D", example = "1")
- private Long chargeUserId;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "鏄惁鍐荤粨", example = "false")
- private Boolean frozen;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
- @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
- private LocalDateTime createTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehouseSaveReqVO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehouseSaveReqVO.java
deleted file mode 100644
index 3e182a0..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/warehouse/vo/MdmWarehouseSaveReqVO.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package cn.iocoder.yudao.module.mdm.controller.admin.warehouse.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-@Schema(description = "绠$悊鍚庡彴 - MDM 浠撳簱鏂板/淇敼 Request VO")
-@Data
-public class MdmWarehouseSaveReqVO {
-
- @Schema(description = "浠撳簱缂栧彿", example = "1")
- private Long id;
-
- @Schema(description = "浠撳簱缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "WH001")
- private String code;
-
- @Schema(description = "浠撳簱鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鎴愬搧浠撳簱")
- private String name;
-
- @Schema(description = "浠撳簱鍦板潃", example = "涓婃捣甯傛郸涓滄柊鍖�")
- private String address;
-
- @Schema(description = "闈㈢Н锛堝钩鏂圭背锛�", example = "1000.00")
- private BigDecimal area;
-
- @Schema(description = "浠撳簱绫诲瀷", example = "1")
- private Integer type;
-
- @Schema(description = "璐熻矗浜虹敤鎴稩D", example = "1")
- private Long chargeUserId;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "鏄惁鍐荤粨", example = "false")
- private Boolean frozen;
-
- @Schema(description = "澶囨敞", example = "澶囨敞淇℃伅")
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/brand/MdmBrandDO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/brand/MdmBrandDO.java
deleted file mode 100644
index 05ffa65..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/brand/MdmBrandDO.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.dataobject.brand;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-/**
- * MDM 鍝佺墝 DO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("md_brand")
-@KeySequence("md_brand_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MdmBrandDO extends BaseDO {
-
- /**
- * 鍝佺墝缂栧彿
- */
- @TableId
- private Long id;
-
- /**
- * 鍝佺墝缂栫爜
- */
- private String code;
-
- /**
- * 鍝佺墝鍚嶇О
- */
- private String name;
-
- /**
- * 鐘舵��
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
- */
- private Integer status;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/category/MdmItemCategoryDO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/category/MdmItemCategoryDO.java
deleted file mode 100644
index 2bce04f..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/category/MdmItemCategoryDO.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.dataobject.category;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-/**
- * MDM 鐗╂枡鍒嗙被 DO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("md_item_category")
-@KeySequence("md_item_category_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MdmItemCategoryDO extends BaseDO {
-
- /**
- * 鍒嗙被缂栧彿
- */
- @TableId
- private Long id;
-
- /**
- * 鐖跺垎绫荤紪鍙凤紙鏍硅妭鐐�=0锛�
- */
- private Long parentId;
-
- /**
- * 鍒嗙被缂栫爜
- */
- private String code;
-
- /**
- * 鍒嗙被鍚嶇О
- */
- private String name;
-
- /**
- * 閫傜敤鐗╂枡绫诲瀷
- *
- * 1: 鍘熸枡
- * 2: 鍗婃垚鍝�
- * 3: 鎴愬搧
- * 4: 杈呮枡
- * NULL: 鍏ㄩ儴
- */
- private Integer itemType;
-
- /**
- * 鎺掑簭
- */
- private Integer sort;
-
- /**
- * 鐘舵��
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
- */
- private Integer status;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemBatchConfigDO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemBatchConfigDO.java
deleted file mode 100644
index 80abad0..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemBatchConfigDO.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.dataobject.item;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-/**
- * MDM 鐗╂枡鎵规灞炴�ч厤缃� DO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("md_item_batch_config")
-@KeySequence("md_item_batch_config_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MdmItemBatchConfigDO extends BaseDO {
-
- /**
- * 缂栧彿
- */
- @TableId
- private Long id;
-
- /**
- * 鐗╂枡缂栧彿
- *
- * 鍏宠仈 {@link MdmItemDO#getId()}
- */
- private Long itemId;
-
- /**
- * 鐢熶骇鏃ユ湡
- */
- private Boolean produceDateFlag;
-
- /**
- * 鏈夋晥鏈�
- */
- private Boolean expireDateFlag;
-
- /**
- * 鍏ュ簱鏃ユ湡
- */
- private Boolean receiptDateFlag;
-
- /**
- * 渚涘簲鍟�
- */
- private Boolean vendorFlag;
-
- /**
- * 瀹㈡埛
- */
- private Boolean clientFlag;
-
- /**
- * 閿�鍞鍗曠紪鍙�
- */
- private Boolean salesOrderCodeFlag;
-
- /**
- * 閲囪喘璁㈠崟缂栧彿
- */
- private Boolean purchaseOrderCodeFlag;
-
- /**
- * 鐢熶骇宸ュ崟
- */
- private Boolean workOrderFlag;
-
- /**
- * 鐢熶骇浠诲姟
- */
- private Boolean taskFlag;
-
- /**
- * 宸ヤ綔绔�
- */
- private Boolean workstationFlag;
-
- /**
- * 宸ュ叿
- */
- private Boolean toolFlag;
-
- /**
- * 妯″叿
- */
- private Boolean moldFlag;
-
- /**
- * 鐢熶骇鎵瑰彿
- */
- private Boolean lotNumberFlag;
-
- /**
- * 璐ㄩ噺鐘舵��
- */
- private Boolean qualityStatusFlag;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemDO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemDO.java
deleted file mode 100644
index 5786294..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemDO.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.dataobject.item;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.brand.MdmBrandDO;
-import cn.iocoder.yudao.module.mdm.enums.MdmItemTypeEnum;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-import java.math.BigDecimal;
-
-/**
- * MDM 鐗╂枡涓绘暟鎹� DO
- *
- * 缁熶竴鐗╂枡鏁版嵁锛孍RP/MES/WMS 鍏辩敤
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("md_item")
-@KeySequence("md_item_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MdmItemDO extends BaseDO {
-
- /**
- * 鐗╂枡ID锛堝叏灞�鍞竴锛�
- */
- @TableId
- private Long id;
-
- /**
- * 鐗╂枡缂栫爜锛堝叏灞�鍞竴锛�
- */
- private String code;
-
- /**
- * 鐗╂枡鍚嶇О
- */
- private String name;
-
- /**
- * 鐗╂枡鏉$爜
- */
- private String barCode;
-
- /**
- * 瑙勬牸鍨嬪彿
- */
- private String specification;
-
- /**
- * 鐗╂枡鍒嗙被缂栧彿
- *
- * 鍏宠仈 {@link MdmItemCategoryDO#getId()}
- */
- private Long categoryId;
-
- /**
- * 涓昏閲忓崟浣嶇紪鍙�
- *
- * 鍏宠仈 {@link MdmUnitMeasureDO#getId()}
- */
- private Long unitMeasureId;
-
- /**
- * 鍝佺墝缂栧彿
- *
- * 鍏宠仈 {@link MdmBrandDO#getId()}
- */
- private Long brandId;
-
- /**
- * 鐗╂枡绫诲瀷
- *
- * 鏋氫妇 {@link MdmItemTypeEnum}
- * 1: 鍘熸枡
- * 2: 鍗婃垚鍝�
- * 3: 鎴愬搧
- * 4: 杈呮枡
- */
- private Integer itemType;
-
- /**
- * 鐘舵��
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
- */
- private Integer status;
-
- /**
- * 閲囪喘浠�
- */
- private BigDecimal purchasePrice;
-
- /**
- * 閿�鍞环
- */
- private BigDecimal salesPrice;
-
- /**
- * 鎴愭湰浠�
- */
- private BigDecimal costPrice;
-
- /**
- * 鏈�浣庝环
- */
- private BigDecimal minPrice;
-
- /**
- * 瀹夊叏搴撳瓨
- */
- private BigDecimal safetyStock;
-
- /**
- * 鏈�浣庡簱瀛橀噺
- */
- private BigDecimal minStock;
-
- /**
- * 鏈�楂樺簱瀛橀噺
- */
- private BigDecimal maxStock;
-
- /**
- * 鏈�灏忚璐ч噺
- */
- private BigDecimal minOrderQty;
-
- /**
- * 閲囪喘鎻愬墠鏈燂紙澶╋級
- */
- private Integer leadTime;
-
- /**
- * 鏄惁鎵规绠$悊
- */
- private Boolean isBatchManaged;
-
- /**
- * 鏄惁搴忓垪鍙风鐞�
- */
- private Boolean isSerialManaged;
-
- /**
- * 鏉$爜瑙勫垯ID
- */
- private Long barcodeRuleId;
-
- /**
- * 淇濊川鏈熷ぉ鏁�
- */
- private Integer expiryDay;
-
- /**
- * 鏄惁楂樺�肩墿鏂�
- */
- private Boolean highValue;
-
- /**
- * 閲嶉噺(kg)
- */
- private BigDecimal weight;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemSkuDO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemSkuDO.java
deleted file mode 100644
index 858d534..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/item/MdmItemSkuDO.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.dataobject.item;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-import java.math.BigDecimal;
-
-/**
- * MDM 鐗╂枡 SKU DO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("mdm_item_sku")
-@KeySequence("mdm_item_sku_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MdmItemSkuDO extends BaseDO {
-
- /**
- * SKU 缂栧彿
- */
- @TableId
- private Long id;
-
- /**
- * 鐗╂枡缂栧彿
- */
- private Long itemId;
-
- /**
- * SKU 缂栫爜
- */
- private String code;
-
- /**
- * SKU 鍚嶇О
- */
- private String name;
-
- /**
- * SKU 鏉$爜
- */
- private String barCode;
-
- /**
- * 闀垮害锛坈m锛�
- */
- private BigDecimal length;
-
- /**
- * 瀹藉害锛坈m锛�
- */
- private BigDecimal width;
-
- /**
- * 楂樺害锛坈m锛�
- */
- private BigDecimal height;
-
- /**
- * 姣涢噸锛坘g锛�
- */
- private BigDecimal grossWeight;
-
- /**
- * 鍑�閲嶏紙kg锛�
- */
- private BigDecimal netWeight;
-
- /**
- * 鎴愭湰浠�
- */
- private BigDecimal costPrice;
-
- /**
- * 閿�鍞环
- */
- private BigDecimal salePrice;
-
- /**
- * 鐘舵��
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
- */
- private Integer status;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/unit/MdmUnitMeasureDO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/unit/MdmUnitMeasureDO.java
deleted file mode 100644
index c9e68ef..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/unit/MdmUnitMeasureDO.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.dataobject.unit;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-import java.math.BigDecimal;
-
-/**
- * MDM 璁¢噺鍗曚綅 DO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("md_unit_measure")
-@KeySequence("md_unit_measure_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MdmUnitMeasureDO extends BaseDO {
-
- /**
- * 鍗曚綅缂栧彿
- */
- @TableId
- private Long id;
-
- /**
- * 鍗曚綅缂栫爜
- */
- private String code;
-
- /**
- * 鍗曚綅鍚嶇О
- */
- private String name;
-
- /**
- * 鏄惁涓诲崟浣�
- */
- private Boolean primaryFlag;
-
- /**
- * 涓诲崟浣嶇紪鍙�
- */
- private Long primaryId;
-
- /**
- * 涓庝富鍗曚綅鎹㈢畻姣斾緥
- */
- private BigDecimal changeRate;
-
- /**
- * 鐘舵��
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
- */
- private Integer status;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/warehouse/MdmWarehouseDO.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/warehouse/MdmWarehouseDO.java
deleted file mode 100644
index 3ddde34..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/dataobject/warehouse/MdmWarehouseDO.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.dataobject.warehouse;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-import java.math.BigDecimal;
-
-/**
- * MDM 浠撳簱涓绘暟鎹� DO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("md_warehouse")
-@KeySequence("md_warehouse_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class MdmWarehouseDO extends BaseDO {
-
- /**
- * 浠撳簱ID
- */
- @TableId
- private Long id;
-
- /**
- * 浠撳簱缂栫爜
- */
- private String code;
-
- /**
- * 浠撳簱鍚嶇О
- */
- private String name;
-
- /**
- * 浠撳簱鍦板潃
- */
- private String address;
-
- /**
- * 闈㈢Н锛堝钩鏂圭背锛�
- */
- private BigDecimal area;
-
- /**
- * 浠撳簱绫诲瀷
- *
- * 1: 鍘熸枡浠�
- * 2: 鎴愬搧浠�
- * 3: 鍗婃垚鍝佷粨
- * 4: 绾胯竟浠�
- */
- private Integer type;
-
- /**
- * 璐熻矗浜虹敤鎴稩D
- */
- private Long chargeUserId;
-
- /**
- * 鐘舵��
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
- */
- private Integer status;
-
- /**
- * 鏄惁鍐荤粨
- */
- private Boolean frozen;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/brand/MdmBrandMapper.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/brand/MdmBrandMapper.java
deleted file mode 100644
index 0b4e107..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/brand/MdmBrandMapper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.mysql.brand;
-
-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.module.mdm.controller.admin.brand.vo.MdmBrandPageReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.brand.MdmBrandDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 鍝佺墝 Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface MdmBrandMapper extends BaseMapperX<MdmBrandDO> {
-
- default PageResult<MdmBrandDO> selectPage(MdmBrandPageReqVO reqVO) {
- return selectPage(reqVO, new LambdaQueryWrapperX<MdmBrandDO>()
- .likeIfPresent(MdmBrandDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmBrandDO::getName, reqVO.getName())
- .eqIfPresent(MdmBrandDO::getStatus, reqVO.getStatus())
- .betweenIfPresent(MdmBrandDO::getCreateTime, reqVO.getCreateTime())
- .orderByDesc(MdmBrandDO::getId));
- }
-
- default List<MdmBrandDO> selectList(MdmBrandDO reqVO) {
- return selectList(new LambdaQueryWrapperX<MdmBrandDO>()
- .likeIfPresent(MdmBrandDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmBrandDO::getName, reqVO.getName())
- .eqIfPresent(MdmBrandDO::getStatus, reqVO.getStatus())
- .orderByDesc(MdmBrandDO::getId));
- }
-
- default MdmBrandDO selectByCode(String code) {
- return selectOne(MdmBrandDO::getCode, code);
- }
-
- default MdmBrandDO selectByName(String name) {
- return selectOne(MdmBrandDO::getName, name);
- }
-
- default List<MdmBrandDO> selectListByIds(Collection<Long> ids) {
- return selectList(MdmBrandDO::getId, ids);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/category/MdmItemCategoryMapper.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/category/MdmItemCategoryMapper.java
deleted file mode 100644
index 0678ec4..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/category/MdmItemCategoryMapper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.mysql.category;
-
-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.module.mdm.controller.admin.category.vo.MdmItemCategoryPageReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 鐗╂枡鍒嗙被 Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface MdmItemCategoryMapper extends BaseMapperX<MdmItemCategoryDO> {
-
- default PageResult<MdmItemCategoryDO> selectPage(MdmItemCategoryPageReqVO reqVO) {
- return selectPage(reqVO, new LambdaQueryWrapperX<MdmItemCategoryDO>()
- .likeIfPresent(MdmItemCategoryDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmItemCategoryDO::getName, reqVO.getName())
- .eqIfPresent(MdmItemCategoryDO::getParentId, reqVO.getParentId())
- .eqIfPresent(MdmItemCategoryDO::getItemType, reqVO.getItemType())
- .eqIfPresent(MdmItemCategoryDO::getStatus, reqVO.getStatus())
- .orderByAsc(MdmItemCategoryDO::getSort));
- }
-
- default List<MdmItemCategoryDO> selectList(MdmItemCategoryDO reqVO) {
- return selectList(new LambdaQueryWrapperX<MdmItemCategoryDO>()
- .likeIfPresent(MdmItemCategoryDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmItemCategoryDO::getName, reqVO.getName())
- .eqIfPresent(MdmItemCategoryDO::getParentId, reqVO.getParentId())
- .eqIfPresent(MdmItemCategoryDO::getItemType, reqVO.getItemType())
- .eqIfPresent(MdmItemCategoryDO::getStatus, reqVO.getStatus())
- .orderByAsc(MdmItemCategoryDO::getSort));
- }
-
- default MdmItemCategoryDO selectByCode(String code) {
- return selectOne(MdmItemCategoryDO::getCode, code);
- }
-
- default MdmItemCategoryDO selectByParentIdAndName(Long parentId, String name) {
- return selectOne(new LambdaQueryWrapperX<MdmItemCategoryDO>()
- .eq(MdmItemCategoryDO::getParentId, parentId)
- .eq(MdmItemCategoryDO::getName, name));
- }
-
- default List<MdmItemCategoryDO> selectListByParentId(Long parentId) {
- return selectList(MdmItemCategoryDO::getParentId, parentId);
- }
-
- default Long selectCountByParentId(Long parentId) {
- return selectCount(MdmItemCategoryDO::getParentId, parentId);
- }
-
- default List<MdmItemCategoryDO> selectListByIds(Collection<Long> ids) {
- return selectList(MdmItemCategoryDO::getId, ids);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemBatchConfigMapper.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemBatchConfigMapper.java
deleted file mode 100644
index 944e428..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemBatchConfigMapper.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.mysql.item;
-
-import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemBatchConfigDO;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * MDM 鐗╂枡鎵规灞炴�ч厤缃� Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface MdmItemBatchConfigMapper extends BaseMapperX<MdmItemBatchConfigDO> {
-
- default MdmItemBatchConfigDO selectByItemId(Long itemId) {
- return selectOne(MdmItemBatchConfigDO::getItemId, itemId);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemMapper.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemMapper.java
deleted file mode 100644
index 0ab2d68..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemMapper.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.mysql.item;
-
-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.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 鐗╂枡涓绘暟鎹� Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface MdmItemMapper extends BaseMapperX<MdmItemDO> {
-
- default PageResult<MdmItemDO> selectPage(MdmItemPageReqVO reqVO, Collection<Long> categoryIds) {
- return selectPage(reqVO, new LambdaQueryWrapperX<MdmItemDO>()
- .likeIfPresent(MdmItemDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmItemDO::getName, reqVO.getName())
- .likeIfPresent(MdmItemDO::getBarCode, reqVO.getBarCode())
- .inIfPresent(MdmItemDO::getCategoryId, categoryIds)
- .eqIfPresent(MdmItemDO::getItemType, reqVO.getItemType())
- .eqIfPresent(MdmItemDO::getBrandId, reqVO.getBrandId())
- .eqIfPresent(MdmItemDO::getStatus, reqVO.getStatus())
- .betweenIfPresent(MdmItemDO::getCreateTime, reqVO.getCreateTime())
- .orderByDesc(MdmItemDO::getId));
- }
-
- default List<MdmItemDO> selectList(MdmItemPageReqVO reqVO, Collection<Long> categoryIds) {
- return selectList(new LambdaQueryWrapperX<MdmItemDO>()
- .likeIfPresent(MdmItemDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmItemDO::getName, reqVO.getName())
- .inIfPresent(MdmItemDO::getCategoryId, categoryIds)
- .eqIfPresent(MdmItemDO::getItemType, reqVO.getItemType())
- .eqIfPresent(MdmItemDO::getStatus, reqVO.getStatus())
- .orderByDesc(MdmItemDO::getId));
- }
-
- default MdmItemDO selectByCode(String code) {
- return selectOne(MdmItemDO::getCode, code);
- }
-
- default MdmItemDO selectByBarCode(String barCode) {
- return selectOne(MdmItemDO::getBarCode, barCode);
- }
-
- default Long selectCountByCategoryId(Long categoryId) {
- return selectCount(MdmItemDO::getCategoryId, categoryId);
- }
-
- default Long selectCountByUnitMeasureId(Long unitMeasureId) {
- return selectCount(MdmItemDO::getUnitMeasureId, unitMeasureId);
- }
-
- default Long selectCountByBrandId(Long brandId) {
- return selectCount(MdmItemDO::getBrandId, brandId);
- }
-
- default List<MdmItemDO> selectListByIds(Collection<Long> ids) {
- return selectList(MdmItemDO::getId, ids);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemSkuMapper.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemSkuMapper.java
deleted file mode 100644
index 422d31e..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/item/MdmItemSkuMapper.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.mysql.item;
-
-import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemSkuDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 鐗╂枡 SKU Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface MdmItemSkuMapper extends BaseMapperX<MdmItemSkuDO> {
-
- default MdmItemSkuDO selectByCode(String code) {
- return selectOne(MdmItemSkuDO::getCode, code);
- }
-
- default MdmItemSkuDO selectByBarCode(String barCode) {
- return selectOne(MdmItemSkuDO::getBarCode, barCode);
- }
-
- default List<MdmItemSkuDO> selectListByItemId(Long itemId) {
- return selectList(new LambdaQueryWrapperX<MdmItemSkuDO>()
- .eq(MdmItemSkuDO::getItemId, itemId)
- .orderByAsc(MdmItemSkuDO::getId));
- }
-
- default List<MdmItemSkuDO> selectListByItemIds(Collection<Long> itemIds) {
- return selectList(MdmItemSkuDO::getItemId, itemIds);
- }
-
- default int deleteByItemId(Long itemId) {
- return delete(MdmItemSkuDO::getItemId, itemId);
- }
-
- default long selectCountByItemId(Long itemId) {
- return selectCount(MdmItemSkuDO::getItemId, itemId);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/unit/MdmUnitMeasureMapper.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/unit/MdmUnitMeasureMapper.java
deleted file mode 100644
index e9ad95b..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/unit/MdmUnitMeasureMapper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.mysql.unit;
-
-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.module.mdm.controller.admin.unit.vo.MdmUnitMeasurePageReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 璁¢噺鍗曚綅 Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface MdmUnitMeasureMapper extends BaseMapperX<MdmUnitMeasureDO> {
-
- default PageResult<MdmUnitMeasureDO> selectPage(MdmUnitMeasurePageReqVO reqVO) {
- return selectPage(reqVO, new LambdaQueryWrapperX<MdmUnitMeasureDO>()
- .likeIfPresent(MdmUnitMeasureDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmUnitMeasureDO::getName, reqVO.getName())
- .eqIfPresent(MdmUnitMeasureDO::getStatus, reqVO.getStatus())
- .betweenIfPresent(MdmUnitMeasureDO::getCreateTime, reqVO.getCreateTime())
- .orderByDesc(MdmUnitMeasureDO::getId));
- }
-
- default List<MdmUnitMeasureDO> selectList(MdmUnitMeasureDO reqVO) {
- return selectList(new LambdaQueryWrapperX<MdmUnitMeasureDO>()
- .likeIfPresent(MdmUnitMeasureDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmUnitMeasureDO::getName, reqVO.getName())
- .eqIfPresent(MdmUnitMeasureDO::getStatus, reqVO.getStatus())
- .orderByDesc(MdmUnitMeasureDO::getId));
- }
-
- default MdmUnitMeasureDO selectByCode(String code) {
- return selectOne(MdmUnitMeasureDO::getCode, code);
- }
-
- default MdmUnitMeasureDO selectByName(String name) {
- return selectOne(MdmUnitMeasureDO::getName, name);
- }
-
- default List<MdmUnitMeasureDO> selectListByIds(Collection<Long> ids) {
- return selectList(MdmUnitMeasureDO::getId, ids);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/warehouse/MdmWarehouseMapper.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/warehouse/MdmWarehouseMapper.java
deleted file mode 100644
index 7356d88..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/dal/mysql/warehouse/MdmWarehouseMapper.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package cn.iocoder.yudao.module.mdm.dal.mysql.warehouse;
-
-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.module.mdm.controller.admin.warehouse.vo.MdmWarehousePageReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.warehouse.MdmWarehouseDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 浠撳簱 Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface MdmWarehouseMapper extends BaseMapperX<MdmWarehouseDO> {
-
- default PageResult<MdmWarehouseDO> selectPage(MdmWarehousePageReqVO reqVO) {
- return selectPage(reqVO, new LambdaQueryWrapperX<MdmWarehouseDO>()
- .likeIfPresent(MdmWarehouseDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmWarehouseDO::getName, reqVO.getName())
- .eqIfPresent(MdmWarehouseDO::getType, reqVO.getType())
- .eqIfPresent(MdmWarehouseDO::getStatus, reqVO.getStatus())
- .betweenIfPresent(MdmWarehouseDO::getCreateTime, reqVO.getCreateTime())
- .orderByDesc(MdmWarehouseDO::getId));
- }
-
- default List<MdmWarehouseDO> selectList(MdmWarehouseDO reqVO) {
- return selectList(new LambdaQueryWrapperX<MdmWarehouseDO>()
- .likeIfPresent(MdmWarehouseDO::getCode, reqVO.getCode())
- .likeIfPresent(MdmWarehouseDO::getName, reqVO.getName())
- .eqIfPresent(MdmWarehouseDO::getType, reqVO.getType())
- .eqIfPresent(MdmWarehouseDO::getStatus, reqVO.getStatus())
- .orderByDesc(MdmWarehouseDO::getId));
- }
-
- default MdmWarehouseDO selectByCode(String code) {
- return selectOne(MdmWarehouseDO::getCode, code);
- }
-
- default MdmWarehouseDO selectByName(String name) {
- return selectOne(MdmWarehouseDO::getName, name);
- }
-
- default List<MdmWarehouseDO> selectListByIds(Collection<Long> ids) {
- return selectList(MdmWarehouseDO::getId, ids);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/enums/ErrorCodeConstants.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/enums/ErrorCodeConstants.java
deleted file mode 100644
index 8186e50..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/enums/ErrorCodeConstants.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package cn.iocoder.yudao.module.mdm.enums;
-
-import cn.iocoder.yudao.framework.common.exception.ErrorCode;
-
-/**
- * MDM 閿欒鐮佹灇涓剧被
- *
- * mdm 妯″潡锛屼娇鐢� 1-050-000 娈�
- */
-public interface ErrorCodeConstants {
-
- // ========== 鐗╂枡鐩稿叧 1-050-001 ~ 1-050-050 ==========
- ErrorCode MDM_ITEM_NOT_EXISTS = new ErrorCode(1_050_001, "鐗╂枡涓嶅瓨鍦�");
- ErrorCode MDM_ITEM_IS_DISABLE = new ErrorCode(1_050_002, "鐗╂枡宸茬鐢�");
- ErrorCode MDM_ITEM_CODE_DUPLICATE = new ErrorCode(1_050_003, "鐗╂枡缂栫爜宸插瓨鍦�");
- ErrorCode MDM_ITEM_SKU_NOT_EXISTS = new ErrorCode(1_050_004, "鐗╂枡SKU涓嶅瓨鍦�");
- ErrorCode MDM_ITEM_SKU_IS_DISABLE = new ErrorCode(1_050_005, "鐗╂枡SKU宸茬鐢�");
- ErrorCode MDM_ITEM_SKU_CODE_DUPLICATE = new ErrorCode(1_050_006, "SKU缂栫爜宸插瓨鍦�");
-
- // ========== 鐗╂枡鍒嗙被鐩稿叧 1-050-051 ~ 1-050-100 ==========
- ErrorCode MDM_ITEM_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_051, "鐗╂枡鍒嗙被涓嶅瓨鍦�");
- ErrorCode MDM_ITEM_CATEGORY_CODE_DUPLICATE = new ErrorCode(1_050_052, "鐗╂枡鍒嗙被缂栫爜宸插瓨鍦�");
- ErrorCode MDM_ITEM_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_050_053, "鐗╂枡鍒嗙被鍚嶇О宸插瓨鍦�");
- ErrorCode MDM_ITEM_CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_050_054, "鐖跺垎绫讳笉瀛樺湪");
- ErrorCode MDM_ITEM_CATEGORY_EXISTS_CHILDREN = new ErrorCode(1_050_055, "瀛樺湪瀛愬垎绫伙紝鏃犳硶鍒犻櫎");
- ErrorCode MDM_ITEM_CATEGORY_EXISTS_ITEM = new ErrorCode(1_050_056, "鍒嗙被涓嬪瓨鍦ㄧ墿鏂欙紝鏃犳硶鍒犻櫎");
-
- // ========== 璁¢噺鍗曚綅鐩稿叧 1-050-101 ~ 1-050-150 ==========
- ErrorCode MDM_UNIT_MEASURE_NOT_EXISTS = new ErrorCode(1_050_101, "璁¢噺鍗曚綅涓嶅瓨鍦�");
- ErrorCode MDM_UNIT_MEASURE_CODE_DUPLICATE = new ErrorCode(1_050_102, "璁¢噺鍗曚綅缂栫爜宸插瓨鍦�");
- ErrorCode MDM_UNIT_MEASURE_NAME_DUPLICATE = new ErrorCode(1_050_103, "璁¢噺鍗曚綅鍚嶇О宸插瓨鍦�");
- ErrorCode MDM_UNIT_MEASURE_EXISTS_ITEM = new ErrorCode(1_050_104, "璁¢噺鍗曚綅琚墿鏂欎娇鐢紝鏃犳硶鍒犻櫎");
-
- // ========== 鍝佺墝鐩稿叧 1-050-151 ~ 1-050-200 ==========
- ErrorCode MDM_BRAND_NOT_EXISTS = new ErrorCode(1_050_151, "鍝佺墝涓嶅瓨鍦�");
- ErrorCode MDM_BRAND_CODE_DUPLICATE = new ErrorCode(1_050_152, "鍝佺墝缂栫爜宸插瓨鍦�");
- ErrorCode MDM_BRAND_NAME_DUPLICATE = new ErrorCode(1_050_153, "鍝佺墝鍚嶇О宸插瓨鍦�");
- ErrorCode MDM_BRAND_EXISTS_ITEM = new ErrorCode(1_050_154, "鍝佺墝琚墿鏂欎娇鐢紝鏃犳硶鍒犻櫎");
-
- // ========== 浠撳簱鐩稿叧 1-050-201 ~ 1-050-250 ==========
- ErrorCode MDM_WAREHOUSE_NOT_EXISTS = new ErrorCode(1_050_201, "浠撳簱涓嶅瓨鍦�");
- ErrorCode MDM_WAREHOUSE_CODE_DUPLICATE = new ErrorCode(1_050_202, "浠撳簱缂栫爜宸插瓨鍦�");
- ErrorCode MDM_WAREHOUSE_NAME_DUPLICATE = new ErrorCode(1_050_203, "浠撳簱鍚嶇О宸插瓨鍦�");
- ErrorCode MDM_WAREHOUSE_IS_DISABLE = new ErrorCode(1_050_204, "浠撳簱宸茬鐢�");
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/enums/MdmItemTypeEnum.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/enums/MdmItemTypeEnum.java
deleted file mode 100644
index ce4eebf..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/enums/MdmItemTypeEnum.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package cn.iocoder.yudao.module.mdm.enums;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * MDM 鐗╂枡绫诲瀷鏋氫妇
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Getter
-@AllArgsConstructor
-public enum MdmItemTypeEnum {
-
- RAW_MATERIAL(1, "鍘熸枡"),
- SEMI_FINISHED(2, "鍗婃垚鍝�"),
- FINISHED(3, "鎴愬搧"),
- AUXILIARY(4, "杈呮枡");
-
- /**
- * 绫诲瀷缂栫爜
- */
- private final Integer type;
-
- /**
- * 绫诲瀷鍚嶇О
- */
- private final String name;
-
- /**
- * 鏍规嵁绫诲瀷缂栫爜鑾峰彇鏋氫妇
- */
- public static MdmItemTypeEnum fromType(Integer type) {
- for (MdmItemTypeEnum value : values()) {
- if (value.getType().equals(type)) {
- return value;
- }
- }
- return null;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/brand/MdmBrandService.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/brand/MdmBrandService.java
deleted file mode 100644
index 66e35dc..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/brand/MdmBrandService.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.brand;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mdm.controller.admin.brand.vo.MdmBrandPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.brand.vo.MdmBrandSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.brand.MdmBrandDO;
-import jakarta.validation.Valid;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-
-/**
- * MDM 鍝佺墝 Service 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmBrandService {
-
- /**
- * 鍒涘缓鍝佺墝
- *
- * @param createReqVO 鍒涘缓淇℃伅
- * @return 缂栧彿
- */
- Long createBrand(@Valid MdmBrandSaveReqVO createReqVO);
-
- /**
- * 鏇存柊鍝佺墝
- *
- * @param updateReqVO 鏇存柊淇℃伅
- */
- void updateBrand(@Valid MdmBrandSaveReqVO updateReqVO);
-
- /**
- * 鏇存柊鍝佺墝鐘舵��
- *
- * @param id 缂栧彿
- * @param status 鐘舵��
- */
- void updateBrandStatus(Long id, Integer status);
-
- /**
- * 鍒犻櫎鍝佺墝
- *
- * @param id 缂栧彿
- */
- void deleteBrand(Long id);
-
- /**
- * 鑾峰緱鍝佺墝
- *
- * @param id 缂栧彿
- * @return 鍝佺墝
- */
- MdmBrandDO getBrand(Long id);
-
- /**
- * 鏍¢獙鍝佺墝瀛樺湪
- *
- * @param id 缂栧彿
- * @return 鍝佺墝
- */
- MdmBrandDO validateBrandExists(Long id);
-
- /**
- * 鑾峰緱鍝佺墝鍒嗛〉
- *
- * @param pageReqVO 鍒嗛〉鏌ヨ
- * @return 鍝佺墝鍒嗛〉
- */
- PageResult<MdmBrandDO> getBrandPage(MdmBrandPageReqVO pageReqVO);
-
- /**
- * 鑾峰緱鍝佺墝鍒楄〃
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 鍝佺墝鍒楄〃
- */
- List<MdmBrandDO> getBrandList(Collection<Long> ids);
-
- /**
- * 鑾峰緱鍝佺墝 Map
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 鍝佺墝 Map
- */
- default Map<Long, MdmBrandDO> getBrandMap(Collection<Long> ids) {
- return convertMap(getBrandList(ids), MdmBrandDO::getId);
- }
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇鍝佺墝
- *
- * @param code 鍝佺墝缂栫爜
- * @return 鍝佺墝
- */
- MdmBrandDO getBrandByCode(String code);
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/brand/MdmBrandServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/brand/MdmBrandServiceImpl.java
deleted file mode 100644
index a53e69c..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/brand/MdmBrandServiceImpl.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.brand;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.brand.vo.MdmBrandPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.brand.vo.MdmBrandSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.brand.MdmBrandDO;
-import cn.iocoder.yudao.module.mdm.dal.mysql.brand.MdmBrandMapper;
-import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.*;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
-
-/**
- * MDM 鍝佺墝 Service 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Service
-@Validated
-public class MdmBrandServiceImpl implements MdmBrandService {
-
- @Resource
- private MdmBrandMapper brandMapper;
-
- @Resource
- private MdmItemMapper itemMapper;
-
- @Override
- public Long createBrand(MdmBrandSaveReqVO createReqVO) {
- // 鏍¢獙鏁版嵁
- validateBrandSaveData(createReqVO);
-
- // 鎻掑叆
- MdmBrandDO brand = BeanUtils.toBean(createReqVO, MdmBrandDO.class);
- brandMapper.insert(brand);
- return brand.getId();
- }
-
- @Override
- public void updateBrand(MdmBrandSaveReqVO updateReqVO) {
- // 鏍¢獙瀛樺湪
- validateBrandExists(updateReqVO.getId());
- // 鏍¢獙鏁版嵁
- validateBrandSaveData(updateReqVO);
-
- // 鏇存柊
- MdmBrandDO updateObj = BeanUtils.toBean(updateReqVO, MdmBrandDO.class);
- brandMapper.updateById(updateObj);
- }
-
- @Override
- public void updateBrandStatus(Long id, Integer status) {
- // 鏍¢獙瀛樺湪
- validateBrandExists(id);
- // 鏇存柊鐘舵��
- brandMapper.updateById(new MdmBrandDO().setId(id).setStatus(status));
- }
-
- @Override
- public void deleteBrand(Long id) {
- // 鏍¢獙瀛樺湪
- validateBrandExists(id);
- // 鏍¢獙鏄惁琚墿鏂欎娇鐢紙鐩存帴浣跨敤 Mapper 閬垮厤寰幆渚濊禆锛�
- if (itemMapper.selectCountByBrandId(id) > 0) {
- throw exception(MDM_BRAND_EXISTS_ITEM);
- }
- // 鍒犻櫎
- brandMapper.deleteById(id);
- }
-
- @Override
- public MdmBrandDO validateBrandExists(Long id) {
- MdmBrandDO brand = brandMapper.selectById(id);
- if (brand == null) {
- throw exception(MDM_BRAND_NOT_EXISTS);
- }
- return brand;
- }
-
- private void validateBrandSaveData(MdmBrandSaveReqVO reqVO) {
- // 鏍¢獙缂栫爜鍞竴
- MdmBrandDO brand = brandMapper.selectByCode(reqVO.getCode());
- if (brand != null && ObjUtil.notEqual(brand.getId(), reqVO.getId())) {
- throw exception(MDM_BRAND_CODE_DUPLICATE);
- }
- // 鏍¢獙鍚嶇О鍞竴
- MdmBrandDO sameName = brandMapper.selectByName(reqVO.getName());
- if (sameName != null && ObjUtil.notEqual(sameName.getId(), reqVO.getId())) {
- throw exception(MDM_BRAND_NAME_DUPLICATE);
- }
- }
-
- @Override
- public MdmBrandDO getBrand(Long id) {
- return brandMapper.selectById(id);
- }
-
- @Override
- public PageResult<MdmBrandDO> getBrandPage(MdmBrandPageReqVO pageReqVO) {
- return brandMapper.selectPage(pageReqVO);
- }
-
- @Override
- public List<MdmBrandDO> getBrandList(Collection<Long> ids) {
- if (CollUtil.isEmpty(ids)) {
- return Collections.emptyList();
- }
- return brandMapper.selectBatchIds(ids);
- }
-
- @Override
- public MdmBrandDO getBrandByCode(String code) {
- return brandMapper.selectByCode(code);
- }
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/category/MdmItemCategoryService.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/category/MdmItemCategoryService.java
deleted file mode 100644
index 6aa972d..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/category/MdmItemCategoryService.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.category;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mdm.controller.admin.category.vo.MdmItemCategoryPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.category.vo.MdmItemCategorySaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
-import jakarta.validation.Valid;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-
-/**
- * MDM 鐗╂枡鍒嗙被 Service 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmItemCategoryService {
-
- /**
- * 鍒涘缓鐗╂枡鍒嗙被
- *
- * @param createReqVO 鍒涘缓淇℃伅
- * @return 缂栧彿
- */
- Long createItemCategory(@Valid MdmItemCategorySaveReqVO createReqVO);
-
- /**
- * 鏇存柊鐗╂枡鍒嗙被
- *
- * @param updateReqVO 鏇存柊淇℃伅
- */
- void updateItemCategory(@Valid MdmItemCategorySaveReqVO updateReqVO);
-
- /**
- * 鏇存柊鐗╂枡鍒嗙被鐘舵��
- *
- * @param id 缂栧彿
- * @param status 鐘舵��
- */
- void updateItemCategoryStatus(Long id, Integer status);
-
- /**
- * 鍒犻櫎鐗╂枡鍒嗙被
- *
- * @param id 缂栧彿
- */
- void deleteItemCategory(Long id);
-
- /**
- * 鑾峰緱鐗╂枡鍒嗙被
- *
- * @param id 缂栧彿
- * @return 鐗╂枡鍒嗙被
- */
- MdmItemCategoryDO getItemCategory(Long id);
-
- /**
- * 鏍¢獙鐗╂枡鍒嗙被瀛樺湪
- *
- * @param id 缂栧彿
- * @return 鐗╂枡鍒嗙被
- */
- MdmItemCategoryDO validateItemCategoryExists(Long id);
-
- /**
- * 鑾峰緱鐗╂枡鍒嗙被鍒嗛〉
- *
- * @param pageReqVO 鍒嗛〉鏌ヨ
- * @return 鐗╂枡鍒嗙被鍒嗛〉
- */
- PageResult<MdmItemCategoryDO> getItemCategoryPage(MdmItemCategoryPageReqVO pageReqVO);
-
- /**
- * 鑾峰緱鐗╂枡鍒嗙被鍒楄〃
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 鐗╂枡鍒嗙被鍒楄〃
- */
- List<MdmItemCategoryDO> getItemCategoryList(Collection<Long> ids);
-
- /**
- * 鑾峰緱鐗╂枡鍒嗙被 Map
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 鐗╂枡鍒嗙被 Map
- */
- default Map<Long, MdmItemCategoryDO> getItemCategoryMap(Collection<Long> ids) {
- return convertMap(getItemCategoryList(ids), MdmItemCategoryDO::getId);
- }
-
- /**
- * 鑾峰緱鎸囧畾鍒嗙被鐨勫瓙鍒嗙被鍒楄〃锛堝寘鍚嚜宸憋級
- *
- * @param id 鍒嗙被缂栧彿
- * @return 瀛愬垎绫诲垪琛�
- */
- List<MdmItemCategoryDO> getItemCategoryChildrenList(Long id);
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/category/MdmItemCategoryServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/category/MdmItemCategoryServiceImpl.java
deleted file mode 100644
index 5565f94..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/category/MdmItemCategoryServiceImpl.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.category;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.category.vo.MdmItemCategoryPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.category.vo.MdmItemCategorySaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO;
-import cn.iocoder.yudao.module.mdm.dal.mysql.category.MdmItemCategoryMapper;
-import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.*;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
-
-/**
- * MDM 鐗╂枡鍒嗙被 Service 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Service
-@Validated
-public class MdmItemCategoryServiceImpl implements MdmItemCategoryService {
-
- @Resource
- private MdmItemCategoryMapper itemCategoryMapper;
-
- @Resource
- private MdmItemMapper itemMapper;
-
- @Override
- public Long createItemCategory(MdmItemCategorySaveReqVO createReqVO) {
- // 鏍¢獙鏁版嵁
- validateItemCategorySaveData(createReqVO);
-
- // 鎻掑叆
- MdmItemCategoryDO itemCategory = BeanUtils.toBean(createReqVO, MdmItemCategoryDO.class);
- itemCategoryMapper.insert(itemCategory);
- return itemCategory.getId();
- }
-
- @Override
- public void updateItemCategory(MdmItemCategorySaveReqVO updateReqVO) {
- // 鏍¢獙瀛樺湪
- validateItemCategoryExists(updateReqVO.getId());
- // 鏍¢獙鏁版嵁
- validateItemCategorySaveData(updateReqVO);
-
- // 鏇存柊
- MdmItemCategoryDO updateObj = BeanUtils.toBean(updateReqVO, MdmItemCategoryDO.class);
- itemCategoryMapper.updateById(updateObj);
- }
-
- @Override
- public void updateItemCategoryStatus(Long id, Integer status) {
- // 鏍¢獙瀛樺湪
- validateItemCategoryExists(id);
- // 鏇存柊鐘舵��
- itemCategoryMapper.updateById(new MdmItemCategoryDO().setId(id).setStatus(status));
- }
-
- @Override
- public void deleteItemCategory(Long id) {
- // 鏍¢獙瀛樺湪
- validateItemCategoryExists(id);
- // 鏍¢獙鏄惁鏈夊瓙鍒嗙被
- if (itemCategoryMapper.selectCountByParentId(id) > 0) {
- throw exception(MDM_ITEM_CATEGORY_EXISTS_CHILDREN);
- }
- // 鏍¢獙鍒嗙被涓嬫槸鍚︽湁鐗╂枡锛堢洿鎺ヤ娇鐢� Mapper 閬垮厤寰幆渚濊禆锛�
- if (itemMapper.selectCountByCategoryId(id) > 0) {
- throw exception(MDM_ITEM_CATEGORY_EXISTS_ITEM);
- }
- // 鍒犻櫎
- itemCategoryMapper.deleteById(id);
- }
-
- @Override
- public MdmItemCategoryDO validateItemCategoryExists(Long id) {
- MdmItemCategoryDO itemCategory = itemCategoryMapper.selectById(id);
- if (itemCategory == null) {
- throw exception(MDM_ITEM_CATEGORY_NOT_EXISTS);
- }
- return itemCategory;
- }
-
- private void validateItemCategorySaveData(MdmItemCategorySaveReqVO reqVO) {
- // 鏍¢獙缂栫爜鍞竴
- MdmItemCategoryDO category = itemCategoryMapper.selectByCode(reqVO.getCode());
- if (category != null && ObjUtil.notEqual(category.getId(), reqVO.getId())) {
- throw exception(MDM_ITEM_CATEGORY_CODE_DUPLICATE);
- }
- // 鏍¢獙鍚屼竴鐖剁骇涓嬪悕绉板敮涓�
- MdmItemCategoryDO sameName = itemCategoryMapper.selectByParentIdAndName(
- reqVO.getParentId() != null ? reqVO.getParentId() : 0L, reqVO.getName());
- if (sameName != null && ObjUtil.notEqual(sameName.getId(), reqVO.getId())) {
- throw exception(MDM_ITEM_CATEGORY_NAME_DUPLICATE);
- }
- // 鏍¢獙鐖跺垎绫诲瓨鍦�
- if (reqVO.getParentId() != null && reqVO.getParentId() > 0) {
- if (itemCategoryMapper.selectById(reqVO.getParentId()) == null) {
- throw exception(MDM_ITEM_CATEGORY_PARENT_NOT_EXISTS);
- }
- }
- }
-
- @Override
- public MdmItemCategoryDO getItemCategory(Long id) {
- return itemCategoryMapper.selectById(id);
- }
-
- @Override
- public PageResult<MdmItemCategoryDO> getItemCategoryPage(MdmItemCategoryPageReqVO pageReqVO) {
- return itemCategoryMapper.selectPage(pageReqVO);
- }
-
- @Override
- public List<MdmItemCategoryDO> getItemCategoryList(Collection<Long> ids) {
- if (CollUtil.isEmpty(ids)) {
- return Collections.emptyList();
- }
- return itemCategoryMapper.selectBatchIds(ids);
- }
-
- @Override
- public List<MdmItemCategoryDO> getItemCategoryChildrenList(Long id) {
- List<MdmItemCategoryDO> result = new ArrayList<>();
- // 娣诲姞鑷繁
- MdmItemCategoryDO self = itemCategoryMapper.selectById(id);
- if (self != null) {
- result.add(self);
- }
- // 閫掑綊鑾峰彇鎵�鏈夊瓙鍒嗙被
- loadChildren(id, result);
- return result;
- }
-
- private void loadChildren(Long parentId, List<MdmItemCategoryDO> result) {
- List<MdmItemCategoryDO> children = itemCategoryMapper.selectListByParentId(parentId);
- if (CollUtil.isNotEmpty(children)) {
- result.addAll(children);
- for (MdmItemCategoryDO child : children) {
- loadChildren(child.getId(), result);
- }
- }
- }
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemService.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemService.java
deleted file mode 100644
index 7235c20..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemService.java
+++ /dev/null
@@ -1,134 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.item;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
-import jakarta.validation.Valid;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-
-/**
- * MDM 鐗╂枡涓绘暟鎹� Service 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmItemService {
-
- /**
- * 鍒涘缓鐗╂枡
- *
- * @param createReqVO 鍒涘缓淇℃伅
- * @return 缂栧彿
- */
- Long createItem(@Valid MdmItemSaveReqVO createReqVO);
-
- /**
- * 鏇存柊鐗╂枡
- *
- * @param updateReqVO 鏇存柊淇℃伅
- */
- void updateItem(@Valid MdmItemSaveReqVO updateReqVO);
-
- /**
- * 鏇存柊鐗╂枡鐘舵��
- *
- * @param id 缂栧彿
- * @param status 鐘舵��
- */
- void updateItemStatus(Long id, Integer status);
-
- /**
- * 鍒犻櫎鐗╂枡
- *
- * @param id 缂栧彿
- */
- void deleteItem(Long id);
-
- /**
- * 鑾峰緱鐗╂枡
- *
- * @param id 缂栧彿
- * @return 鐗╂枡
- */
- MdmItemDO getItem(Long id);
-
- /**
- * 鏍¢獙鐗╂枡瀛樺湪
- *
- * @param id 缂栧彿
- * @return 鐗╂枡
- */
- MdmItemDO validateItemExists(Long id);
-
- /**
- * 鏍¢獙鐗╂枡瀛樺湪涓斿惎鐢�
- *
- * @param id 缂栧彿
- * @return 鐗╂枡
- */
- MdmItemDO validateItemExistsAndEnable(Long id);
-
- /**
- * 鑾峰緱鐗╂枡鍒嗛〉
- *
- * @param pageReqVO 鍒嗛〉鏌ヨ
- * @return 鐗╂枡鍒嗛〉
- */
- PageResult<MdmItemDO> getItemPage(MdmItemPageReqVO pageReqVO);
-
- /**
- * 鑾峰緱鐗╂枡鍒楄〃
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 鐗╂枡鍒楄〃
- */
- List<MdmItemDO> getItemList(Collection<Long> ids);
-
- /**
- * 鑾峰緱鐗╂枡 Map
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 鐗╂枡 Map
- */
- default Map<Long, MdmItemDO> getItemMap(Collection<Long> ids) {
- return convertMap(getItemList(ids), MdmItemDO::getId);
- }
-
- /**
- * 鍩轰簬鐗╂枡鍒嗙被缂栧彿锛岃幏寰楃墿鏂欐暟閲�
- *
- * @param categoryId 鐗╂枡鍒嗙被缂栧彿
- * @return 鐗╂枡鏁伴噺
- */
- Long getItemCountByCategoryId(Long categoryId);
-
- /**
- * 鍩轰簬璁¢噺鍗曚綅缂栧彿锛岃幏寰楃墿鏂欐暟閲�
- *
- * @param unitMeasureId 璁¢噺鍗曚綅缂栧彿
- * @return 鐗╂枡鏁伴噺
- */
- Long getItemCountByUnitMeasureId(Long unitMeasureId);
-
- /**
- * 鍩轰簬鍝佺墝缂栧彿锛岃幏寰楃墿鏂欐暟閲�
- *
- * @param brandId 鍝佺墝缂栧彿
- * @return 鐗╂枡鏁伴噺
- */
- Long getItemCountByBrandId(Long brandId);
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇鐗╂枡
- *
- * @param code 鐗╂枡缂栫爜
- * @return 鐗╂枡
- */
- MdmItemDO getItemByCode(String code);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
deleted file mode 100644
index b273316..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemServiceImpl.java
+++ /dev/null
@@ -1,189 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.item;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO;
-import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper;
-import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService;
-import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService;
-import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.*;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
-
-/**
- * MDM 鐗╂枡涓绘暟鎹� Service 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Service
-@Validated
-public class MdmItemServiceImpl implements MdmItemService {
-
- @Resource
- private MdmItemMapper itemMapper;
-
- @Resource
- private MdmItemCategoryService itemCategoryService;
- @Resource
- private MdmUnitMeasureService unitMeasureService;
- @Resource
- private MdmBrandService brandService;
-
- @Override
- public Long createItem(MdmItemSaveReqVO createReqVO) {
- // 鏍¢獙鏁版嵁
- validateItemSaveData(createReqVO);
-
- // 鎻掑叆
- MdmItemDO item = BeanUtils.toBean(createReqVO, MdmItemDO.class);
- itemMapper.insert(item);
- return item.getId();
- }
-
- @Override
- public void updateItem(MdmItemSaveReqVO updateReqVO) {
- // 鏍¢獙瀛樺湪
- validateItemExists(updateReqVO.getId());
- // 鏍¢獙鏁版嵁
- validateItemSaveData(updateReqVO);
-
- // 鏇存柊
- MdmItemDO updateObj = BeanUtils.toBean(updateReqVO, MdmItemDO.class);
- itemMapper.updateById(updateObj);
- }
-
- private void validateItemSaveData(MdmItemSaveReqVO reqVO) {
- // 鏍¢獙鐗╂枡缂栫爜鐨勫敮涓�鎬�
- validateItemCodeUnique(reqVO.getId(), reqVO.getCode());
- // 鏍¢獙鐗╂枡鍒嗙被瀛樺湪
- validateCategoryExists(reqVO.getCategoryId());
- // 鏍¢獙璁¢噺鍗曚綅瀛樺湪
- validateUnitMeasureExists(reqVO.getUnitMeasureId());
- // 鏍¢獙鍝佺墝瀛樺湪锛堝鏋滄湁锛�
- if (reqVO.getBrandId() != null) {
- validateBrandExists(reqVO.getBrandId());
- }
- }
-
- @Override
- public void updateItemStatus(Long id, Integer status) {
- // 鏍¢獙瀛樺湪
- validateItemExists(id);
- // 鏇存柊鐘舵��
- itemMapper.updateById(new MdmItemDO().setId(id).setStatus(status));
- }
-
- @Override
- public void deleteItem(Long id) {
- // 鏍¢獙瀛樺湪
- validateItemExists(id);
- // 鍒犻櫎
- itemMapper.deleteById(id);
- }
-
- @Override
- public MdmItemDO validateItemExists(Long id) {
- MdmItemDO item = itemMapper.selectById(id);
- if (item == null) {
- throw exception(MDM_ITEM_NOT_EXISTS);
- }
- return item;
- }
-
- @Override
- public MdmItemDO validateItemExistsAndEnable(Long id) {
- MdmItemDO item = validateItemExists(id);
- if (ObjUtil.notEqual(cn.iocoder.yudao.framework.common.enums.CommonStatusEnum.ENABLE.getStatus(), item.getStatus())) {
- throw exception(MDM_ITEM_IS_DISABLE);
- }
- return item;
- }
-
- private void validateItemCodeUnique(Long id, String code) {
- MdmItemDO item = itemMapper.selectByCode(code);
- if (item == null) {
- return;
- }
- if (ObjUtil.notEqual(item.getId(), id)) {
- throw exception(MDM_ITEM_CODE_DUPLICATE);
- }
- }
-
- private void validateCategoryExists(Long categoryId) {
- if (itemCategoryService.getItemCategory(categoryId) == null) {
- throw exception(MDM_ITEM_CATEGORY_NOT_EXISTS);
- }
- }
-
- private void validateUnitMeasureExists(Long unitMeasureId) {
- if (unitMeasureService.getUnitMeasure(unitMeasureId) == null) {
- throw exception(MDM_UNIT_MEASURE_NOT_EXISTS);
- }
- }
-
- private void validateBrandExists(Long brandId) {
- if (brandService.getBrand(brandId) == null) {
- throw exception(MDM_BRAND_NOT_EXISTS);
- }
- }
-
- @Override
- public MdmItemDO getItem(Long id) {
- return itemMapper.selectById(id);
- }
-
- @Override
- public PageResult<MdmItemDO> getItemPage(MdmItemPageReqVO pageReqVO) {
- // 鏌ユ壘鏃讹紝濡傛灉鏌ユ壘鏌愪釜鍒嗙被缂栧彿锛屽垯鍖呭惈瀹冪殑瀛愬垎绫�
- Set<Long> categoryIds = null;
- if (pageReqVO.getCategoryId() != null) {
- categoryIds = new HashSet<>();
- categoryIds.add(pageReqVO.getCategoryId());
- List<cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO> children =
- itemCategoryService.getItemCategoryChildrenList(pageReqVO.getCategoryId());
- categoryIds.addAll(convertSet(children, cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO::getId));
- }
- // 鍒嗛〉鏌ヨ
- return itemMapper.selectPage(pageReqVO, categoryIds);
- }
-
- @Override
- public List<MdmItemDO> getItemList(Collection<Long> ids) {
- if (CollUtil.isEmpty(ids)) {
- return Collections.emptyList();
- }
- return itemMapper.selectBatchIds(ids);
- }
-
- @Override
- public Long getItemCountByCategoryId(Long categoryId) {
- return itemMapper.selectCountByCategoryId(categoryId);
- }
-
- @Override
- public Long getItemCountByUnitMeasureId(Long unitMeasureId) {
- return itemMapper.selectCountByUnitMeasureId(unitMeasureId);
- }
-
- @Override
- public Long getItemCountByBrandId(Long brandId) {
- return itemMapper.selectCountByBrandId(brandId);
- }
-
- @Override
- public MdmItemDO getItemByCode(String code) {
- return itemMapper.selectByCode(code);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemSkuService.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemSkuService.java
deleted file mode 100644
index 4944e36..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemSkuService.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.item;
-
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemSkuDO;
-import jakarta.validation.Valid;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-
-/**
- * MDM 鐗╂枡 SKU Service 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmItemSkuService {
-
- /**
- * 鍒涘缓 SKU
- *
- * @param sku 鍒涘缓淇℃伅
- * @return 缂栧彿
- */
- Long createItemSku(@Valid MdmItemSkuDO sku);
-
- /**
- * 鎵归噺鍒涘缓 SKU
- *
- * @param itemId 鐗╂枡缂栧彿
- * @param skuList SKU 鍒楄〃
- */
- void createItemSkuList(Long itemId, List<MdmItemSkuDO> skuList);
-
- /**
- * 鏇存柊 SKU
- *
- * @param sku 鏇存柊淇℃伅
- */
- void updateItemSku(@Valid MdmItemSkuDO sku);
-
- /**
- * 鎵归噺鏇存柊 SKU
- *
- * @param itemId 鐗╂枡缂栧彿
- * @param skuList SKU 鍒楄〃
- */
- void updateItemSkuList(Long itemId, List<MdmItemSkuDO> skuList);
-
- /**
- * 鍒犻櫎 SKU
- *
- * @param id 缂栧彿
- */
- void deleteItemSku(Long id);
-
- /**
- * 鍒犻櫎鐗╂枡鐨勬墍鏈� SKU
- *
- * @param itemId 鐗╂枡缂栧彿
- */
- void deleteItemSkuListByItemId(Long itemId);
-
- /**
- * 鑾峰緱 SKU
- *
- * @param id 缂栧彿
- * @return SKU
- */
- MdmItemSkuDO getItemSku(Long id);
-
- /**
- * 鏍¢獙 SKU 瀛樺湪
- *
- * @param id 缂栧彿
- * @return SKU
- */
- MdmItemSkuDO validateItemSkuExists(Long id);
-
- /**
- * 鏍¢獙 SKU 瀛樺湪涓斿惎鐢�
- *
- * @param id 缂栧彿
- * @return SKU
- */
- MdmItemSkuDO validateItemSkuExistsAndEnable(Long id);
-
- /**
- * 鑾峰緱鐗╂枡鐨� SKU 鍒楄〃
- *
- * @param itemId 鐗╂枡缂栧彿
- * @return SKU 鍒楄〃
- */
- List<MdmItemSkuDO> getItemSkuListByItemId(Long itemId);
-
- /**
- * 鑾峰緱 SKU 鍒楄〃
- *
- * @param ids 缂栧彿鏁扮粍
- * @return SKU 鍒楄〃
- */
- List<MdmItemSkuDO> getItemSkuList(Collection<Long> ids);
-
- /**
- * 鑾峰緱 SKU Map
- *
- * @param ids 缂栧彿鏁扮粍
- * @return SKU Map
- */
- default Map<Long, MdmItemSkuDO> getItemSkuMap(Collection<Long> ids) {
- return convertMap(getItemSkuList(ids), MdmItemSkuDO::getId);
- }
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇 SKU
- *
- * @param code SKU 缂栫爜
- * @return SKU
- */
- MdmItemSkuDO getItemSkuByCode(String code);
-
- /**
- * 鏍规嵁鏉$爜鑾峰彇 SKU
- *
- * @param barCode SKU 鏉$爜
- * @return SKU
- */
- MdmItemSkuDO getItemSkuByBarCode(String barCode);
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemSkuServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemSkuServiceImpl.java
deleted file mode 100644
index 170844f..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/item/MdmItemSkuServiceImpl.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.item;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjUtil;
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemSkuDO;
-import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemSkuMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.*;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
-
-/**
- * MDM 鐗╂枡 SKU Service 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Service
-@Validated
-public class MdmItemSkuServiceImpl implements MdmItemSkuService {
-
- @Resource
- private MdmItemSkuMapper itemSkuMapper;
-
- @Override
- public Long createItemSku(MdmItemSkuDO sku) {
- // 鏍¢獙缂栫爜鍞竴
- validateItemSkuCodeUnique(null, sku.getCode());
- // 璁剧疆榛樿鐘舵��
- if (sku.getStatus() == null) {
- sku.setStatus(CommonStatusEnum.ENABLE.getStatus());
- }
- itemSkuMapper.insert(sku);
- return sku.getId();
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void createItemSkuList(Long itemId, List<MdmItemSkuDO> skuList) {
- if (CollUtil.isEmpty(skuList)) {
- return;
- }
- for (MdmItemSkuDO sku : skuList) {
- sku.setItemId(itemId);
- createItemSku(sku);
- }
- }
-
- @Override
- public void updateItemSku(MdmItemSkuDO sku) {
- // 鏍¢獙瀛樺湪
- validateItemSkuExists(sku.getId());
- // 鏍¢獙缂栫爜鍞竴
- validateItemSkuCodeUnique(sku.getId(), sku.getCode());
- itemSkuMapper.updateById(sku);
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void updateItemSkuList(Long itemId, List<MdmItemSkuDO> skuList) {
- // 绗竴姝ワ紝鍒犻櫎鏃х殑 SKU
- itemSkuMapper.deleteByItemId(itemId);
- // 绗簩姝ワ紝鎻掑叆鏂扮殑 SKU
- if (CollUtil.isEmpty(skuList)) {
- return;
- }
- for (MdmItemSkuDO sku : skuList) {
- sku.setItemId(itemId);
- sku.setId(null); // 娓呯┖ ID锛屼綔涓烘柊鎻掑叆
- if (sku.getStatus() == null) {
- sku.setStatus(CommonStatusEnum.ENABLE.getStatus());
- }
- itemSkuMapper.insert(sku);
- }
- }
-
- private void validateItemSkuCodeUnique(Long id, String code) {
- MdmItemSkuDO sku = itemSkuMapper.selectByCode(code);
- if (sku == null) {
- return;
- }
- if (id == null || ObjUtil.notEqual(sku.getId(), id)) {
- throw exception(MDM_ITEM_SKU_CODE_DUPLICATE);
- }
- }
-
- @Override
- public void deleteItemSku(Long id) {
- // 鏍¢獙瀛樺湪
- validateItemSkuExists(id);
- // 鍒犻櫎
- itemSkuMapper.deleteById(id);
- }
-
- @Override
- public void deleteItemSkuListByItemId(Long itemId) {
- itemSkuMapper.deleteByItemId(itemId);
- }
-
- @Override
- public MdmItemSkuDO validateItemSkuExists(Long id) {
- MdmItemSkuDO sku = itemSkuMapper.selectById(id);
- if (sku == null) {
- throw exception(MDM_ITEM_SKU_NOT_EXISTS);
- }
- return sku;
- }
-
- @Override
- public MdmItemSkuDO validateItemSkuExistsAndEnable(Long id) {
- MdmItemSkuDO sku = validateItemSkuExists(id);
- if (CommonStatusEnum.isDisable(sku.getStatus())) {
- throw exception(MDM_ITEM_SKU_IS_DISABLE);
- }
- return sku;
- }
-
- @Override
- public MdmItemSkuDO getItemSku(Long id) {
- return itemSkuMapper.selectById(id);
- }
-
- @Override
- public List<MdmItemSkuDO> getItemSkuListByItemId(Long itemId) {
- return itemSkuMapper.selectListByItemId(itemId);
- }
-
- @Override
- public List<MdmItemSkuDO> getItemSkuList(Collection<Long> ids) {
- if (CollUtil.isEmpty(ids)) {
- return Collections.emptyList();
- }
- return itemSkuMapper.selectBatchIds(ids);
- }
-
- @Override
- public MdmItemSkuDO getItemSkuByCode(String code) {
- return itemSkuMapper.selectByCode(code);
- }
-
- @Override
- public MdmItemSkuDO getItemSkuByBarCode(String barCode) {
- return itemSkuMapper.selectByBarCode(barCode);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/unit/MdmUnitMeasureService.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/unit/MdmUnitMeasureService.java
deleted file mode 100644
index d5023a0..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/unit/MdmUnitMeasureService.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.unit;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mdm.controller.admin.unit.vo.MdmUnitMeasurePageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.unit.vo.MdmUnitMeasureSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
-import jakarta.validation.Valid;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
-
-/**
- * MDM 璁¢噺鍗曚綅 Service 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmUnitMeasureService {
-
- /**
- * 鍒涘缓璁¢噺鍗曚綅
- *
- * @param createReqVO 鍒涘缓淇℃伅
- * @return 缂栧彿
- */
- Long createUnitMeasure(@Valid MdmUnitMeasureSaveReqVO createReqVO);
-
- /**
- * 鏇存柊璁¢噺鍗曚綅
- *
- * @param updateReqVO 鏇存柊淇℃伅
- */
- void updateUnitMeasure(@Valid MdmUnitMeasureSaveReqVO updateReqVO);
-
- /**
- * 鏇存柊璁¢噺鍗曚綅鐘舵��
- *
- * @param id 缂栧彿
- * @param status 鐘舵��
- */
- void updateUnitMeasureStatus(Long id, Integer status);
-
- /**
- * 鍒犻櫎璁¢噺鍗曚綅
- *
- * @param id 缂栧彿
- */
- void deleteUnitMeasure(Long id);
-
- /**
- * 鑾峰緱璁¢噺鍗曚綅
- *
- * @param id 缂栧彿
- * @return 璁¢噺鍗曚綅
- */
- MdmUnitMeasureDO getUnitMeasure(Long id);
-
- /**
- * 鏍¢獙璁¢噺鍗曚綅瀛樺湪
- *
- * @param id 缂栧彿
- * @return 璁¢噺鍗曚綅
- */
- MdmUnitMeasureDO validateUnitMeasureExists(Long id);
-
- /**
- * 鑾峰緱璁¢噺鍗曚綅鍒嗛〉
- *
- * @param pageReqVO 鍒嗛〉鏌ヨ
- * @return 璁¢噺鍗曚綅鍒嗛〉
- */
- PageResult<MdmUnitMeasureDO> getUnitMeasurePage(MdmUnitMeasurePageReqVO pageReqVO);
-
- /**
- * 鑾峰緱璁¢噺鍗曚綅鍒楄〃
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 璁¢噺鍗曚綅鍒楄〃
- */
- List<MdmUnitMeasureDO> getUnitMeasureList(Collection<Long> ids);
-
- /**
- * 鑾峰緱璁¢噺鍗曚綅 Map
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 璁¢噺鍗曚綅 Map
- */
- default Map<Long, MdmUnitMeasureDO> getUnitMeasureMap(Collection<Long> ids) {
- return convertMap(getUnitMeasureList(ids), MdmUnitMeasureDO::getId);
- }
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇璁¢噺鍗曚綅
- *
- * @param code 鍗曚綅缂栫爜
- * @return 璁¢噺鍗曚綅
- */
- MdmUnitMeasureDO getUnitMeasureByCode(String code);
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/unit/MdmUnitMeasureServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/unit/MdmUnitMeasureServiceImpl.java
deleted file mode 100644
index f3c581d..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/unit/MdmUnitMeasureServiceImpl.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.unit;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.unit.vo.MdmUnitMeasurePageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.unit.vo.MdmUnitMeasureSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO;
-import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper;
-import cn.iocoder.yudao.module.mdm.dal.mysql.unit.MdmUnitMeasureMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.*;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
-
-/**
- * MDM 璁¢噺鍗曚綅 Service 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Service
-@Validated
-public class MdmUnitMeasureServiceImpl implements MdmUnitMeasureService {
-
- @Resource
- private MdmUnitMeasureMapper unitMeasureMapper;
-
- @Resource
- private MdmItemMapper itemMapper;
-
- @Override
- public Long createUnitMeasure(MdmUnitMeasureSaveReqVO createReqVO) {
- // 鏍¢獙鏁版嵁
- validateUnitMeasureSaveData(createReqVO);
-
- // 鎻掑叆
- MdmUnitMeasureDO unitMeasure = BeanUtils.toBean(createReqVO, MdmUnitMeasureDO.class);
- unitMeasureMapper.insert(unitMeasure);
- return unitMeasure.getId();
- }
-
- @Override
- public void updateUnitMeasure(MdmUnitMeasureSaveReqVO updateReqVO) {
- // 鏍¢獙瀛樺湪
- validateUnitMeasureExists(updateReqVO.getId());
- // 鏍¢獙鏁版嵁
- validateUnitMeasureSaveData(updateReqVO);
-
- // 鏇存柊
- MdmUnitMeasureDO updateObj = BeanUtils.toBean(updateReqVO, MdmUnitMeasureDO.class);
- unitMeasureMapper.updateById(updateObj);
- }
-
- @Override
- public void updateUnitMeasureStatus(Long id, Integer status) {
- // 鏍¢獙瀛樺湪
- validateUnitMeasureExists(id);
- // 鏇存柊鐘舵��
- unitMeasureMapper.updateById(new MdmUnitMeasureDO().setId(id).setStatus(status));
- }
-
- @Override
- public void deleteUnitMeasure(Long id) {
- // 鏍¢獙瀛樺湪
- validateUnitMeasureExists(id);
- // 鏍¢獙鏄惁琚墿鏂欎娇鐢紙鐩存帴浣跨敤 Mapper 閬垮厤寰幆渚濊禆锛�
- if (itemMapper.selectCountByUnitMeasureId(id) > 0) {
- throw exception(MDM_UNIT_MEASURE_EXISTS_ITEM);
- }
- // 鍒犻櫎
- unitMeasureMapper.deleteById(id);
- }
-
- @Override
- public MdmUnitMeasureDO validateUnitMeasureExists(Long id) {
- MdmUnitMeasureDO unitMeasure = unitMeasureMapper.selectById(id);
- if (unitMeasure == null) {
- throw exception(MDM_UNIT_MEASURE_NOT_EXISTS);
- }
- return unitMeasure;
- }
-
- private void validateUnitMeasureSaveData(MdmUnitMeasureSaveReqVO reqVO) {
- // 鏍¢獙缂栫爜鍞竴
- MdmUnitMeasureDO unit = unitMeasureMapper.selectByCode(reqVO.getCode());
- if (unit != null && ObjUtil.notEqual(unit.getId(), reqVO.getId())) {
- throw exception(MDM_UNIT_MEASURE_CODE_DUPLICATE);
- }
- // 鏍¢獙鍚嶇О鍞竴
- MdmUnitMeasureDO sameName = unitMeasureMapper.selectByName(reqVO.getName());
- if (sameName != null && ObjUtil.notEqual(sameName.getId(), reqVO.getId())) {
- throw exception(MDM_UNIT_MEASURE_NAME_DUPLICATE);
- }
- }
-
- @Override
- public MdmUnitMeasureDO getUnitMeasure(Long id) {
- return unitMeasureMapper.selectById(id);
- }
-
- @Override
- public PageResult<MdmUnitMeasureDO> getUnitMeasurePage(MdmUnitMeasurePageReqVO pageReqVO) {
- return unitMeasureMapper.selectPage(pageReqVO);
- }
-
- @Override
- public List<MdmUnitMeasureDO> getUnitMeasureList(Collection<Long> ids) {
- if (CollUtil.isEmpty(ids)) {
- return Collections.emptyList();
- }
- return unitMeasureMapper.selectBatchIds(ids);
- }
-
- @Override
- public MdmUnitMeasureDO getUnitMeasureByCode(String code) {
- return unitMeasureMapper.selectByCode(code);
- }
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/warehouse/MdmWarehouseService.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/warehouse/MdmWarehouseService.java
deleted file mode 100644
index b517658..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/warehouse/MdmWarehouseService.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.warehouse;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mdm.controller.admin.warehouse.vo.MdmWarehousePageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.warehouse.vo.MdmWarehouseSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.warehouse.MdmWarehouseDO;
-import jakarta.validation.Valid;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * MDM 浠撳簱 Service 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface MdmWarehouseService {
-
- /**
- * 鍒涘缓浠撳簱
- *
- * @param createReqVO 鍒涘缓淇℃伅
- * @return 缂栧彿
- */
- Long createWarehouse(@Valid MdmWarehouseSaveReqVO createReqVO);
-
- /**
- * 鏇存柊浠撳簱
- *
- * @param updateReqVO 鏇存柊淇℃伅
- */
- void updateWarehouse(@Valid MdmWarehouseSaveReqVO updateReqVO);
-
- /**
- * 鏇存柊浠撳簱鐘舵��
- *
- * @param id 缂栧彿
- * @param status 鐘舵��
- */
- void updateWarehouseStatus(Long id, Integer status);
-
- /**
- * 鍒犻櫎浠撳簱
- *
- * @param id 缂栧彿
- */
- void deleteWarehouse(Long id);
-
- /**
- * 鑾峰緱浠撳簱
- *
- * @param id 缂栧彿
- * @return 浠撳簱
- */
- MdmWarehouseDO getWarehouse(Long id);
-
- /**
- * 鏍¢獙浠撳簱瀛樺湪
- *
- * @param id 缂栧彿
- * @return 浠撳簱
- */
- MdmWarehouseDO validateWarehouseExists(Long id);
-
- /**
- * 鏍¢獙浠撳簱瀛樺湪涓斿惎鐢�
- *
- * @param id 缂栧彿
- * @return 浠撳簱
- */
- MdmWarehouseDO validateWarehouseExistsAndEnable(Long id);
-
- /**
- * 鑾峰緱浠撳簱鍒嗛〉
- *
- * @param pageReqVO 鍒嗛〉鏌ヨ
- * @return 浠撳簱鍒嗛〉
- */
- PageResult<MdmWarehouseDO> getWarehousePage(MdmWarehousePageReqVO pageReqVO);
-
- /**
- * 鑾峰緱浠撳簱鍒楄〃
- *
- * @param ids 缂栧彿鏁扮粍
- * @return 浠撳簱鍒楄〃
- */
- List<MdmWarehouseDO> getWarehouseList(Collection<Long> ids);
-
- /**
- * 鏍规嵁缂栫爜鑾峰彇浠撳簱
- *
- * @param code 浠撳簱缂栫爜
- * @return 浠撳簱
- */
- MdmWarehouseDO getWarehouseByCode(String code);
-
-}
diff --git a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/warehouse/MdmWarehouseServiceImpl.java b/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/warehouse/MdmWarehouseServiceImpl.java
deleted file mode 100644
index 994b65e..0000000
--- a/yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/service/warehouse/MdmWarehouseServiceImpl.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package cn.iocoder.yudao.module.mdm.service.warehouse;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ObjUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.controller.admin.warehouse.vo.MdmWarehousePageReqVO;
-import cn.iocoder.yudao.module.mdm.controller.admin.warehouse.vo.MdmWarehouseSaveReqVO;
-import cn.iocoder.yudao.module.mdm.dal.dataobject.warehouse.MdmWarehouseDO;
-import cn.iocoder.yudao.module.mdm.dal.mysql.warehouse.MdmWarehouseMapper;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.*;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*;
-
-/**
- * MDM 浠撳簱 Service 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Service
-@Validated
-public class MdmWarehouseServiceImpl implements MdmWarehouseService {
-
- @Resource
- private MdmWarehouseMapper warehouseMapper;
-
- @Override
- public Long createWarehouse(MdmWarehouseSaveReqVO createReqVO) {
- // 鏍¢獙鏁版嵁
- validateWarehouseSaveData(createReqVO);
-
- // 鎻掑叆
- MdmWarehouseDO warehouse = BeanUtils.toBean(createReqVO, MdmWarehouseDO.class);
- warehouseMapper.insert(warehouse);
- return warehouse.getId();
- }
-
- @Override
- public void updateWarehouse(MdmWarehouseSaveReqVO updateReqVO) {
- // 鏍¢獙瀛樺湪
- validateWarehouseExists(updateReqVO.getId());
- // 鏍¢獙鏁版嵁
- validateWarehouseSaveData(updateReqVO);
-
- // 鏇存柊
- MdmWarehouseDO updateObj = BeanUtils.toBean(updateReqVO, MdmWarehouseDO.class);
- warehouseMapper.updateById(updateObj);
- }
-
- @Override
- public void updateWarehouseStatus(Long id, Integer status) {
- // 鏍¢獙瀛樺湪
- validateWarehouseExists(id);
- // 鏇存柊鐘舵��
- warehouseMapper.updateById(new MdmWarehouseDO().setId(id).setStatus(status));
- }
-
- @Override
- public void deleteWarehouse(Long id) {
- // 鏍¢獙瀛樺湪
- validateWarehouseExists(id);
- // TODO: 鏍¢獙鏄惁琚簱瀛樹娇鐢�
- // 鍒犻櫎
- warehouseMapper.deleteById(id);
- }
-
- @Override
- public MdmWarehouseDO validateWarehouseExists(Long id) {
- MdmWarehouseDO warehouse = warehouseMapper.selectById(id);
- if (warehouse == null) {
- throw exception(MDM_WAREHOUSE_NOT_EXISTS);
- }
- return warehouse;
- }
-
- @Override
- public MdmWarehouseDO validateWarehouseExistsAndEnable(Long id) {
- MdmWarehouseDO warehouse = validateWarehouseExists(id);
- if (warehouse.getStatus() != null && warehouse.getStatus() != 0) {
- throw exception(MDM_WAREHOUSE_IS_DISABLE);
- }
- return warehouse;
- }
-
- private void validateWarehouseSaveData(MdmWarehouseSaveReqVO reqVO) {
- // 鏍¢獙缂栫爜鍞竴
- MdmWarehouseDO warehouse = warehouseMapper.selectByCode(reqVO.getCode());
- if (warehouse != null && ObjUtil.notEqual(warehouse.getId(), reqVO.getId())) {
- throw exception(MDM_WAREHOUSE_CODE_DUPLICATE);
- }
- // 鏍¢獙鍚嶇О鍞竴
- MdmWarehouseDO sameName = warehouseMapper.selectByName(reqVO.getName());
- if (sameName != null && ObjUtil.notEqual(sameName.getId(), reqVO.getId())) {
- throw exception(MDM_WAREHOUSE_NAME_DUPLICATE);
- }
- }
-
- @Override
- public MdmWarehouseDO getWarehouse(Long id) {
- return warehouseMapper.selectById(id);
- }
-
- @Override
- public PageResult<MdmWarehouseDO> getWarehousePage(MdmWarehousePageReqVO pageReqVO) {
- return warehouseMapper.selectPage(pageReqVO);
- }
-
- @Override
- public List<MdmWarehouseDO> getWarehouseList(Collection<Long> ids) {
- if (CollUtil.isEmpty(ids)) {
- return Collections.emptyList();
- }
- return warehouseMapper.selectListByIds(ids);
- }
-
- @Override
- public MdmWarehouseDO getWarehouseByCode(String code) {
- return warehouseMapper.selectByCode(code);
- }
-
-}
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
index 50548f9..323e0f1 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
@@ -36,6 +36,10 @@
*/
private String mobile;
/**
+ * 閭
+ */
+ private String email;
+ /**
* 鍒涘缓鏃堕棿锛堟敞鍐屾椂闂达級
*/
private LocalDateTime createTime;
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressRespVO.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressRespVO.java
index 26a4988..7f6d0f1 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressRespVO.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/address/vo/AddressRespVO.java
@@ -16,4 +16,7 @@
@Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
+ @Schema(description = "鍦板尯鍚嶇О", example = "涓婃捣涓婃捣甯傛櫘闄�鍖�")
+ private String areaName;
+
}
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java
index b240602..01e4dd3 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java
@@ -5,7 +5,9 @@
import org.hibernate.validator.constraints.URL;
import org.springframework.format.annotation.DateTimeFormat;
+import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.List;
@@ -26,6 +28,11 @@
@NotNull(message = "鐘舵�佷笉鑳戒负绌�")
private Byte status;
+ @Schema(description = "閭", example = "member@iocoder.cn")
+ @Email(message = "閭鏍煎紡涓嶆纭�")
+ @Size(max = 50, message = "閭闀垮害涓嶈兘瓒呰繃 50 涓瓧绗�")
+ private String email;
+
@Schema(description = "鐢ㄦ埛鏄电О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鏉庡洓")
@NotNull(message = "鐢ㄦ埛鏄电О涓嶈兘涓虹┖")
private String nickname;
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java
index abb9428..299e6e2 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java
@@ -21,6 +21,9 @@
@Schema(description = "鎵嬫満鍙�", example = "15601691300")
private String mobile;
+ @Schema(description = "閭", example = "member@iocoder.cn")
+ private String email;
+
@Schema(description = "鐢ㄦ埛鏄电О", example = "鏉庡洓")
private String nickname;
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java
index 72e4fa3..fd9b907 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserInfoRespVO.java
@@ -23,6 +23,9 @@
@Schema(description = "鐢ㄦ埛鎵嬫満鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300")
private String mobile;
+ @Schema(description = "閭", example = "member@iocoder.cn")
+ private String email;
+
@Schema(description = "鐢ㄦ埛鎬у埆", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer sex;
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java
index cca08e9..4ddcdbd 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppMemberUserUpdateReqVO.java
@@ -1,8 +1,8 @@
package cn.iocoder.yudao.module.member.controller.app.user.vo;
-import cn.iocoder.yudao.framework.common.validation.InEnum;
-import cn.iocoder.yudao.module.system.enums.common.SexEnum;
import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.Size;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
@@ -17,6 +17,11 @@
@URL(message = "澶村儚蹇呴』鏄� URL 鏍煎紡")
private String avatar;
+ @Schema(description = "閭", example = "member@iocoder.cn")
+ @Email(message = "閭鏍煎紡涓嶆纭�")
+ @Size(max = 50, message = "閭闀垮害涓嶈兘瓒呰繃 50 涓瓧绗�")
+ private String email;
+
@Schema(description = "鎬у埆", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer sex;
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java
index 39dc9fa..693bb90 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java
@@ -40,6 +40,9 @@
return AreaUtils.format(areaId);
}
+ @Mapping(source = "areaId", target = "areaName", qualifiedByName = "convertAreaIdToAreaName")
+ AddressRespVO convert03(MemberAddressDO bean);
+
List<AddressRespVO> convertList2(List<MemberAddressDO> list);
}
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java
index 97ddc19..11954c0 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java
@@ -46,6 +46,10 @@
*/
private String mobile;
/**
+ * 閭
+ */
+ private String email;
+ /**
* 鍔犲瘑鍚庣殑瀵嗙爜
*
* 鍥犱负鐩墠浣跨敤 {@link BCryptPasswordEncoder} 鍔犲瘑鍣紝鎵�浠ユ棤闇�鑷繁澶勭悊 salt 鐩�
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
index 3f87102..9da83b1 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
@@ -2,10 +2,10 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
-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.member.controller.admin.user.vo.MemberUserPageReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -13,6 +13,7 @@
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* 浼氬憳 User Mapper
@@ -26,6 +27,10 @@
return selectOne(MemberUserDO::getMobile, mobile);
}
+ default MemberUserDO selectByEmail(String email) {
+ return selectOne(MemberUserDO::getEmail, email);
+ }
+
default List<MemberUserDO> selectListByNicknameLike(String nickname) {
return selectList(new LambdaQueryWrapperX<MemberUserDO>()
.likeIfPresent(MemberUserDO::getNickname, nickname));
@@ -34,20 +39,23 @@
default PageResult<MemberUserDO> selectPage(MemberUserPageReqVO reqVO) {
// 澶勭悊 tagIds 杩囨护鏉′欢
String tagIdSql = "";
+ Object[] tagIdParams = new Object[0];
if (CollUtil.isNotEmpty(reqVO.getTagIds())) {
- tagIdSql = reqVO.getTagIds().stream()
- .map(tagId -> "FIND_IN_SET(" + tagId + ", tag_ids)")
+ tagIdSql = IntStream.range(0, reqVO.getTagIds().size())
+ .mapToObj(index -> MyBatisUtils.findInSetWithParamIndex("tag_ids", index))
.collect(Collectors.joining(" OR "));
+ tagIdParams = reqVO.getTagIds().toArray();
}
// 鍒嗛〉鏌ヨ
return selectPage(reqVO, new LambdaQueryWrapperX<MemberUserDO>()
.likeIfPresent(MemberUserDO::getMobile, reqVO.getMobile())
+ .likeIfPresent(MemberUserDO::getEmail, reqVO.getEmail())
.betweenIfPresent(MemberUserDO::getLoginDate, reqVO.getLoginDate())
.likeIfPresent(MemberUserDO::getNickname, reqVO.getNickname())
.betweenIfPresent(MemberUserDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(MemberUserDO::getLevelId, reqVO.getLevelId())
.eqIfPresent(MemberUserDO::getGroupId, reqVO.getGroupId())
- .apply(StrUtil.isNotEmpty(tagIdSql), tagIdSql)
+ .apply(CollUtil.isNotEmpty(reqVO.getTagIds()), tagIdSql, tagIdParams)
.orderByDesc(MemberUserDO::getId));
}
@@ -61,7 +69,7 @@
default Long selectCountByTagId(Long tagId) {
return selectCount(new LambdaQueryWrapperX<MemberUserDO>()
- .apply("FIND_IN_SET({0}, tag_ids)", tagId));
+ .apply(MyBatisUtils.findInSet("tag_ids"), tagId));
}
/**
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
index ee970a5..c28fcfc 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
@@ -14,6 +14,7 @@
ErrorCode USER_MOBILE_NOT_EXISTS = new ErrorCode(1_004_001_001, "鎵嬫満鍙锋湭娉ㄥ唽鐢ㄦ埛");
ErrorCode USER_MOBILE_USED = new ErrorCode(1_004_001_002, "淇敼鎵嬫満澶辫触锛岃鎵嬫満鍙�({})宸茬粡琚娇鐢�");
ErrorCode USER_POINT_NOT_ENOUGH = new ErrorCode(1_004_001_003, "鐢ㄦ埛绉垎浣欓涓嶈冻");
+ ErrorCode USER_EMAIL_USED = new ErrorCode(1_004_001_004, "淇敼閭澶辫触锛岃閭({})宸茬粡琚娇鐢�");
// ========== AUTH 妯″潡 1-004-003-000 ==========
ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_004_003_000, "鐧诲綍澶辫触锛岃处鍙峰瘑鐮佷笉姝g‘");
diff --git a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
index d596ab6..7cfbeb5 100644
--- a/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
+++ b/yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
@@ -142,6 +142,12 @@
@Override
public void updateUser(Long userId, AppMemberUserUpdateReqVO reqVO) {
+ // 1.1 妫�娴嬬敤鎴锋槸鍚﹀瓨鍦�
+ validateUserExists(userId);
+ // 1.2 鏍¢獙鎵嬫満鏄惁宸茬粡琚粦瀹�
+ validateEmailUnique(userId, reqVO.getEmail());
+
+ // 2. 鏇存柊鐢ㄦ埛
MemberUserDO updateObj = BeanUtils.toBean(reqVO, MemberUserDO.class).setId(userId);
memberUserMapper.updateById(updateObj);
}
@@ -238,6 +244,8 @@
validateUserExists(updateReqVO.getId());
// 鏍¢獙鎵嬫満鍞竴
validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile());
+ // 鏍¢獙閭鍞竴
+ validateEmailUnique(updateReqVO.getId(), updateReqVO.getEmail());
// 鏇存柊
MemberUserDO updateObj = MemberUserConvert.INSTANCE.convert(updateReqVO);
@@ -274,6 +282,24 @@
}
}
+ @VisibleForTesting
+ void validateEmailUnique(Long id, String email) {
+ if (StrUtil.isBlank(email)) {
+ return;
+ }
+ MemberUserDO user = memberUserMapper.selectByEmail(email);
+ if (user == null) {
+ return;
+ }
+ // 濡傛灉 id 涓虹┖锛岃鏄庝笉鐢ㄦ瘮杈冩槸鍚︿负鐩稿悓 id 鐨勭敤鎴�
+ if (id == null) {
+ throw exception(USER_EMAIL_USED, email);
+ }
+ if (!user.getId().equals(id)) {
+ throw exception(USER_EMAIL_USED, email);
+ }
+ }
+
@Override
public PageResult<MemberUserDO> getUserPage(MemberUserPageReqVO pageReqVO) {
return memberUserMapper.selectPage(pageReqVO);
diff --git a/yudao-module-member/src/test/resources/sql/create_tables.sql b/yudao-module-member/src/test/resources/sql/create_tables.sql
index 782a818..9775a30 100644
--- a/yudao-module-member/src/test/resources/sql/create_tables.sql
+++ b/yudao-module-member/src/test/resources/sql/create_tables.sql
@@ -11,6 +11,7 @@
"avatar" varchar(255) NOT NULL DEFAULT '' COMMENT '澶村儚',
"status" tinyint NOT NULL COMMENT '鐘舵��',
"mobile" varchar(11) NOT NULL COMMENT '鎵嬫満鍙�',
+ "email" varchar(50) NULL COMMENT '閭',
"password" varchar(100) NOT NULL DEFAULT '' COMMENT '瀵嗙爜',
"register_ip" varchar(32) NOT NULL COMMENT '娉ㄥ唽 IP',
"login_ip" varchar(50) NULL DEFAULT '' COMMENT '鏈�鍚庣櫥褰旾P',
diff --git a/yudao-module-mes/pom.xml b/yudao-module-mes/pom.xml
index 0884fe3..a20eadb 100644
--- a/yudao-module-mes/pom.xml
+++ b/yudao-module-mes/pom.xml
@@ -24,20 +24,6 @@
<version>${revision}</version>
</dependency>
- <!-- MDM 涓绘暟鎹鐞嗘ā鍧� -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-mdm</artifactId>
- <version>${revision}</version>
- </dependency>
-
- <!-- BPM 娴佺▼妯″潡 -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-bpm</artifactId>
- <version>${revision}</version>
- </dependency>
-
<!-- 涓氬姟缁勪欢 -->
<!-- Web 鐩稿叧 -->
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/MesProAndonConfigController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/MesProAndonConfigController.java
index e4d9df3..3b803e4 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/MesProAndonConfigController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/MesProAndonConfigController.java
@@ -11,6 +11,8 @@
import cn.iocoder.yudao.module.mes.controller.admin.pro.andon.vo.config.MesProAndonConfigSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.andon.MesProAndonConfigDO;
import cn.iocoder.yudao.module.mes.service.pro.andon.MesProAndonConfigService;
+import cn.iocoder.yudao.module.system.api.permission.RoleApi;
+import cn.iocoder.yudao.module.system.api.permission.dto.RoleRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
@@ -40,6 +42,8 @@
@Resource
private AdminUserApi adminUserApi;
+ @Resource
+ private RoleApi roleApi;
@PostMapping("/create")
@Operation(summary = "鍒涘缓瀹夌伅鍛煎彨閰嶇疆")
@@ -102,10 +106,15 @@
// 1. 鎵归噺鑾峰彇鍏宠仈鏁版嵁
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(list, MesProAndonConfigDO::getHandlerUserId));
+ Map<Long, RoleRespDTO> roleMap = roleApi.getRoleMap(
+ convertSet(list, MesProAndonConfigDO::getHandlerRoleId));
// 2. 鎷兼帴 VO
- return BeanUtils.toBean(list, MesProAndonConfigRespVO.class, vo ->
- MapUtils.findAndThen(userMap, vo.getHandlerUserId(),
- user -> vo.setHandlerUserNickname(user.getNickname())));
+ return BeanUtils.toBean(list, MesProAndonConfigRespVO.class, vo -> {
+ MapUtils.findAndThen(userMap, vo.getHandlerUserId(),
+ user -> vo.setHandlerUserNickname(user.getNickname()));
+ MapUtils.findAndThen(roleMap, vo.getHandlerRoleId(),
+ role -> vo.setHandlerRoleName(role.getName()));
+ });
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/vo/config/MesProAndonConfigRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/vo/config/MesProAndonConfigRespVO.java
index ed1e541..dad6996 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/vo/config/MesProAndonConfigRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/andon/vo/config/MesProAndonConfigRespVO.java
@@ -21,6 +21,9 @@
@Schema(description = "澶勭疆浜鸿鑹茬紪鍙�", example = "10")
private Long handlerRoleId;
+ @Schema(description = "澶勭疆浜鸿鑹插悕绉�", example = "鐢熶骇缁忕悊")
+ private String handlerRoleName;
+
@Schema(description = "澶勭疆浜虹紪鍙�", example = "100")
private Long handlerUserId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java
index 87ff297..152502e 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderController.java
@@ -38,7 +38,6 @@
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "绠$悊鍚庡彴 - MES 鐢熶骇宸ュ崟")
@RestController
@@ -137,15 +136,6 @@
@PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')")
public CommonResult<Boolean> cancelWorkOrder(@RequestParam("id") Long id) {
workOrderService.cancelWorkOrder(id);
- return success(true);
- }
-
- @PutMapping("/submit")
- @Operation(summary = "鎻愪氦宸ュ崟瀹℃壒")
- @Parameter(name = "id", description = "缂栧彿", required = true)
- @PreAuthorize("@ss.hasPermission('mes:pro-work-order:update')")
- public CommonResult<Boolean> submitWorkOrder(@RequestParam("id") Long id) {
- workOrderService.submitWorkOrder(id, getLoginUserId());
return success(true);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defectrecord/MesQcDefectRecordController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defectrecord/MesQcDefectRecordController.java
index 604b395..898d750 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defectrecord/MesQcDefectRecordController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defectrecord/MesQcDefectRecordController.java
@@ -52,6 +52,15 @@
return success(true);
}
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱璐ㄦ缂洪櫡璁板綍")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('mes:qc-defect:query')")
+ public CommonResult<MesQcDefectRecordRespVO> getDefectRecord(@RequestParam("id") Long id) {
+ MesQcDefectRecordDO record = defectRecordService.getDefectRecord(id);
+ return success(BeanUtils.toBean(record, MesQcDefectRecordRespVO.class));
+ }
+
@GetMapping("/page")
@Operation(summary = "鑾峰緱璐ㄦ缂洪櫡璁板綍鍒嗛〉")
@PreAuthorize("@ss.hasPermission('mes:qc-defect:query')")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptController.java
index 55f7361..24a5379 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptController.java
@@ -26,11 +26,6 @@
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-/**
- * MES 鏉傞」鍏ュ簱鍗� Controller
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 鏉傞」鍏ュ簱鍗�")
@RestController
@RequestMapping("/mes/wm/misc-receipt")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptLineController.java
index 817392f..8abd396 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptLineController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptLineController.java
@@ -36,9 +36,6 @@
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
-/**
- * MES 鏉傞」鍏ュ簱鍗曡 Controller
- */
@Tag(name = "绠$悊鍚庡彴 - MES 鏉傞」鍏ュ簱鍗曡")
@RestController
@RequestMapping("/mes/wm/misc-receipt-line")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueController.java
index 6f45fb9..a461d13 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueController.java
@@ -36,11 +36,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-/**
- * MES 澶栧崗鍙戞枡鍗� Controller
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 澶栧崗鍙戞枡鍗�")
@RestController
@RequestMapping("/mes/wm/outsource-issue")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueDetailController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueDetailController.java
index 281c547..e92fca2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueDetailController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueDetailController.java
@@ -34,11 +34,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-/**
- * MES 澶栧崗鍙戞枡鍗曟槑缁� Controller
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 澶栧崗鍙戞枡鍗曟槑缁�")
@RestController
@RequestMapping("/mes/wm/outsource-issue-detail")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueLineController.java
index aa62901..f629379 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueLineController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/outsourceissue/MesWmOutsourceIssueLineController.java
@@ -34,11 +34,6 @@
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-/**
- * MES 澶栧崗鍙戞枡鍗曡 Controller
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 澶栧崗鍙戞枡鍗曡")
@RestController
@RequestMapping("/mes/wm/outsource-issue-line")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageController.java
index 805a9b1..5c52e6f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageController.java
@@ -32,12 +32,6 @@
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
-// DONE @AI锛氭鏌ヤ笅 java 绫伙紝鏄笉鏄� author 娌″姞銆�
-/**
- * MES 瑁呯鍗� Controller
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 瑁呯鍗�")
@RestController
@RequestMapping("/mes/wm/package")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageLineController.java
index 12ae8c1..2b8724a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageLineController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/packages/MesWmPackageLineController.java
@@ -32,11 +32,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-/**
- * MES 瑁呯鏄庣粏 Controller
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 瑁呯鏄庣粏")
@RestController
@RequestMapping("/mes/wm/package-line")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesController.java
index d765f69..074e7b1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesController.java
@@ -34,11 +34,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-/**
- * 绠$悊鍚庡彴 - MES 閿�鍞��璐у崟 Controller
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 閿�鍞��璐у崟")
@RestController
@RequestMapping("/mes/wm/return-sales")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesDetailController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesDetailController.java
index 4e41139..d9d291f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesDetailController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesDetailController.java
@@ -34,11 +34,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-/**
- * 绠$悊鍚庡彴 - MES 閿�鍞��璐х浉鍏�
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 閿�鍞��璐ф槑缁�")
@RestController
@RequestMapping("/mes/wm/return-sales-detail")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesLineController.java
index f57e781..e32fff1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesLineController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/MesWmReturnSalesLineController.java
@@ -30,11 +30,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-/**
- * 绠$悊鍚庡彴 - MES 閿�鍞��璐х浉鍏�
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - MES 閿�鍞��璐у崟琛�")
@RestController
@RequestMapping("/mes/wm/return-sales-line")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/MesWmSnController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/MesWmSnController.java
index 63d5afe..7b14295 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/MesWmSnController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/MesWmSnController.java
@@ -65,8 +65,19 @@
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
- buildGroupItemInfo(pageResult.getList());
+ buildSnGroupItemVO(pageResult.getList());
return success(pageResult);
+ }
+
+ @GetMapping("/list-by-uuid")
+ @Operation(summary = "鑾峰緱鎵规 SN 鐮佹槑缁嗗垪琛�")
+ @Parameter(name = "uuid", description = "鎵规 UUID", required = true)
+ @PreAuthorize("@ss.hasPermission('mes:wm-sn:query')")
+ public CommonResult<List<MesWmSnRespVO>> getSnListByUuid(
+ @RequestParam("uuid") @NotBlank(message = "鎵规 UUID 涓嶈兘涓虹┖") String uuid) {
+ List<MesWmSnRespVO> list = BeanUtils.toBean(snService.getSnListByUuid(uuid), MesWmSnRespVO.class);
+ buildSnItemVO(list);
+ return success(list);
}
@DeleteMapping("/delete-batch")
@@ -85,7 +96,7 @@
public void exportSnGroupExcel(@Valid MesWmSnPageReqVO reqVO, HttpServletResponse response) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<MesWmSnGroupRespVO> list = snService.getSnGroupPage(reqVO).getList();
- buildGroupItemInfo(list);
+ buildSnGroupItemVO(list);
ExcelUtils.write(response, "SN鐮佸垎缁�.xls", "鏁版嵁", MesWmSnGroupRespVO.class, list);
}
@@ -96,13 +107,13 @@
@ApiAccessLog(operateType = EXPORT)
public void exportSnExcel(@RequestParam("uuid") String uuid, HttpServletResponse response) throws IOException {
List<MesWmSnRespVO> list = BeanUtils.toBean(snService.getSnListByUuid(uuid), MesWmSnRespVO.class);
- buildItemInfo(list);
+ buildSnItemVO(list);
ExcelUtils.write(response, "SN鐮佹槑缁�.xls", "鏁版嵁", MesWmSnRespVO.class, list);
}
// ==================== 鎷兼帴 VO ====================
- private void buildGroupItemInfo(List<MesWmSnGroupRespVO> list) {
+ private void buildSnGroupItemVO(List<MesWmSnGroupRespVO> list) {
if (CollUtil.isEmpty(list)) {
return;
}
@@ -115,7 +126,7 @@
}));
}
- private void buildItemInfo(List<MesWmSnRespVO> list) {
+ private void buildSnItemVO(List<MesWmSnRespVO> list) {
if (CollUtil.isEmpty(list)) {
return;
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java
index a1affa9..578cfd9 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workorder/MesProWorkOrderDO.java
@@ -131,10 +131,6 @@
*/
private Integer status;
/**
- * BPM 娴佺▼瀹炰緥缂栧彿
- */
- private String processInstanceId;
- /**
* 澶囨敞
*/
private String remark;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/template/MesQcTemplateMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/template/MesQcTemplateMapper.java
index 29242fe..3c7280a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/template/MesQcTemplateMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/template/MesQcTemplateMapper.java
@@ -24,7 +24,7 @@
.likeIfPresent(MesQcTemplateDO::getName, reqVO.getName())
.orderByDesc(MesQcTemplateDO::getId);
if (reqVO.getType() != null) {
- query.apply(MyBatisUtils.findInSet("types", reqVO.getType()));
+ query.apply(MyBatisUtils.findInSet("types"), reqVO.getType());
}
query.eqIfPresent(MesQcTemplateDO::getStatus, reqVO.getStatus());
return selectPage(reqVO, query);
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/barcode/MesWmBarcodeMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/barcode/MesWmBarcodeMapper.java
index d361912..3c851e9 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/barcode/MesWmBarcodeMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/barcode/MesWmBarcodeMapper.java
@@ -7,6 +7,8 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.barcode.MesWmBarcodeDO;
import org.apache.ibatis.annotations.Mapper;
+import java.util.Collection;
+
/**
* MES 鏉$爜娓呭崟 Mapper
*
@@ -43,4 +45,10 @@
return selectCount(MesWmBarcodeDO::getConfigId, configId);
}
+ default int deleteByBizTypeAndBizIds(Integer bizType, Collection<Long> bizIds) {
+ return delete(new LambdaQueryWrapperX<MesWmBarcodeDO>()
+ .eq(MesWmBarcodeDO::getBizType, bizType)
+ .inIfPresent(MesWmBarcodeDO::getBizId, bizIds));
+ }
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
index 1181d4a..14c22c2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -263,8 +263,6 @@
ErrorCode PRO_WORK_ORDER_NOT_CONFIRMED = new ErrorCode(1_040_502_003, "鍙湁宸茬‘璁ょ姸鎬佺殑宸ュ崟鎵嶈兘鎵ц姝ゆ搷浣�");
ErrorCode PRO_WORK_ORDER_HAS_CHILDREN = new ErrorCode(1_040_502_004, "瀛樺湪瀛愬伐鍗曪紝鏃犳硶鍒犻櫎");
ErrorCode PRO_WORK_ORDER_PRODUCT_MISMATCH = new ErrorCode(1_040_502_005, "褰撳墠浜у搧鐗╂枡涓庣敓浜у伐鍗曚骇鍝佷笉涓�鑷�");
- ErrorCode PRO_WORK_ORDER_SUBMIT_FAIL_NOT_PREPARE = new ErrorCode(1_040_502_006, "宸ュ崟鎻愪氦澶辫触锛屽彧鏈夎崏绋跨姸鎬佺殑宸ュ崟鎵嶈兘鎻愪氦");
- ErrorCode PRO_WORK_ORDER_UPDATE_AUDIT_STATUS_FAIL_NOT_AUDITING = new ErrorCode(1_040_502_007, "宸ュ崟瀹℃壒鐘舵�佹洿鏂板け璐ワ紝宸ュ崟涓嶅浜庡鎵逛腑");
ErrorCode PRO_WORK_ORDER_BOM_NOT_EXISTS = new ErrorCode(1_040_502_100, "鐢熶骇宸ュ崟BOM涓嶅瓨鍦�");
// ========== MES 鐢熶骇绠$悊-鐢熶骇浠诲姟锛�1-040-503-000锛� ==========
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
index 2bef47c..518f5b5 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
@@ -29,6 +29,7 @@
public static final int WM_STOCK = 106; // 搴撳瓨锛歁esWmMaterialStockDO
public static final int WM_BATCH = 107; // 鎵规锛歁esWmBatchDO
public static final int WM_TRANSACTION = 108; // 搴撳瓨浜嬪姟娴佹按锛歁esWmTransactionDO
+ public static final int WM_SN = 109; // SN 鐮侊細MesWmSnDO
public static final int WM_ITEM_RECEIPT_IN = 110; // 閲囪喘鍏ュ簱锛歁esWmItemReceiptDO
public static final int WM_TRANSFER_OUT = 111; // 璋冩嫧鍑哄簱锛歁esWmTransferDO
public static final int WM_TRANSFER_IN = 112; // 璋冩嫧鍏ュ簱锛歁esWmTransferDO
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java
index 075dd53..d1e8262 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderStatusEnum.java
@@ -22,33 +22,23 @@
*/
PREPARE(0, "鑽夌"),
/**
- * 瀹℃壒涓�
- *
- * 瀵瑰簲 MesProWorkOrderService#submitWorkOrder 鏂规硶
- */
- AUDITING(1, "瀹℃壒涓�"),
- /**
* 宸茬‘璁�
*
- * 瀵瑰簲 MesProWorkOrderService#confirmWorkOrder 鏂规硶锛堝鎵归�氳繃鍚庤嚜鍔ㄧ‘璁わ級
+ * 瀵瑰簲 MesProWorkOrderService#confirmWorkOrder 鏂规硶
*/
- CONFIRMED(2, "宸茬‘璁�"),
+ CONFIRMED(1, "宸茬‘璁�"),
/**
* 宸插畬鎴�
*
* 瀵瑰簲 MesProWorkOrderService#finishWorkOrder 鏂规硶
*/
- FINISHED(3, "宸插畬鎴�"),
+ FINISHED(2, "宸插畬鎴�"),
/**
* 宸插彇娑�
*
* 瀵瑰簲 MesProWorkOrderService#cancelWorkOrder 鏂规硶
*/
- CANCELED(4, "宸插彇娑�"),
- /**
- * 瀹℃壒涓嶉�氳繃
- */
- REJECTED(5, "瀹℃壒涓嶉�氳繃");
+ CANCELED(3, "宸插彇娑�");
public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProWorkOrderStatusEnum::getStatus).toArray(Integer[]::new);
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/BarcodeBizTypeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/BarcodeBizTypeEnum.java
index 4b25d41..ae1cf3b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/BarcodeBizTypeEnum.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/BarcodeBizTypeEnum.java
@@ -22,6 +22,7 @@
PACKAGE(MesBizTypeConstants.WM_PACKAGE, "瑁呯鍗�"),
STOCK(MesBizTypeConstants.WM_STOCK, "搴撳瓨"),
BATCH(MesBizTypeConstants.WM_BATCH, "鎵规"),
+ SN(MesBizTypeConstants.WM_SN, "SN 鐮�"),
PROCARD(MesBizTypeConstants.PRO_CARD, "娴佽浆鍗�"),
WORKORDER(MesBizTypeConstants.PRO_WORKORDER, "宸ュ崟"),
TRANSORDER(MesBizTypeConstants.PRO_TRANS_ORDER, "娴佽浆鍗�"),
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
index 25cf9ae..13bd663 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
@@ -32,6 +32,8 @@
@Validated
public class MesMdAutoCodeRecordServiceImpl implements MesMdAutoCodeRecordService {
+ private static final int GENERATE_MAX_RETRY_COUNT = 10;
+
@Resource
private MesMdAutoCodeRecordMapper recordMapper;
@@ -63,10 +65,34 @@
throw exception(AUTO_CODE_GENERATE_FAILED);
}
- // 2.1 鏋勫缓涓婁笅鏂�
- MesMdAutoCodeContext context = new MesMdAutoCodeContext()
- .setRule(rule).setParts(parts).setInputChar(inputChar);
- // 2.2 閬嶅巻鍒嗘锛岀敓鎴愮紪鐮�
+ // 2. 寰幆鐢熸垚缂栫爜锛岃烦杩囧洜 Redis 娴佹按鍙疯惤鍚庡鑷寸殑鍘嗗彶閲嶅缂栫爜
+ for (int i = 0; i < GENERATE_MAX_RETRY_COUNT; i++) {
+ // 2.1 鐢熸垚缂栫爜
+ MesMdAutoCodeContext context = new MesMdAutoCodeContext()
+ .setRule(rule).setParts(parts).setInputChar(inputChar);
+ String result = generateCode(rule, parts, context);
+ // 2.2 浜屾鏍¢獙锛堥槻姝㈤噸澶嶏級
+ MesMdAutoCodeRecordDO existRecord = recordMapper.selectByResult(result);
+ if (existRecord != null) {
+ continue;
+ }
+ // 2.3 淇濆瓨鐢熸垚璁板綍
+ MesMdAutoCodeRecordDO record = new MesMdAutoCodeRecordDO()
+ .setRuleId(rule.getId()).setResult(result)
+ .setSerialNo(context.getSerialNo()).setInputChar(inputChar);
+ recordMapper.insert(record);
+ return result;
+ }
+
+ // 3. 閲嶈瘯澶氭鍚庝粛鐒跺け璐ワ紝鎶涘嚭寮傚父
+ throw exception(AUTO_CODE_GENERATE_FAILED);
+ }
+
+ /**
+ * 鐢熸垚缂栫爜
+ */
+ private String generateCode(MesMdAutoCodeRuleDO rule, List<MesMdAutoCodePartDO> parts,
+ MesMdAutoCodeContext context) {
StringBuilder codeBuilder = new StringBuilder();
for (MesMdAutoCodePartDO part : parts) {
MesMdAutoCodePartStrategy strategy = strategyMap.get(part.getType());
@@ -78,22 +104,11 @@
// 鎷兼帴鍒嗘缂栫爜
codeBuilder.append(partCode);
}
- // 2.3 琛ラ綈澶勭悊
+ // 琛ラ綈澶勭悊
String result = codeBuilder.toString();
if (Boolean.TRUE.equals(rule.getPadded()) && rule.getMaxLength() != null) {
result = padCode(result, rule);
}
-
- // 3.1 浜屾鏍¢獙锛堥槻姝㈤噸澶嶏級
- MesMdAutoCodeRecordDO existRecord = recordMapper.selectByResult(result);
- if (existRecord != null) {
- throw exception(AUTO_CODE_GENERATE_FAILED);
- }
- // 3.2 淇濆瓨鐢熸垚璁板綍
- MesMdAutoCodeRecordDO record = new MesMdAutoCodeRecordDO()
- .setRuleId(rule.getId()).setResult(result)
- .setSerialNo(context.getSerialNo()).setInputChar(inputChar);
- recordMapper.insert(record);
return result;
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
index 7585be0..81f2dee 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
@@ -6,8 +6,6 @@
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportExcelVO;
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemPageReqVO;
@@ -40,10 +38,6 @@
/**
* MES 鐗╂枡浜у搧 Service 瀹炵幇绫�
*
- * 鏀归�犺鏄庯細MES 鐗╂枡涓绘暟鎹潵婧愪簬 MDM
- * - getItem/getItemList/validateItemExists 璋冪敤 MDM API
- * - MES 鐗规湁閰嶇疆锛堟壒娆¢厤缃�丅OM銆丼OP銆丼IP锛変繚鐣欏湪 MES 妯″潡绠$悊
- *
* @author 鑺嬮亾婧愮爜
*/
@Service
@@ -52,9 +46,6 @@
@Resource
private MesMdItemMapper itemMapper;
-
- @Resource
- private MdmItemApi mdmItemApi;
@Resource
private MesMdItemTypeService itemTypeService;
@@ -156,14 +147,20 @@
@Override
public MesMdItemDO validateItemExists(Long id) {
- MdmItemRespDTO item = mdmItemApi.validateItemExists(id).getCheckedData();
- return BeanUtils.toBean(item, MesMdItemDO.class);
+ MesMdItemDO item = itemMapper.selectById(id);
+ if (item == null) {
+ throw exception(MD_ITEM_NOT_EXISTS);
+ }
+ return item;
}
@Override
public MesMdItemDO validateItemExistsAndEnable(Long id) {
- MdmItemRespDTO item = mdmItemApi.validateItemExistsAndEnable(id).getCheckedData();
- return BeanUtils.toBean(item, MesMdItemDO.class);
+ MesMdItemDO item = validateItemExists(id);
+ if (ObjUtil.notEqual(CommonStatusEnum.ENABLE.getStatus(), item.getStatus())) {
+ throw exception(MD_ITEM_IS_DISABLE);
+ }
+ return item;
}
private void validateItemCodeUnique(Long id, String code) {
@@ -242,18 +239,21 @@
@Override
public MesMdItemDO getItem(Long id) {
- // 浠� MDM 鑾峰彇鐗╂枡涓绘暟鎹�
- MdmItemRespDTO item = mdmItemApi.getItem(id).getCheckedData();
- return BeanUtils.toBean(item, MesMdItemDO.class);
+ return itemMapper.selectById(id);
}
@Override
public PageResult<MesMdItemDO> getItemPage(MesMdItemPageReqVO pageReqVO) {
- // 璋冪敤 MDM API 鍒嗛〉鏌ヨ锛圡ES 鐗╂枡瀵瑰簲 MDM 鐗╂枡绫诲瀷=鐗╂枡锛�
- cn.iocoder.yudao.framework.common.pojo.PageResult<MdmItemRespDTO> mdmPageResult =
- mdmItemApi.getItemPage(1, pageReqVO.getStatus(), pageReqVO.getPageNo(), pageReqVO.getPageSize()).getCheckedData();
- List<MesMdItemDO> itemList = BeanUtils.toBean(mdmPageResult.getList(), MesMdItemDO.class);
- return new PageResult<>(itemList, mdmPageResult.getTotal());
+ // 鏌ユ壘鏃讹紝濡傛灉鏌ユ壘鏌愪釜鍒嗙被缂栧彿锛屽垯鍖呭惈瀹冪殑瀛愬垎绫�
+ Set<Long> itemTypeIds = null;
+ if (pageReqVO.getItemTypeId() != null) {
+ itemTypeIds = new HashSet<>();
+ itemTypeIds.add(pageReqVO.getItemTypeId());
+ List<MesMdItemTypeDO> children = itemTypeService.getItemTypeChildrenList(pageReqVO.getItemTypeId());
+ itemTypeIds.addAll(convertSet(children, MesMdItemTypeDO::getId));
+ }
+ // 鍒嗛〉鏌ヨ
+ return itemMapper.selectPage(pageReqVO, itemTypeIds);
}
@Override
@@ -261,19 +261,17 @@
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
}
- List<MdmItemRespDTO> itemList = mdmItemApi.getItemList(ids).getCheckedData();
- return BeanUtils.toBean(itemList, MesMdItemDO.class);
+ return itemMapper.selectByIds(ids);
}
@Override
public Long getItemCountByItemTypeId(Long itemTypeId) {
- // MES 鍒嗙被闇�瑕佹槧灏勫埌 MDM 鍒嗙被
- return mdmItemApi.getItemCountByCategoryId(itemTypeId).getCheckedData();
+ return itemMapper.selectCountByItemTypeId(itemTypeId);
}
@Override
public Long getItemCountByUnitMeasureId(Long unitMeasureId) {
- return mdmItemApi.getItemCountByUnitMeasureId(unitMeasureId).getCheckedData();
+ return itemMapper.selectCountByUnitMeasureId(unitMeasureId);
}
@Override
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java
index 58822ef..31d2581 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderService.java
@@ -122,22 +122,6 @@
void cancelWorkOrder(Long id);
/**
- * 鎻愪氦宸ュ崟瀹℃壒
- *
- * @param id 缂栧彿
- * @param userId 鐢ㄦ埛缂栧彿
- */
- void submitWorkOrder(Long id, Long userId);
-
- /**
- * 鏇存柊宸ュ崟鐨勫鎵圭姸鎬�
- *
- * @param id 缂栧彿
- * @param bpmResult BPM 瀹℃壒缁撴灉
- */
- void updateWorkOrderAuditStatus(Long id, Integer bpmResult);
-
- /**
* 绱姞宸ュ崟鐨勫凡鐢熶骇鏁伴噺
*
* @param id 宸ュ崟缂栧彿
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java
index 67f0159..99332dd 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderServiceImpl.java
@@ -4,8 +4,6 @@
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
-import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemBatchConfigDO;
@@ -18,7 +16,6 @@
import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -39,13 +36,7 @@
*/
@Service
@Validated
-@Slf4j
public class MesProWorkOrderServiceImpl implements MesProWorkOrderService {
-
- /**
- * BPM 鐢熶骇宸ュ崟瀹℃壒娴佺▼鏍囪瘑
- */
- public static final String BPM_PROCESS_DEFINITION_KEY = "mes-pro-work-order-audit";
@Resource
private MesProWorkOrderMapper workOrderMapper;
@@ -60,9 +51,6 @@
private MesWmBarcodeService barcodeService;
@Resource
private MesProTaskService taskService;
-
- @Resource
- private BpmProcessInstanceApi bpmProcessInstanceApi;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -260,69 +248,6 @@
@Override
public Long getWorkOrderCountByVendorId(Long vendorId) {
return workOrderMapper.selectCountByVendorId(vendorId);
- }
-
- // ==================== BPM 娴佺▼瀹℃壒 ====================
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void submitWorkOrder(Long id, Long userId) {
- // 1. 鏍¢獙宸ュ崟澶勪簬鑽夌鐘舵��
- MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
- if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.PREPARE.getStatus())) {
- throw exception(PRO_WORK_ORDER_SUBMIT_FAIL_NOT_PREPARE);
- }
-
- // 2. 鍒涘缓鐢熶骇宸ュ崟瀹℃壒娴佺▼瀹炰緥
- String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
- .setProcessDefinitionKey(BPM_PROCESS_DEFINITION_KEY)
- .setBusinessKey(String.valueOf(id)));
-
- // 3. 鏇存柊宸ュ崟宸ヤ綔娴佺紪鍙枫�佺姸鎬佷负瀹℃壒涓�
- workOrderMapper.updateById(new MesProWorkOrderDO()
- .setId(id)
- .setProcessInstanceId(processInstanceId)
- .setStatus(MesProWorkOrderStatusEnum.AUDITING.getStatus()));
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void updateWorkOrderAuditStatus(Long id, Integer bpmResult) {
- // 1. 鏍¢獙宸ュ崟瀛樺湪
- MesProWorkOrderDO workOrder = validateWorkOrderExists(id);
-
- // 2. 鏍¢獙宸ュ崟澶勪簬瀹℃壒涓�
- if (ObjUtil.notEqual(workOrder.getStatus(), MesProWorkOrderStatusEnum.AUDITING.getStatus())) {
- log.error("[updateWorkOrderAuditStatus][workOrder({}) 涓嶅浜庡鎵逛腑锛屾棤娉曟洿鏂板鎵圭粨鏋�({})]",
- workOrder.getId(), bpmResult);
- throw exception(PRO_WORK_ORDER_UPDATE_AUDIT_STATUS_FAIL_NOT_AUDITING);
- }
-
- // 3. 鏇存柊宸ュ崟瀹℃壒缁撴灉
- Integer auditStatus = convertBpmResultToWorkOrderStatus(bpmResult);
- workOrderMapper.updateById(new MesProWorkOrderDO()
- .setId(id)
- .setStatus(auditStatus));
- }
-
- /**
- * 灏� BPM 瀹℃壒缁撴灉杞崲涓� MES 宸ュ崟鐘舵��
- *
- * @param bpmResult BPM 瀹℃壒缁撴灉
- * @return MES 宸ュ崟鐘舵��
- */
- private Integer convertBpmResultToWorkOrderStatus(Integer bpmResult) {
- // BPM 瀹℃壒缁撴灉锛�2=閫氳繃锛�3=涓嶉�氳繃锛�4=宸插彇娑�
- if (bpmResult == 2) {
- return MesProWorkOrderStatusEnum.CONFIRMED.getStatus();
- } else if (bpmResult == 3) {
- return MesProWorkOrderStatusEnum.REJECTED.getStatus();
- } else if (bpmResult == 4) {
- return MesProWorkOrderStatusEnum.PREPARE.getStatus();
- } else {
- log.warn("[convertBpmResultToWorkOrderStatus][鏈煡鐨� BPM 瀹℃壒缁撴灉({})]", bpmResult);
- return MesProWorkOrderStatusEnum.AUDITING.getStatus();
- }
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/listener/MesProWorkOrderStatusListener.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/listener/MesProWorkOrderStatusListener.java
deleted file mode 100644
index cd1b809..0000000
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/listener/MesProWorkOrderStatusListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.module.mes.service.pro.workorder.listener;
-
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
-import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
-import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
-import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderServiceImpl;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Component;
-
-/**
- * 鐢熶骇宸ュ崟瀹℃壒鐨勭粨鏋滅殑鐩戝惉鍣ㄥ疄鐜扮被
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Component
-public class MesProWorkOrderStatusListener extends BpmProcessInstanceStatusEventListener {
-
- @Resource
- private MesProWorkOrderService workOrderService;
-
- @Override
- public String getProcessDefinitionKey() {
- return MesProWorkOrderServiceImpl.BPM_PROCESS_DEFINITION_KEY;
- }
-
- @Override
- protected void onEvent(BpmProcessInstanceStatusEvent event) {
- workOrderService.updateWorkOrderAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordService.java
index 3d0acce..2a9f836 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordService.java
@@ -36,6 +36,14 @@
void deleteDefectRecord(Long id);
/**
+ * 鑾峰緱璐ㄦ缂洪櫡璁板綍
+ *
+ * @param id 缂栧彿
+ * @return 璐ㄦ缂洪櫡璁板綍
+ */
+ MesQcDefectRecordDO getDefectRecord(Long id);
+
+ /**
* 鑾峰緱璐ㄦ缂洪櫡璁板綍鍒嗛〉
*
* @param pageReqVO 鍒嗛〉鏌ヨ
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordServiceImpl.java
index 49c76d3..c007080 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defectrecord/MesQcDefectRecordServiceImpl.java
@@ -107,6 +107,11 @@
}
@Override
+ public MesQcDefectRecordDO getDefectRecord(Long id) {
+ return defectRecordMapper.selectById(id);
+ }
+
+ @Override
public PageResult<MesQcDefectRecordDO> getDefectRecordPage(MesQcDefectRecordPageReqVO pageReqVO) {
return defectRecordMapper.selectPage(pageReqVO);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeService.java
index a70cb3e..a420dfa 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeService.java
@@ -6,6 +6,8 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.barcode.MesWmBarcodeDO;
import jakarta.validation.Valid;
+import java.util.Collection;
+
/**
* MES 鏉$爜娓呭崟 Service 鎺ュ彛
*
@@ -36,6 +38,14 @@
void deleteBarcode(Long id);
/**
+ * 鍩轰簬涓氬姟绫诲瀷鍜屼笟鍔$紪鍙锋暟缁勶紝鍒犻櫎鏉$爜
+ *
+ * @param bizType 涓氬姟绫诲瀷
+ * @param bizIds 涓氬姟缂栧彿鏁扮粍
+ */
+ void deleteBarcodeByBizTypeAndBizIds(Integer bizType, Collection<Long> bizIds);
+
+ /**
* 鑾峰緱鏉$爜
*
* @param id 缂栧彿
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java
index d2d826f..2320ceb 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/barcode/MesWmBarcodeServiceImpl.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.service.wm.barcode;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@@ -13,6 +14,8 @@
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+
+import java.util.Collection;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -165,6 +168,14 @@
barcodeMapper.deleteById(id);
}
+ @Override
+ public void deleteBarcodeByBizTypeAndBizIds(Integer bizType, Collection<Long> bizIds) {
+ if (CollUtil.isEmpty(bizIds)) {
+ return;
+ }
+ barcodeMapper.deleteByBizTypeAndBizIds(bizType, bizIds);
+ }
+
private MesWmBarcodeDO validateBarcodeExists(Long id) {
MesWmBarcodeDO barcode = barcodeMapper.selectById(id);
if (barcode == null) {
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java
index 0f9ebed..e07b1c4 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.service.wm.sn;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGenerateReqVO;
@@ -8,9 +9,11 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.sn.MesWmSnDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.sn.MesWmSnMapper;
import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
+import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -19,6 +22,8 @@
import java.util.ArrayList;
import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
/**
* MES SN 鐮� Service 瀹炵幇绫�
@@ -39,6 +44,8 @@
private MesMdItemService itemService;
@Resource
private MesProWorkOrderService workOrderService;
+ @Resource
+ private MesWmBarcodeService barcodeService;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -62,6 +69,9 @@
}
// 鎵归噺鎻掑叆
snMapper.insertBatch(sns);
+ // 鑷姩鐢熸垚鏉$爜
+ sns.forEach(sn -> barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.SN.getValue(),
+ sn.getId(), sn.getCode(), sn.getCode()));
}
@Override
@@ -77,7 +87,16 @@
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteSnByUuid(String uuid) {
+ List<MesWmSnDO> sns = snMapper.selectListByUuid(uuid);
+ if (CollUtil.isEmpty(sns)) {
+ return;
+ }
+
+ // 鍒犻櫎 SN 鐮佸叧鑱旂殑鏉$爜璁板綍
+ barcodeService.deleteBarcodeByBizTypeAndBizIds(BarcodeBizTypeEnum.SN.getValue(),
+ convertList(sns, MesWmSnDO::getId));
+ // 鍒犻櫎 SN 鐮�
snMapper.deleteByUuid(uuid);
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java
index a566df9..275e13c 100644
--- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImplTest.java
@@ -99,6 +99,42 @@
}
@Test
+ public void testGenerateAutoCode_retryWhenResultExists() {
+ // 鍑嗗鍙傛暟
+ String ruleCode = "DV_MACHINERY_CODE";
+ MesMdAutoCodeRuleDO rule = new MesMdAutoCodeRuleDO().setId(5L).setCode(ruleCode).setPadded(false);
+ MesMdAutoCodePartDO part1 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.FIXED_CHAR.getType())
+ .setFixCharacter("M").setLength(1).setSort(1);
+ MesMdAutoCodePartDO part2 = new MesMdAutoCodePartDO().setType(MesMdAutoCodePartTypeEnum.SERIAL_NUMBER.getType())
+ .setSerialStartNo(1).setSerialStep(1).setLength(5).setSort(2).setCycleFlag(false);
+ // mock
+ when(ruleService.getAutoCodeRuleByCode(ruleCode)).thenReturn(rule);
+ when(partService.getAutoCodePartListByRuleId(5L)).thenReturn(Arrays.asList(part1, part2));
+ when(fixedCharStrategy.generate(eq(part1), any(MesMdAutoCodeContext.class))).thenReturn("M");
+ long[] serialNoRef = {0L};
+ when(serialNumberStrategy.generate(eq(part2), any(MesMdAutoCodeContext.class))).thenAnswer(invocation -> {
+ MesMdAutoCodeContext context = invocation.getArgument(1);
+ long serialNo = ++serialNoRef[0];
+ context.setSerialNo(serialNo);
+ return String.format("%05d", serialNo);
+ });
+ when(recordMapper.selectByResult("M00001")).thenReturn(new MesMdAutoCodeRecordDO());
+ when(recordMapper.selectByResult("M00002")).thenReturn(new MesMdAutoCodeRecordDO());
+ when(recordMapper.selectByResult("M00003")).thenReturn(null);
+
+ // 璋冪敤
+ String result = recordService.generateAutoCode(ruleCode, null);
+ // 鏂█
+ assertEquals("M00003", result);
+ ArgumentCaptor<MesMdAutoCodeRecordDO> captor = ArgumentCaptor.forClass(MesMdAutoCodeRecordDO.class);
+ verify(recordMapper).insert(captor.capture());
+ MesMdAutoCodeRecordDO record = captor.getValue();
+ assertEquals(5L, record.getRuleId());
+ assertEquals("M00003", record.getResult());
+ assertEquals(3L, record.getSerialNo());
+ }
+
+ @Test
public void testGenerateAutoCode_withInputChar() {
// 鍑嗗鍙傛暟
String ruleCode = "CLIENT_CODE";
diff --git a/yudao-module-mp/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java b/yudao-module-mp/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java
index 0f68baf..f6a8d6d 100644
--- a/yudao-module-mp/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java
+++ b/yudao-module-mp/src/main/java/cn/iocoder/yudao/module/mp/service/handler/user/SubscribeHandler.java
@@ -43,7 +43,7 @@
} catch (WxErrorException e) {
log.error("[handle][绮変笣({})] 鑾峰彇绮変笣淇℃伅澶辫触锛�", wxMessage.getFromUser(), e);
// 鐗规畩鎯呭喌锛堜釜浜鸿处鍙凤紝鏃犳帴鍙f潈闄愶級锛歨ttps://t.zsxq.com/cLFq5
- if (ObjUtil.equal(e.getError().getErrorCode(), WxMpErrorMsgEnum.CODE_48001)) {
+ if (ObjUtil.equal(e.getError().getErrorCode(), WxMpErrorMsgEnum.CODE_48001.getCode())) {
wxMpUser = new WxMpUser();
wxMpUser.setOpenId(wxMessage.getFromUser());
wxMpUser.setSubscribe(true);
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/PayChannelController.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/PayChannelController.java
index b7b0aed..95d8d27 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/PayChannelController.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/channel/PayChannelController.java
@@ -71,6 +71,15 @@
return success(PayChannelConvert.INSTANCE.convert(channel));
}
+ @GetMapping("/list")
+ @Operation(summary = "鑾峰緱鎸囧畾搴旂敤鐨勬敮浠樻笭閬撳垪琛�")
+ @Parameter(name = "appId", description = "搴旂敤缂栧彿", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('pay:channel:query')")
+ public CommonResult<List<PayChannelRespVO>> getChannelList(@RequestParam("appId") Long appId) {
+ List<PayChannelDO> list = channelService.getChannelListByAppId(appId);
+ return success(PayChannelConvert.INSTANCE.convertList(list));
+ }
+
@GetMapping("/get-enable-code-list")
@Operation(summary = "鑾峰緱鎸囧畾搴旂敤鐨勫紑鍚殑鏀粯娓犻亾缂栫爜鍒楄〃")
@Parameter(name = "appId", description = "搴旂敤缂栧彿", required = true, example = "1")
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java
index 6d47f9a..98283d9 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java
@@ -19,9 +19,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
-/**
- * @author jason
- */
@Tag(name = "鐢ㄦ埛 APP - 閽卞寘")
@RestController
@RequestMapping("/pay/wallet")
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/convert/channel/PayChannelConvert.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/convert/channel/PayChannelConvert.java
index 5baf598..97ea284 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/convert/channel/PayChannelConvert.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/convert/channel/PayChannelConvert.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.pay.convert.channel;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelRespVO;
import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO;
@@ -8,6 +9,8 @@
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
+
+import java.util.List;
@Mapper
public interface PayChannelConvert {
@@ -23,6 +26,15 @@
@Mapping(target = "config",expression = "java(cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString(bean.getConfig()))")
PayChannelRespVO convert(PayChannelDO bean);
+ default List<PayChannelRespVO> convertList(List<PayChannelDO> list) {
+ // 鍒楄〃涓嶄笅鍙� config锛堝瘑閽�/璇佷功锛夛紝璇︽儏鎺ュ彛鍐嶈繑鍥炲畬鏁撮厤缃�
+ return CollectionUtils.convertList(list, channel -> {
+ PayChannelRespVO vo = convert(channel);
+ vo.setConfig(null);
+ return vo;
+ });
+ }
+
PageResult<PayChannelRespVO> convertPage(PageResult<PayChannelDO> page);
}
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/channel/PayChannelMapper.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/channel/PayChannelMapper.java
index e698498..ad54cd1 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/channel/PayChannelMapper.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/channel/PayChannelMapper.java
@@ -28,4 +28,8 @@
.eq(PayChannelDO::getStatus, status));
}
+ default List<PayChannelDO> selectListByAppId(Long appId) {
+ return selectList(PayChannelDO::getAppId, appId);
+ }
+
}
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
index 59e6b3e..b6fb5f3 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/transfer/PayTransferMapper.java
@@ -26,6 +26,14 @@
.eq(PayTransferDO::getStatus, whereStatus));
}
+ default int updateChannelPackageInfoIfAbsent(Long id, String channelPackageInfo) {
+ return update(new PayTransferDO().setChannelPackageInfo(channelPackageInfo),
+ new LambdaQueryWrapper<PayTransferDO>()
+ .eq(PayTransferDO::getId, id)
+ .and(wrapper -> wrapper.isNull(PayTransferDO::getChannelPackageInfo)
+ .or().eq(PayTransferDO::getChannelPackageInfo, "")));
+ }
+
default PayTransferDO selectByAppIdAndMerchantOrderId(Long appId, String merchantOrderId) {
return selectOne(PayTransferDO::getAppId, appId,
PayTransferDO::getMerchantTransferId, merchantOrderId);
@@ -59,7 +67,3 @@
}
}
-
-
-
-
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
index 3b54862..ab986ef 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
@@ -74,6 +74,9 @@
}
// 鐗规畩锛氬己鍒朵娇鐢ㄥ井淇″叕閽ユā寮忥紝閬垮厤鐏板害鏈熼棿鐨勯棶棰橈紒锛侊紒
payConfig.setStrictlyNeedWechatPaySerial(true);
+ // 鐗规畩锛歸eixin-java-pay 鍙湁閰嶇疆 publicKeyPath 鍚庯紝鍐嶅紑鍚� fullPublicKeyModel锛屾墠浼氫娇鐢� PublicCertificateVerifier
+ // 瀵瑰簲 https://t.zsxq.com/5Q9lO 甯栧瓙
+ payConfig.setFullPublicKeyModel(true);
}
// 鍒涘缓 client 瀹㈡埛绔�
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelService.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelService.java
index c397986..1dccf62 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelService.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelService.java
@@ -94,6 +94,14 @@
List<PayChannelDO> getEnableChannelList(Long appId);
/**
+ * 鑾峰緱鎸囧畾搴旂敤鐨勬笭閬撳垪琛�
+ *
+ * @param appId 搴旂敤缂栧彿
+ * @return 娓犻亾鍒楄〃
+ */
+ List<PayChannelDO> getChannelListByAppId(Long appId);
+
+ /**
* 鑾峰緱鎸囧畾缂栧彿鐨勬敮浠樺鎴风
*
* @param id 缂栧彿
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
index 63d0f26..234fcaf 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
@@ -157,6 +157,11 @@
}
@Override
+ public List<PayChannelDO> getChannelListByAppId(Long appId) {
+ return payChannelMapper.selectListByAppId(appId);
+ }
+
+ @Override
public PayClient getPayClient(Long id) {
PayChannelDO channel = validPayChannel(id);
return payClientFactory.createOrUpdatePayClient(id, channel.getCode(), channel.getConfig());
diff --git a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
index 8f123f8..e2edb15 100644
--- a/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
+++ b/yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java
@@ -2,6 +2,7 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@@ -162,6 +163,7 @@
throw exception(PAY_TRANSFER_NOT_FOUND);
}
if (PayTransferStatusEnum.isProcessing(transfer.getStatus())) { // 濡傛灉宸茬粡鏄浆璐︿腑锛岀洿鎺ヨ繑鍥烇紝涓嶇敤閲嶅鏇存柊
+ updateChannelPackageInfoIfAbsent(transfer, notify);
log.info("[notifyTransferProgressing][transfer({}) 宸茬粡鏄浆璐︿腑鐘舵�侊紝鏃犻渶鏇存柊]", transfer.getId());
return;
}
@@ -175,11 +177,35 @@
new PayTransferDO().setStatus(PayTransferStatusEnum.PROCESSING.getStatus())
.setChannelPackageInfo(notify.getChannelPackageInfo()));
if (updateCounts == 0) {
+ PayTransferDO latestTransfer = transferMapper.selectById(transfer.getId());
+ if (latestTransfer != null && PayTransferStatusEnum.isProcessing(latestTransfer.getStatus())) {
+ updateChannelPackageInfoIfAbsent(latestTransfer, notify);
+ log.info("[notifyTransferProgressing][transfer({}) 宸茶骞跺彂鏇存柊涓鸿浆璐︿腑鐘舵�侊紝鏃犻渶閲嶅鏇存柊]",
+ transfer.getId());
+ return;
+ }
throw exception(PAY_TRANSFER_NOTIFY_FAIL_STATUS_IS_NOT_WAITING);
}
log.info("[notifyTransferProgressing][transfer({}) 鏇存柊涓鸿浆璐﹁繘琛屼腑鐘舵�乚", transfer.getId());
}
+ /**
+ * 琛ュ厖娓犻亾 package 淇℃伅锛氬鐞嗗悓姝ヤ换鍔″厛鏇存柊涓鸿浆璐︿腑锛屽彂璧疯浆璐︽帴鍙e悗杩斿洖 channelPackageInfo 鐨勫満鏅�
+ *
+ * @see <a href="https://github.com/YunaiV/ruoyi-vue-pro/issues/1144">Issue #1144</a>
+ */
+ private void updateChannelPackageInfoIfAbsent(PayTransferDO transfer, PayTransferRespDTO notify) {
+ if (StrUtil.isBlank(notify.getChannelPackageInfo())
+ || StrUtil.isNotBlank(transfer.getChannelPackageInfo())) {
+ return;
+ }
+ int updateCount = transferMapper.updateChannelPackageInfoIfAbsent(transfer.getId(),
+ notify.getChannelPackageInfo());
+ if (updateCount > 0) {
+ log.info("[updateChannelPackageInfoIfAbsent][transfer({}) 琛ュ厖娓犻亾 package 淇℃伅]", transfer.getId());
+ }
+ }
+
private void notifyTransferSuccess(PayChannelDO channel, PayTransferRespDTO notify) {
// 1. 鏍¢獙鐘舵��
PayTransferDO transfer = transferMapper.selectByAppIdAndNo(channel.getAppId(), notify.getOutTransferNo());
diff --git a/yudao-module-pay/src/test/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceTest.java b/yudao-module-pay/src/test/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceTest.java
new file mode 100644
index 0000000..26bd189
--- /dev/null
+++ b/yudao-module-pay/src/test/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceTest.java
@@ -0,0 +1,91 @@
+package cn.iocoder.yudao.module.pay.service.transfer;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
+import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
+import cn.iocoder.yudao.module.pay.dal.dataobject.transfer.PayTransferDO;
+import cn.iocoder.yudao.module.pay.dal.mysql.transfer.PayTransferMapper;
+import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
+import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
+import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
+import cn.iocoder.yudao.module.pay.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
+import cn.iocoder.yudao.module.pay.service.app.PayAppService;
+import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
+import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
+
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * {@link PayTransferServiceImpl} 鐨勫崟鍏冩祴璇曠被
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Import({PayTransferServiceImpl.class, PayNoRedisDAO.class})
+public class PayTransferServiceTest extends BaseDbAndRedisUnitTest {
+
+ @Resource
+ private PayTransferServiceImpl transferService;
+
+ @Resource
+ private PayTransferMapper transferMapper;
+
+ @MockitoBean
+ private PayProperties payProperties;
+ @MockitoBean
+ private PayAppService appService;
+ @MockitoBean
+ private PayChannelService channelService;
+ @MockitoBean
+ private PayNotifyService notifyService;
+
+ @Test
+ public void testNotifyTransferProgressing_fillChannelPackageInfoIfAbsent() {
+ // mock 鏁版嵁锛圥ayTransferDO锛夛細鍚屾浠诲姟鍏堟妸 WAITING 鏇存柊涓� PROCESSING锛屼絾鏄笉杩斿洖 package 淇℃伅
+ PayTransferDO transfer = randomPojo(PayTransferDO.class,
+ o -> o.setAppId(10L)
+ .setNo("T110")
+ .setStatus(PayTransferStatusEnum.PROCESSING.getStatus())
+ .setChannelPackageInfo(null));
+ transferMapper.insert(transfer);
+ // 鍑嗗鍙傛暟
+ PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setAppId(10L));
+ PayTransferRespDTO createNotify = PayTransferRespDTO.processingOf("WX_TRANSFER_110",
+ "T110", "create");
+ createNotify.setChannelPackageInfo("package-info-110");
+
+ // 璋冪敤锛氭ā鎷熷彂璧疯浆璐︽帴鍙i殢鍚庤繑鍥� PROCESSING锛屽苟鎼哄甫寰俊纭鏀舵 package 淇℃伅
+ transferService.notifyTransfer(channel, createNotify);
+
+ // 鏂█锛氬凡鏄� PROCESSING 鏃朵粛浼氳ˉ鍐� package 淇℃伅
+ PayTransferDO dbTransfer = transferMapper.selectById(transfer.getId());
+ assertEquals(PayTransferStatusEnum.PROCESSING.getStatus(), dbTransfer.getStatus());
+ assertEquals("package-info-110", dbTransfer.getChannelPackageInfo());
+ }
+
+ @Test
+ public void testNotifyTransferProgressing_notOverwriteChannelPackageInfo() {
+ // mock 鏁版嵁锛圥ayTransferDO锛夛細宸茬粡瀛樺湪 package 淇℃伅
+ PayTransferDO transfer = randomPojo(PayTransferDO.class,
+ o -> o.setAppId(10L)
+ .setNo("T110")
+ .setStatus(PayTransferStatusEnum.PROCESSING.getStatus())
+ .setChannelPackageInfo("package-info-110"));
+ transferMapper.insert(transfer);
+ // 鍑嗗鍙傛暟
+ PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setAppId(10L));
+ PayTransferRespDTO syncNotify = PayTransferRespDTO.processingOf("WX_TRANSFER_110",
+ "T110", "sync");
+
+ // 璋冪敤锛氬悗缁悓姝ヤ换鍔′笉杩斿洖 package 淇℃伅
+ transferService.notifyTransfer(channel, syncNotify);
+
+ // 鏂█锛氬凡鏈� package 淇℃伅涓嶈绌哄�艰鐩�
+ PayTransferDO dbTransfer = transferMapper.selectById(transfer.getId());
+ assertEquals("package-info-110", dbTransfer.getChannelPackageInfo());
+ }
+
+}
diff --git a/yudao-module-pay/src/test/resources/sql/create_tables.sql b/yudao-module-pay/src/test/resources/sql/create_tables.sql
index 6af612f..a3df280 100644
--- a/yudao-module-pay/src/test/resources/sql/create_tables.sql
+++ b/yudao-module-pay/src/test/resources/sql/create_tables.sql
@@ -165,12 +165,14 @@
`user_name` varchar(64) NULL DEFAULT NULL,
`status` tinyint(4) NOT NULL,
`notify_url` varchar(1024) NULL DEFAULT NULL,
+ `user_ip` varchar(50) NULL DEFAULT NULL,
`channel_transfer_no` varchar(64) NULL DEFAULT NULL,
`success_time` datetime(0) NULL DEFAULT NULL,
`channel_error_code` varchar(128) NULL DEFAULT NULL,
`channel_error_msg` varchar(256) NULL DEFAULT NULL,
`channel_notify_data` varchar(1024) NULL DEFAULT NULL,
`channel_extras` varchar(1024) NULL DEFAULT NULL,
+ `channel_package_info` varchar(1024) NULL DEFAULT NULL,
`creator` varchar(64) NULL DEFAULT '',
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updater` varchar(64) NULL DEFAULT '',
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/message/user/AdminUserProfileUpdateMessage.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/message/user/AdminUserProfileUpdateMessage.java
new file mode 100644
index 0000000..13f3cc6
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/message/user/AdminUserProfileUpdateMessage.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.system.api.message.user;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * 绠$悊鍛樼敤鎴疯祫鏂欙紙鏄电О / 澶村儚锛夊彉鏇存秷鎭�
+ * <p>
+ * 浠呭綋 nickname 鎴� avatar 鐪熺殑鍙戠敓鍙樺寲鏃舵墠鍙戦�侊紱璁㈤槄鏂规嵁姝ゅ仛涓嬫父鍒嗗彂锛�
+ * 渚嬪 IM 妯″潡鍚戣鐢ㄦ埛鐨勬墍鏈夊ソ鍙嬫帹閫� FRIEND_INFO_UPDATED 閫氱煡
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class AdminUserProfileUpdateMessage {
+
+ /**
+ * 鐢ㄦ埛缂栧彿
+ */
+ @NotNull(message = "鐢ㄦ埛缂栧彿涓嶈兘涓虹┖")
+ private Long userId;
+ /**
+ * 鍙樻洿鍚庣殑鏄电О锛堟棤鍙樻洿鏃朵负 null锛�
+ */
+ private String nickname;
+ /**
+ * 鍙樻洿鍚庣殑澶村儚锛堟棤鍙樻洿鏃朵负 null锛�
+ */
+ private String avatar;
+
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApi.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApi.java
index 309c9ef..c09e9cf 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApi.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApi.java
@@ -1,6 +1,11 @@
package cn.iocoder.yudao.module.system.api.permission;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.system.api.permission.dto.RoleRespDTO;
+
import java.util.Collection;
+import java.util.List;
+import java.util.Map;
/**
* 瑙掕壊 API 鎺ュ彛
@@ -18,4 +23,31 @@
*/
void validRoleList(Collection<Long> ids);
+ /**
+ * 鑾峰緱瑙掕壊淇℃伅
+ *
+ * @param id 瑙掕壊缂栧彿
+ * @return 瑙掕壊淇℃伅
+ */
+ RoleRespDTO getRole(Long id);
+
+ /**
+ * 鑾峰緱瑙掕壊淇℃伅鏁扮粍
+ *
+ * @param ids 瑙掕壊缂栧彿鏁扮粍
+ * @return 瑙掕壊淇℃伅鏁扮粍
+ */
+ List<RoleRespDTO> getRoleList(Collection<Long> ids);
+
+ /**
+ * 鑾峰緱鎸囧畾缂栧彿鐨勮鑹� Map
+ *
+ * @param ids 瑙掕壊缂栧彿鏁扮粍
+ * @return 瑙掕壊 Map
+ */
+ default Map<Long, RoleRespDTO> getRoleMap(Collection<Long> ids) {
+ List<RoleRespDTO> list = getRoleList(ids);
+ return CollectionUtils.convertMap(list, RoleRespDTO::getId);
+ }
+
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApiImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApiImpl.java
index 6b75606..ed1bb3a 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApiImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/RoleApiImpl.java
@@ -1,10 +1,14 @@
package cn.iocoder.yudao.module.system.api.permission;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.system.api.permission.dto.RoleRespDTO;
+import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.util.Collection;
+import java.util.List;
/**
* 瑙掕壊 API 瀹炵幇绫�
@@ -21,4 +25,16 @@
public void validRoleList(Collection<Long> ids) {
roleService.validateRoleList(ids);
}
+
+ @Override
+ public RoleRespDTO getRole(Long id) {
+ RoleDO role = roleService.getRole(id);
+ return BeanUtils.toBean(role, RoleRespDTO.class);
+ }
+
+ @Override
+ public List<RoleRespDTO> getRoleList(Collection<Long> ids) {
+ List<RoleDO> list = roleService.getRoleList(ids);
+ return BeanUtils.toBean(list, RoleRespDTO.class);
+ }
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/dto/RoleRespDTO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/dto/RoleRespDTO.java
new file mode 100644
index 0000000..e119e3f
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/permission/dto/RoleRespDTO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.system.api.permission.dto;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import lombok.Data;
+
+/**
+ * 瑙掕壊 Response DTO
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Data
+public class RoleRespDTO {
+
+ /**
+ * 瑙掕壊缂栧彿
+ */
+ private Long id;
+ /**
+ * 瑙掕壊鍚嶇О
+ */
+ private String name;
+ /**
+ * 瑙掕壊缂栫爜
+ */
+ private String code;
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ private Integer sort;
+ /**
+ * 瑙掕壊鐘舵��
+ *
+ * 鏋氫妇 {@link CommonStatusEnum}
+ */
+ private Integer status;
+
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java
index 507fb4b..0092b27 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java
@@ -56,6 +56,14 @@
List<AdminUserRespDTO> getUserListByPostIds(Collection<Long> postIds);
/**
+ * 鏍规嵁鏄电О妯$硦鎼滅储鐢ㄦ埛
+ *
+ * @param nickname 鏄电О鍏抽敭璇�
+ * @return 鐢ㄦ埛鍒楄〃
+ */
+ List<AdminUserRespDTO> getUserListByNickname(String nickname);
+
+ /**
* 鑾峰緱鐢ㄦ埛 Map
*
* @param ids 鐢ㄦ埛缂栧彿鏁扮粍
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java
index 9876e3a..8bf1e19 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java
@@ -81,6 +81,12 @@
}
@Override
+ public List<AdminUserRespDTO> getUserListByNickname(String nickname) {
+ List<AdminUserDO> users = userService.getUserListByNickname(nickname);
+ return BeanUtils.toBean(users, AdminUserRespDTO.class);
+ }
+
+ @Override
public void validateUserList(Collection<Long> ids) {
userService.validateUserList(ids);
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java
index 52ac150..2b8d586 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.controller.admin.mail;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -80,10 +81,11 @@
return success(BeanUtils.toBean(pageResult, MailTemplateRespVO.class));
}
- @GetMapping({"/list-all-simple", "simple-list"})
- @Operation(summary = "鑾峰緱閭欢妯$増绮剧畝鍒楄〃")
- public CommonResult<List<MailTemplateSimpleRespVO>> getSimpleTemplateList() {
- List<MailTemplateDO> list = mailTempleService.getMailTemplateList();
+ @GetMapping({"/list-all-simple", "/simple-list"})
+ @Operation(summary = "鑾峰緱閭欢妯$増绮剧畝鍒楄〃", description = "鍙寘鍚寮�鍚殑閭欢妯$増锛屼富瑕佺敤浜庡墠绔殑涓嬫媺閫夐」")
+ public CommonResult<List<MailTemplateSimpleRespVO>> getSimpleMailTemplateList() {
+ List<MailTemplateDO> list = mailTempleService.getMailTemplateListByStatus(
+ CommonStatusEnum.ENABLE.getStatus());
return success(BeanUtils.toBean(list, MailTemplateSimpleRespVO.class));
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java
index 29833ff..a2003aa 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/MailTemplateSimpleRespVO.java
@@ -13,4 +13,7 @@
@Schema(description = "妯$増鍚嶅瓧", requiredMode = Schema.RequiredMode.REQUIRED, example = "鍝掑搾鍝�")
private String name;
+ @Schema(description = "妯$増缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "mail_001")
+ private String code;
+
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java
index a4a0003..0aed501 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/NotifyTemplateController.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.system.controller.admin.notify;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -8,6 +9,7 @@
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateRespVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateSendReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.notify.vo.template.NotifyTemplateSimpleRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import cn.iocoder.yudao.module.system.service.notify.NotifySendService;
import cn.iocoder.yudao.module.system.service.notify.NotifyTemplateService;
@@ -86,6 +88,14 @@
return success(BeanUtils.toBean(pageResult, NotifyTemplateRespVO.class));
}
+ @GetMapping({"/list-all-simple", "/simple-list"})
+ @Operation(summary = "鑾峰緱绔欏唴淇℃ā鐗堢簿绠�鍒楄〃", description = "鍙寘鍚寮�鍚殑绔欏唴淇℃ā鐗堬紝涓昏鐢ㄤ簬鍓嶇鐨勪笅鎷夐�夐」")
+ public CommonResult<List<NotifyTemplateSimpleRespVO>> getSimpleNotifyTemplateList() {
+ List<NotifyTemplateDO> list = notifyTemplateService.getNotifyTemplateListByStatus(
+ CommonStatusEnum.ENABLE.getStatus());
+ return success(BeanUtils.toBean(list, NotifyTemplateSimpleRespVO.class));
+ }
+
@PostMapping("/send-notify")
@Operation(summary = "鍙戦�佺珯鍐呬俊")
@PreAuthorize("@ss.hasPermission('system:notify-template:send-notify')")
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSimpleRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSimpleRespVO.java
new file mode 100644
index 0000000..b48e6ca
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/template/NotifyTemplateSimpleRespVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.system.controller.admin.notify.vo.template;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 绔欏唴淇℃ā鐗堢殑绮剧畝 Response VO")
+@Data
+public class NotifyTemplateSimpleRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "妯$増鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "绯荤粺閫氱煡")
+ private String name;
+
+ @Schema(description = "妯$増缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "notify_001")
+ private String code;
+
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java
index a7b7325..147ce82 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/PermissionController.java
@@ -20,11 +20,6 @@
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-/**
- * 鏉冮檺 Controller锛屾彁渚涜祴浜堢敤鎴枫�佽鑹茬殑鏉冮檺鐨� API 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
@Tag(name = "绠$悊鍚庡彴 - 鏉冮檺")
@RestController
@RequestMapping("/system/permission")
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java
index 8ffd4bb..0bd3bcc 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsTemplateController.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.sms;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -10,6 +11,7 @@
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateRespVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSendReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSimpleRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
import cn.iocoder.yudao.module.system.service.sms.SmsTemplateService;
@@ -88,6 +90,14 @@
return success(BeanUtils.toBean(pageResult, SmsTemplateRespVO.class));
}
+ @GetMapping({"/list-all-simple", "/simple-list"})
+ @Operation(summary = "鑾峰緱鐭俊妯℃澘绮剧畝鍒楄〃", description = "鍙寘鍚寮�鍚殑鐭俊妯℃澘锛屼富瑕佺敤浜庡墠绔殑涓嬫媺閫夐」")
+ public CommonResult<List<SmsTemplateSimpleRespVO>> getSimpleSmsTemplateList() {
+ List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateListByStatus(
+ CommonStatusEnum.ENABLE.getStatus());
+ return success(BeanUtils.toBean(list, SmsTemplateSimpleRespVO.class));
+ }
+
@GetMapping("/export-excel")
@Operation(summary = "瀵煎嚭鐭俊妯℃澘 Excel")
@PreAuthorize("@ss.hasPermission('system:sms-template:export')")
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSimpleRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSimpleRespVO.java
new file mode 100644
index 0000000..44cb882
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/template/SmsTemplateSimpleRespVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.system.controller.admin.sms.vo.template;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 鐭俊妯℃澘鐨勭簿绠� Response VO")
+@Data
+public class SmsTemplateSimpleRespVO {
+
+ @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "妯℃澘鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "楠岃瘉鐮�")
+ private String name;
+
+ @Schema(description = "妯℃澘缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "sms_001")
+ private String code;
+
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
index 820c132..7cb7d78 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.user;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
@@ -29,6 +30,7 @@
import java.io.IOException;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -130,8 +132,16 @@
@GetMapping({"/list-all-simple", "/simple-list"})
@Operation(summary = "鑾峰彇鐢ㄦ埛绮剧畝淇℃伅鍒楄〃", description = "鍙寘鍚寮�鍚殑鐢ㄦ埛锛屼富瑕佺敤浜庡墠绔殑涓嬫媺閫夐」")
- public CommonResult<List<UserSimpleRespVO>> getSimpleUserList() {
- List<AdminUserDO> list = userService.getUserListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ public CommonResult<List<UserSimpleRespVO>> getSimpleUserList(
+ @RequestParam(value = "deptId", required = false) Long deptId) {
+ List<AdminUserDO> list;
+ if (deptId != null) {
+ List<Long> deptIds = Collections.singletonList(deptId);
+ list = userService.getDeptUsers(deptIds);
+ } else {
+ list = userService.getUserListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ }
+
// 鎷兼帴鏁版嵁
Map<Long, DeptDO> deptMap = deptService.getDeptMap(
convertList(list, AdminUserDO::getDeptId));
@@ -194,4 +204,34 @@
return success(userService.importUserList(list, updateSupport));
}
+ // ==================== 鍏嶉壌鏉冩帴鍙o紙鐢ㄤ簬 IM 鐐瑰ご鍍忓脊鍚嶇墖銆佸姞濂藉弸鎼滅储绛夊満鏅級 ====================
+
+ @GetMapping("/get-simple")
+ @Operation(summary = "鑾峰緱鐢ㄦ埛绮剧畝淇℃伅", description = "鐢ㄤ簬鐐瑰ご鍍忓脊鍚嶇墖绛夊満鏅紱鍏嶉壌鏉�")
+ @Parameter(name = "id", description = "鐢ㄦ埛缂栧彿", required = true, example = "1024")
+ public CommonResult<UserSimpleRespVO> getSimpleUser(@RequestParam("id") Long id) {
+ AdminUserDO user = userService.getUser(id);
+ if (user == null) {
+ return success(null);
+ }
+ // 鎷兼帴鏁版嵁
+ DeptDO dept = user.getDeptId() != null ? deptService.getDept(user.getDeptId()) : null;
+ Map<Long, DeptDO> deptMap = dept != null ? Collections.singletonMap(dept.getId(), dept) : Collections.emptyMap();
+ return success(CollUtil.getFirst(UserConvert.INSTANCE.convertSimpleList(
+ Collections.singletonList(user), deptMap)));
+ }
+
+ @GetMapping("/list-by-nickname")
+ @Operation(summary = "鎸夋樀绉版ā绯婃悳绱㈢敤鎴风簿绠�淇℃伅", description = "鐢ㄤ簬鍔犲ソ鍙嬬瓑鍦烘櫙锛涘厤閴存潈锛涘綋鍓嶄粎鎸夋樀绉板尮閰�")
+ @Parameter(name = "nickname", description = "鏄电О鍏抽敭璇�", required = true, example = "鑺嬮亾")
+ public CommonResult<List<UserSimpleRespVO>> getSimpleUserListByNickname(@RequestParam("nickname") String nickname) {
+ if (StrUtil.isBlank(nickname)) {
+ return success(Collections.emptyList());
+ }
+ // 鎷兼帴鏁版嵁
+ List<AdminUserDO> list = userService.getUserListByNickname(nickname.trim());
+ Map<Long, DeptDO> deptMap = deptService.getDeptMap(convertList(list, AdminUserDO::getDeptId));
+ return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap));
+ }
+
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSimpleRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSimpleRespVO.java
index 6dac286..3d19d67 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSimpleRespVO.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSimpleRespVO.java
@@ -17,6 +17,11 @@
@Schema(description = "鐢ㄦ埛鏄电О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鑺嬮亾")
private String nickname;
+ @Schema(description = "澶村儚")
+ private String avatar;
+ @Schema(description = "鎬у埆", example = "1")
+ private Integer sex;
+
@Schema(description = "閮ㄩ棬ID", example = "鎴戞槸涓�涓敤鎴�")
private Long deptId;
@Schema(description = "閮ㄩ棬鍚嶇О", example = "IT 閮�")
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java
index 44fab07..fe2ed48 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailLogMapper.java
@@ -21,7 +21,7 @@
.eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus())
.betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime())
.apply(StrUtil.isNotBlank(reqVO.getToMail()),
- MyBatisUtils.findInSet("to_mails", reqVO.getToMail()))
+ MyBatisUtils.findInSet("to_mails"), reqVO.getToMail())
.orderByDesc(MailLogDO::getId));
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java
index 1730e58..24911df 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/mail/MailTemplateMapper.java
@@ -7,6 +7,8 @@
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
@Mapper
public interface MailTemplateMapper extends BaseMapperX<MailTemplateDO> {
@@ -28,4 +30,8 @@
return selectOne(MailTemplateDO::getCode, code);
}
+ default List<MailTemplateDO> selectListByStatus(Integer status) {
+ return selectList(MailTemplateDO::getStatus, status);
+ }
+
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java
index 1fcb8ee..d5ea599 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyTemplateMapper.java
@@ -7,6 +7,8 @@
import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
@Mapper
public interface NotifyTemplateMapper extends BaseMapperX<NotifyTemplateDO> {
@@ -23,4 +25,8 @@
.orderByDesc(NotifyTemplateDO::getId));
}
+ default List<NotifyTemplateDO> selectListByStatus(Integer status) {
+ return selectList(NotifyTemplateDO::getStatus, status);
+ }
+
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java
index a9a1ebb..af69597 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/sms/SmsTemplateMapper.java
@@ -7,6 +7,8 @@
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
@Mapper
public interface SmsTemplateMapper extends BaseMapperX<SmsTemplateDO> {
@@ -30,4 +32,8 @@
return selectCount(SmsTemplateDO::getChannelId, channelId);
}
+ default List<SmsTemplateDO> selectListByStatus(Integer status) {
+ return selectList(SmsTemplateDO::getStatus, status);
+ }
+
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java
index a58b057..c3e5ae3 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantMapper.java
@@ -29,7 +29,7 @@
default List<TenantDO> selectListByWebsite(String website) {
return selectList(new LambdaQueryWrapperX<TenantDO>()
- .apply(MyBatisUtils.findInSet("websites", website)));
+ .apply(MyBatisUtils.findInSet("websites"), website));
}
default Long selectCountByPackageId(Long packageId) {
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/QiniuSmsClient.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/QiniuSmsClient.java
index 41ba95b..500b3ed 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/QiniuSmsClient.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/QiniuSmsClient.java
@@ -2,7 +2,6 @@
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
@@ -10,6 +9,7 @@
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
@@ -120,7 +120,7 @@
.setSuccess("DELIVRD".equals(statusObj.getStr("status"))) // 鏄惁鎺ユ敹鎴愬姛
.setErrorMsg(statusObj.getStr("status")) // 鐘舵�佹姤鍛婄紪鐮�
.setMobile(statusObj.getStr("mobile")) // 鎵嬫満鍙�
- .setReceiveTime(LocalDateTimeUtil.of(statusObj.getLong("delivrd_at") * 1000L)) // 鐘舵�佹姤鍛婃椂闂�
+ .setReceiveTime(LocalDateTimeUtils.ofEpochSecond(statusObj.getLong("delivrd_at"))) // 鐘舵�佹姤鍛婃椂闂�
.setSerialNo(statusObj.getStr("message_id")) // 鍙戦�佸簭鍒楀彿
.setLogId(statusObj.getLong("seq")); // 鐢ㄦ埛搴忓垪鍙�
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/social/config/YudaoWxClientConfiguration.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/social/config/YudaoWxClientConfiguration.java
deleted file mode 100644
index 40bebc8..0000000
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/social/config/YudaoWxClientConfiguration.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package cn.iocoder.yudao.module.system.framework.social.config;
-
-import cn.binarywang.wx.miniapp.config.WxMaConfig;
-import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
-import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
-import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
-import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
-import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
-import me.chanjar.weixin.common.redis.WxRedisOps;
-import me.chanjar.weixin.mp.config.WxMpConfigStorage;
-import me.chanjar.weixin.mp.config.WxMpHostConfig;
-import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
-import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.data.redis.core.StringRedisTemplate;
-
-/**
- * WxJava Boot 4 compatibility: bypass starter storage config that still initializes Apache HttpClient 4 builders.
- */
-@Configuration(proxyBeanMethods = false)
-@Slf4j
-public class YudaoWxClientConfiguration {
-
- @Bean
- @ConditionalOnProperty(prefix = WxMpProperties.PREFIX + ".config-storage", name = "type", havingValue = "redistemplate")
- @ConditionalOnClass(StringRedisTemplate.class)
- @ConditionalOnMissingBean(WxMpConfigStorage.class)
- public WxMpConfigStorage wxMpConfigStorage(WxMpProperties properties, ApplicationContext applicationContext) {
- StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
- WxRedisOps redisOps = new RedisTemplateWxRedisOps(redisTemplate);
- WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(redisOps, properties.getConfigStorage().getKeyPrefix());
- applyWxMpConfig(config, properties);
- log.debug("[wxMpConfigStorage][using local Boot 4 compatible WxJava config]");
- return config;
- }
-
- @Bean
- @ConditionalOnProperty(prefix = WxMaProperties.PREFIX + ".config-storage", name = "type", havingValue = "redistemplate")
- @ConditionalOnClass(StringRedisTemplate.class)
- @ConditionalOnMissingBean(WxMaConfig.class)
- public WxMaConfig wxMaConfig(WxMaProperties properties, ApplicationContext applicationContext) {
- StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
- WxRedisOps redisOps = new RedisTemplateWxRedisOps(redisTemplate);
- WxMaRedisBetterConfigImpl config = new WxMaRedisBetterConfigImpl(redisOps, properties.getConfigStorage().getKeyPrefix());
- applyWxMaConfig(config, properties);
- log.debug("[wxMaConfig][using local Boot 4 compatible WxJava config]");
- return config;
- }
-
- private void applyWxMpConfig(WxMpDefaultConfigImpl config, WxMpProperties properties) {
- config.setAppId(properties.getAppId());
- config.setSecret(properties.getSecret());
- config.setToken(properties.getToken());
- config.setAesKey(properties.getAesKey());
- config.setUseStableAccessToken(properties.isUseStableAccessToken());
-
- WxMpProperties.ConfigStorage storage = properties.getConfigStorage();
- config.setHttpProxyHost(storage.getHttpProxyHost());
- config.setHttpProxyUsername(storage.getHttpProxyUsername());
- config.setHttpProxyPassword(storage.getHttpProxyPassword());
- if (storage.getHttpProxyPort() != null) {
- config.setHttpProxyPort(storage.getHttpProxyPort());
- }
-
- if (properties.getHosts() != null && StringUtils.isNotEmpty(properties.getHosts().getApiHost())) {
- WxMpHostConfig hostConfig = new WxMpHostConfig();
- hostConfig.setApiHost(properties.getHosts().getApiHost());
- hostConfig.setOpenHost(properties.getHosts().getOpenHost());
- hostConfig.setMpHost(properties.getHosts().getMpHost());
- config.setHostConfig(hostConfig);
- }
- }
-
- private void applyWxMaConfig(WxMaDefaultConfigImpl config, WxMaProperties properties) {
- WxMaProperties.ConfigStorage storage = properties.getConfigStorage();
- config.setAppid(StringUtils.trimToNull(properties.getAppid()));
- config.setSecret(StringUtils.trimToNull(properties.getSecret()));
- config.setToken(StringUtils.trimToNull(properties.getToken()));
- config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
- config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
- config.useStableAccessToken(properties.isUseStableAccessToken());
- config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
- config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
-
- config.setHttpProxyHost(storage.getHttpProxyHost());
- config.setHttpProxyUsername(storage.getHttpProxyUsername());
- config.setHttpProxyPassword(storage.getHttpProxyPassword());
- if (storage.getHttpProxyPort() != null) {
- config.setHttpProxyPort(storage.getHttpProxyPort());
- }
-
- config.setRetrySleepMillis(Math.max(storage.getRetrySleepMillis(), 1000));
- config.setMaxRetryTimes(Math.max(storage.getMaxRetryTimes(), 0));
- }
-
-}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/weixin/config/YudaoWxClientConfiguration.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/weixin/config/YudaoWxClientConfiguration.java
new file mode 100644
index 0000000..f36e9b0
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/weixin/config/YudaoWxClientConfiguration.java
@@ -0,0 +1,111 @@
+package cn.iocoder.yudao.module.system.framework.weixin.config;
+
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
+import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
+import me.chanjar.weixin.common.redis.WxRedisOps;
+import me.chanjar.weixin.mp.config.WxMpConfigStorage;
+import me.chanjar.weixin.mp.config.WxMpHostConfig;
+import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
+import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+/**
+ * 寰俊鍏紬鍙枫�佸皬绋嬪簭锛坵eixin-java锛夌殑閰嶇疆绫�
+ *
+ * weixin-java 4.8.x 鐨� {@code AbstractWxMpConfigStorageConfiguration} / {@code AbstractWxMaConfigStorageConfiguration}
+ * 鍦ㄥ垵濮嬪寲 config storage 鏃讹紝浼氭棤鏉′欢璋冪敤 {@code DefaultApacheHttpClientBuilder.get()}锛屽悗鑰呭湪绫诲姞杞芥椂寮曠敤
+ * Apache HttpClient 4.x 鐨� {@code org.apache.http.ssl.TrustStrategy} 绛夌被锛屽鑷村惎鍔ㄦ姤
+ * {@code NoClassDefFoundError}锛圫pring Boot 4.x / 鏂扮増 Spring Cloud Alibaba 涓嶅啀浼犻�� HttpClient 4.x锛夈��
+ *
+ * 鏈厤缃被鑷鍒涘缓 {@link WxMpConfigStorage} / {@link WxMaConfig} bean锛岀粫杩囧畼鏂圭殑鍒濆鍖栭�昏緫锛�
+ * 閰嶅悎 {@code http-client-type: HttpComponents} 閰嶇疆锛屽彧渚濊禆 Apache HttpClient 5.x銆�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Configuration(proxyBeanMethods = false)
+@Slf4j
+public class YudaoWxClientConfiguration {
+
+ @Bean
+ @ConditionalOnProperty(prefix = WxMpProperties.PREFIX + ".config-storage", name = "type", havingValue = "redistemplate")
+ @ConditionalOnClass(StringRedisTemplate.class)
+ @ConditionalOnMissingBean(WxMpConfigStorage.class)
+ public WxMpConfigStorage wxMpConfigStorage(WxMpProperties properties, ApplicationContext applicationContext) {
+ StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
+ WxRedisOps redisOps = new RedisTemplateWxRedisOps(redisTemplate);
+ WxMpRedisConfigImpl config = new WxMpRedisConfigImpl(redisOps, properties.getConfigStorage().getKeyPrefix());
+ applyWxMpConfig(config, properties);
+ return config;
+ }
+
+ @Bean
+ @ConditionalOnProperty(prefix = WxMaProperties.PREFIX + ".config-storage", name = "type", havingValue = "redistemplate")
+ @ConditionalOnClass(StringRedisTemplate.class)
+ @ConditionalOnMissingBean(WxMaConfig.class)
+ public WxMaConfig wxMaConfig(WxMaProperties properties, ApplicationContext applicationContext) {
+ StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
+ WxRedisOps redisOps = new RedisTemplateWxRedisOps(redisTemplate);
+ WxMaRedisBetterConfigImpl config = new WxMaRedisBetterConfigImpl(redisOps, properties.getConfigStorage().getKeyPrefix());
+ applyWxMaConfig(config, properties);
+ return config;
+ }
+
+ private void applyWxMpConfig(WxMpDefaultConfigImpl config, WxMpProperties properties) {
+ config.setAppId(properties.getAppId());
+ config.setSecret(properties.getSecret());
+ config.setToken(properties.getToken());
+ config.setAesKey(properties.getAesKey());
+ config.setUseStableAccessToken(properties.isUseStableAccessToken());
+
+ WxMpProperties.ConfigStorage storage = properties.getConfigStorage();
+ config.setHttpProxyHost(storage.getHttpProxyHost());
+ config.setHttpProxyUsername(storage.getHttpProxyUsername());
+ config.setHttpProxyPassword(storage.getHttpProxyPassword());
+ if (storage.getHttpProxyPort() != null) {
+ config.setHttpProxyPort(storage.getHttpProxyPort());
+ }
+
+ if (properties.getHosts() != null && StringUtils.isNotEmpty(properties.getHosts().getApiHost())) {
+ WxMpHostConfig hostConfig = new WxMpHostConfig();
+ hostConfig.setApiHost(properties.getHosts().getApiHost());
+ hostConfig.setOpenHost(properties.getHosts().getOpenHost());
+ hostConfig.setMpHost(properties.getHosts().getMpHost());
+ config.setHostConfig(hostConfig);
+ }
+ }
+
+ private void applyWxMaConfig(WxMaDefaultConfigImpl config, WxMaProperties properties) {
+ WxMaProperties.ConfigStorage storage = properties.getConfigStorage();
+ config.setAppid(StringUtils.trimToNull(properties.getAppid()));
+ config.setSecret(StringUtils.trimToNull(properties.getSecret()));
+ config.setToken(StringUtils.trimToNull(properties.getToken()));
+ config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
+ config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
+ config.useStableAccessToken(properties.isUseStableAccessToken());
+ config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
+ config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
+
+ config.setHttpProxyHost(storage.getHttpProxyHost());
+ config.setHttpProxyUsername(storage.getHttpProxyUsername());
+ config.setHttpProxyPassword(storage.getHttpProxyPassword());
+ if (storage.getHttpProxyPort() != null) {
+ config.setHttpProxyPort(storage.getHttpProxyPort());
+ }
+
+ config.setRetrySleepMillis(Math.max(storage.getRetrySleepMillis(), 1000));
+ config.setMaxRetryTimes(Math.max(storage.getMaxRetryTimes(), 0));
+ }
+
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/weixin/package-info.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/weixin/package-info.java
new file mode 100644
index 0000000..70caf0f
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/weixin/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * 寰俊鍏紬鍙枫�佸皬绋嬪簭锛坵eixin-java锛夌殑鎷撳睍锛岃烦杩� httpclient 4.x 鐨勭‖渚濊禆
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+package cn.iocoder.yudao.module.system.framework.weixin;
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/user/AdminUserProducer.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/user/AdminUserProducer.java
new file mode 100644
index 0000000..4af3931
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/user/AdminUserProducer.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.system.mq.producer.user;
+
+import cn.iocoder.yudao.module.system.api.message.user.AdminUserProfileUpdateMessage;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+/**
+ * 绠$悊鍛樼敤鎴� Producer
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@Slf4j
+@Component
+public class AdminUserProducer {
+
+ @Resource
+ private ApplicationContext applicationContext;
+
+ /**
+ * 鍙戦�� {@link AdminUserProfileUpdateMessage} 娑堟伅
+ *
+ * @param userId 鐢ㄦ埛缂栧彿
+ * @param nickname 鍙樻洿鍚庣殑鏄电О锛堟棤鍙樻洿浼� null锛�
+ * @param avatar 鍙樻洿鍚庣殑澶村儚锛堟棤鍙樻洿浼� null锛�
+ */
+ public void sendUserProfileUpdateMessage(Long userId, String nickname, String avatar) {
+ applicationContext.publishEvent(new AdminUserProfileUpdateMessage()
+ .setUserId(userId).setNickname(nickname).setAvatar(avatar));
+ }
+
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java
index 0ee9e2b..49c846f 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateService.java
@@ -70,6 +70,14 @@
List<MailTemplateDO> getMailTemplateList();
/**
+ * 鑾峰彇鎸囧畾鐘舵�佺殑閭欢妯$増鏁扮粍
+ *
+ * @param status 鐘舵��
+ * @return 閭欢妯$増鏁扮粍
+ */
+ List<MailTemplateDO> getMailTemplateListByStatus(Integer status);
+
+ /**
* 浠庣紦瀛樹腑鑾峰彇閭欢妯$増
*
* @param code 妯℃澘缂栫爜
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java
index 2ee46db..2c3f413 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java
@@ -113,7 +113,9 @@
}
@Override
- public MailTemplateDO getMailTemplate(Long id) {return mailTemplateMapper.selectById(id);}
+ public MailTemplateDO getMailTemplate(Long id) {
+ return mailTemplateMapper.selectById(id);
+ }
@Override
@Cacheable(value = RedisKeyConstants.MAIL_TEMPLATE, key = "#code", unless = "#result == null")
@@ -127,7 +129,14 @@
}
@Override
- public List<MailTemplateDO> getMailTemplateList() {return mailTemplateMapper.selectList();}
+ public List<MailTemplateDO> getMailTemplateList() {
+ return mailTemplateMapper.selectList();
+ }
+
+ @Override
+ public List<MailTemplateDO> getMailTemplateListByStatus(Integer status) {
+ return mailTemplateMapper.selectListByStatus(status);
+ }
@Override
public String formatMailTemplateContent(String content, Map<String, Object> params) {
@@ -236,4 +245,4 @@
return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
}
-}
\ No newline at end of file
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java
index 2253ba9..0d9135b 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateService.java
@@ -70,6 +70,14 @@
PageResult<NotifyTemplateDO> getNotifyTemplatePage(NotifyTemplatePageReqVO pageReqVO);
/**
+ * 鑾峰緱鎸囧畾鐘舵�佺殑绔欏唴淇℃ā鐗堝垪琛�
+ *
+ * @param status 鐘舵��
+ * @return 绔欏唴淇℃ā鐗堝垪琛�
+ */
+ List<NotifyTemplateDO> getNotifyTemplateListByStatus(Integer status);
+
+ /**
* 鏍煎紡鍖栫珯鍐呬俊鍐呭
*
* @param content 绔欏唴淇℃ā鏉跨殑鍐呭
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java
index 45a832d..4b1b70d 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImpl.java
@@ -115,6 +115,11 @@
return notifyTemplateMapper.selectPage(pageReqVO);
}
+ @Override
+ public List<NotifyTemplateDO> getNotifyTemplateListByStatus(Integer status) {
+ return notifyTemplateMapper.selectListByStatus(status);
+ }
+
@VisibleForTesting
void validateNotifyTemplateCodeDuplicate(Long id, String code) {
NotifyTemplateDO template = notifyTemplateMapper.selectByCode(code);
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java
index c73f70f..f26fe7b 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateService.java
@@ -71,6 +71,14 @@
PageResult<SmsTemplateDO> getSmsTemplatePage(SmsTemplatePageReqVO pageReqVO);
/**
+ * 鑾峰緱鎸囧畾鐘舵�佺殑鐭俊妯℃澘鍒楄〃
+ *
+ * @param status 鐘舵��
+ * @return 鐭俊妯℃澘鍒楄〃
+ */
+ List<SmsTemplateDO> getSmsTemplateListByStatus(Integer status);
+
+ /**
* 鑾峰緱鎸囧畾鐭俊娓犻亾涓嬬殑鐭俊妯℃澘鏁伴噺
*
* @param channelId 鐭俊娓犻亾缂栧彿
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
index 65d2017..bf1dbb3 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
@@ -131,6 +131,11 @@
}
@Override
+ public List<SmsTemplateDO> getSmsTemplateListByStatus(Integer status) {
+ return smsTemplateMapper.selectListByStatus(status);
+ }
+
+ @Override
public Long getSmsTemplateCountByChannelId(Long channelId) {
return smsTemplateMapper.selectCountByChannelId(channelId);
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java
index 947c723..4ec9765 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java
@@ -158,6 +158,14 @@
*/
List<AdminUserDO> getUserList(Collection<Long> ids);
+
+ /**
+ * 鑾峰緱鍏ㄩ儴鐢ㄦ埛鍒楄〃
+ *
+ * @return 鐢ㄦ埛鍒楄〃
+ */
+ List<AdminUserDO> getUserListAll();
+
/**
* 鏍¢獙鐢ㄦ埛浠槸鍚︽湁鏁堛�傚涓嬫儏鍐碉紝瑙嗕负鏃犳晥锛�
* 1. 鐢ㄦ埛缂栧彿涓嶅瓨鍦�
@@ -206,6 +214,13 @@
List<AdminUserDO> getUserListByStatus(Integer status);
/**
+ * 鑾峰緱鎸囧畾閮ㄩ棬鐨勭敤鎴�
+ * @param deptIds
+ * @return
+ */
+ List<AdminUserDO> getDeptUsers(Collection<Long> deptIds);
+
+ /**
* 鍒ゆ柇瀵嗙爜鏄惁鍖归厤
*
* @param rawPassword 鏈姞瀵嗙殑瀵嗙爜
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
index 84e3bb6..c2840b8 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
@@ -25,6 +25,7 @@
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
+import cn.iocoder.yudao.module.system.mq.producer.user.AdminUserProducer;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
@@ -87,6 +88,9 @@
@Resource
private ConfigApi configApi;
+
+ @Resource
+ private AdminUserProducer adminUserProducer;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -158,6 +162,8 @@
userMapper.updateById(updateObj);
// 2.2 鏇存柊宀椾綅
updateUserPost(updateReqVO, updateObj);
+ // 2.3 鏄电О / 澶村儚鍙樺寲鏃讹紝鍙戦�佹秷鎭緵涓嬫父璁㈤槄锛堝 IM 妯″潡鎺� FRIEND_INFO_UPDATED锛�
+ publishUserProfileUpdatedIfChanged(oldUser, updateReqVO.getNickname(), updateReqVO.getAvatar());
// 3. 璁板綍鎿嶄綔鏃ュ織涓婁笅鏂�
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class));
@@ -188,12 +194,30 @@
@Override
public void updateUserProfile(Long id, UserProfileUpdateReqVO reqVO) {
- // 鏍¢獙姝g‘鎬�
- validateUserExists(id);
+ // 1. 鏍¢獙姝g‘鎬�
+ AdminUserDO oldUser = validateUserExists(id);
validateEmailUnique(id, reqVO.getEmail());
validateMobileUnique(id, reqVO.getMobile());
- // 鎵ц鏇存柊
+
+ // 2. 鎵ц鏇存柊
userMapper.updateById(BeanUtils.toBean(reqVO, AdminUserDO.class).setId(id));
+
+ // 3. 鏄电О / 澶村儚鍙樺寲鏃讹紝鍙戦�佹秷鎭緵涓嬫父璁㈤槄锛堝 IM 妯″潡鎺� FRIEND_INFO_UPDATED锛�
+ publishUserProfileUpdatedIfChanged(oldUser, reqVO.getNickname(), reqVO.getAvatar());
+ }
+
+ /**
+ * 浠呭綋 nickname 鎴� avatar 璺熸棫鍊间笉涓�鑷存椂锛屽彂閫� AdminUserProfileUpdateMessage
+ */
+ private void publishUserProfileUpdatedIfChanged(AdminUserDO oldUser, String newNickname, String newAvatar) {
+ boolean nicknameChanged = newNickname != null && !ObjUtil.equal(oldUser.getNickname(), newNickname);
+ boolean avatarChanged = newAvatar != null && !ObjUtil.equal(oldUser.getAvatar(), newAvatar);
+ if (!nicknameChanged && !avatarChanged) {
+ return;
+ }
+ adminUserProducer.sendUserProfileUpdateMessage(oldUser.getId(),
+ nicknameChanged ? newNickname : null,
+ avatarChanged ? newAvatar : null);
}
@Override
@@ -329,6 +353,11 @@
}
return userMapper.selectByIds(ids);
}
+
+ public List<AdminUserDO> getUserListAll() {
+ return userMapper.selectList();
+ }
+
@Override
public void validateUserList(Collection<Long> ids) {
@@ -535,6 +564,11 @@
}
@Override
+ public List<AdminUserDO> getDeptUsers(Collection<Long> deptIds) {
+ return userMapper.selectListByDeptIds(deptIds);
+ }
+
+ @Override
public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
return passwordEncoder.matches(rawPassword, encodedPassword);
}
diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java
index ec8aada..8817519 100644
--- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java
+++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java
@@ -160,8 +160,8 @@
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserId(2L)));
// 娴嬭瘯 userType 涓嶅尮閰�
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
- // 娴嬭瘯 toMails 涓嶅尮閰嶏紙鐗规畩锛歠ind_in_set 鏃犳硶鍗曟祴锛�
-// mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setToMails(Lists.newArrayList("788@qq.com"))));
+ // 娴嬭瘯 toMails 涓嶅尮閰�
+ mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setToMails(Lists.newArrayList("788@qq.com"))));
// 娴嬭瘯 accountId 涓嶅尮閰�
mailLogMapper.insert(cloneIgnoreId(dbMailLog, o -> o.setAccountId(11L)));
// 娴嬭瘯 templateId 涓嶅尮閰�
@@ -174,7 +174,7 @@
MailLogPageReqVO reqVO = new MailLogPageReqVO();
reqVO.setUserId(1L);
reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
-// reqVO.setToMail("768@qq.com");
+ reqVO.setToMail("768@qq.com");
reqVO.setAccountId(10L);
reqVO.setTemplateId(100L);
reqVO.setSendStatus(MailSendStatusEnum.INIT.getStatus());
diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java
index fa9b709..af0211e 100644
--- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java
+++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImplTest.java
@@ -157,6 +157,23 @@
}
@Test
+ public void testGetMailTemplateListByStatus() {
+ // mock 鏁版嵁
+ MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class,
+ o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
+ mailTemplateMapper.insert(dbMailTemplate);
+ mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate,
+ o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+
+ // 璋冪敤
+ List<MailTemplateDO> list = mailTemplateService.getMailTemplateListByStatus(
+ CommonStatusEnum.ENABLE.getStatus());
+ // 鏂█
+ assertEquals(1, list.size());
+ assertPojoEquals(dbMailTemplate, list.get(0));
+ }
+
+ @Test
public void testGetMailTemplate() {
// mock 鏁版嵁
MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class);
diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java
index ba1f98e..6217a6f 100644
--- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java
+++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifyTemplateServiceImplTest.java
@@ -12,6 +12,7 @@
import jakarta.annotation.Resource;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
@@ -137,6 +138,23 @@
}
@Test
+ public void testGetNotifyTemplateListByStatus() {
+ // mock 鏁版嵁
+ NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class,
+ o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
+ notifyTemplateMapper.insert(dbNotifyTemplate);
+ notifyTemplateMapper.insert(cloneIgnoreId(dbNotifyTemplate,
+ o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+
+ // 璋冪敤
+ List<NotifyTemplateDO> list = notifyTemplateService.getNotifyTemplateListByStatus(
+ CommonStatusEnum.ENABLE.getStatus());
+ // 鏂█
+ assertEquals(1, list.size());
+ assertPojoEquals(dbNotifyTemplate, list.get(0));
+ }
+
+ @Test
public void testGetNotifyTemplate() {
// mock 鏁版嵁
NotifyTemplateDO dbNotifyTemplate = randomPojo(NotifyTemplateDO.class);
diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
index 344f566..5847b79 100644
--- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
+++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
@@ -245,6 +245,22 @@
}
@Test
+ public void testGetSmsTemplateListByStatus() {
+ // mock 鏁版嵁
+ SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
+ smsTemplateMapper.insert(dbSmsTemplate);
+ smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate,
+ o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+
+ // 璋冪敤
+ List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateListByStatus(
+ CommonStatusEnum.ENABLE.getStatus());
+ // 鏂█
+ assertEquals(1, list.size());
+ assertPojoEquals(dbSmsTemplate, list.get(0));
+ }
+
+ @Test
public void testGetSmsTemplateCountByChannelId() {
// mock 鏁版嵁
SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> o.setChannelId(1L));
diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
index 0194072..253cbe5 100644
--- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
+++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
@@ -22,7 +22,6 @@
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
@@ -334,7 +333,6 @@
}
@Test
- @Disabled // H2 涓嶆敮鎸� find_in_set 鍑芥暟
public void testGetTenantByWebsite() {
// mock 鏁版嵁
TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setWebsites(singletonList("https://www.iocoder.cn")));
diff --git a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java
index 370ce3c..68c8510 100644
--- a/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java
+++ b/yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java
@@ -23,6 +23,7 @@
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.enums.common.SexEnum;
+import cn.iocoder.yudao.module.system.mq.producer.user.AdminUserProducer;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
@@ -85,6 +86,8 @@
private ConfigApi configApi;
@MockitoBean
private OAuth2TokenService oauth2TokenService;
+ @MockitoBean
+ private AdminUserProducer adminUserProducer;
@BeforeEach
public void before() {
diff --git a/yudao-module-wms/pom.xml b/yudao-module-wms/pom.xml
index 5b5e53c..9365862 100644
--- a/yudao-module-wms/pom.xml
+++ b/yudao-module-wms/pom.xml
@@ -24,13 +24,6 @@
<version>${revision}</version>
</dependency>
- <!-- MDM 涓绘暟鎹鐞嗘ā鍧� -->
- <dependency>
- <groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-mdm</artifactId>
- <version>${revision}</version>
- </dependency>
-
<!-- 涓氬姟缁勪欢 -->
<!-- Web 鐩稿叧 -->
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/WmsInventoryApi.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/WmsInventoryApi.java
deleted file mode 100644
index 762e5a5..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/WmsInventoryApi.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.*;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * WMS 搴撳瓨鎿嶄綔 API 鎺ュ彛
- *
- * 鎻愪緵缁� ERP銆丮ES 绛夋ā鍧楄皟鐢紝瀹炵幇璺ㄦā鍧楀簱瀛樻搷浣�
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface WmsInventoryApi {
-
- String PREFIX = "/rpc-api/wms/inventory";
-
- // ==================== 鍏ュ簱鎿嶄綔 ====================
-
- /**
- * 鍏ュ簱鎿嶄綔
- *
- * @param reqDTO 鍏ュ簱璇锋眰
- * @return 鍏ュ簱缁撴灉
- */
- CommonResult<WmsReceiptResultDTO> receipt(WmsReceiptReqDTO reqDTO);
-
- // ==================== 鍑哄簱鎿嶄綔 ====================
-
- /**
- * 鍑哄簱鎿嶄綔
- *
- * @param reqDTO 鍑哄簱璇锋眰
- * @return 鍑哄簱缁撴灉
- */
- CommonResult<WmsShipmentResultDTO> shipment(WmsShipmentReqDTO reqDTO);
-
- // ==================== 搴撳瓨棰勭暀 ====================
-
- /**
- * 搴撳瓨棰勭暀锛堥攣搴撳瓨锛�
- *
- * @param reqDTO 棰勭暀璇锋眰
- * @return 棰勭暀鍗曞彿
- */
- CommonResult<String> reserve(WmsReserveReqDTO reqDTO);
-
- /**
- * 閲婃斁搴撳瓨棰勭暀
- *
- * @param reserveNo 棰勭暀鍗曞彿
- */
- CommonResult<Boolean> releaseReserve(String reserveNo);
-
- /**
- * 浣跨敤棰勭暀搴撳瓨锛堝嚭搴撴椂鎵e噺棰勭暀锛�
- *
- * @param reqDTO 浣跨敤棰勭暀璇锋眰
- */
- CommonResult<Boolean> useReserve(WmsUseReserveReqDTO reqDTO);
-
- // ==================== 搴撳瓨鏌ヨ ====================
-
- /**
- * 鏌ヨ搴撳瓨
- *
- * @param reqDTO 鏌ヨ璇锋眰
- * @return 搴撳瓨鍒楄〃
- */
- CommonResult<List<WmsInventoryRespDTO>> getInventoryList(WmsInventoryQueryReqDTO reqDTO);
-
- /**
- * 鏌ヨ鍙敤搴撳瓨锛堟�诲簱瀛� - 棰勭暀搴撳瓨锛�
- *
- * @param skuId SKU 缂栧彿
- * @param warehouseId 浠撳簱缂栧彿
- * @return 鍙敤搴撳瓨鏁伴噺
- */
- CommonResult<BigDecimal> getAvailableQuantity(Long skuId, Long warehouseId);
-
-}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/WmsInventoryApiImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/WmsInventoryApiImpl.java
deleted file mode 100644
index 9fe4523..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/WmsInventoryApiImpl.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.*;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryTransactionDO;
-import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryMapper;
-import cn.iocoder.yudao.module.wms.enums.inventory.WmsTransactionTypeEnum;
-import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
-import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryReserveService;
-import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService;
-import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryTransactionService;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * WMS 搴撳瓨鎿嶄綔 API 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@RestController
-@RequestMapping(WmsInventoryApi.PREFIX)
-@Service
-@Validated
-@Slf4j
-public class WmsInventoryApiImpl implements WmsInventoryApi {
-
- @Resource
- private WmsInventoryService inventoryService;
-
- @Resource
- private WmsInventoryReserveService reserveService;
-
- @Resource
- private WmsInventoryTransactionService transactionService;
-
- @Resource
- private WmsInventoryMapper inventoryMapper;
-
- // ==================== 鍏ュ簱鎿嶄綔 ====================
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public CommonResult<WmsReceiptResultDTO> receipt(WmsReceiptReqDTO reqDTO) {
- // 1. 鏋勫缓搴撳瓨鍙樻洿璇锋眰
- WmsInventoryChangeReqDTO changeReq = buildInventoryChangeReq(reqDTO);
-
- // 2. 鎵ц鍏ュ簱鍙樻洿
- inventoryService.changeInventory(changeReq);
-
- // 3. 璁板綍浜嬪姟娴佹按
- List<WmsInventoryTransactionDO> transactions = buildReceiptTransactions(reqDTO);
- transactionService.createTransactionList(transactions);
-
- // 4. 鏋勫缓杩斿洖缁撴灉
- WmsReceiptResultDTO result = new WmsReceiptResultDTO();
- result.setReceiptOrderNo(generateReceiptNo());
- result.setTotalQuantity(calculateTotalQuantity(reqDTO.getItems()));
- return success(result);
- }
-
- // ==================== 鍑哄簱鎿嶄綔 ====================
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public CommonResult<WmsShipmentResultDTO> shipment(WmsShipmentReqDTO reqDTO) {
- // 1. 濡傛灉鏈夐鐣欏崟鍙凤紝鍏堜娇鐢ㄩ鐣�
- if (reqDTO.getReserveNo() != null) {
- WmsUseReserveReqDTO useReq = new WmsUseReserveReqDTO();
- useReq.setReserveNo(reqDTO.getReserveNo());
- useReq.setQuantity(calculateTotalQuantity(reqDTO.getItems()));
- reserveService.useReserve(useReq);
- }
-
- // 2. 鏋勫缓搴撳瓨鍙樻洿璇锋眰锛堝嚭搴撲负璐熸暟锛�
- WmsInventoryChangeReqDTO changeReq = buildShipmentChangeReq(reqDTO);
-
- // 3. 鎵ц鍑哄簱鍙樻洿
- inventoryService.changeInventory(changeReq);
-
- // 4. 璁板綍浜嬪姟娴佹按
- List<WmsInventoryTransactionDO> transactions = buildShipmentTransactions(reqDTO);
- transactionService.createTransactionList(transactions);
-
- // 5. 鏋勫缓杩斿洖缁撴灉
- WmsShipmentResultDTO result = new WmsShipmentResultDTO();
- result.setShipmentOrderNo(generateShipmentNo());
- result.setTotalQuantity(calculateTotalQuantity(reqDTO.getItems()));
- return success(result);
- }
-
- // ==================== 搴撳瓨棰勭暀 ====================
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public CommonResult<String> reserve(WmsReserveReqDTO reqDTO) {
- return success(reserveService.createReserve(reqDTO));
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public CommonResult<Boolean> releaseReserve(String reserveNo) {
- reserveService.releaseReserve(reserveNo);
- return success(true);
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public CommonResult<Boolean> useReserve(WmsUseReserveReqDTO reqDTO) {
- reserveService.useReserve(reqDTO);
- return success(true);
- }
-
- // ==================== 搴撳瓨鏌ヨ ====================
-
- @Override
- public CommonResult<List<WmsInventoryRespDTO>> getInventoryList(WmsInventoryQueryReqDTO reqDTO) {
- // 1. 鏌ヨ搴撳瓨
- List<WmsInventoryDO> inventories = inventoryMapper.selectListByQuery(reqDTO);
-
- // 2. 杞崲缁撴灉
- List<WmsInventoryRespDTO> results = new ArrayList<>();
- for (WmsInventoryDO inventory : inventories) {
- WmsInventoryRespDTO resp = BeanUtils.toBean(inventory, WmsInventoryRespDTO.class);
- // 璁$畻棰勭暀鏁伴噺
- BigDecimal reserveQuantity = reserveService.getReserveQuantity(
- inventory.getSkuId(), inventory.getWarehouseId());
- resp.setReserveQuantity(reserveQuantity);
- resp.setAvailableQuantity(inventory.getQuantity().subtract(reserveQuantity));
- results.add(resp);
- }
- return success(results);
- }
-
- @Override
- public CommonResult<BigDecimal> getAvailableQuantity(Long skuId, Long warehouseId) {
- return success(inventoryService.getAvailableQuantity(skuId, warehouseId));
- }
-
- // ==================== 绉佹湁鏂规硶 ====================
-
- private WmsInventoryChangeReqDTO buildInventoryChangeReq(WmsReceiptReqDTO reqDTO) {
- WmsInventoryChangeReqDTO changeReq = new WmsInventoryChangeReqDTO();
- changeReq.setOrderType(reqDTO.getBizType());
- changeReq.setOrderNo(reqDTO.getBizNo());
-
- List<WmsInventoryChangeReqDTO.Item> items = new ArrayList<>();
- for (WmsReceiptReqDTO.Item item : reqDTO.getItems()) {
- WmsInventoryChangeReqDTO.Item changeItem = new WmsInventoryChangeReqDTO.Item();
- changeItem.setSkuId(item.getSkuId());
- changeItem.setWarehouseId(reqDTO.getWarehouseId());
- changeItem.setQuantity(item.getQuantity()); // 鍏ュ簱涓烘鏁�
- changeItem.setPrice(item.getPrice());
- changeItem.setRemark(item.getRemark());
- items.add(changeItem);
- }
- changeReq.setItems(items);
- return changeReq;
- }
-
- private WmsInventoryChangeReqDTO buildShipmentChangeReq(WmsShipmentReqDTO reqDTO) {
- WmsInventoryChangeReqDTO changeReq = new WmsInventoryChangeReqDTO();
- changeReq.setOrderType(reqDTO.getBizType());
- changeReq.setOrderNo(reqDTO.getBizNo());
-
- List<WmsInventoryChangeReqDTO.Item> items = new ArrayList<>();
- for (WmsShipmentReqDTO.Item item : reqDTO.getItems()) {
- WmsInventoryChangeReqDTO.Item changeItem = new WmsInventoryChangeReqDTO.Item();
- changeItem.setSkuId(item.getSkuId());
- changeItem.setWarehouseId(reqDTO.getWarehouseId());
- changeItem.setQuantity(item.getQuantity().negate()); // 鍑哄簱涓鸿礋鏁�
- changeItem.setRemark(item.getRemark());
- items.add(changeItem);
- }
- changeReq.setItems(items);
- return changeReq;
- }
-
- private List<WmsInventoryTransactionDO> buildReceiptTransactions(WmsReceiptReqDTO reqDTO) {
- List<WmsInventoryTransactionDO> transactions = new ArrayList<>();
- for (WmsReceiptReqDTO.Item item : reqDTO.getItems()) {
- WmsInventoryTransactionDO transaction = WmsInventoryTransactionDO.builder()
- .transactionNo(generateTransactionNo())
- .transactionType(WmsTransactionTypeEnum.RECEIPT.getType())
- .bizType(reqDTO.getBizType())
- .bizId(reqDTO.getBizId())
- .bizNo(reqDTO.getBizNo())
- .skuId(item.getSkuId())
- .warehouseId(reqDTO.getWarehouseId())
- .quantity(item.getQuantity())
- .transactionTime(reqDTO.getReceiptTime() != null ? reqDTO.getReceiptTime() : LocalDateTime.now())
- .remark(item.getRemark())
- .build();
- transactions.add(transaction);
- }
- return transactions;
- }
-
- private List<WmsInventoryTransactionDO> buildShipmentTransactions(WmsShipmentReqDTO reqDTO) {
- List<WmsInventoryTransactionDO> transactions = new ArrayList<>();
- for (WmsShipmentReqDTO.Item item : reqDTO.getItems()) {
- WmsInventoryTransactionDO transaction = WmsInventoryTransactionDO.builder()
- .transactionNo(generateTransactionNo())
- .transactionType(WmsTransactionTypeEnum.SHIPMENT.getType())
- .bizType(reqDTO.getBizType())
- .bizId(reqDTO.getBizId())
- .bizNo(reqDTO.getBizNo())
- .skuId(item.getSkuId())
- .warehouseId(reqDTO.getWarehouseId())
- .quantity(item.getQuantity().negate())
- .reserveNo(reqDTO.getReserveNo())
- .transactionTime(reqDTO.getShipmentTime() != null ? reqDTO.getShipmentTime() : LocalDateTime.now())
- .remark(item.getRemark())
- .build();
- transactions.add(transaction);
- }
- return transactions;
- }
-
- private BigDecimal calculateTotalQuantity(List<?> items) {
- if (CollUtil.isEmpty(items)) {
- return BigDecimal.ZERO;
- }
- BigDecimal total = BigDecimal.ZERO;
- for (Object item : items) {
- if (item instanceof WmsReceiptReqDTO.Item) {
- total = total.add(((WmsReceiptReqDTO.Item) item).getQuantity());
- } else if (item instanceof WmsShipmentReqDTO.Item) {
- total = total.add(((WmsShipmentReqDTO.Item) item).getQuantity());
- }
- }
- return total;
- }
-
- private String generateReceiptNo() {
- return "RCPT" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
- + UUID.randomUUID().toString().substring(0, 6).toUpperCase();
- }
-
- private String generateShipmentNo() {
- return "SHIP" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
- + UUID.randomUUID().toString().substring(0, 6).toUpperCase();
- }
-
- private String generateTransactionNo() {
- return "TRX" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
- + UUID.randomUUID().toString().substring(0, 6).toUpperCase();
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsInventoryQueryReqDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsInventoryQueryReqDTO.java
deleted file mode 100644
index dedbc16..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsInventoryQueryReqDTO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory.dto;
-
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * WMS 搴撳瓨鏌ヨ璇锋眰 DTO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class WmsInventoryQueryReqDTO {
-
- /**
- * SKU 缂栧彿鍒楄〃
- */
- private List<Long> skuIds;
-
- /**
- * 浠撳簱缂栧彿鍒楄〃
- */
- private List<Long> warehouseIds;
-
- /**
- * 鏄惁鍙煡璇㈡湁搴撳瓨鐨�
- */
- private Boolean onlyPositive;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsInventoryRespDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsInventoryRespDTO.java
deleted file mode 100644
index 54b4012..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsInventoryRespDTO.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory.dto;
-
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-/**
- * WMS 搴撳瓨鍝嶅簲 DTO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class WmsInventoryRespDTO {
-
- /**
- * 搴撳瓨 ID
- */
- private Long id;
-
- /**
- * SKU 缂栧彿
- */
- private Long skuId;
-
- /**
- * SKU 鍚嶇О
- */
- private String skuName;
-
- /**
- * 浠撳簱缂栧彿
- */
- private Long warehouseId;
-
- /**
- * 浠撳簱鍚嶇О
- */
- private String warehouseName;
-
- /**
- * 搴撳瓨鏁伴噺
- */
- private BigDecimal quantity;
-
- /**
- * 棰勭暀鏁伴噺
- */
- private BigDecimal reserveQuantity;
-
- /**
- * 鍙敤鏁伴噺锛堝簱瀛樻暟閲� - 棰勭暀鏁伴噺锛�
- */
- private BigDecimal availableQuantity;
-
- /**
- * 鏇存柊鏃堕棿
- */
- private LocalDateTime updateTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReceiptReqDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReceiptReqDTO.java
deleted file mode 100644
index 76b630b..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReceiptReqDTO.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory.dto;
-
-import jakarta.validation.Valid;
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-import java.util.List;
-
-/**
- * WMS 鍏ュ簱璇锋眰 DTO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class WmsReceiptReqDTO {
-
- /**
- * 涓氬姟绫诲瀷
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.module.wms.enums.inventory.WmsInventoryBizTypeEnum}
- */
- @NotNull(message = "涓氬姟绫诲瀷涓嶈兘涓虹┖")
- private Integer bizType;
-
- /**
- * 涓氬姟鍗曟嵁 ID
- */
- @NotNull(message = "涓氬姟鍗曟嵁ID涓嶈兘涓虹┖")
- private Long bizId;
-
- /**
- * 涓氬姟鍗曟嵁鍙�
- */
- private String bizNo;
-
- /**
- * 浠撳簱缂栧彿
- */
- @NotNull(message = "浠撳簱涓嶈兘涓虹┖")
- private Long warehouseId;
-
- /**
- * 鍏ュ簱鏃堕棿
- */
- private LocalDateTime receiptTime;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
- /**
- * 鍏ュ簱鏄庣粏
- */
- @NotEmpty(message = "鍏ュ簱鏄庣粏涓嶈兘涓虹┖")
- @Valid
- private List<Item> items;
-
- /**
- * 鍏ュ簱鏄庣粏椤�
- */
- @Data
- public static class Item {
-
- /**
- * SKU 缂栧彿
- */
- @NotNull(message = "SKU涓嶈兘涓虹┖")
- private Long skuId;
-
- /**
- * 鍏ュ簱鏁伴噺
- */
- @NotNull(message = "鍏ュ簱鏁伴噺涓嶈兘涓虹┖")
- private BigDecimal quantity;
-
- /**
- * 鍗曚环锛堝彲閫夛級
- */
- private BigDecimal price;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReceiptResultDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReceiptResultDTO.java
deleted file mode 100644
index f6eeab0..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReceiptResultDTO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory.dto;
-
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * WMS 鍏ュ簱缁撴灉 DTO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class WmsReceiptResultDTO {
-
- /**
- * 鍏ュ簱鍗� ID
- */
- private Long receiptOrderId;
-
- /**
- * 鍏ュ簱鍗曞彿
- */
- private String receiptOrderNo;
-
- /**
- * 鎬诲叆搴撴暟閲�
- */
- private BigDecimal totalQuantity;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReserveReqDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReserveReqDTO.java
deleted file mode 100644
index 91576f8..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsReserveReqDTO.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory.dto;
-
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-/**
- * WMS 搴撳瓨棰勭暀璇锋眰 DTO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class WmsReserveReqDTO {
-
- /**
- * 涓氬姟绫诲瀷
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.module.wms.enums.inventory.WmsReserveBizTypeEnum}
- */
- @NotNull(message = "涓氬姟绫诲瀷涓嶈兘涓虹┖")
- private Integer bizType;
-
- /**
- * 涓氬姟鍗曟嵁 ID
- */
- @NotNull(message = "涓氬姟鍗曟嵁ID涓嶈兘涓虹┖")
- private Long bizId;
-
- /**
- * 涓氬姟鍗曟嵁鍙�
- */
- private String bizNo;
-
- /**
- * SKU 缂栧彿
- */
- @NotNull(message = "SKU涓嶈兘涓虹┖")
- private Long skuId;
-
- /**
- * 浠撳簱缂栧彿
- */
- @NotNull(message = "浠撳簱涓嶈兘涓虹┖")
- private Long warehouseId;
-
- /**
- * 棰勭暀鏁伴噺
- */
- @NotNull(message = "棰勭暀鏁伴噺涓嶈兘涓虹┖")
- private BigDecimal quantity;
-
- /**
- * 杩囨湡鏃堕棿锛堝彲閫夛紝棰勭暀鑷姩閲婃斁鏃堕棿锛�
- */
- private LocalDateTime expireTime;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsShipmentReqDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsShipmentReqDTO.java
deleted file mode 100644
index 9ce3fc1..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsShipmentReqDTO.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory.dto;
-
-import jakarta.validation.Valid;
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-import java.util.List;
-
-/**
- * WMS 鍑哄簱璇锋眰 DTO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class WmsShipmentReqDTO {
-
- /**
- * 涓氬姟绫诲瀷
- *
- * 鏋氫妇 {@link cn.iocoder.yudao.module.wms.enums.inventory.WmsInventoryBizTypeEnum}
- */
- @NotNull(message = "涓氬姟绫诲瀷涓嶈兘涓虹┖")
- private Integer bizType;
-
- /**
- * 涓氬姟鍗曟嵁 ID
- */
- @NotNull(message = "涓氬姟鍗曟嵁ID涓嶈兘涓虹┖")
- private Long bizId;
-
- /**
- * 涓氬姟鍗曟嵁鍙�
- */
- private String bizNo;
-
- /**
- * 浠撳簱缂栧彿
- */
- @NotNull(message = "浠撳簱涓嶈兘涓虹┖")
- private Long warehouseId;
-
- /**
- * 鍑哄簱鏃堕棿
- */
- private LocalDateTime shipmentTime;
-
- /**
- * 棰勭暀鍗曞彿锛堝鏋滀娇鐢ㄤ簡棰勭暀锛�
- */
- private String reserveNo;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
- /**
- * 鍑哄簱鏄庣粏
- */
- @NotEmpty(message = "鍑哄簱鏄庣粏涓嶈兘涓虹┖")
- @Valid
- private List<Item> items;
-
- /**
- * 鍑哄簱鏄庣粏椤�
- */
- @Data
- public static class Item {
-
- /**
- * SKU 缂栧彿
- */
- @NotNull(message = "SKU涓嶈兘涓虹┖")
- private Long skuId;
-
- /**
- * 鍑哄簱鏁伴噺
- */
- @NotNull(message = "鍑哄簱鏁伴噺涓嶈兘涓虹┖")
- private BigDecimal quantity;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsShipmentResultDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsShipmentResultDTO.java
deleted file mode 100644
index fd7267e..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsShipmentResultDTO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory.dto;
-
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * WMS 鍑哄簱缁撴灉 DTO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class WmsShipmentResultDTO {
-
- /**
- * 鍑哄簱鍗� ID
- */
- private Long shipmentOrderId;
-
- /**
- * 鍑哄簱鍗曞彿
- */
- private String shipmentOrderNo;
-
- /**
- * 鎬诲嚭搴撴暟閲�
- */
- private BigDecimal totalQuantity;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsUseReserveReqDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsUseReserveReqDTO.java
deleted file mode 100644
index 86e3048..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/inventory/dto/WmsUseReserveReqDTO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.inventory.dto;
-
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-
-import java.math.BigDecimal;
-
-/**
- * WMS 浣跨敤棰勭暀璇锋眰 DTO
- *
- * 鍑哄簱鏃舵墸鍑忛鐣欏簱瀛�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-public class WmsUseReserveReqDTO {
-
- /**
- * 棰勭暀鍗曞彿
- */
- @NotNull(message = "棰勭暀鍗曞彿涓嶈兘涓虹┖")
- private String reserveNo;
-
- /**
- * 浣跨敤鏁伴噺
- */
- @NotNull(message = "浣跨敤鏁伴噺涓嶈兘涓虹┖")
- private BigDecimal quantity;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/stock/WmsStockApi.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/stock/WmsStockApi.java
deleted file mode 100644
index a1168a8..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/stock/WmsStockApi.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.stock;
-
-import cn.iocoder.yudao.module.wms.api.stock.dto.*;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
-/**
- * WMS 搴撳瓨鏈嶅姟 API 鎺ュ彛
- *
- * 鎻愪緵缁� ERP銆丮ES 绛夋ā鍧楄皟鐢紝瀹炵幇璺ㄦā鍧楀簱瀛樻搷浣�
- * 浣跨敤缁熶竴鐨勭墿鏂橧D锛坢d_item.id锛�
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface WmsStockApi {
-
- // ==================== 搴撳瓨璁板綍鎿嶄綔 ====================
-
- /**
- * 鍒涘缓搴撳瓨璁板綍锛堝叆搴擄級
- *
- * @param dto 搴撳瓨璁板綍鍒涘缓璇锋眰
- * @return 搴撳瓨璁板綍ID
- */
- Long createStockRecord(StockRecordCreateDTO dto);
-
- /**
- * 鎵归噺鍒涘缓搴撳瓨璁板綍
- *
- * @param dtoList 搴撳瓨璁板綍鍒涘缓璇锋眰鍒楄〃
- * @return 搴撳瓨璁板綍ID鍒楄〃
- */
- List<Long> createStockRecordBatch(List<StockRecordCreateDTO> dtoList);
-
- // ==================== 搴撳瓨閿佸畾 ====================
-
- /**
- * 閿佸畾搴撳瓨
- *
- * @param itemId 鐗╂枡ID
- * @param warehouseId 浠撳簱ID
- * @param quantity 閿佸畾鏁伴噺
- * @return 閿佸畾鍗曞彿
- */
- String lockStock(Long itemId, Long warehouseId, BigDecimal quantity);
-
- /**
- * 鎵归噺閿佸畾搴撳瓨
- *
- * @param itemId 鐗╂枡ID
- * @param warehouseId 浠撳簱ID
- * @param quantity 閿佸畾鏁伴噺
- * @param bizType 涓氬姟绫诲瀷
- * @param bizId 涓氬姟鍗曟嵁ID
- * @return 閿佸畾鍗曞彿
- */
- String lockStockWithBiz(Long itemId, Long warehouseId, BigDecimal quantity, Integer bizType, Long bizId);
-
- /**
- * 瑙i攣搴撳瓨
- *
- * @param lockNo 閿佸畾鍗曞彿
- */
- void unlockStock(String lockNo);
-
- // ==================== 搴撳瓨鏌ヨ ====================
-
- /**
- * 鏌ヨ鍙敤搴撳瓨
- *
- * @param itemId 鐗╂枡ID
- * @param warehouseId 浠撳簱ID
- * @return 鍙敤搴撳瓨鏁伴噺
- */
- BigDecimal getAvailableStock(Long itemId, Long warehouseId);
-
- /**
- * 鎵归噺鏌ヨ搴撳瓨
- *
- * @param itemIds 鐗╂枡ID鍒楄〃
- * @param warehouseId 浠撳簱ID
- * @return 鐗╂枡ID -> 鍙敤搴撳瓨鏁伴噺
- */
- Map<Long, BigDecimal> getAvailableStockMap(List<Long> itemIds, Long warehouseId);
-
- /**
- * 鏌ヨ鎵�鏈変粨搴撶殑搴撳瓨
- *
- * @param itemId 鐗╂枡ID
- * @return 浠撳簱ID -> 鍙敤搴撳瓨鏁伴噺
- */
- Map<Long, BigDecimal> getAvailableStockByWarehouse(Long itemId);
-
- // ==================== 搴撳瓨鏍¢獙 ====================
-
- /**
- * 鏍¢獙搴撳瓨鍏呰冻
- *
- * @param itemId 鐗╂枡ID
- * @param warehouseId 浠撳簱ID
- * @param quantity 闇�姹傛暟閲�
- * @return true=鍏呰冻, false=涓嶈冻
- */
- boolean validateStockEnough(Long itemId, Long warehouseId, BigDecimal quantity);
-
- /**
- * 鏍¢獙搴撳瓨鍏呰冻锛堜笉瓒虫椂鎶涘嚭寮傚父锛�
- *
- * @param itemId 鐗╂枡ID
- * @param warehouseId 浠撳簱ID
- * @param quantity 闇�姹傛暟閲�
- * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 搴撳瓨涓嶈冻鏃舵姏鍑哄紓甯�
- */
- void checkStockEnough(Long itemId, Long warehouseId, BigDecimal quantity);
-
- // ==================== 搴撳瓨鎵e噺 ====================
-
- /**
- * 鎵e噺搴撳瓨锛堝嚭搴擄級
- *
- * @param itemId 鐗╂枡ID
- * @param warehouseId 浠撳簱ID
- * @param quantity 鎵e噺鏁伴噺
- * @param bizType 涓氬姟绫诲瀷
- * @param bizId 涓氬姟鍗曟嵁ID
- * @param bizNo 涓氬姟鍗曟嵁鍙�
- */
- void deductStock(Long itemId, Long warehouseId, BigDecimal quantity, Integer bizType, Long bizId, String bizNo);
-
- /**
- * 澧炲姞搴撳瓨锛堝叆搴擄級
- *
- * @param itemId 鐗╂枡ID
- * @param warehouseId 浠撳簱ID
- * @param quantity 澧炲姞鏁伴噺
- * @param bizType 涓氬姟绫诲瀷
- * @param bizId 涓氬姟鍗曟嵁ID
- * @param bizNo 涓氬姟鍗曟嵁鍙�
- */
- void addStock(Long itemId, Long warehouseId, BigDecimal quantity, Integer bizType, Long bizId, String bizNo);
-
-}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/stock/dto/StockRecordCreateDTO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/stock/dto/StockRecordCreateDTO.java
deleted file mode 100644
index d089a35..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/api/stock/dto/StockRecordCreateDTO.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package cn.iocoder.yudao.module.wms.api.stock.dto;
-
-import lombok.Data;
-import lombok.experimental.Accessors;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-/**
- * 搴撳瓨璁板綍鍒涘缓 DTO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Data
-@Accessors(chain = true)
-public class StockRecordCreateDTO implements Serializable {
-
- /**
- * 鐗╂枡ID锛堝叧鑱� md_item.id锛�
- */
- private Long itemId;
-
- /**
- * 浠撳簱ID锛堝叧鑱� md_warehouse.id锛�
- */
- private Long warehouseId;
-
- /**
- * 搴撲綅ID锛堝彲閫夛級
- */
- private Long locationId;
-
- /**
- * 鎵规鍙凤紙鍙�夛級
- */
- private String batchCode;
-
- /**
- * 鍙樺姩鏁伴噺锛堟鏁�=鍏ュ簱锛岃礋鏁�=鍑哄簱锛�
- */
- private BigDecimal quantity;
-
- /**
- * 涓氬姟绫诲瀷
- *
- * 鏋氫妇鍊硷細
- * 10: 閲囪喘鍏ュ簱
- * 20: 閿�鍞嚭搴�
- * 30: 鐢熶骇鍏ュ簱
- * 40: 鐢熶骇棰嗘枡
- * 50: 鐢熶骇閫�鏂�
- * 60: 閲囪喘閫�璐у嚭搴�
- * 70: 閿�鍞��璐у叆搴�
- * 80: 璋冩嫧鍏ュ簱
- * 90: 璋冩嫧鍑哄簱
- * 100: 鐩樼泩鍏ュ簱
- * 110: 鐩樹簭鍑哄簱
- */
- private Integer bizType;
-
- /**
- * 涓氬姟鍗曟嵁ID
- */
- private Long bizId;
-
- /**
- * 涓氬姟鍗曟嵁鍙�
- */
- private String bizNo;
-
- /**
- * 璁¢噺鍗曚綅ID
- */
- private Long unitMeasureId;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryReserveController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryReserveController.java
deleted file mode 100644
index a870292..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryReserveController.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package cn.iocoder.yudao.module.wms.controller.admin.inventory;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
-import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryReservePageReqVO;
-import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryReserveRespVO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryReserveDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
-import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
-import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryReserveService;
-import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
-import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-import java.util.Map;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
-
-@Tag(name = "绠$悊鍚庡彴 - 搴撳瓨棰勭暀")
-@RestController
-@RequestMapping("/wms/inventory-reserve")
-@Validated
-public class WmsInventoryReserveController {
-
- @Resource
- private WmsInventoryReserveService reserveService;
-
- @Resource
- private WmsItemSkuService itemSkuService;
-
- @Resource
- private WmsWarehouseService warehouseService;
-
- @GetMapping("/page")
- @Operation(summary = "鑾峰緱搴撳瓨棰勭暀鍒嗛〉")
- @PreAuthorize("@ss.hasPermission('wms:inventory-reserve:query')")
- public CommonResult<PageResult<WmsInventoryReserveRespVO>> getInventoryReservePage(@Valid WmsInventoryReservePageReqVO reqVO) {
- PageResult<WmsInventoryReserveDO> pageResult = reserveService.getReservePage(reqVO);
- // 杞崲
- PageResult<WmsInventoryReserveRespVO> voPageResult = BeanUtils.toBean(pageResult, WmsInventoryReserveRespVO.class);
- // 琛ュ厖淇℃伅
- enrichReserveList(voPageResult.getList());
- return success(voPageResult);
- }
-
- @GetMapping("/get")
- @Operation(summary = "鑾峰緱搴撳瓨棰勭暀璇︽儏")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('wms:inventory-reserve:query')")
- public CommonResult<WmsInventoryReserveRespVO> getInventoryReserve(@RequestParam("id") Long id) {
- WmsInventoryReserveDO reserve = reserveService.getReserve(id);
- if (reserve == null) {
- return success(null);
- }
- WmsInventoryReserveRespVO respVO = BeanUtils.toBean(reserve, WmsInventoryReserveRespVO.class);
- // 琛ュ厖淇℃伅
- enrichReserve(respVO);
- return success(respVO);
- }
-
- @PostMapping("/release")
- @Operation(summary = "閲婃斁搴撳瓨棰勭暀")
- @Parameter(name = "id", description = "缂栧彿", required = true, example = "1")
- @PreAuthorize("@ss.hasPermission('wms:inventory-reserve:release')")
- public CommonResult<Boolean> releaseInventoryReserve(@RequestParam("id") Long id) {
- WmsInventoryReserveDO reserve = reserveService.getReserve(id);
- if (reserve != null) {
- reserveService.releaseReserve(reserve.getReserveNo());
- }
- return success(true);
- }
-
- /**
- * 鎵归噺琛ュ厖棰勭暀璁板綍淇℃伅
- */
- private void enrichReserveList(List<WmsInventoryReserveRespVO> list) {
- if (list == null || list.isEmpty()) {
- return;
- }
- // 鑾峰彇 SKU 淇℃伅
- Map<Long, WmsItemSkuDO> skuMap = itemSkuService.getItemSkuMap(
- convertSet(list, WmsInventoryReserveRespVO::getSkuId));
- // 鑾峰彇浠撳簱淇℃伅
- Map<Long, WmsWarehouseDO> warehouseMap = warehouseService.getWarehouseMap(
- convertSet(list, WmsInventoryReserveRespVO::getWarehouseId));
-
- for (WmsInventoryReserveRespVO vo : list) {
- // 涓氬姟绫诲瀷鍚嶇О
- vo.setBizTypeName(DictFrameworkUtils.parseDictDataLabel(DictTypeConstants.WMS_RESERVE_BIZ_TYPE, vo.getBizType()));
- // 鐘舵�佸悕绉�
- vo.setStatusName(DictFrameworkUtils.parseDictDataLabel(DictTypeConstants.WMS_RESERVE_STATUS, vo.getStatus()));
- // SKU 鍚嶇О
- WmsItemSkuDO sku = skuMap.get(vo.getSkuId());
- if (sku != null) {
- vo.setSkuName(sku.getName());
- }
- // 浠撳簱鍚嶇О
- WmsWarehouseDO warehouse = warehouseMap.get(vo.getWarehouseId());
- if (warehouse != null) {
- vo.setWarehouseName(warehouse.getName());
- }
- }
- }
-
- /**
- * 琛ュ厖鍗曚釜棰勭暀璁板綍淇℃伅
- */
- private void enrichReserve(WmsInventoryReserveRespVO vo) {
- // 涓氬姟绫诲瀷鍚嶇О
- vo.setBizTypeName(DictFrameworkUtils.parseDictDataLabel(DictTypeConstants.WMS_RESERVE_BIZ_TYPE, vo.getBizType()));
- // 鐘舵�佸悕绉�
- vo.setStatusName(DictFrameworkUtils.parseDictDataLabel(DictTypeConstants.WMS_RESERVE_STATUS, vo.getStatus()));
- // SKU 鍚嶇О
- List<WmsItemSkuDO> skuList = itemSkuService.getItemSkuListByIds(List.of(vo.getSkuId()));
- if (!skuList.isEmpty()) {
- vo.setSkuName(skuList.get(0).getName());
- }
- // 浠撳簱鍚嶇О
- WmsWarehouseDO warehouse = warehouseService.getWarehouse(vo.getWarehouseId());
- if (warehouse != null) {
- vo.setWarehouseName(warehouse.getName());
- }
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryReservePageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryReservePageReqVO.java
deleted file mode 100644
index ae48ffa..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryReservePageReqVO.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package cn.iocoder.yudao.module.wms.controller.admin.inventory.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@Schema(description = "绠$悊鍚庡彴 - 搴撳瓨棰勭暀鍒嗛〉 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class WmsInventoryReservePageReqVO extends PageParam {
-
- @Schema(description = "棰勭暀鍗曞彿", example = "RES202606260001")
- private String reserveNo;
-
- @Schema(description = "涓氬姟绫诲瀷", example = "10")
- private Integer bizType;
-
- @Schema(description = "涓氬姟鍗曟嵁鍙�", example = "SO202606260001")
- private String bizNo;
-
- @Schema(description = "鐘舵��", example = "0")
- private Integer status;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryReserveRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryReserveRespVO.java
deleted file mode 100644
index 35bbe3d..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryReserveRespVO.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package cn.iocoder.yudao.module.wms.controller.admin.inventory.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-@Schema(description = "绠$悊鍚庡彴 - 搴撳瓨棰勭暀 Response VO")
-@Data
-public class WmsInventoryReserveRespVO {
-
- @Schema(description = "缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long id;
-
- @Schema(description = "棰勭暀鍗曞彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "RES202606260001")
- private String reserveNo;
-
- @Schema(description = "涓氬姟绫诲瀷", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
- private Integer bizType;
-
- @Schema(description = "涓氬姟绫诲瀷鍚嶇О", example = "閿�鍞鐣�")
- private String bizTypeName;
-
- @Schema(description = "涓氬姟鍗曟嵁ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
- private Long bizId;
-
- @Schema(description = "涓氬姟鍗曟嵁鍙�", example = "SO202606260001")
- private String bizNo;
-
- @Schema(description = "SKU缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long skuId;
-
- @Schema(description = "SKU鍚嶇О", example = "鍟嗗搧A-绾㈣壊-L")
- private String skuName;
-
- @Schema(description = "浠撳簱缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- private Long warehouseId;
-
- @Schema(description = "浠撳簱鍚嶇О", example = "涓讳粨搴�")
- private String warehouseName;
-
- @Schema(description = "棰勭暀鏁伴噺", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
- private BigDecimal reserveQuantity;
-
- @Schema(description = "宸蹭娇鐢ㄦ暟閲�", example = "0.00")
- private BigDecimal usedQuantity;
-
- @Schema(description = "鐘舵��", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
- private Integer status;
-
- @Schema(description = "鐘舵�佸悕绉�", example = "棰勭暀涓�")
- private String statusName;
-
- @Schema(description = "杩囨湡鏃堕棿", example = "2026-06-30 00:00:00")
- private LocalDateTime expireTime;
-
- @Schema(description = "澶囨敞", example = "閿�鍞鍗曢鐣�")
- private String remark;
-
- @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
- private LocalDateTime createTime;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java
index 42981fb..8dde808 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java
@@ -24,9 +24,6 @@
@Schema(description = "鍟嗗搧鍝佺墝缂栧彿", example = "2048")
private Long brandId;
- @Schema(description = "鍟嗗搧鐘舵��", example = "0")
- private Integer status;
-
@Schema(description = "鍒涘缓鏃堕棿")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java
index e17a80d..5ae42c3 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java
@@ -29,9 +29,6 @@
@Schema(description = "鍟嗗搧鍝佺墝缂栧彿", example = "2048")
private Long brandId;
- @Schema(description = "鍟嗗搧鐘舵��", example = "0")
- private Integer status;
-
@Schema(description = "鍒涘缓鏃堕棿")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java
index b7b0ae5..6b8cadf 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java
@@ -36,9 +36,6 @@
@Size(max = 20, message = "鍗曚綅闀垮害涓嶈兘瓒呰繃 20 涓瓧绗�")
private String unit;
- @Schema(description = "璁¢噺鍗曚綅缂栧彿", example = "1")
- private Long unitMeasureId;
-
@Schema(description = "鍟嗗搧鍝佺墝缂栧彿", example = "1")
private Long brandId;
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryReserveDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryReserveDO.java
deleted file mode 100644
index cf3d160..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryReserveDO.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package cn.iocoder.yudao.module.wms.dal.dataobject.inventory;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
-import cn.iocoder.yudao.module.wms.enums.inventory.WmsReserveBizTypeEnum;
-import cn.iocoder.yudao.module.wms.enums.inventory.WmsReserveStatusEnum;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-/**
- * WMS 搴撳瓨棰勭暀 DO
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("wms_inventory_reserve")
-@KeySequence("wms_inventory_reserve_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class WmsInventoryReserveDO extends BaseDO {
-
- /**
- * 缂栧彿
- */
- @TableId
- private Long id;
-
- /**
- * 棰勭暀鍗曞彿
- */
- private String reserveNo;
-
- /**
- * 涓氬姟绫诲瀷
- *
- * 鏋氫妇 {@link WmsReserveBizTypeEnum}
- */
- private Integer bizType;
-
- /**
- * 涓氬姟鍗曟嵁 ID
- */
- private Long bizId;
-
- /**
- * 涓氬姟鍗曟嵁鍙�
- */
- private String bizNo;
-
- /**
- * SKU 缂栧彿
- *
- * 鍏宠仈 {@link WmsItemSkuDO#getId()}
- */
- private Long skuId;
-
- /**
- * 浠撳簱缂栧彿
- *
- * 鍏宠仈 {@link WmsWarehouseDO#getId()}
- */
- private Long warehouseId;
-
- /**
- * 棰勭暀鏁伴噺
- */
- private BigDecimal reserveQuantity;
-
- /**
- * 宸蹭娇鐢ㄦ暟閲�
- */
- private BigDecimal usedQuantity;
-
- /**
- * 鐘舵��
- *
- * 鏋氫妇 {@link WmsReserveStatusEnum}
- */
- private Integer status;
-
- /**
- * 杩囨湡鏃堕棿
- */
- private LocalDateTime expireTime;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryTransactionDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryTransactionDO.java
deleted file mode 100644
index 3b0c38a..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryTransactionDO.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package cn.iocoder.yudao.module.wms.dal.dataobject.inventory;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
-import cn.iocoder.yudao.module.wms.enums.inventory.WmsTransactionTypeEnum;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-
-/**
- * WMS 搴撳瓨浜嬪姟娴佹按 DO
- *
- * 璁板綍姣忎竴绗斿簱瀛樺彉鍔ㄦ搷浣�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@TableName("wms_inventory_transaction")
-@KeySequence("wms_inventory_transaction_seq")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class WmsInventoryTransactionDO extends BaseDO {
-
- /**
- * 缂栧彿
- */
- @TableId
- private Long id;
-
- /**
- * 浜嬪姟娴佹按鍙�
- */
- private String transactionNo;
-
- /**
- * 浜嬪姟绫诲瀷
- *
- * 鏋氫妇 {@link WmsTransactionTypeEnum}
- */
- private Integer transactionType;
-
- /**
- * 涓氬姟绫诲瀷
- */
- private Integer bizType;
-
- /**
- * 涓氬姟鍗曟嵁 ID
- */
- private Long bizId;
-
- /**
- * 涓氬姟鍗曟嵁鍙�
- */
- private String bizNo;
-
- /**
- * SKU 缂栧彿
- *
- * 鍏宠仈 {@link WmsItemSkuDO#getId()}
- */
- private Long skuId;
-
- /**
- * 浠撳簱缂栧彿
- *
- * 鍏宠仈 {@link WmsWarehouseDO#getId()}
- */
- private Long warehouseId;
-
- /**
- * 鍙樺姩鏁伴噺
- *
- * 姝f暟=鍏ュ簱锛岃礋鏁�=鍑哄簱
- */
- private BigDecimal quantity;
-
- /**
- * 鍙樺姩鍓嶆暟閲�
- */
- private BigDecimal beforeQuantity;
-
- /**
- * 鍙樺姩鍚庢暟閲�
- */
- private BigDecimal afterQuantity;
-
- /**
- * 鍏宠仈棰勭暀 ID
- */
- private Long reserveId;
-
- /**
- * 鍏宠仈棰勭暀鍗曞彿
- */
- private String reserveNo;
-
- /**
- * 浜嬪姟鏃堕棿
- */
- private LocalDateTime transactionTime;
-
- /**
- * 澶囨敞
- */
- private String remark;
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java
index ec67fc9..7236b49 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java
@@ -76,11 +76,6 @@
/**
* 閿�鍞环锛屽崟浣嶅厓
*/
- private BigDecimal salePrice;
-
- /**
- * 鐘舵��
- */
- private Integer status;
+ private BigDecimal sellingPrice;
}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryMapper.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryMapper.java
index f4dc280..bc9b074 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryMapper.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryMapper.java
@@ -6,7 +6,6 @@
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.query.MPJLambdaWrapperX;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.WmsInventoryQueryReqDTO;
import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryListReqVO;
import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
@@ -102,7 +101,6 @@
}
return selectList(new LambdaQueryWrapperX<WmsInventoryDO>()
.in(WmsInventoryDO::getId, ids)
- .orderByAsc(WmsInventoryDO::getId)
.last("FOR UPDATE"));
}
@@ -122,19 +120,6 @@
return;
}
throw new IllegalArgumentException("鏈煡搴撳瓨缁熻缁村害锛�" + type);
- }
-
- /**
- * 鏍规嵁 API 鏌ヨ鏉′欢鏌ヨ搴撳瓨鍒楄〃
- */
- default List<WmsInventoryDO> selectListByQuery(WmsInventoryQueryReqDTO reqDTO) {
- LambdaQueryWrapperX<WmsInventoryDO> query = new LambdaQueryWrapperX<WmsInventoryDO>()
- .inIfPresent(WmsInventoryDO::getSkuId, reqDTO.getSkuIds())
- .inIfPresent(WmsInventoryDO::getWarehouseId, reqDTO.getWarehouseIds());
- if (Boolean.TRUE.equals(reqDTO.getOnlyPositive())) {
- query.gt(WmsInventoryDO::getQuantity, BigDecimal.ZERO);
- }
- return selectList(query);
}
}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryReserveMapper.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryReserveMapper.java
deleted file mode 100644
index a2f3f97..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryReserveMapper.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package cn.iocoder.yudao.module.wms.dal.mysql.inventory;
-
-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.module.wms.api.inventory.dto.WmsInventoryQueryReqDTO;
-import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryReservePageReqVO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryReserveDO;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-import org.apache.ibatis.annotations.Select;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * WMS 搴撳瓨棰勭暀 Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface WmsInventoryReserveMapper extends BaseMapperX<WmsInventoryReserveDO> {
-
- default PageResult<WmsInventoryReserveDO> selectPage(WmsInventoryReservePageReqVO reqVO) {
- return selectPage(reqVO, new LambdaQueryWrapperX<WmsInventoryReserveDO>()
- .likeIfPresent(WmsInventoryReserveDO::getReserveNo, reqVO.getReserveNo())
- .eqIfPresent(WmsInventoryReserveDO::getBizType, reqVO.getBizType())
- .likeIfPresent(WmsInventoryReserveDO::getBizNo, reqVO.getBizNo())
- .eqIfPresent(WmsInventoryReserveDO::getStatus, reqVO.getStatus())
- .orderByDesc(WmsInventoryReserveDO::getId));
- }
-
- default List<WmsInventoryReserveDO> selectListByBiz(Integer bizType, Long bizId) {
- return selectList(new LambdaQueryWrapperX<WmsInventoryReserveDO>()
- .eq(WmsInventoryReserveDO::getBizType, bizType)
- .eq(WmsInventoryReserveDO::getBizId, bizId)
- .in(WmsInventoryReserveDO::getStatus, 0, 1)); // 棰勭暀涓垨閮ㄥ垎浣跨敤
- }
-
- default WmsInventoryReserveDO selectByReserveNo(String reserveNo) {
- return selectOne(WmsInventoryReserveDO::getReserveNo, reserveNo);
- }
-
- /**
- * 鏌ヨ鎸囧畾 SKU 鍜屼粨搴撶殑棰勭暀鏁伴噺
- */
- @Select("SELECT IFNULL(SUM(reserve_quantity - used_quantity), 0) FROM wms_inventory_reserve " +
- "WHERE sku_id = #{skuId} AND warehouse_id = #{warehouseId} AND status IN (0, 1) AND deleted = 0")
- BigDecimal selectReserveQuantity(@Param("skuId") Long skuId, @Param("warehouseId") Long warehouseId);
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryTransactionMapper.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryTransactionMapper.java
deleted file mode 100644
index 386d78e..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryTransactionMapper.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.wms.dal.mysql.inventory;
-
-import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryTransactionDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.List;
-
-/**
- * WMS 搴撳瓨浜嬪姟娴佹按 Mapper
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Mapper
-public interface WmsInventoryTransactionMapper extends BaseMapperX<WmsInventoryTransactionDO> {
-
- default List<WmsInventoryTransactionDO> selectListByBiz(Integer bizType, Long bizId) {
- return selectList(new LambdaQueryWrapperX<WmsInventoryTransactionDO>()
- .eq(WmsInventoryTransactionDO::getBizType, bizType)
- .eq(WmsInventoryTransactionDO::getBizId, bizId)
- .orderByAsc(WmsInventoryTransactionDO::getTransactionTime));
- }
-
- default WmsInventoryTransactionDO selectByTransactionNo(String transactionNo) {
- return selectOne(WmsInventoryTransactionDO::getTransactionNo, transactionNo);
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java
index 0b4500c..e854bc5 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java
@@ -13,8 +13,4 @@
String RECEIPT_ORDER_TYPE = "wms_receipt_order_type";
String SHIPMENT_ORDER_TYPE = "wms_shipment_order_type";
- String WMS_RESERVE_BIZ_TYPE = "wms_reserve_biz_type";
- String WMS_RESERVE_STATUS = "wms_reserve_status";
- String WMS_TRANSACTION_TYPE = "wms_transaction_type";
-
}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
index 1d9bf0e..2175627 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
@@ -87,13 +87,5 @@
// ========== WMS 搴撳瓨 1-060-300-000 ==========
ErrorCode INVENTORY_QUANTITY_NOT_ENOUGH = new ErrorCode(1_060_300_000,
"搴撳瓨涓嶈冻锛屽晢鍝侊細{}锛屽晢鍝佽鏍硷細{}锛屼粨搴擄細{}锛屽綋鍓嶅簱瀛橈細{}锛屽彉鏇存暟閲忥細{}");
- ErrorCode INVENTORY_QUANTITY_NOT_ENOUGH_FOR_RESERVE = new ErrorCode(1_060_300_001,
- "鍙敤搴撳瓨涓嶈冻锛孲KU锛歿}锛屼粨搴擄細{}锛屽彲鐢ㄥ簱瀛橈細{}锛岄鐣欐暟閲忥細{}");
-
- // ========== WMS 搴撳瓨棰勭暀 1-060-301-000 ==========
- ErrorCode INVENTORY_RESERVE_NOT_EXISTS = new ErrorCode(1_060_301_000, "搴撳瓨棰勭暀涓嶅瓨鍦�");
- ErrorCode INVENTORY_RESERVE_STATUS_INVALID = new ErrorCode(1_060_301_001, "搴撳瓨棰勭暀鐘舵�佷笉鍏佽姝ゆ搷浣�");
- ErrorCode INVENTORY_RESERVE_QUANTITY_NOT_ENOUGH = new ErrorCode(1_060_301_002,
- "棰勭暀鏁伴噺涓嶈冻锛岄鐣欏崟鍙凤細{}锛屽墿浣欓鐣欙細{}锛岃姹備娇鐢細{}");
}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsInventoryBizTypeEnum.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsInventoryBizTypeEnum.java
deleted file mode 100644
index 89b19c8..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsInventoryBizTypeEnum.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package cn.iocoder.yudao.module.wms.enums.inventory;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * WMS 搴撳瓨涓氬姟绫诲瀷鏋氫妇
- *
- * 鐢ㄤ簬鍖哄垎搴撳瓨鎿嶄綔鐨勪笟鍔℃潵婧�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Getter
-@AllArgsConstructor
-public enum WmsInventoryBizTypeEnum implements ArrayValuable<Integer> {
-
- // ========== 鍏ュ簱绫诲瀷 [100, 150) ==========
-
- PURCHASE_RECEIPT(100, "ERP 閲囪喘鍏ュ簱"),
- PRODUCE_RECEIPT(101, "MES 鐢熶骇鍏ュ簱"),
- RETURN_RECEIPT(102, "閫�璐у叆搴�"),
- OTHER_RECEIPT(103, "鍏朵粬鍏ュ簱"),
- OTHER(104, "鍏朵粬"),
-
- // ========== 鍑哄簱绫诲瀷 [150, 200) ==========
-
- SALE_SHIPMENT(150, "ERP 閿�鍞嚭搴�"),
- PRODUCE_MATERIAL(151, "MES 鐢熶骇棰嗘枡"),
- RETURN_SHIPMENT(152, "閫�璐у嚭搴�"),
- OTHER_SHIPMENT(153, "鍏朵粬鍑哄簱"),
-
- ;
-
- public static final Integer[] ARRAYS = Arrays.stream(values())
- .map(WmsInventoryBizTypeEnum::getType).toArray(Integer[]::new);
-
- /**
- * 绫诲瀷
- */
- private final Integer type;
- /**
- * 鍚嶇О
- */
- private final String name;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
- /**
- * 鍒ゆ柇鏄惁涓哄叆搴撶被鍨�
- */
- public static boolean isReceiptType(Integer type) {
- return type != null && type >= 100 && type < 150;
- }
-
- /**
- * 鍒ゆ柇鏄惁涓哄嚭搴撶被鍨�
- */
- public static boolean isShipmentType(Integer type) {
- return type != null && type >= 150 && type < 200;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsReserveBizTypeEnum.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsReserveBizTypeEnum.java
deleted file mode 100644
index d8e7bff..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsReserveBizTypeEnum.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package cn.iocoder.yudao.module.wms.enums.inventory;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * WMS 搴撳瓨棰勭暀涓氬姟绫诲瀷鏋氫妇
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Getter
-@AllArgsConstructor
-public enum WmsReserveBizTypeEnum implements ArrayValuable<Integer> {
-
- SALE(10, "閿�鍞鐣�"),
- PRODUCE(20, "鐢熶骇棰勭暀"),
- ;
-
- public static final Integer[] ARRAYS = Arrays.stream(values())
- .map(WmsReserveBizTypeEnum::getType).toArray(Integer[]::new);
-
- /**
- * 绫诲瀷
- */
- private final Integer type;
- /**
- * 鍚嶇О
- */
- private final String name;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsReserveStatusEnum.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsReserveStatusEnum.java
deleted file mode 100644
index 4e2766d..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsReserveStatusEnum.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package cn.iocoder.yudao.module.wms.enums.inventory;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * WMS 搴撳瓨棰勭暀鐘舵�佹灇涓�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Getter
-@AllArgsConstructor
-public enum WmsReserveStatusEnum implements ArrayValuable<Integer> {
-
- RESERVED(0, "棰勭暀涓�"),
- PARTIAL_USED(1, "閮ㄥ垎浣跨敤"),
- USED(2, "宸蹭娇鐢�"),
- RELEASED(3, "宸查噴鏀�"),
- ;
-
- public static final Integer[] ARRAYS = Arrays.stream(values())
- .map(WmsReserveStatusEnum::getStatus).toArray(Integer[]::new);
-
- /**
- * 鐘舵��
- */
- private final Integer status;
- /**
- * 鍚嶇О
- */
- private final String name;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsTransactionTypeEnum.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsTransactionTypeEnum.java
deleted file mode 100644
index a5e6cd6..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/inventory/WmsTransactionTypeEnum.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package cn.iocoder.yudao.module.wms.enums.inventory;
-
-import cn.iocoder.yudao.framework.common.core.ArrayValuable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.util.Arrays;
-
-/**
- * WMS 搴撳瓨浜嬪姟绫诲瀷鏋氫妇
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Getter
-@AllArgsConstructor
-public enum WmsTransactionTypeEnum implements ArrayValuable<Integer> {
-
- RECEIPT(10, "鍏ュ簱"),
- SHIPMENT(20, "鍑哄簱"),
- RESERVE(30, "棰勭暀"),
- RELEASE(40, "閲婃斁"),
- CHECK(50, "鐩樼偣"),
- MOVE(60, "璋冩嫧"),
- ;
-
- public static final Integer[] ARRAYS = Arrays.stream(values())
- .map(WmsTransactionTypeEnum::getType).toArray(Integer[]::new);
-
- /**
- * 绫诲瀷
- */
- private final Integer type;
- /**
- * 鍚嶇О
- */
- private final String name;
-
- @Override
- public Integer[] array() {
- return ARRAYS;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/stock/StockBizTypeEnum.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/stock/StockBizTypeEnum.java
deleted file mode 100644
index 9f1b614..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/stock/StockBizTypeEnum.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package cn.iocoder.yudao.module.wms.enums.stock;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-/**
- * 搴撳瓨涓氬姟绫诲瀷鏋氫妇
- *
- * 瀹氫箟搴撳瓨鍙樺姩鐨勪笟鍔℃潵婧�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Getter
-@AllArgsConstructor
-public enum StockBizTypeEnum {
-
- // ==================== 鍏ュ簱绫诲瀷 ====================
-
- PURCHASE_IN(10, "閲囪喘鍏ュ簱"),
- PURCHASE_IN_CANCEL(11, "閲囪喘鍏ュ簱浣滃簾"),
-
- PRODUCE_IN(30, "鐢熶骇鍏ュ簱"),
- PRODUCE_IN_CANCEL(31, "鐢熶骇鍏ュ簱浣滃簾"),
-
- PRODUCE_RETURN(50, "鐢熶骇閫�鏂�"),
- PRODUCE_RETURN_CANCEL(51, "鐢熶骇閫�鏂欎綔搴�"),
-
- SALE_RETURN_IN(70, "閿�鍞��璐у叆搴�"),
- SALE_RETURN_IN_CANCEL(71, "閿�鍞��璐у叆搴撲綔搴�"),
-
- TRANSFER_IN(80, "璋冩嫧鍏ュ簱"),
- TRANSFER_IN_CANCEL(81, "璋冩嫧鍏ュ簱浣滃簾"),
-
- CHECK_IN(100, "鐩樼泩鍏ュ簱"),
- CHECK_IN_CANCEL(101, "鐩樼泩鍏ュ簱浣滃簾"),
-
- // ==================== 鍑哄簱绫诲瀷 ====================
-
- SALE_OUT(20, "閿�鍞嚭搴�"),
- SALE_OUT_CANCEL(21, "閿�鍞嚭搴撲綔搴�"),
-
- PRODUCE_ISSUE(40, "鐢熶骇棰嗘枡"),
- PRODUCE_ISSUE_CANCEL(41, "鐢熶骇棰嗘枡浣滃簾"),
-
- PURCHASE_RETURN_OUT(60, "閲囪喘閫�璐у嚭搴�"),
- PURCHASE_RETURN_OUT_CANCEL(61, "閲囪喘閫�璐у嚭搴撲綔搴�"),
-
- TRANSFER_OUT(90, "璋冩嫧鍑哄簱"),
- TRANSFER_OUT_CANCEL(91, "璋冩嫧鍑哄簱浣滃簾"),
-
- CHECK_OUT(110, "鐩樹簭鍑哄簱"),
- CHECK_OUT_CANCEL(111, "鐩樹簭鍑哄簱浣滃簾");
-
- /**
- * 涓氬姟绫诲瀷缂栫爜
- */
- private final Integer type;
-
- /**
- * 涓氬姟绫诲瀷鍚嶇О
- */
- private final String name;
-
- /**
- * 鍒ゆ柇鏄惁涓哄叆搴撶被鍨�
- */
- public boolean isInbound() {
- // 鍏ュ簱绫诲瀷缂栫爜锛�10, 30, 50, 70, 80, 100
- return type % 20 == 10 || type == 50 || type == 70 || type == 100;
- }
-
- /**
- * 鍒ゆ柇鏄惁涓哄嚭搴撶被鍨�
- */
- public boolean isOutbound() {
- // 鍑哄簱绫诲瀷缂栫爜锛�20, 40, 60, 90, 110
- return type % 20 == 0 && type != 0 && !isInbound();
- }
-
- /**
- * 鍒ゆ柇鏄惁涓轰綔搴熺被鍨�
- */
- public boolean isCancel() {
- return type % 10 == 1 && type != 11; // 浣滃簾绫诲瀷鐨勭紪鐮佸熬鏁颁负 1
- }
-
- /**
- * 鑾峰彇瀵瑰簲鐨勬甯镐笟鍔$被鍨嬶紙濡傛灉鏄綔搴熺被鍨嬶級
- */
- public StockBizTypeEnum getNormalType() {
- if (isCancel()) {
- return fromType(type - 1);
- }
- return this;
- }
-
- /**
- * 鑾峰彇瀵瑰簲鐨勪綔搴熶笟鍔$被鍨嬶紙濡傛灉鏄甯哥被鍨嬶級
- */
- public StockBizTypeEnum getCancelType() {
- if (!isCancel()) {
- return fromType(type + 1);
- }
- return this;
- }
-
- /**
- * 鏍规嵁绫诲瀷缂栫爜鑾峰彇鏋氫妇
- */
- public static StockBizTypeEnum fromType(Integer type) {
- for (StockBizTypeEnum value : values()) {
- if (value.getType().equals(type)) {
- return value;
- }
- }
- return null;
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryReserveService.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryReserveService.java
deleted file mode 100644
index b503994..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryReserveService.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package cn.iocoder.yudao.module.wms.service.inventory;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.*;
-import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryReservePageReqVO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryReserveDO;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * WMS 搴撳瓨棰勭暀 Service 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface WmsInventoryReserveService {
-
- /**
- * 鍒涘缓搴撳瓨棰勭暀
- *
- * @param reqDTO 棰勭暀璇锋眰
- * @return 棰勭暀鍗曞彿
- */
- String createReserve(WmsReserveReqDTO reqDTO);
-
- /**
- * 閲婃斁搴撳瓨棰勭暀
- *
- * @param reserveNo 棰勭暀鍗曞彿
- */
- void releaseReserve(String reserveNo);
-
- /**
- * 浣跨敤棰勭暀搴撳瓨锛堟墸鍑忥級
- *
- * @param reqDTO 浣跨敤璇锋眰
- */
- void useReserve(WmsUseReserveReqDTO reqDTO);
-
- /**
- * 鏍规嵁涓氬姟鏌ヨ棰勭暀璁板綍
- *
- * @param bizType 涓氬姟绫诲瀷
- * @param bizId 涓氬姟鍗曟嵁ID
- * @return 棰勭暀璁板綍鍒楄〃
- */
- List<WmsInventoryReserveDO> getReserveListByBiz(Integer bizType, Long bizId);
-
- /**
- * 鑾峰彇搴撳瓨棰勭暀鍒嗛〉
- *
- * @param reqVO 鍒嗛〉璇锋眰
- * @return 鍒嗛〉缁撴灉
- */
- PageResult<WmsInventoryReserveDO> getReservePage(WmsInventoryReservePageReqVO reqVO);
-
- /**
- * 鑾峰彇棰勭暀璇︽儏
- *
- * @param id 棰勭暀ID
- * @return 棰勭暀璁板綍
- */
- WmsInventoryReserveDO getReserve(Long id);
-
- /**
- * 鏌ヨ鎸囧畾 SKU 鍜屼粨搴撶殑棰勭暀鏁伴噺
- *
- * @param skuId SKU缂栧彿
- * @param warehouseId 浠撳簱缂栧彿
- * @return 棰勭暀鏁伴噺
- */
- BigDecimal getReserveQuantity(Long skuId, Long warehouseId);
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryReserveServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryReserveServiceImpl.java
deleted file mode 100644
index 44ac36e..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryReserveServiceImpl.java
+++ /dev/null
@@ -1,210 +0,0 @@
-package cn.iocoder.yudao.module.wms.service.inventory;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.wms.api.inventory.dto.*;
-import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryReservePageReqVO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryReserveDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryTransactionDO;
-import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryReserveMapper;
-import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryTransactionMapper;
-import cn.iocoder.yudao.module.wms.enums.inventory.WmsReserveStatusEnum;
-import cn.iocoder.yudao.module.wms.enums.inventory.WmsTransactionTypeEnum;
-import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.validation.annotation.Validated;
-
-import java.math.BigDecimal;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
-import java.util.UUID;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
-
-/**
- * WMS 搴撳瓨棰勭暀 Service 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Service
-@Validated
-@Slf4j
-public class WmsInventoryReserveServiceImpl implements WmsInventoryReserveService {
-
- @Resource
- private WmsInventoryReserveMapper reserveMapper;
-
- @Resource
- private WmsInventoryTransactionMapper transactionMapper;
-
- @Resource
- private WmsInventoryService inventoryService;
-
- @Resource
- private WmsInventoryTransactionService transactionService;
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public String createReserve(WmsReserveReqDTO reqDTO) {
- // 1. 鏍¢獙鍙敤搴撳瓨
- BigDecimal availableQuantity = inventoryService.getAvailableQuantity(reqDTO.getSkuId(), reqDTO.getWarehouseId());
- if (availableQuantity.compareTo(reqDTO.getQuantity()) < 0) {
- throw exception(INVENTORY_QUANTITY_NOT_ENOUGH_FOR_RESERVE,
- reqDTO.getSkuId(), reqDTO.getWarehouseId(), availableQuantity, reqDTO.getQuantity());
- }
-
- // 2. 鐢熸垚棰勭暀鍗曞彿
- String reserveNo = generateReserveNo();
-
- // 3. 鍒涘缓棰勭暀璁板綍
- WmsInventoryReserveDO reserve = BeanUtils.toBean(reqDTO, WmsInventoryReserveDO.class);
- reserve.setReserveNo(reserveNo);
- reserve.setReserveQuantity(reqDTO.getQuantity());
- reserve.setUsedQuantity(BigDecimal.ZERO);
- reserve.setStatus(WmsReserveStatusEnum.RESERVED.getStatus());
- reserveMapper.insert(reserve);
-
- // 4. 璁板綍浜嬪姟娴佹按
- transactionService.createTransaction(buildReserveTransaction(reserve, reqDTO.getQuantity()));
-
- return reserveNo;
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void releaseReserve(String reserveNo) {
- // 1. 鏌ヨ棰勭暀璁板綍
- WmsInventoryReserveDO reserve = reserveMapper.selectByReserveNo(reserveNo);
- if (reserve == null) {
- throw exception(INVENTORY_RESERVE_NOT_EXISTS);
- }
- // 1.1 鏍¢獙鐘舵�侊細鍙湁棰勭暀涓垨閮ㄥ垎浣跨敤鐘舵�佸彲閲婃斁
- if (reserve.getStatus() != WmsReserveStatusEnum.RESERVED.getStatus()
- && reserve.getStatus() != WmsReserveStatusEnum.PARTIAL_USED.getStatus()) {
- throw exception(INVENTORY_RESERVE_STATUS_INVALID);
- }
-
- // 2. 璁$畻閲婃斁鏁伴噺
- BigDecimal releaseQuantity = reserve.getReserveQuantity().subtract(reserve.getUsedQuantity());
-
- // 3. 鏇存柊棰勭暀鐘舵��
- reserve.setStatus(WmsReserveStatusEnum.RELEASED.getStatus());
- reserveMapper.updateById(reserve);
-
- // 4. 璁板綍浜嬪姟娴佹按锛堥噴鏀句负璐熸暟锛�
- transactionService.createTransaction(buildReleaseTransaction(reserve, releaseQuantity.negate()));
- }
-
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void useReserve(WmsUseReserveReqDTO reqDTO) {
- // 1. 鏌ヨ棰勭暀璁板綍
- WmsInventoryReserveDO reserve = reserveMapper.selectByReserveNo(reqDTO.getReserveNo());
- if (reserve == null) {
- throw exception(INVENTORY_RESERVE_NOT_EXISTS);
- }
- // 1.1 鏍¢獙鐘舵��
- if (reserve.getStatus() != WmsReserveStatusEnum.RESERVED.getStatus()
- && reserve.getStatus() != WmsReserveStatusEnum.PARTIAL_USED.getStatus()) {
- throw exception(INVENTORY_RESERVE_STATUS_INVALID);
- }
-
- // 2. 璁$畻鍓╀綑鍙娇鐢ㄦ暟閲�
- BigDecimal remainQuantity = reserve.getReserveQuantity().subtract(reserve.getUsedQuantity());
- if (reqDTO.getQuantity().compareTo(remainQuantity) > 0) {
- throw exception(INVENTORY_RESERVE_QUANTITY_NOT_ENOUGH, reqDTO.getReserveNo(), remainQuantity, reqDTO.getQuantity());
- }
-
- // 3. 鏇存柊宸蹭娇鐢ㄦ暟閲忓拰鐘舵��
- BigDecimal newUsedQuantity = reserve.getUsedQuantity().add(reqDTO.getQuantity());
- reserve.setUsedQuantity(newUsedQuantity);
- if (newUsedQuantity.compareTo(reserve.getReserveQuantity()) == 0) {
- reserve.setStatus(WmsReserveStatusEnum.USED.getStatus());
- } else {
- reserve.setStatus(WmsReserveStatusEnum.PARTIAL_USED.getStatus());
- }
- reserveMapper.updateById(reserve);
- }
-
- @Override
- public List<WmsInventoryReserveDO> getReserveListByBiz(Integer bizType, Long bizId) {
- return reserveMapper.selectListByBiz(bizType, bizId);
- }
-
- @Override
- public PageResult<WmsInventoryReserveDO> getReservePage(WmsInventoryReservePageReqVO reqVO) {
- return reserveMapper.selectPage(reqVO);
- }
-
- @Override
- public WmsInventoryReserveDO getReserve(Long id) {
- return reserveMapper.selectById(id);
- }
-
- @Override
- public BigDecimal getReserveQuantity(Long skuId, Long warehouseId) {
- return reserveMapper.selectReserveQuantity(skuId, warehouseId);
- }
-
- /**
- * 鐢熸垚棰勭暀鍗曞彿
- */
- private String generateReserveNo() {
- return "RES" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))
- + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
- }
-
- /**
- * 鏋勫缓棰勭暀浜嬪姟娴佹按
- */
- private WmsInventoryTransactionDO buildReserveTransaction(WmsInventoryReserveDO reserve, BigDecimal quantity) {
- return WmsInventoryTransactionDO.builder()
- .transactionNo(generateTransactionNo())
- .transactionType(WmsTransactionTypeEnum.RESERVE.getType())
- .bizType(reserve.getBizType())
- .bizId(reserve.getBizId())
- .bizNo(reserve.getBizNo())
- .skuId(reserve.getSkuId())
- .warehouseId(reserve.getWarehouseId())
- .quantity(quantity)
- .reserveId(reserve.getId())
- .reserveNo(reserve.getReserveNo())
- .transactionTime(LocalDateTime.now())
- .remark(reserve.getRemark())
- .build();
- }
-
- /**
- * 鏋勫缓閲婃斁浜嬪姟娴佹按
- */
- private WmsInventoryTransactionDO buildReleaseTransaction(WmsInventoryReserveDO reserve, BigDecimal quantity) {
- return WmsInventoryTransactionDO.builder()
- .transactionNo(generateTransactionNo())
- .transactionType(WmsTransactionTypeEnum.RELEASE.getType())
- .bizType(reserve.getBizType())
- .bizId(reserve.getBizId())
- .bizNo(reserve.getBizNo())
- .skuId(reserve.getSkuId())
- .warehouseId(reserve.getWarehouseId())
- .quantity(quantity)
- .reserveId(reserve.getId())
- .reserveNo(reserve.getReserveNo())
- .transactionTime(LocalDateTime.now())
- .remark("閲婃斁棰勭暀")
- .build();
- }
-
- /**
- * 鐢熸垚浜嬪姟娴佹按鍙�
- */
- private String generateTransactionNo() {
- return "TRX" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
- + UUID.randomUUID().toString().substring(0, 6).toUpperCase();
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryService.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryService.java
index 6329588..8eb2c5d 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryService.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryService.java
@@ -7,7 +7,6 @@
import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryCheckReqDTO;
-import java.math.BigDecimal;
import java.util.List;
/**
@@ -62,14 +61,5 @@
* @param reqDTO 搴撳瓨鍙樻洿璇锋眰
*/
void changeInventory(WmsInventoryChangeReqDTO reqDTO);
-
- /**
- * 鑾峰彇鍙敤搴撳瓨鏁伴噺锛堟�诲簱瀛� - 棰勭暀搴撳瓨锛�
- *
- * @param skuId SKU 缂栧彿
- * @param warehouseId 浠撳簱缂栧彿
- * @return 鍙敤搴撳瓨鏁伴噺
- */
- BigDecimal getAvailableQuantity(Long skuId, Long warehouseId);
}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImpl.java
index 37f2cf0..3ff81ad 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImpl.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImpl.java
@@ -10,11 +10,9 @@
import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryHistoryDO;
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryReserveDO;
import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryMapper;
-import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryReserveMapper;
import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryCheckReqDTO;
import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
@@ -52,9 +50,6 @@
@Resource
private WmsInventoryHistoryService inventoryHistoryService;
-
- @Resource
- private WmsInventoryReserveMapper reserveMapper;
@Resource
private WmsItemSkuService itemSkuService;
@@ -297,21 +292,6 @@
WmsItemDO itemDO = itemService.validateItemExists(skuDO.getItemId());
return exception(INVENTORY_QUANTITY_NOT_ENOUGH, itemDO.getName(), skuDO.getName(),
item.getWarehouseId(), beforeQuantity, item.getQuantity());
- }
-
- @Override
- public BigDecimal getAvailableQuantity(Long skuId, Long warehouseId) {
- // 1. 鏌ヨ搴撳瓨鏁伴噺
- WmsInventoryDO inventory = inventoryMapper.selectBySkuIdAndWarehouseId(skuId, warehouseId);
- if (inventory == null) {
- return BigDecimal.ZERO;
- }
-
- // 2. 鏌ヨ棰勭暀鏁伴噺
- BigDecimal reserveQuantity = reserveMapper.selectReserveQuantity(skuId, warehouseId);
-
- // 3. 璁$畻鍙敤鏁伴噺
- return inventory.getQuantity().subtract(reserveQuantity != null ? reserveQuantity : BigDecimal.ZERO);
}
}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryTransactionService.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryTransactionService.java
deleted file mode 100644
index 961032c..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryTransactionService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.wms.service.inventory;
-
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryTransactionDO;
-
-import java.util.List;
-
-/**
- * WMS 搴撳瓨浜嬪姟娴佹按 Service 鎺ュ彛
- *
- * @author 鑺嬮亾婧愮爜
- */
-public interface WmsInventoryTransactionService {
-
- /**
- * 鍒涘缓浜嬪姟娴佹按
- *
- * @param transaction 浜嬪姟娴佹按
- * @return 浜嬪姟娴佹按ID
- */
- Long createTransaction(WmsInventoryTransactionDO transaction);
-
- /**
- * 鎵归噺鍒涘缓浜嬪姟娴佹按
- *
- * @param transactions 浜嬪姟娴佹按鍒楄〃
- */
- void createTransactionList(List<WmsInventoryTransactionDO> transactions);
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryTransactionServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryTransactionServiceImpl.java
deleted file mode 100644
index 930183f..0000000
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryTransactionServiceImpl.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package cn.iocoder.yudao.module.wms.service.inventory;
-
-import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryTransactionDO;
-import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryTransactionMapper;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.List;
-
-/**
- * WMS 搴撳瓨浜嬪姟娴佹按 Service 瀹炵幇绫�
- *
- * @author 鑺嬮亾婧愮爜
- */
-@Service
-@Validated
-@Slf4j
-public class WmsInventoryTransactionServiceImpl implements WmsInventoryTransactionService {
-
- @Resource
- private WmsInventoryTransactionMapper transactionMapper;
-
- @Override
- public Long createTransaction(WmsInventoryTransactionDO transaction) {
- transactionMapper.insert(transaction);
- return transaction.getId();
- }
-
- @Override
- public void createTransactionList(List<WmsInventoryTransactionDO> transactions) {
- if (transactions != null && !transactions.isEmpty()) {
- transactionMapper.insertBatch(transactions);
- }
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java
index 7875778..191ca86 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java
@@ -1,24 +1,23 @@
package cn.iocoder.yudao.module.wms.service.md.item;
import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemCreateReqDTO;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemUpdateReqDTO;
-import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi;
-import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemListReqVO;
import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO;
import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemSaveReqVO;
import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemMapper;
import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
-import java.util.*;
-import java.util.stream.Collectors;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
@@ -26,91 +25,129 @@
/**
* WMS 鍟嗗搧 Service 瀹炵幇绫�
*
- * 鏀归�犺鏄庯細WMS 鍟嗗搧鏁版嵁鏉ユ簮浜� MDM 鐗╂枡涓绘暟鎹�
- * - 鎵�鏈夋搷浣滆皟鐢� MDM API
- * - WMS 鍟嗗搧瀵瑰簲 MDM 鐗╂枡绫诲瀷 = 鐗╂枡锛坕temType = 1锛�
- * - 瀛楁鏄犲皠锛歐msItemDO.unit <- MDM 璁¢噺鍗曚綅鍚嶇О
- *
* @author 鑺嬮亾婧愮爜
*/
@Service
@Validated
public class WmsItemServiceImpl implements WmsItemService {
- /** WMS 鍟嗗搧瀵瑰簲鐨� MDM 鐗╂枡绫诲瀷锛氱墿鏂� */
- private static final int MDM_ITEM_TYPE_MATERIAL = 1;
-
@Resource
- private MdmItemApi mdmItemApi;
-
+ private WmsItemMapper itemMapper;
@Resource
- private MdmUnitMeasureApi mdmUnitMeasureApi;
+ @Lazy // 寤惰繜鍔犺浇锛岄伩鍏嶅惊鐜緷璧�
+ private WmsItemCategoryService categoryService;
+ @Resource
+ @Lazy // 寤惰繜鍔犺浇锛岄伩鍏嶅惊鐜緷璧�
+ private WmsItemBrandService brandService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
@Override
+ @Transactional(rollbackFor = Exception.class)
public Long createItem(WmsItemSaveReqVO createReqVO) {
// 鏍¢獙鏁版嵁
validateItemSaveData(createReqVO);
- // 鏋勫缓鍒涘缓璇锋眰骞惰皟鐢� MDM API
- MdmItemCreateReqDTO createReqDTO = buildCreateReqDTO(createReqVO);
- return mdmItemApi.createItem(createReqDTO).getCheckedData();
+ // 鎻掑叆鍟嗗搧
+ WmsItemDO item = BeanUtils.toBean(createReqVO, WmsItemDO.class);
+ itemMapper.insert(item);
+ // 鎻掑叆 SKU
+ itemSkuService.createItemSkuList(item.getId(), createReqVO.getSkus());
+ return item.getId();
}
@Override
+ @Transactional(rollbackFor = Exception.class)
public void updateItem(WmsItemSaveReqVO updateReqVO) {
// 鏍¢獙瀛樺湪
validateItemExists(updateReqVO.getId());
// 鏍¢獙鏁版嵁
validateItemSaveData(updateReqVO);
- // 鏋勫缓鏇存柊璇锋眰骞惰皟鐢� MDM API
- MdmItemUpdateReqDTO updateReqDTO = buildUpdateReqDTO(updateReqVO);
- mdmItemApi.updateItem(updateReqDTO);
+ // 鏇存柊鍟嗗搧
+ WmsItemDO updateObj = BeanUtils.toBean(updateReqVO, WmsItemDO.class);
+ itemMapper.updateById(updateObj);
+ // 鏇存柊 SKU
+ itemSkuService.updateItemSkuList(updateReqVO.getId(), updateReqVO.getSkus());
+ }
+
+ private void validateItemSaveData(WmsItemSaveReqVO reqVO) {
+ // 鏍¢獙鍟嗗搧缂栧彿鍞竴
+ validateItemCodeUnique(reqVO.getId(), reqVO.getCode());
+ // 鏍¢獙鍟嗗搧鍚嶇О鍞竴
+ validateItemNameUnique(reqVO.getId(), reqVO.getName());
+ // 鏍¢獙鍟嗗搧鍒嗙被瀛樺湪
+ validateCategoryExists(reqVO.getCategoryId());
+ // 鏍¢獙鍟嗗搧鍝佺墝瀛樺湪
+ validateBrandExists(reqVO.getBrandId());
+ }
+
+ private void validateItemCodeUnique(Long id, String code) {
+ WmsItemDO item = itemMapper.selectByCode(code);
+ if (item == null) {
+ return;
+ }
+ if (id == null || ObjectUtil.notEqual(item.getId(), id)) {
+ throw exception(ITEM_CODE_DUPLICATE);
+ }
+ }
+
+ private void validateItemNameUnique(Long id, String name) {
+ WmsItemDO item = itemMapper.selectByName(name);
+ if (item == null) {
+ return;
+ }
+ if (id == null || ObjectUtil.notEqual(item.getId(), id)) {
+ throw exception(ITEM_NAME_DUPLICATE);
+ }
+ }
+
+ private void validateCategoryExists(Long categoryId) {
+ categoryService.validateItemCategoryExists(categoryId);
+ }
+
+ private void validateBrandExists(Long brandId) {
+ if (brandId == null) {
+ return;
+ }
+ brandService.validateItemBrandExists(brandId);
}
@Override
+ @Transactional(rollbackFor = Exception.class)
public void deleteItem(Long id) {
// 鏍¢獙瀛樺湪
validateItemExists(id);
- // WMS 鍟嗗搧鍒犻櫎瀹為檯涓虹鐢紙MDM 鐗╂枡涓嶈兘鐗╃悊鍒犻櫎锛�
- mdmItemApi.updateItemStatus(id, CommonStatusEnum.DISABLE.getStatus());
+
+ // 鍒犻櫎鍟嗗搧鍜� SKU
+ itemSkuService.deleteItemSkuListByItemId(id);
+ itemMapper.deleteById(id);
}
@Override
public WmsItemDO validateItemExists(Long id) {
- MdmItemRespDTO item = mdmItemApi.validateItemExists(id).getCheckedData();
- return convertToWmsItemDO(item);
+ WmsItemDO item = itemMapper.selectById(id);
+ if (item == null) {
+ throw exception(ITEM_NOT_EXISTS);
+ }
+ return item;
}
@Override
public WmsItemDO getItem(Long id) {
- MdmItemRespDTO item = mdmItemApi.getItem(id).getCheckedData();
- if (item == null) {
- return null;
- }
- return convertToWmsItemDO(item);
+ return itemMapper.selectById(id);
}
@Override
public PageResult<WmsItemDO> getItemPage(WmsItemPageReqVO pageReqVO) {
- // 璋冪敤 MDM API 鍒嗛〉鏌ヨ
- PageResult<MdmItemRespDTO> mdmPageResult = mdmItemApi.getItemPage(
- MDM_ITEM_TYPE_MATERIAL,
- pageReqVO.getStatus(),
- pageReqVO.getPageNo(),
- pageReqVO.getPageSize()
- ).getCheckedData();
-
- // 杞崲缁撴灉
- List<WmsItemDO> itemList = convertToWmsItemDOList(mdmPageResult.getList());
- return new PageResult<>(itemList, mdmPageResult.getTotal());
+ return itemMapper.selectPage(pageReqVO,
+ categoryService.getSelfAndChildItemCategoryIdList(pageReqVO.getCategoryId()));
}
@Override
public List<WmsItemDO> getItemList(WmsItemListReqVO listReqVO) {
- // 璋冪敤 MDM API 鑾峰彇鍒楄〃
- List<MdmItemRespDTO> itemList = mdmItemApi.getItemListByStatus(listReqVO.getStatus()).getCheckedData();
- return convertToWmsItemDOList(itemList);
+ return itemMapper.selectList(listReqVO,
+ categoryService.getSelfAndChildItemCategoryIdList(listReqVO.getCategoryId()));
}
@Override
@@ -118,140 +155,17 @@
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
}
- List<MdmItemRespDTO> itemList = mdmItemApi.getItemList(ids).getCheckedData();
- return convertToWmsItemDOList(itemList);
+ return itemMapper.selectByIds(ids);
}
@Override
public long getItemCountByCategoryId(Long categoryId) {
- return mdmItemApi.getItemCountByCategoryId(categoryId).getCheckedData();
+ return itemMapper.selectCountByCategoryId(categoryId);
}
@Override
public long getItemCountByBrandId(Long brandId) {
- // MDM 鏆傛棤鎸夊搧鐗岀粺璁℃柟娉曪紝杩斿洖 0
- return 0L;
+ return itemMapper.selectCountByBrandId(brandId);
}
- // ==================== 绉佹湁鏂规硶 ====================
-
- /**
- * 鏍¢獙鍟嗗搧淇濆瓨鏁版嵁
- */
- private void validateItemSaveData(WmsItemSaveReqVO reqVO) {
- // 鏍¢獙鍟嗗搧缂栫爜鍞竴
- if (reqVO.getCode() != null) {
- MdmItemRespDTO existItem = mdmItemApi.getItemByCode(reqVO.getCode()).getCheckedData();
- if (existItem != null && !existItem.getId().equals(reqVO.getId())) {
- throw exception(ITEM_CODE_DUPLICATE);
- }
- }
- // 鏍¢獙鍟嗗搧鍚嶇О鍞竴
- if (reqVO.getName() != null) {
- // MDM 鏆傛棤鎸夊悕绉版煡璇㈡柟娉曪紝璺宠繃姝ゆ牎楠�
- }
- }
-
- /**
- * 鏋勫缓鍒涘缓璇锋眰 DTO
- */
- private MdmItemCreateReqDTO buildCreateReqDTO(WmsItemSaveReqVO saveReqVO) {
- MdmItemCreateReqDTO createReqDTO = new MdmItemCreateReqDTO();
- createReqDTO.setCode(saveReqVO.getCode());
- createReqDTO.setName(saveReqVO.getName());
- createReqDTO.setCategoryId(saveReqVO.getCategoryId());
- createReqDTO.setBrandId(saveReqVO.getBrandId());
- createReqDTO.setUnitMeasureId(saveReqVO.getUnitMeasureId());
- createReqDTO.setItemType(MDM_ITEM_TYPE_MATERIAL);
- createReqDTO.setStatus(CommonStatusEnum.ENABLE.getStatus());
- createReqDTO.setRemark(saveReqVO.getRemark());
- return createReqDTO;
- }
-
- /**
- * 鏋勫缓鏇存柊璇锋眰 DTO
- */
- private MdmItemUpdateReqDTO buildUpdateReqDTO(WmsItemSaveReqVO saveReqVO) {
- MdmItemUpdateReqDTO updateReqDTO = new MdmItemUpdateReqDTO();
- updateReqDTO.setId(saveReqVO.getId());
- updateReqDTO.setCode(saveReqVO.getCode());
- updateReqDTO.setName(saveReqVO.getName());
- updateReqDTO.setCategoryId(saveReqVO.getCategoryId());
- updateReqDTO.setBrandId(saveReqVO.getBrandId());
- updateReqDTO.setUnitMeasureId(saveReqVO.getUnitMeasureId());
- updateReqDTO.setStatus(CommonStatusEnum.ENABLE.getStatus());
- updateReqDTO.setRemark(saveReqVO.getRemark());
- return updateReqDTO;
- }
-
- /**
- * 杞崲 MDM 鐗╂枡涓� WMS 鍟嗗搧
- */
- private WmsItemDO convertToWmsItemDO(MdmItemRespDTO mdmItem) {
- if (mdmItem == null) {
- return null;
- }
- WmsItemDO item = new WmsItemDO();
- item.setId(mdmItem.getId());
- item.setCode(mdmItem.getCode());
- item.setName(mdmItem.getName());
- item.setCategoryId(mdmItem.getCategoryId());
- item.setBrandId(mdmItem.getBrandId());
- item.setRemark(mdmItem.getRemark());
-
- // 鑾峰彇璁¢噺鍗曚綅鍚嶇О
- if (mdmItem.getUnitMeasureId() != null) {
- MdmUnitMeasureRespDTO unit = mdmUnitMeasureApi.getUnitMeasure(mdmItem.getUnitMeasureId()).getCheckedData();
- if (unit != null) {
- item.setUnit(unit.getName());
- }
- }
- return item;
- }
-
- /**
- * 鎵归噺杞崲 MDM 鐗╂枡鍒楄〃涓� WMS 鍟嗗搧鍒楄〃
- */
- private List<WmsItemDO> convertToWmsItemDOList(List<MdmItemRespDTO> mdmItemList) {
- if (CollUtil.isEmpty(mdmItemList)) {
- return Collections.emptyList();
- }
-
- // 鎵归噺鑾峰彇璁¢噺鍗曚綅
- Set<Long> unitIds = mdmItemList.stream()
- .map(MdmItemRespDTO::getUnitMeasureId)
- .filter(Objects::nonNull)
- .collect(Collectors.toSet());
-
- Map<Long, MdmUnitMeasureRespDTO> unitMap = new HashMap<>();
- if (!unitIds.isEmpty()) {
- List<MdmUnitMeasureRespDTO> units = mdmUnitMeasureApi.getUnitMeasureList(unitIds).getCheckedData();
- for (MdmUnitMeasureRespDTO unit : units) {
- unitMap.put(unit.getId(), unit);
- }
- }
-
- // 杞崲鍒楄〃
- List<WmsItemDO> result = new ArrayList<>();
- for (MdmItemRespDTO mdmItem : mdmItemList) {
- WmsItemDO item = new WmsItemDO();
- item.setId(mdmItem.getId());
- item.setCode(mdmItem.getCode());
- item.setName(mdmItem.getName());
- item.setCategoryId(mdmItem.getCategoryId());
- item.setBrandId(mdmItem.getBrandId());
- item.setRemark(mdmItem.getRemark());
-
- // 璁剧疆鍗曚綅鍚嶇О
- if (mdmItem.getUnitMeasureId() != null) {
- MdmUnitMeasureRespDTO unit = unitMap.get(mdmItem.getUnitMeasureId());
- if (unit != null) {
- item.setUnit(unit.getName());
- }
- }
- result.add(item);
- }
- return result;
- }
-
-}
\ No newline at end of file
+}
diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java
index 427e41f..8306fc0 100644
--- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java
+++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java
@@ -5,8 +5,6 @@
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.mdm.api.item.MdmItemSkuApi;
-import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemSkuRespDTO;
import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuPageReqVO;
import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSaveReqVO;
import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
@@ -35,9 +33,6 @@
/**
* WMS 鍟嗗搧 SKU Service 瀹炵幇绫�
*
- * 鏀归�犺鏄庯細WMS SKU 鏁版嵁鏉ユ簮浜� MDM 鐗╂枡 SKU
- * - getItemSkuListByIds/validateItemSkuExists 璋冪敤 MDM SKU API
- *
* @author 鑺嬮亾婧愮爜
*/
@Service
@@ -46,10 +41,6 @@
@Resource
private WmsItemSkuMapper itemSkuMapper;
-
- @Resource
- private MdmItemSkuApi mdmItemSkuApi;
-
@Resource
@Lazy // 寤惰繜鍔犺浇锛岄伩鍏嶅惊鐜緷璧�
private WmsInventoryService inventoryService;
@@ -120,26 +111,26 @@
@Override
public WmsItemSkuDO validateItemSkuExists(Long id) {
- MdmItemSkuRespDTO sku = mdmItemSkuApi.validateItemSkuExists(id).getCheckedData();
- return BeanUtils.toBean(sku, WmsItemSkuDO.class);
+ WmsItemSkuDO sku = itemSkuMapper.selectById(id);
+ if (sku == null) {
+ throw exception(ITEM_SKU_NOT_EXISTS);
+ }
+ return sku;
}
@Override
public List<WmsItemSkuDO> getItemSkuList(Long itemId) {
- List<MdmItemSkuRespDTO> list = mdmItemSkuApi.getItemSkuListByItemId(itemId).getCheckedData();
- return BeanUtils.toBean(list, WmsItemSkuDO.class);
+ return itemSkuMapper.selectListByItemId(itemId);
}
@Override
public List<WmsItemSkuDO> getItemSkuList(Collection<Long> itemIds) {
- // MDM API 鏆備笉鏀寔鎸夊涓墿鏂� ID 鏌ヨ SKU锛屾殏鏃惰繑鍥炵┖鍒楄〃
- return ListUtil.of();
+ return itemSkuMapper.selectListByItemIds(itemIds);
}
@Override
public List<WmsItemSkuDO> getItemSkuList(Collection<Long> itemIds, String code, String name) {
- // MDM API 鏆備笉鏀寔澶嶆潅鏌ヨ锛屾殏鏃惰繑鍥炵┖鍒楄〃
- return ListUtil.of();
+ return itemSkuMapper.selectList(itemIds, code, name);
}
@Override
@@ -147,14 +138,12 @@
if (CollUtil.isEmpty(ids)) {
return ListUtil.of();
}
- List<MdmItemSkuRespDTO> list = mdmItemSkuApi.getItemSkuList(ids).getCheckedData();
- return BeanUtils.toBean(list, WmsItemSkuDO.class);
+ return itemSkuMapper.selectByIds(ids);
}
@Override
public PageResult<WmsItemSkuDO> getItemSkuPage(WmsItemSkuPageReqVO pageReqVO) {
- // MDM API 鏆備笉鏀寔鍒嗛〉鏌ヨ SKU锛屾殏鏃惰繑鍥炵┖缁撴灉
- return new PageResult<>(ListUtil.of(), 0L);
+ return itemSkuMapper.selectPage(pageReqVO);
}
private void validateItemSkuList(List<WmsItemSkuSaveReqVO> skus) {
diff --git a/yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImplTest.java b/yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImplTest.java
index 22b4ca1..3585c6e 100644
--- a/yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImplTest.java
+++ b/yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImplTest.java
@@ -241,6 +241,46 @@
}
@Test
+ public void testChangeInventory_multipleExistingInventoryKeys() {
+ // mock 鏁版嵁
+ WmsItemDO item = createItem("ITEM-001", "绾㈠瘜澹嫻鏋�");
+ WmsItemSkuDO sku = createSku(item.getId(), "SKU-001", "10kg 绠辫");
+ inventoryMapper.insert(createInventory(sku.getId(), 200L, "7.00"));
+ inventoryMapper.insert(createInventory(sku.getId(), 100L, "5.00"));
+ WmsInventoryChangeReqDTO reqDTO = createChangeReq(sku.getId(), 100L, "2.00");
+ List<WmsInventoryChangeReqDTO.Item> items = new ArrayList<>(reqDTO.getItems());
+ items.add(new WmsInventoryChangeReqDTO.Item()
+ .setSkuId(sku.getId())
+ .setWarehouseId(200L)
+ .setQuantity(new BigDecimal("3.00"))
+ .setPrice(new BigDecimal("100.00"))
+ .setTotalPrice(new BigDecimal("300.00"))
+ .setRemark("娴嬭瘯鍏ュ簱 2"));
+ reqDTO.setItems(items);
+
+ // 璋冪敤
+ inventoryService.changeInventory(reqDTO);
+
+ // 鏂█锛氬鏉″凡瀛樺湪搴撳瓨浣欓鍒嗗埆鏇存柊
+ WmsInventoryDO inventory1 = inventoryMapper.selectBySkuIdAndWarehouseId(sku.getId(), 100L);
+ assertNotNull(inventory1);
+ assertEquals(0, new BigDecimal("7.00").compareTo(inventory1.getQuantity()));
+ WmsInventoryDO inventory2 = inventoryMapper.selectBySkuIdAndWarehouseId(sku.getId(), 200L);
+ assertNotNull(inventory2);
+ assertEquals(0, new BigDecimal("10.00").compareTo(inventory2.getQuantity()));
+ // 鏂█锛氬簱瀛樻祦姘翠繚鎸佸叆鍙傛槑缁嗛『搴�
+ List<WmsInventoryHistoryDO> histories = inventoryHistoryMapper.selectList();
+ histories.sort(Comparator.comparing(WmsInventoryHistoryDO::getId));
+ assertEquals(2, histories.size());
+ assertEquals(100L, histories.get(0).getWarehouseId());
+ assertEquals(0, new BigDecimal("5.00").compareTo(histories.get(0).getBeforeQuantity()));
+ assertEquals(0, new BigDecimal("7.00").compareTo(histories.get(0).getAfterQuantity()));
+ assertEquals(200L, histories.get(1).getWarehouseId());
+ assertEquals(0, new BigDecimal("7.00").compareTo(histories.get(1).getBeforeQuantity()));
+ assertEquals(0, new BigDecimal("10.00").compareTo(histories.get(1).getAfterQuantity()));
+ }
+
+ @Test
public void testChangeInventory_concurrentCreateSameInventoryOnlyOneBalance() throws Exception {
// mock 鏁版嵁
WmsItemDO item = createItem("ITEM-001", "绾㈠瘜澹嫻鏋�");
diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml
index 8005054..fcac3d7 100644
--- a/yudao-server/pom.xml
+++ b/yudao-server/pom.xml
@@ -32,12 +32,12 @@
<version>${revision}</version>
</dependency>
- <!-- 浼氬憳涓績銆傞粯璁ゆ敞閲婏紝淇濊瘉缂栬瘧閫熷害 -->
-<!-- <dependency>-->
-<!-- <groupId>cn.iocoder.boot</groupId>-->
-<!-- <artifactId>yudao-module-member</artifactId>-->
-<!-- <version>${revision}</version>-->
-<!-- </dependency>-->
+ <!-- 浼氬憳涓績 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-module-member</artifactId>
+ <version>${revision}</version>
+ </dependency>
<!-- 鏁版嵁鎶ヨ〃銆傞粯璁ゆ敞閲婏紝淇濊瘉缂栬瘧閫熷害 -->
<!-- <dependency>-->
@@ -45,7 +45,7 @@
<!-- <artifactId>yudao-module-report</artifactId>-->
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
- <!-- 宸ヤ綔娴併�傞粯璁ゆ敞閲婏紝淇濊瘉缂栬瘧閫熷害 -->
+ <!-- 宸ヤ綔娴� -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-bpm</artifactId>
@@ -65,7 +65,7 @@
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
- <!-- 鍟嗗煄鐩稿叧妯″潡銆傞粯璁ゆ敞閲婏紝淇濊瘉缂栬瘧閫熷害-->
+ <!-- 鍟嗗煄鐩稿叧妯″潡銆傞粯璁ゆ敞閲婏紝淇濊瘉缂栬瘧閫熷害 -->
<!-- <dependency>-->
<!-- <groupId>cn.iocoder.boot</groupId>-->
<!-- <artifactId>yudao-module-product</artifactId>-->
@@ -87,14 +87,14 @@
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
- <!-- CRM 鐩稿叧妯″潡銆傞粯璁ゆ敞閲婏紝淇濊瘉缂栬瘧閫熷害 -->
+ <!-- CRM 鐩稿叧妯″潡 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-crm</artifactId>
<version>${revision}</version>
</dependency>
- <!-- ERP 鐩稿叧妯″潡銆傞粯璁ゆ敞閲婏紝淇濊瘉缂栬瘧閫熷害 -->
+ <!-- ERP 鐩稿叧妯″潡 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-erp</artifactId>
@@ -129,10 +129,10 @@
<version>${revision}</version>
</dependency>
- <!-- MDM 涓绘暟鎹鐞嗘ā鍧� -->
+ <!-- IM 鐩稿叧妯″潡 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
- <artifactId>yudao-module-mdm</artifactId>
+ <artifactId>yudao-module-im</artifactId>
<version>${revision}</version>
</dependency>
diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml
index 812e23c..e7d979f 100644
--- a/yudao-server/src/main/resources/application-dev.yaml
+++ b/yudao-server/src/main/resources/application-dev.yaml
@@ -7,11 +7,21 @@
autoconfigure:
# noinspection SpringBootApplicationYaml
exclude:
- - com.binarywang.spring.starter.wxjava.mp.config.storage.WxMpInRedisTemplateConfigStorageConfiguration
- - com.binarywang.spring.starter.wxjava.miniapp.config.storage.WxMaInRedisTemplateConfigStorageConfiguration
- - org.dromara.trans.config.TransServiceConfig # easy-trans 3.0.6 渚濊禆 Spring Boot 3 鐨� RestTemplateBuilder锛屾殏鏃剁鐢�
- org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Qdrant锛屾墜鍔ㄥ垱寤�
+ - org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Redis锛屾墜鍔ㄥ垱寤�
- org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Milvus锛屾墜鍔ㄥ垱寤�
+ - org.dromara.trans.config.TransServiceConfig # TODO 鑺嬭壙锛歟asy-trans 鍏煎 Spring Boot 4 鍚庣Щ闄わ紙TransServiceConfig 寮曠敤浜嗗凡绉婚櫎鐨� RestTemplateBuilder锛�
+ # TODO 鑺嬭壙锛歴pring-ai-alibaba 2.0.0-M1.1 鐨� DashScope 鑷姩閰嶇疆鏆備笉鍏煎 Spring AI 2.0.0
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAgentAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeImageAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeVideoAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAudioSpeechAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAudioTranscriptionAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeRerankAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeEmbeddingAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeMultimodalEmbeddingAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAsyncToolCallingManagerAutoConfiguration
# 鏁版嵁婧愰厤缃」
datasource:
druid: # Druid 銆愮洃鎺с�戠浉鍏崇殑鍏ㄥ眬閰嶇疆
diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml
index 0bbd73a..e256fdc 100644
--- a/yudao-server/src/main/resources/application-local.yaml
+++ b/yudao-server/src/main/resources/application-local.yaml
@@ -6,12 +6,22 @@
autoconfigure:
# noinspection SpringBootApplicationYaml
exclude:
-# - com.binarywang.spring.starter.wxjava.mp.config.storage.WxMpInRedisTemplateConfigStorageConfiguration
-# - com.binarywang.spring.starter.wxjava.miniapp.config.storage.WxMaInRedisTemplateConfigStorageConfiguration
- org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 榛樿 local 鐜锛屼笉寮�鍚� Quartz 鐨勮嚜鍔ㄩ厤缃�
- - org.dromara.trans.config.TransServiceConfig # easy-trans 3.0.6 渚濊禆 Spring Boot 3 鐨� RestTemplateBuilder锛屾殏鏃剁鐢�
- org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Qdrant锛屾墜鍔ㄥ垱寤�
+ - org.springframework.ai.vectorstore.redis.autoconfigure.RedisVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Redis锛屾墜鍔ㄥ垱寤�
- org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Milvus锛屾墜鍔ㄥ垱寤�
+ - org.dromara.trans.config.TransServiceConfig # TODO 鑺嬭壙锛歟asy-trans 鍏煎 Spring Boot 4 鍚庣Щ闄わ紙TransServiceConfig 寮曠敤浜嗗凡绉婚櫎鐨� RestTemplateBuilder锛�
+ # TODO 鑺嬭壙锛歴pring-ai-alibaba 2.0.0-M1.1 鐨� DashScope 鑷姩閰嶇疆鏆備笉鍏煎 Spring AI 2.0.0
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeChatAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAgentAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeImageAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeVideoAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAudioSpeechAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAudioTranscriptionAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeRerankAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeEmbeddingAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeMultimodalEmbeddingAutoConfiguration
+ - com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAsyncToolCallingManagerAutoConfiguration
# 鏁版嵁婧愰厤缃」
datasource:
druid: # Druid 銆愮洃鎺с�戠浉鍏崇殑鍏ㄥ眬閰嶇疆
@@ -58,6 +68,7 @@
# url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 杩炴帴鐨勭ず渚�
# url: jdbc:kingbase8://127.0.0.1:54321/test # 浜哄ぇ閲戜粨 KingbaseES 杩炴帴鐨勭ず渚�
# url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 杩炴帴鐨勭ず渚�
+ # url: jdbc:postgresql://127.0.0.1:5866/ruoyi-vue-pro # 鐎氶珮 HighGo 杩炴帴鐨勭ず渚�
username: root
password: 123456
# username: sa # SQL Server 杩炴帴鐨勭ず渚�
@@ -66,6 +77,8 @@
# password: SYSDBA001 # DM 杩炴帴鐨勭ず渚�
# username: root # OpenGauss 杩炴帴鐨勭ず渚�
# password: Yudao@2024 # OpenGauss 杩炴帴鐨勭ず渚�
+ # username: root # 鐎氶珮 HighGo 杩炴帴鐨勭ず渚�
+ # password: 123456 # 鐎氶珮 HighGo 杩炴帴鐨勭ず渚�
slave: # 妯℃嫙浠庡簱锛屽彲鏍规嵁鑷繁闇�瑕佷慨鏀�
lazy: true # 寮�鍚噿鍔犺浇锛屼繚璇佸惎鍔ㄩ�熷害
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
@@ -73,7 +86,7 @@
password: 123456
# tdengine: # IoT 鏁版嵁搴擄紙闇�瑕� IoT 鐗╄仈缃戝啀寮�鍚櫌锛侊級
# lazy: true # 寮�鍚噿鍔犺浇锛屼繚璇佸惎鍔ㄩ�熷害
-# url: jdbc:TAOS-WS://127.0.0.1:6041/ruoyi_vue_pro?varcharAsString=true
+# url: jdbc:TAOS-WS://127.0.0.1:6041/ruoyi_vue_pro?varcharAsString=true&enableAutoReconnect=true # 鍙傝锛歨ttps://t.zsxq.com/qaX9c锛屽紑鍚� TDengine WebSocket 鑷姩閲嶈繛
# driver-class-name: com.taosdata.jdbc.ws.WebSocketDriver
# username: root
# password: taosdata
@@ -197,6 +210,7 @@
cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG
cn.iocoder.yudao.module.iot.service.rule: debug
cn.iocoder.yudao.module.ai.dal.mysql: debug
+ cn.iocoder.yudao.module.im.dal.mysql: debug
org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 鑺嬭壙锛氬厛绂佺敤锛孲pring Boot 3.X 瀛樺湪閮ㄥ垎閿欒鐨� WARN 鎻愮ず
debug: false
diff --git a/yudao-server/src/main/resources/application-test.yaml b/yudao-server/src/main/resources/application-test.yaml
deleted file mode 100644
index e5560b4..0000000
--- a/yudao-server/src/main/resources/application-test.yaml
+++ /dev/null
@@ -1,284 +0,0 @@
-server:
- port: 48080
-
---- #################### 鏁版嵁搴撶浉鍏抽厤缃� ####################
-spring:
- autoconfigure:
- # noinspection SpringBootApplicationYaml
- exclude:
- # - com.binarywang.spring.starter.wxjava.mp.config.storage.WxMpInRedisTemplateConfigStorageConfiguration
- # - com.binarywang.spring.starter.wxjava.miniapp.config.storage.WxMaInRedisTemplateConfigStorageConfiguration
- - org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration # 榛樿 local 鐜锛屼笉寮�鍚� Quartz 鐨勮嚜鍔ㄩ厤缃�
- - org.dromara.trans.config.TransServiceConfig # easy-trans 3.0.6 渚濊禆 Spring Boot 3 鐨� RestTemplateBuilder锛屾殏鏃剁鐢�
- - org.springframework.ai.vectorstore.qdrant.autoconfigure.QdrantVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Qdrant锛屾墜鍔ㄥ垱寤�
- - org.springframework.ai.vectorstore.milvus.autoconfigure.MilvusVectorStoreAutoConfiguration # 绂佺敤 AI 妯″潡鐨� Milvus锛屾墜鍔ㄥ垱寤�
- # 鏁版嵁婧愰厤缃」
- datasource:
- druid: # Druid 銆愮洃鎺с�戠浉鍏崇殑鍏ㄥ眬閰嶇疆
- web-stat-filter:
- enabled: true
- stat-view-servlet:
- enabled: true
- allow: # 璁剧疆鐧藉悕鍗曪紝涓嶅~鍒欏厑璁告墍鏈夎闂�
- url-pattern: /druid/*
- login-username: # 鎺у埗鍙扮鐞嗙敤鎴峰悕鍜屽瘑鐮�
- login-password:
- filter:
- stat:
- enabled: true
- log-slow-sql: true # 鎱� SQL 璁板綍
- slow-sql-millis: 100
- merge-sql: true
- wall:
- config:
- multi-statement-allow: true
- dynamic: # 澶氭暟鎹簮閰嶇疆
- druid: # Druid 銆愯繛鎺ユ睜銆戠浉鍏崇殑鍏ㄥ眬閰嶇疆
- initial-size: 1 # 鍒濆杩炴帴鏁�
- min-idle: 1 # 鏈�灏忚繛鎺ユ睜鏁伴噺
- max-active: 20 # 鏈�澶ц繛鎺ユ睜鏁伴噺
- max-wait: 60000 # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂达紝鍗曚綅锛氭绉掞紙1 鍒嗛挓锛�
- time-between-eviction-runs-millis: 60000 # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶏細姣锛�1 鍒嗛挓锛�
- min-evictable-idle-time-millis: 600000 # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忕敓瀛樼殑鏃堕棿锛屽崟浣嶏細姣锛�10 鍒嗛挓锛�
- max-evictable-idle-time-millis: 1800000 # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�澶х敓瀛樼殑鏃堕棿锛屽崟浣嶏細姣锛�30 鍒嗛挓锛�
- validation-query: SELECT 1 FROM DUAL # 閰嶇疆妫�娴嬭繛鎺ユ槸鍚︽湁鏁�
- test-while-idle: true
- test-on-borrow: false
- test-on-return: false
- pool-prepared-statements: true # 鏄惁寮�鍚� PreparedStatement 缂撳瓨
- max-pool-prepared-statement-per-connection-size: 20 # 姣忎釜杩炴帴缂撳瓨鐨� PreparedStatement 鏁伴噺
- primary: master
- datasource:
- master:
- url: jdbc:mysql://172.17.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 杩炴帴鐨勭ず渚�
- # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 杩炴帴鐨勭ず渚�
- # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 杩炴帴鐨勭ず渚�
- # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 杩炴帴鐨勭ず渚�
- # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 杩炴帴鐨勭ず渚�
- # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 杩炴帴鐨勭ず渚�
- # url: jdbc:kingbase8://127.0.0.1:54321/test # 浜哄ぇ閲戜粨 KingbaseES 杩炴帴鐨勭ず渚�
- # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 杩炴帴鐨勭ず渚�
- username: root
- password: xd@123456..
- # username: sa # SQL Server 杩炴帴鐨勭ず渚�
- # password: Yudao@2024 # SQL Server 杩炴帴鐨勭ず渚�
- # username: SYSDBA # DM 杩炴帴鐨勭ず渚�
- # password: SYSDBA001 # DM 杩炴帴鐨勭ず渚�
- # username: root # OpenGauss 杩炴帴鐨勭ず渚�
- # password: Yudao@2024 # OpenGauss 杩炴帴鐨勭ず渚�
- slave: # 妯℃嫙浠庡簱锛屽彲鏍规嵁鑷繁闇�瑕佷慨鏀�
- lazy: true # 寮�鍚噿鍔犺浇锛屼繚璇佸惎鍔ㄩ�熷害
- url: jdbc:mysql://172.17.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
- username: root
- password: xd@123456..
- # tdengine: # IoT 鏁版嵁搴擄紙闇�瑕� IoT 鐗╄仈缃戝啀寮�鍚櫌锛侊級
- # lazy: true # 寮�鍚噿鍔犺浇锛屼繚璇佸惎鍔ㄩ�熷害
- # url: jdbc:TAOS-WS://127.0.0.1:6041/ruoyi_vue_pro?varcharAsString=true
- # driver-class-name: com.taosdata.jdbc.ws.WebSocketDriver
- # username: root
- # password: taosdata
- # druid:
- # validation-query: SELECT SERVER_STATUS() # TDengine 鏁版嵁婧愮殑鏈夋晥鎬ф鏌� SQL
-
- # Redis 閰嶇疆銆俁edisson 榛樿鐨勯厤缃冻澶熶娇鐢紝涓�鑸笉闇�瑕佽繘琛岃皟浼�
- data:
- redis:
- host: 172.17.0.1 # 鍦板潃
- port: 6379 # 绔彛
- database: 14 # 鏁版嵁搴撶储寮�
-# password: dev # 瀵嗙爜锛屽缓璁敓浜х幆澧冨紑鍚�
-
---- #################### 瀹氭椂浠诲姟鐩稿叧閰嶇疆 ####################
-
-# Quartz 閰嶇疆椤癸紝瀵瑰簲 QuartzProperties 閰嶇疆绫�
-spring:
- quartz:
- auto-startup: true # 鏈湴寮�鍙戠幆澧冿紝灏介噺涓嶈寮�鍚� Job
- scheduler-name: schedulerName # Scheduler 鍚嶅瓧銆傞粯璁や负 schedulerName
- job-store-type: jdbc # Job 瀛樺偍鍣ㄧ被鍨嬨�傞粯璁や负 memory 琛ㄧず鍐呭瓨锛屽彲閫� jdbc 浣跨敤鏁版嵁搴撱��
- wait-for-jobs-to-complete-on-shutdown: true # 搴旂敤鍏抽棴鏃讹紝鏄惁绛夊緟瀹氭椂浠诲姟鎵ц瀹屾垚銆傞粯璁や负 false 锛屽缓璁缃负 true
- properties: # 娣诲姞 Quartz Scheduler 闄勫姞灞炴�э紝鏇村鍙互鐪� http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 鏂囨。
- org:
- quartz:
- # Scheduler 鐩稿叧閰嶇疆
- scheduler:
- instanceName: schedulerName
- instanceId: AUTO # 鑷姩鐢熸垚 instance ID
- # JobStore 鐩稿叧閰嶇疆
- jobStore:
- # JobStore 瀹炵幇绫汇�傚彲瑙佸崥瀹細https://blog.csdn.net/weixin_42458219/article/details/122247162
- class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
- isClustered: true # 鏄泦缇ゆā寮�
- clusterCheckinInterval: 15000 # 闆嗙兢妫�鏌ラ鐜囷紝鍗曚綅锛氭绉掋�傞粯璁や负 15000锛屽嵆 15 绉�
- misfireThreshold: 60000 # misfire 闃�鍊硷紝鍗曚綅锛氭绉掋��
- # 绾跨▼姹犵浉鍏抽厤缃�
- threadPool:
- threadCount: 25 # 绾跨▼姹犲ぇ灏忋�傞粯璁や负 10 銆�
- threadPriority: 5 # 绾跨▼浼樺厛绾�
- class: org.quartz.simpl.SimpleThreadPool # 绾跨▼姹犵被鍨�
- jdbc: # 浣跨敤 JDBC 鐨� JobStore 鐨勬椂鍊欙紝JDBC 鐨勯厤缃�
- initialize-schema: NEVER # 鏄惁鑷姩浣跨敤 SQL 鍒濆鍖� Quartz 琛ㄧ粨鏋勩�傝繖閲岃缃垚 never 锛屾垜浠墜鍔ㄥ垱寤鸿〃缁撴瀯銆�
-
---- #################### 娑堟伅闃熷垪鐩稿叧 ####################
-
-# rocketmq 閰嶇疆椤癸紝瀵瑰簲 RocketMQProperties 閰嶇疆绫�
-rocketmq:
- name-server: 127.0.0.1:9876 # RocketMQ Namesrv
-
-spring:
- # RabbitMQ 閰嶇疆椤癸紝瀵瑰簲 RabbitProperties 閰嶇疆绫�
- rabbitmq:
- host: 127.0.0.1 # RabbitMQ 鏈嶅姟鐨勫湴鍧�
- port: 5672 # RabbitMQ 鏈嶅姟鐨勭鍙�
- username: rabbit # RabbitMQ 鏈嶅姟鐨勮处鍙�
- password: rabbit # RabbitMQ 鏈嶅姟鐨勫瘑鐮�
- # Kafka 閰嶇疆椤癸紝瀵瑰簲 KafkaProperties 閰嶇疆绫�
- kafka:
- bootstrap-servers: 127.0.0.1:9092 # 鎸囧畾 Kafka Broker 鍦板潃锛屽彲浠ヨ缃涓紝浠ラ�楀彿鍒嗛殧
-
---- #################### 鏈嶅姟淇濋殰鐩稿叧閰嶇疆 ####################
-
-# Lock4j 閰嶇疆椤�
-lock4j:
- acquire-timeout: 3000 # 鑾峰彇鍒嗗竷寮忛攣瓒呮椂鏃堕棿锛岄粯璁や负 3000 姣
- expire: 30000 # 鍒嗗竷寮忛攣鐨勮秴鏃舵椂闂达紝榛樿涓� 30000 姣
-
---- #################### 鐩戞帶鐩稿叧閰嶇疆 ####################
-
-# Actuator 鐩戞帶绔偣鐨勯厤缃」
-management:
- endpoints:
- web:
- base-path: /actuator # Actuator 鎻愪緵鐨� API 鎺ュ彛鐨勬牴鐩綍銆傞粯璁や负 /actuator
- exposure:
- include: '*' # 闇�瑕佸紑鏀剧殑绔偣銆傞粯璁ゅ�煎彧鎵撳紑 health 鍜� info 涓や釜绔偣銆傞�氳繃璁剧疆 * 锛屽彲浠ュ紑鏀炬墍鏈夌鐐广��
-
-# Spring Boot Admin 閰嶇疆椤�
-spring:
- boot:
- admin:
- # Spring Boot Admin Client 瀹㈡埛绔殑鐩稿叧閰嶇疆
- client:
- url: http://127.0.0.1:${server.port}/${spring.boot.admin.context-path} # 璁剧疆 Spring Boot Admin Server 鍦板潃
- instance:
- service-host-type: IP # 娉ㄥ唽瀹炰緥鏃讹紝浼樺厛浣跨敤 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
- username: admin
- password: admin
- # Spring Boot Admin Server 鏈嶅姟绔殑鐩稿叧閰嶇疆
- context-path: /admin # 閰嶇疆 Spring
- # 鍏佽宓屽叆 iframe 鐨勫煙鍚嶏紙鏀寔閫氶厤绗︼級锛屽疄闄呴儴缃叉椂锛屽彲浠ユ敼涓� "'self' [浣犵殑鍏綉鍩熷悕]"
- frame-ancestors: "'self' localhost localhost:48080 127.0.0.1 127.0.0.1:48080"
-
-# 鏃ュ織鏂囦欢閰嶇疆
-logging:
- file:
- name: ${user.home}/logs/${spring.application.name}.log # 鏃ュ織鏂囦欢鍚嶏紝鍏ㄨ矾寰�
- level:
- # 閰嶇疆鑷繁鍐欑殑 MyBatis Mapper 鎵撳嵃鏃ュ織
- cn.iocoder.yudao.module.bpm.dal.mysql: debug
- cn.iocoder.yudao.module.infra.dal.mysql: debug
- cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper: INFO # 閰嶇疆 ApiErrorLogMapper 鐨勬棩蹇楃骇鍒负 info锛岄伩鍏嶅拰 GlobalExceptionHandler 閲嶅鎵撳嵃
- cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper: INFO # 閰嶇疆 JobLogMapper 鐨勬棩蹇楃骇鍒负 info
- cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper: INFO # 閰嶇疆 FileConfigMapper 鐨勬棩蹇楃骇鍒负 info
- cn.iocoder.yudao.module.pay.dal.mysql: debug
- cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper: INFO # 閰嶇疆 PayNotifyTaskMapper 鐨勬棩蹇楃骇鍒负 info
- cn.iocoder.yudao.module.system.dal.mysql: debug
- cn.iocoder.yudao.module.system.dal.mysql.sms.SmsChannelMapper: INFO # 閰嶇疆 SmsChannelMapper 鐨勬棩蹇楃骇鍒负 info
- cn.iocoder.yudao.module.tool.dal.mysql: debug
- cn.iocoder.yudao.module.member.dal.mysql: debug
- cn.iocoder.yudao.module.trade.dal.mysql: debug
- cn.iocoder.yudao.module.promotion.dal.mysql: debug
- cn.iocoder.yudao.module.statistics.dal.mysql: debug
- cn.iocoder.yudao.module.crm.dal.mysql: debug
- cn.iocoder.yudao.module.erp.dal.mysql: debug
- cn.iocoder.yudao.module.mes.dal.mysql: debug
- cn.iocoder.yudao.module.wms.dal.mysql: debug
- cn.iocoder.yudao.module.iot.dal.mysql: debug
- cn.iocoder.yudao.module.iot.dal.tdengine: DEBUG
- cn.iocoder.yudao.module.iot.service.rule: debug
- cn.iocoder.yudao.module.ai.dal.mysql: debug
- org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 鑺嬭壙锛氬厛绂佺敤锛孲pring Boot 3.X 瀛樺湪閮ㄥ垎閿欒鐨� WARN 鎻愮ず
-
-debug: false
-
---- #################### 寰俊鍏紬鍙枫�佸皬绋嬪簭鐩稿叧閰嶇疆 ####################
-wx:
- mp: # 鍏紬鍙烽厤缃紙蹇呭~锛夛紝鍙傝 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 鏂囨。
- # app-id: wx041349c6f39b268b # 娴嬭瘯鍙凤紙鐗涘笇灏ф彁渚涚殑锛�
- # secret: 5abee519483bc9f8cb37ce280e814bd0
- # app-id: wx5b23ba7a5589ecbb # 娴嬭瘯鍙凤紙鑷繁鐨勶級
- # secret: 2a7b3b20c537e52e74afd395eb85f61f
- app-id: wxf56b1542b9e85f8a # 娴嬭瘯鍙凤紙Kongdy 鎻愪緵鐨勶級
- secret: 496379dcef1ba869e9234de8d598cfd3
- # 瀛樺偍閰嶇疆锛岃В鍐� AccessToken 鐨勮法鑺傜偣鐨勫叡浜�
- config-storage:
- type: RedisTemplate # 閲囩敤 RedisTemplate 鎿嶄綔 Redis锛屼細鑷姩浠� Spring 涓幏鍙�
- key-prefix: wx # Redis Key 鐨勫墠缂�
- http-client-type: HttpComponents # 閲囩敤 HttpComponents锛圚ttpClient 5锛夎姹傚井淇″叕浼楀彿骞冲彴
- miniapp: # 灏忕▼搴忛厤缃紙蹇呭~锛夛紝鍙傝 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 鏂囨。
- # appid: wx62056c0d5e8db250 # 娴嬭瘯鍙凤紙鐗涘笇灏ф彁渚涚殑锛�
- # secret: 333ae72f41552af1e998fe1f54e1584a
- # appid: wx63c280fe3248a3e7 # wenhualian鐨勬帴鍙f祴璇曞彿
- # secret: 6f270509224a7ae1296bbf1c8cb97aed
- appid: wxc4598c446f8a9cb3 # 娴嬭瘯鍙凤紙Kongdy 鎻愪緵鐨勶級
- secret: 4a1a04e07f6a4a0751b39c3064a92c8b
- # appid: wx66186af0759f47c9 # 娴嬭瘯鍙凤紙puhui 鎻愪緵鐨勶級
- # secret: 3218bcbd112cbc614c7264ceb20144ac
- config-storage:
- type: RedisTemplate # 閲囩敤 RedisTemplate 鎿嶄綔 Redis锛屼細鑷姩浠� Spring 涓幏鍙�
- key-prefix: wa # Redis Key 鐨勫墠缂�
- http-client-type: HttpComponents # 閲囩敤 HttpComponents锛圚ttpClient 5锛夎姹傚井淇″皬绋嬪簭骞冲彴
-
---- #################### 鑺嬮亾鐩稿叧閰嶇疆 ####################
-
-# 鑺嬮亾閰嶇疆椤癸紝璁剧疆褰撳墠椤圭洰鎵�鏈夎嚜瀹氫箟鐨勯厤缃�
-yudao:
- captcha:
- enable: false # 鏈湴鐜锛屾殏鏃跺叧闂浘鐗囬獙璇佺爜锛屾柟渚跨櫥褰曠瓑鎺ュ彛鐨勬祴璇曪紱
- security:
- mock-enable: true
- pay:
- order-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/order # 鏀粯娓犻亾鐨勩�愭敮浠樸�戝洖璋冨湴鍧�
- refund-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/refund # 鏀粯娓犻亾鐨勩�愰��娆俱�戝洖璋冨湴鍧�
- transfer-notify-url: https://yutou.mynatapp.cc/admin-api/pay/notify/transfer # 鏀粯娓犻亾鐨勩�愯浆璐︺�戝洖璋冨湴鍧�
- access-log: # 璁块棶鏃ュ織鐨勯厤缃」
- enable: false
- demo: false # 鍏抽棴婕旂ず妯″紡
- wxa-code:
- env-version: develop # 灏忕▼搴忕増鏈�: 姝e紡鐗堜负 "release"锛涗綋楠岀増涓� "trial"锛涘紑鍙戠増涓� "develop"
- wxa-subscribe-message:
- miniprogram-state: developer # 璺宠浆灏忕▼搴忕被鍨嬶細寮�鍙戠増涓� 鈥渄eveloper鈥濓紱浣撻獙鐗堜负 鈥渢rial鈥濅负锛涙寮忕増涓� 鈥渇ormal鈥�
- tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 鍦板浘鐨勫瘑閽� https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
-
-justauth:
- enabled: true
- type:
- DINGTALK: # 閽夐拤
- client-id: dingvrnreaje3yqvzhxg
- client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI
- ignore-check-redirect-uri: true
- WECHAT_ENTERPRISE: # 浼佷笟寰俊
- client-id: wwd411c69a39ad2e54
- client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw
- agent-id: 1000004
- ignore-check-redirect-uri: true
- # noinspection SpringBootApplicationYaml
- WECHAT_MINI_PROGRAM: # 寰俊灏忕▼搴�
- client-id: ${wx.miniapp.appid}
- client-secret: ${wx.miniapp.secret}
- ignore-check-redirect-uri: true
- ignore-check-state: true # 寰俊灏忕▼搴忥紝涓嶄細浣跨敤鍒� state锛屾墍浠ヤ笉杩涜鏍¢獙
- WECHAT_MP: # 寰俊鍏紬鍙�
- client-id: ${wx.mp.app-id}
- client-secret: ${wx.mp.secret}
- ignore-check-redirect-uri: true
- ALIPAY: # 鏀粯瀹濆皬绋嬪簭
- client-id: xx
- client-secret: xx
- alipay-public-key: xx
- ignore-check-redirect-uri: true
- ignore-check-state: true
- cache:
- type: REDIS
- prefix: 'social_auth_state:' # 缂撳瓨鍓嶇紑锛岀洰鍓嶅彧瀵� Redis 缂撳瓨鐢熸晥锛岄粯璁� JUSTAUTH::STATE::
- timeout: 24h # 瓒呮椂鏃堕暱锛岀洰鍓嶅彧瀵� Redis 缂撳瓨鐢熸晥锛岄粯璁� 3 鍒嗛挓
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index b7c315c..17509ee 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -14,19 +14,16 @@
multipart:
max-file-size: 16MB # 鍗曚釜鏂囦欢澶у皬
max-request-size: 32MB # 璁剧疆鎬讳笂浼犵殑鏂囦欢澶у皬
+ encoding:
+ enabled: true
+ charset: UTF-8 # 蹇呴』璁剧疆 UTF-8锛岄伩鍏� WebFlux 娴佸紡杩斿洖锛圓I 鍦烘櫙锛変細涔辩爜闂
+ force: true
# Cache 閰嶇疆椤�
cache:
type: REDIS
redis:
time-to-live: 1h # 璁剧疆杩囨湡鏃堕棿涓� 1 灏忔椂
-
-server:
- servlet:
- encoding:
- enabled: true
- charset: UTF-8 # 蹇呴』璁剧疆 UTF-8锛岄伩鍏� WebFlux 娴佸紡杩斿洖锛圓I 鍦烘櫙锛変細涔辩爜闂
- force: true
--- #################### 鎺ュ彛鏂囨。閰嶇疆 ####################
@@ -156,19 +153,12 @@
client:
host: 127.0.0.1
port: 19530
- qianfan: # 鏂囧績涓�瑷�
- api-key: x0cuLZ7XsaTCU08vuJWO87Lg
- secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
- zhipuai: # 鏅鸿氨 AI
- api-key: 32f84543e54eee31f8d56b2bd6020573.3vh9idLJZ2ZhxDEs
openai: # OpenAI 瀹樻柟
- api-key: sk-aN6nWn3fILjrgLFT0fC4Aa60B72e4253826c77B29dC94f17
- base-url: https://api.gptsapi.net
- azure: # OpenAI 寰蒋
- openai:
- endpoint: https://eastusprejade.openai.azure.com
+ base-url: ${OPENAI_BASE_URL}
+ api-key: ${OPENAI_API_KEY}
anthropic: # Anthropic Claude
- api-key: sk-muubv7cXeLw0Etgs743f365cD5Ea44429946Fa7e672d8942
+ base-url: ${ANTHROPIC_BASE_URL}
+ api-key: ${ANTHROPIC_API_KEY}
ollama:
base-url: http://127.0.0.1:11434
chat:
@@ -176,16 +166,17 @@
stabilityai:
api-key: sk-e53UqbboF8QJCscYvzJscJxJXoFcFg4iJjl1oqgE7baJETmx
dashscope: # 閫氫箟鍗冮棶
- api-key: sk-47aa124781be4bfb95244cc62f6xxxx
- minimax: # Minimax锛歨ttps://www.minimaxi.com/
- api-key: xxxx
- moonshot: # 鏈堜箣鏆楅潰锛圞IMI锛�
- api-key: sk-abc
+ api-key: ${DASHSCOPE_API_KEY}
deepseek: # DeepSeek
- api-key: sk-e94db327cc7d457d99a8de8810fc6b12
+ api-key: ${DEEPSEEK_API_KEY}
chat:
options:
- model: deepseek-chat
+ model: deepseek-v4-flash
+ google:
+ genai: # 璋锋瓕 Gemini
+ api-key: ${GEMINI_API_KEY}
+ chat:
+ model: gemini-2.5-flash
model:
rerank: false # 鏄惁寮�鍚�滈�氫箟鍗冮棶鈥濈殑 Rerank 妯″瀷锛屽~鍐� dashscope 寮�鍚�
mcp:
@@ -208,31 +199,50 @@
yudao:
ai:
- gemini: # 璋锋瓕 Gemini
- enable: true
- api-key: AIzaSyAVoBxgoFvvte820vEQMma2LKBnC98bqMQ
- model: gemini-2.5-flash
doubao: # 瀛楄妭璞嗗寘
enable: true
- api-key: 5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272
- model: doubao-1-5-lite-32k-250115
+ api-key: ${DOUBAO_API_KEY}
+ model: doubao-seed-2-1-turbo-260628
hunyuan: # 鑵捐娣峰厓
enable: true
- api-key: sk-abc
- model: hunyuan-turbo
+ api-key: ${HUNYUAN_API_KEY}
+ model: hy3-preview
siliconflow: # 纭呭熀娴佸姩
enable: true
- api-key: sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz
- model: deepseek-ai/DeepSeek-R1-Distill-Qwen-7B
+ api-key: ${SILICONFLOW_API_KEY}
+ model: deepseek-ai/DeepSeek-V4-Pro
xinghuo: # 璁鏄熺伀
enable: true
- appKey: 75b161ed2aef4719b275d6e7f2a4d4cd
- secretKey: YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz
- model: x1
+ api-key: ${XINGHUO_API_KEY}
+ model: x2-flash
baichuan: # 鐧惧窛鏅鸿兘
enable: true
- api-key: sk-abc
- model: Baichuan4-Turbo
+ api-key: ${BAICHUAN_API_KEY}
+ model: Baichuan-M3
+ yiyan: # 鏂囧績涓�瑷�
+ enable: false
+ api-key: ${YIYAN_API_KEY}
+ model: ernie-5.1
+ zhipu: # 鏅鸿氨 AI锛圙LM锛�
+ enable: false
+ api-key: ${ZHIPU_API_KEY}
+ model: glm-5.2
+ minimax: # MiniMax
+ enable: false
+ api-key: ${MINIMAX_API_KEY}
+ model: MiniMax-M3
+ moonshot: # 鏈堜箣鏆楅潰锛圞IMI锛�
+ enable: false
+ api-key: ${MOONSHOT_API_KEY}
+ model: kimi-k2.6
+ stepfun: # 闃惰穬鏄熻景
+ enable: false
+ api-key: ${STEPFUN_API_KEY}
+ model: step-3.7-flash
+ grok: # Grok
+ enable: false
+ api-key: ${GROK_API_KEY}
+ model: grok-4.3
midjourney:
enable: true
# base-url: https://api.holdai.top/mj-relax/mj
@@ -265,7 +275,7 @@
permit-all_urls:
- /admin-api/mp/open/** # 寰俊鍏紬鍙峰紑鏀惧钩鍙帮紝寰俊鍥炶皟鎺ュ彛锛屼笉闇�瑕佺櫥褰�
api-encrypt:
- enable: false # 鏄惁寮�鍚� API 鍔犲瘑銆係pring Boot 鍙墽琛� jar 涓� Hutool AES 浼氳Е鍙� BC Provider 绛惧悕鏍¢獙锛屼复鏃跺叧闂�
+ enable: true # 鏄惁寮�鍚� API 鍔犲瘑
algorithm: AES # 鍔犲瘑绠楁硶锛屾敮鎸� AES銆丷SA 绛�
request-key: 52549111389893486934626385991395 # 銆怉ES 妗堜緥銆戣姹傚姞瀵嗙殑绉橀挜锛岋紝蹇呴』 16銆�24銆�32 浣�
response-key: 96103715984234343991809655248883 # 銆怉ES 妗堜緥銆戝搷搴斿姞瀵嗙殑绉橀挜锛孉ES 妗堜緥锛屽繀椤� 16銆�24銆�32 浣�
--
Gitblit v1.9.3