huangxiaoqiang
2025-06-12 c54e0666bdd34fbe133fe521bf9d46dd6c0fe53e
代码提交
已删除20个文件
已修改67个文件
已复制9个文件
已添加187个文件
已重命名4个文件
408613 ■■■■■ 文件已修改
项目代码/WCS/WIDESEAWCS_Client/dist.zip 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/package-lock.json 13882 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/package.json 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/api/http.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/components/DeviceLine.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/components/DeviceLineVo.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/components/DeviceStacker.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/extension/basicinfo/Dt_StationManager.js 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/extension/basicinfo/router.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceInfo.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceProtocol.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceProtocolDetail.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/extension/quartzJob/dispatchInfo.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/extension/system/Sys_User/Sys_UserGridHeader.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/extension/taskinfo/task.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/main.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/router/index.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/router/redirect.js 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/router/viewGird.js 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/uitils/eventBus.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/uitils/signalr.js 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/Devicestatus/AGVStatus.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/Home.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/Index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/Login.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/basicinfo/Dt_StationManager.vue 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/charts/bigdata.vue 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/quartzJob/deviceInfo.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/syslog/txt_log.vue 297 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/system/AgvStation.vue 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/system/Sys_User.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/taskinfo/task.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/src/views/taskinfo/task_hty.vue 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Client/yarn.lock 10203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/CodeChunks.db 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/CodeChunks.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/CodeChunks.db-wal 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/SemanticSymbols.db 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/SemanticSymbols.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/SemanticSymbols.db-wal 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/read.lock 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/DocumentLayout.backup.json 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/DocumentLayout.json 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/HierarchyCache.v1.txt 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/.vscode/launch.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoRepository/Dt_StationManagerRepository.cs 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoRepository/WIDESEAWCS_BasicInfoRepository.csproj 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/Dt_StationManagerService.cs 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/WIDESEAWCS_BasicInfoService.csproj 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/Http/HttpHelper.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/WIDESEAWCS_Common.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/BaseCommunicator.cs 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/CommunicationException.cs 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensDBDataType.cs 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensS7Communicator.cs 711 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/WIDESEAWCS_Communicator.csproj 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/AOP/LogAOP.cs 287 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/AOP/SqlSugarAop.cs 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/App.cs 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Attributes/ModelValidateAttribute.cs 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Authorization/AuthorizationResponse.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Authorization/AuthorizationSetup.cs 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Authorization/JwtHelper.cs 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseController/ApiBaseController.cs 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/PageDataOptions.cs 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/PageGridData.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/Permissions.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/SaveModel.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/WebResponseContent.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/IRepository.cs 418 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/RepositoryBase.cs 855 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/IUnitOfWorkManage.cs 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/UnitOfWork.cs 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/UnitOfWorkManage.cs 194 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseServices/IService.cs 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseServices/ServiceBase.cs 808 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseServices/ServiceFunFilter.cs 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/Caching.cs 351 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICaching.cs 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/AppSecret.cs 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/CacheConst.cs 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/ErrorMsgConst.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/HtmlElementType.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/SqlDbTypeName.cs 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/TenantConst.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/TenantStatus.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Core/ConfigurableOptions.cs 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Core/IConfigurableOptions.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Core/InternalApp.cs 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/DB/BaseDBConfig.cs 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/DB/MainDb.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/DB/Models/BaseEntity.cs 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/DB/RepositorySetting.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Enums/EnumHelper.cs 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Enums/LinqExpressionType.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Enums/RouterInOutType.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/AllOptionRegister.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/ApplicationSetup.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/AutofacModuleRegister.cs 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/CorsSetup.cs 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/DbSetup.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/HttpContextSetup.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/InitializationHostServiceSetup.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/IpPolicyRateLimitSetup.cs 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/MemoryCacheSetup.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/MiniProfilerSetup.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/SqlsugarSetup.cs 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/SwaggerSetup.cs 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/ActionExecuteFilter.cs 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/ApiAuthorizeFilter.cs 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/ExporterHeaderFilter.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/GlobalExceptionsFilter.cs 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/UseServiceDIAttribute.cs 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/AppSettings.cs 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/ConsoleHelper.cs 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/ExportHelper.cs 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/FileHelper.cs 451 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpContextHelper.cs 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpHelper.cs 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/MethodInfoExtensions.cs 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/ObjectExtension.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/RuntimeExtension.cs 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/SecurityEncDecryptHelper.cs 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/UtilConvert.cs 438 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/HostedService/SeedDataHostedService.cs 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/HttpContextUser/AspNetUser.cs 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/HttpContextUser/IUser.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/IDependency.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/LogLock.cs 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/Logger.cs 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/QuartzLogger.cs 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/RequestLogModel.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/ApiLogMiddleware.cs 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/ExceptionHandlerMiddleware.cs 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/HttpRequestMiddleware.cs 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/IpLimitMiddleware.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/JwtTokenAuthMiddleware.cs 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/MiddlewareHelpers.cs 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/SwaggerAuthMiddleware.cs 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/SwaggerMiddleware.cs 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Seed/DBContext.cs 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Seed/DBSeed.cs 321 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Seed/FrameSeed.cs 582 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Tenants/ITenantEntity.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Tenants/MultiTenantAttribute.cs 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Tenants/TenantUtil.cs 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Utilities/EntityProperties.cs 364 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Utilities/LambdaExtensions.cs 183 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Utilities/ModelValidate.cs 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Utilities/VierificationCode.cs 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/WIDESEAWCS_Core - Backup.csproj 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/WIDESEAWCS_Core.csproj 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/Enum/TaskEnumHelper.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/Enum/TaskStatusEnum.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/Enum/TaskTypeEnum.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/Enum/TaskTypeGroup.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/WIDESEAWCS_DTO.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoRepository/IDt_StationManagerRepository.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoRepository/WIDESEAWCS_IBasicInfoRepository.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IDt_StationManagerService.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/WIDESEAWCS_IBasicInfoService.csproj 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/WIDESEAWCS_ISystemRepository.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemServices/IAgvStationService.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemServices/WIDESEAWCS_ISystemServices.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/ITaskRepository.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/WIDESEAWCS_ITaskInfoRepository.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/WIDESEAWCS_ITaskInfoService.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_StationManager.cs 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/System/AGVStation.cs 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/Dt_Task.cs 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/Dt_Task_hty.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/WIDESEAWCS_Model.csproj 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/CommonConveyorLine.cs 343 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/CommonConveyorLine_After.cs 342 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/CommonConveyorLine_BZ.cs 342 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/CommonConveyorLine_GW.cs 342 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/Enum/ConveyorLineStatus.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/IConveyorLine.cs 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/CustomException/QuartzJobException.cs 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DeviceInfoDTO.cs 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DeviceProDTO.cs 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DeviceProtocolDetailDTO.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DispatchInfoDTO.cs 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DispatchStatusDTO.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/RoutersAddDTO.cs 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/CustomException/StackerCraneException.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/DataLengthAttribute.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/DeviceCommand.cs 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/DeviceStatus.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/IDevice.cs 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceEnum/DeviceStatus.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/JobBase.cs 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DeviceInfo.cs 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DeviceProtocol.cs 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DeviceProtocolDetail.cs 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DispatchInfo.cs 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_Router.cs 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzExtensions/JobSetup.cs 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzExtensions/QuartzJobAutofacModuleRegister.cs 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzExtensions/QuartzJobDataTableHostedService.cs 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzExtensions/QuartzJobHostedService.cs 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/ISchedulerCenter.cs 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/JobFactory.cs 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/SchedulerCenterServer.cs 458 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceInfoRepository.cs 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceProtocolDetailRepository.cs 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceProtocolRepository.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DispatchInfoRepository.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceInfoRepository.cs 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceProtocolDetailRepository.cs 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceProtocolRepository.cs 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDispatchInfoRepository.cs 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IRouterRepository.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/RouterRepository.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Seed/QuartzJobCreateDataTabel.cs 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DeviceInfoService.cs 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DeviceProtocolDetailService.cs 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DeviceProtocolService.cs 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DispatchInfoService.cs 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDeviceInfoService.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDeviceProtocolDetailService.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDeviceProtocolService.cs 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDispatchInfoService.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IRouterService.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/RouterService.cs 332 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ShuttleCar/IShuttleCar.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ShuttleCar/ShuttleCar.cs 206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/CommonStackerCrane.cs 509 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/CommonStackerStationCrane.cs 501 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Enum/StackerCraneStatus.cs 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/IStackerCrane.cs 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Spec/SpeStackerCrane.cs 286 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/StackerCraneTaskCompletedEventArgs.cs 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Storage.cs 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/WIDESEAWCS_QuartzJob.csproj 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/.config/dotnet-tools.json 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/Dt_StationManagerController.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/QuartzJob/DeviceProtocolController.cs 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/QuartzJob/SchedulerController.cs 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/System/AgvStationController.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/System/Sys_DictionaryController.cs 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/System/Sys_LogController.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/CustomProfile.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-23/B202站台241223.txt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-23/LineJob站台241223.txt 253055 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-23/LineJob错误信息站台241223.txt 17595 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-29/LineJob站台241229.txt 13025 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-29/LineJob错误信息站台241229.txt 950 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-30/B202站台241230.txt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-30/LineJob站台241230.txt 71355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-30/LineJob错误信息站台241230.txt 5070 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Program.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Properties/PublishProfiles/FolderProfile.pubxml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Properties/PublishProfiles/FolderProfile1.pubxml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/GlobalUsing.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Hub/ISimpleHub.cs 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Hub/SimpleHub.cs 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Provider/UserIdProvider.cs 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Service/INoticeService.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Service/SignalrNoticeService.cs 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/WIDESEAWCS_SignalR.csproj 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemRepository/WIDESEAWCS_SystemRepository.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemServices/AgvStationService.cs 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemServices/WIDESEAWCS_SystemServices.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/TaskRepository.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/WIDESEAWCS_TaskInfoRepository.csproj 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskExecuteDetailService.cs 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs 102 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Task_HtyService.cs 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/WIDESEAWCS_TaskInfoService.csproj 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs 277 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/ConveyorLineTaskCommand.cs 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs 148 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneDBName.cs 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/大屏/package-lock.json 136 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/大屏/src/views/centerRight1.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/AGV交互协议/AGV RCS --WCS 交互协议表V1.0.docx 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/AGV交互协议/PC交互(1).xls 补丁 | 查看 | 原始文档 | blame | 历史
项目资料/AGV交互协议/江西AGV与WCS和输送通信协议 2025.6.10(1).xlsx 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/dist.zip
Binary files differ
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/package-lock.json
ÎļþÌ«´ó
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/package.json
@@ -13,10 +13,12 @@
    "@microsoft/signalr": "^6.0.4",
    "ali-oss": "^6.17.1",
    "axios": "^0.21.1",
    "bootstrap": "^5.3.3",
    "core-js": "^3.6.5",
    "echarts": "^5.0.2",
    "element-plus": "^2.2.14",
    "less": "^4.1.1",
    "mitt": "^3.0.1",
    "vue": "^3.2.37",
    "vue-draggable-next": "^2.0.1",
    "vue-router": "^4.0.0-0",
@@ -62,5 +64,6 @@
  },
  "eslintIgnore": [
    "*"
  ]
  ],
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/api/http.js
@@ -13,13 +13,14 @@
let loadingStatus = false;
if (process.env.NODE_ENV == 'development') {
    axios.defaults.baseURL = 'http://127.0.0.1:9291/';
    // axios.defaults.baseURL = 'http://192.168.20.251:9291/';
}
else if (process.env.NODE_ENV == 'debug') {
    axios.defaults.baseURL = 'http://127.0.0.1:9291/';
    axios.defaults.baseURL = 'http://127.0.0.1:8098/';
}
else if (process.env.NODE_ENV == 'production') {
    axios.defaults.baseURL = 'http://127.0.0.1:9291/';
    axios.defaults.baseURL = 'http://192.168.20.253:9291/';
}
if (!axios.defaults.baseURL.endsWith('/')) {
    axios.defaults.baseURL+="/";
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/components/DeviceLine.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
<template>
    <div class="Linebox" >
        <div class="card">
            <div class="card-header">
                <div id="lines2">
                    <div class="card-body">{{ device.deviceName }}<br />
                        -{{ device.childDeviceCode }}-
                    </div>
                </div>
            </div>
            <div class="card-body">
                <ul class="list-group lis">
                    <li class="list-group-item list-group-item-dark">读取信号</li>
                    <li class="list-group-item list-group-item-secondary">任务号:{{
                        device.data.command.taskNum }}</li>
                    <li class="list-group-item list-group-item-secondary">托盘号:{{
                        device.data.command.barcode }}</li>
                    <li class="list-group-item list-group-item-secondary">终点地址:{{
                        device.data.command.targetAddress }}</li>
                    <li :class="getSignalClass(device.data.writeInteractiveSignal[6])">扫码站台入库请求</li>
                    <li :class="getSignalClass(device.data.writeInteractiveSignal[4])">堆垛机出库站台请求</li>
                    <li :class="getSignalClass(device.data.writeInteractiveSignal[2])">堆垛机入库站台请求</li>
                    <li :class="getSignalClass(device.data.writeInteractiveSignal[0])">线体出库口请求</li>
                </ul>
                <ul class="list-group lis">
                    <li class="list-group-item list-group-item-dark">写入信号</li>
                    <li class="list-group-item list-group-item-secondary">任务号:{{
                        device.data.commandWrite.taskNum }}</li>
                    <li class="list-group-item list-group-item-secondary">托盘号:{{
                        device.data.commandWrite.barcode }}</li>
                    <li class="list-group-item list-group-item-secondary">终点地址:{{
                        device.data.commandWrite.targetAddress }}</li>
                    <li :class="getSignalClass(device.data.writeInteractiveSignal[7])">扫码站台入库请求</li>
                    <li :class="getSignalClass(device.data.writeInteractiveSignal[5])">堆垛机出库站台请求</li>
                    <li :class="getSignalClass(device.data.writeInteractiveSignal[3])">堆垛机入库站台请求</li>
                    <li :class="getSignalClass(device.data.writeInteractiveSignal[1])">线体出库口请求</li>
                </ul>
            </div>
        </div>
    </div>
</template>
<script setup>
import { defineProps } from "vue";
// å®šä¹‰ç»„件属性
const props = defineProps({
    device: {
        type: Object,
        required: true
    }
});
// èŽ·å–ä¿¡å·ç±»å
const getSignalClass = (signal) => {
    // console.log("🚀 ~ getSignalClass ~ signal:", signal)
    return signal !== true ? 'list-group-item list-group-item-danger' : 'list-group-item list-group-item-success';
};
</script>
<style scoped>
/* .Stackerbox{
    width: 220px;
    float: left;
} */
.Linebox{
  width: 500px;
  float: left;
}
.box1{
  float: left;
}
.card-body{
  text-align: center;
  border-radius: 6% ;
}
.Stacker{
  background-color: burlywood;
}
.lis{
  float: left;
  width: 233px;
}
</style>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/components/DeviceLineVo.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
<template>
     <div class="Linebox">
    <div class="card">
      <div class="card-header">
        <div id="lines2" >
          <div class="card-body">{{device.deviceName}}<br/>
            -{{ device.data.childDeviceCode }}-
          </div>
        </div>
      </div>
      <div class="card-body">
        <ul class="list-group lis">
          <li class="list-group-item list-group-item-dark">读取信号</li>
          <li class="list-group-item list-group-item-secondary">任务号:{{ device.data.commandAfter.conveyorLineTaskNum }}</li>
          <li class="list-group-item list-group-item-secondary">托盘号:{{ device.data.commandAfter.conveyorLineBarcode }}</li>
          <li class="list-group-item list-group-item-secondary">终点地址:{{ device.data.commandAfter.conveyorLineTargetAddress }}</li>
          <li class="list-group-item list-group-item-secondary">是否有盘:{{ device.data.commandAfter.hasPallet }}</li>
          <li class="list-group-item list-group-item-secondary">报警代码:{{ device.data.commandAfter.conveyorLineAlarm }}</li>
          <li class="list-group-item list-group-item-secondary">请求反馈:{{ device.data.commandAfter.responState }}</li>
          <li  :class="device.data.commandAfter.interactiveSignal !=0 ? 'list-group-item list-group-item-success'  :'list-group-item list-group-item-danger'">交互信号</li>
        </ul>
      </div>
    </div>
</div>
</template>
<script setup>
import { defineProps } from "vue";
// å®šä¹‰ç»„件属性
const props = defineProps({
    device: {
        type: Object,
        required: true
    }
});
// èŽ·å–ä¿¡å·ç±»å
const getSignalClass = (signal) => {
    // console.log("🚀 ~ getSignalClass ~ signal:", signal)
    return signal !== true ? 'list-group-item list-group-item-danger' : 'list-group-item list-group-item-success';
};
</script>
<style scoped>
.Stackerbox {
  width: 220px;
  float: left;
}
.Linebox {
  width: 300px;
  float: left;
}
.box1 {
  float: left;
}
.card-body {
  text-align: center;
  border-radius: 6%;
}
.Stacker {
  background-color: burlywood;
}
.lis {
  float: left;
  width: 266px;
}
</style>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/components/DeviceStacker.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
<template>
    <div class="Stackerbox">
        <div class="card">
          <div class="card-header">
            <div>
              <div class="card-body Stacker">
                {{ Stacker.deviceName }}
              </div>
            </div>
          </div>
          <div class="card-body">
            <ul class="list-group">
              <li class="list-group-item list-group-item-secondary">
                ä»»åŠ¡å·ï¼š{{ Stacker.data.currentTaskNum || '暂无任务号' }}
              </li>
              <li class="list-group-item list-group-item-secondary">
                ä¸Šä¸€ä¸ªä»»åŠ¡ï¼š{{ Stacker.data.LastTaskNum || '暂无任务号' }}
              </li>
              <li :class="getStatusClass(Stacker.data.stackerCraneAutoStatusDes)">
                å·¥ä½œæ¨¡å¼ï¼š{{ Stacker.data.stackerCraneAutoStatusDes }}
              </li>
              <li :class="getStatusClass(Stacker.data.stackerCraneStatusDes)">
                è®¾å¤‡çŠ¶æ€ï¼š{{ Stacker.data.stackerCraneStatusDes }}
              </li>
              <li :class="getStatusClass(Stacker.data.stackerCraneWorkStatusDes)">
                å·¥ä½œçŠ¶æ€ï¼š{{ Stacker.data.stackerCraneWorkStatusDes }}
              </li>
              <li class="list-group-item list-group-item-secondary">
                èµ·ç‚¹ï¼š{{ Stacker.data.SourceAddress || '暂无任务' }}
              </li>
              <li class="list-group-item list-group-item-secondary">
                ç»ˆç‚¹ï¼š{{ Stacker.data.TargetAddress || '暂无任务' }}
              </li>
              <li class="list-group-item list-group-item-secondary">
                å‘½ä»¤æ–¹å¼ï¼š{{ Stacker.data.Command==1? '取放物料作业': '移动到指定位置' }}
              </li>
              <li class="list-group-item list-group-item-secondary">
                AGV电量:{{ Stacker.data.electricity+'%' }}
              </li>
            </ul>
          </div>
        </div>
      </div>
</template>
<script setup>
import { defineProps } from "vue";
// å®šä¹‰ç»„件属性
const props = defineProps({
    Stacker: {
        type: Object,
        required: true
    }
});
// èŽ·å–çŠ¶æ€ç±»åï¼ˆä¼˜åŒ–çŠ¶æ€åˆ¤æ–­ï¼‰
const getStatusClass = (status) => {
  if (status === '联机' || status === '无故障' || status === '空闲') {
    return 'list-group-item list-group-item-success';
  }
  if (status === '故障' || status === '停机') {
    return 'list-group-item list-group-item-danger';
  }
  return 'list-group-item list-group-item-warning'; // é»˜è®¤è­¦å‘ŠçŠ¶æ€
};
</script>
<style lang="scss" scoped>
</style>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/extension/basicinfo/Dt_StationManager.js
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/extension/basicinfo/router.js
@@ -56,7 +56,7 @@
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceInfo.js
@@ -1,29 +1,39 @@
import gridBody from './extend/importDevicePro.vue'
import gridBody from "./extend/importDevicePro.vue";
let extension = {
  components: {
    //查询界面扩展组件
    gridHeader: '',
    gridHeader: "",
    gridBody: gridBody,
    gridFooter: '',
    gridFooter: "",
    //新建、编辑弹出框扩展组件
    modelHeader: '',
    modelBody: '',
    modelFooter: ''
    modelHeader: "",
    modelBody: "",
    modelFooter: "",
  },
  tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
  tableAction: "", //指定某张表的权限(这里填写表名,默认不用填写)
  buttons: { view: [], box: [], detail: [] }, //扩展的按钮
  methods: {
    //下面这些方法可以保留也可以删除
    onInit() {
      // console.log(this.detailOptions.buttons);
      // console.log(this.$refs.detail)
      var detailImport = this.detailOptions.buttons.find(item=>item.value == 'import');
      var detailImport = this.detailOptions.buttons.find(
        (item) => item.value == "import"
      );
      if(detailImport){
        detailImport.onClick = function () {
          this.$refs.gridBody.open();
        };
        }
      }
      // this.buttons.unshift({
      //   //也可以用push或者splice方法来修改buttons数组
      //   name: "开启服务", //按钮名称
      //   icon: "el-icon-document", //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
      //   type: "primary", //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
      //   onClick: function () {
      //     this.$Message.success("开启服务");
      //   },
      // });
    },
    onInited() {
      //框架初始化配置后
@@ -50,7 +60,7 @@
    },
    rowClick({ row, column, event }) {
      //查询界面点击行事件
      this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
    },
    modelOpenAfter(row) {
      //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
@@ -64,15 +74,14 @@
      //console.log(this.$refs)
      this.$nextTick(() => {
        if (this.$refs.upload_excel) {
          alert('点击了上传按钮')
          alert("点击了上传按钮");
          this.$refs.upload_excel.upload = function () {
            console.log('点击了上传按钮')
          }
            console.log("点击了上传按钮");
          };
        }
        // alert(1)
      })
    }
  }
      });
    },
  },
};
export default extension;
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceProtocol.js
@@ -42,7 +42,7 @@
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceProtocolDetail.js
@@ -42,7 +42,7 @@
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/extension/quartzJob/dispatchInfo.js
@@ -42,7 +42,7 @@
      },
      rowClick({ row, column, event }) {
        //查询界面点击行事件
        this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
        // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
      },
      modelOpenAfter(row) {
        //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/extension/system/Sys_User/Sys_UserGridHeader.vue
@@ -62,7 +62,7 @@
        "/api/user/modifyUserPwd?password=" +
        this.password +
        "&userName=" +
        this.row.UserName;
        this.row.userName;
      this.http.post(url, {}, true).then((x) => {
        if (!x.status) {
          return this.$message.error(x.message);
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/extension/taskinfo/task.js
@@ -67,7 +67,7 @@
        },
        rowClick({ row, column, event }) {
            //查询界面点击行事件
            this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
            // this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
        },
        modelOpenAfter(row) {
            //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/main.js
@@ -11,7 +11,7 @@
// import 'dayjs/locale/zh-cn'
// import locale from 'element-plus/lib/locale/lang/zh-cn'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'bootstrap/dist/css/bootstrap.min.css';
import permission from './api/permission'
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/router/index.js
@@ -40,8 +40,7 @@
    meta:{
        anonymous:true
      }
  },
  {
  },{
    path: '/bigdata',
    name: 'bigdata',
    component: () => import('@/views/charts/bigdata.vue'),
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/router/redirect.js
@@ -1,22 +1,26 @@
let redirect = [{
    path: '/404',
    name: '404',
    component: () => import('@/components/redirect/404'),
let redirect = [
  {
    path: "/404",
    name: "404",
    component: () => import("@/components/redirect/404"),
    meta:{
        anonymous:true
      }
}, {
    path: '/401',
    name: '401',
    component: () => import('@/components/redirect/401')
}, {
    path: '/coding',
    name: 'coding',
    component: () => import('@/components/redirect/coding')
}, {
    path: '/message',
    name: 'message',
    component: () => import('@/components/redirect/Message.vue')
}]
      anonymous: true,
    },
  },
  {
    path: "/401",
    name: "401",
    component: () => import("@/components/redirect/401"),
  },
  {
    path: "/coding",
    name: "coding",
    component: () => import("@/components/redirect/coding"),
  },
  {
    path: "/message",
    name: "message",
    component: () => import("@/components/redirect/Message.vue"),
  },
];
export default redirect;
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/router/viewGird.js
@@ -4,10 +4,6 @@
    path: '/Sys_Log',
    name: 'sys_Log',
    component: () => import('@/views/system/Sys_Log.vue')
  },{
    path: '/txt_log',
    name: 'txt_log',
    component: () => import('@/views/syslog/txt_log.vue')
  },
  {
    path: '/Sys_User',
@@ -65,10 +61,17 @@
    path: '/router',
    name: 'router',
    component: () => import('@/views/basicinfo/router.vue')
  },  {
    path: '/AgvStation',
    name: 'AgvStation',
    component: () => import('@/views/system/AgvStation.vue')
  }]
  },
  {
    path: '/AGVStatus',
    name: 'AGVStatus',
    component: () => import('@/views/Devicestatus/AGVStatus.vue')
  },
  {
    path: '/Dt_StationManager',
    name: 'Dt_StationManager',
    component: () => import('@/views/basicinfo/Dt_StationManager.vue')
  },
]
export default viewgird
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/uitils/eventBus.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,5 @@
import mitt from 'mitt';
const eventBus = mitt();
export default eventBus;
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/uitils/signalr.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,106 @@
// import sysConfig from '@/config/index'
// import tool from '@/utils/tool'
import store from "../store/index";
import http from "@/../src/api/http.js";
import * as signalR from "@microsoft/signalr";
import { ElNotification } from "element-plus";
import eventBus from "./eventBus";
// import * as signalrMessage from './mqtt/message'
//使用signalr
export default function useSignalr() {
  // const userInfo = tool.data.get('USER_INFO') //用户信息
  let openedNotification = null; // ä¿å­˜å½“前打开的Notification实例
  let socketUrl = "hubs/simple"; //socket地址
  // if (sysConfig.VITE_PROXY === 'false') {
  socketUrl = http.ipAddress + socketUrl; //判断是否要走代理模式,走了的话发布之后直接nginx代理
  // }
  //开始
  const startSignalr = () => {
    //初始化连接
    const connection = init();
    // å¯åŠ¨è¿žæŽ¥
    connection
      .start()
      .then(() => {
        console.log("启动连接");
      })
      .catch((err) => {
        console.log("连接失败", err);
      });
  };
  //初始化
  const init = () => {
    console.log("初始化SignalR对象");
    // SignalR对象
    const connection = new signalR.HubConnectionBuilder()
      .withUrl(socketUrl, {
        accessTokenFactory: () => store.getters.getToken(),
        skipNegotiation: true,
        transport: signalR.HttpTransportType.WebSockets,
      })
      .withAutomaticReconnect({
        nextRetryDelayInMilliseconds: () => {
          return 5000; // æ¯5秒重连一次
        },
      }) //自动重新连接
      .configureLogging(signalR.LogLevel.Information)
      .build();
    connection.keepAliveIntervalInMilliseconds = 15 * 1000; // å¿ƒè·³æ£€æµ‹15s
    // connection.serverTimeoutInMilliseconds = 30 * 60 * 1000 // è¶…æ—¶æ—¶é—´30m
    // æ–­å¼€è¿žæŽ¥
    connection.onclose(async () => {
      console.log("断开连接");
    });
    //断线重新
    connection.onreconnected(() => {
      console.log("断线重新连接成功");
    });
    //消息处理
    receiveMsg(connection);
    return connection;
  };
  //接收消息处理
  const receiveMsg = (connection) => {
    //接收登出
    connection.on("LoginOut", (data) => {
      // signalrMessage.loginOut(data)
    });
    connection.on("NewMessage", (data) => {
      eventBus.emit("stackerDataError", data);
      if (openedNotification === null || openedNotification.closed) {
        // ä¸Šä¸€ä¸ªNotification已关闭或尚未打开
        openedNotification = ElNotification({
          title: "成功",
          message: data,
          type: "success",
          onClose: () => {
            // Notification已关闭
            openedNotification = null; // æ¸…空当前打开的Notification实例
            console.log("Notification已关闭");
          },
        });
      }
    });
    connection.on("StackerData", (data) => {
      console.log(data)
      eventBus.emit("stackerData", data);
    });
    connection.on("LineData", (data) => {
      eventBus.emit("locationData", data);
    });
    connection.on("Logs", (data) => {
      eventBus.emit("Logs", data);
    });
  };
  //页面销毁
  // onUnmounted(() => {})
  return { startSignalr };
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/Devicestatus/AGVStatus.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
<template>
   <el-row>
     <el-col :span="24">
       <device-stacker v-for="stacker in Stackers" :key="stacker.deviceName" :Stacker="stacker"></device-stacker>
     </el-col>
   </el-row>
 </template>
 <script setup>
 import { onMounted, reactive, toRefs } from "vue";
 import eventBus from "@/uitils/eventBus";
 import DeviceStacker from "@/components/DeviceStacker.vue";
 // å †åž›æœº
 const Stackers = reactive([]);
 // è®¾å¤‡åˆ—表(修改重复设备名称)
 const devices = reactive([]);
 const intToBitArrayFromBinaryString = (num, numBits) => {
   let binaryString = num.toString(2).padStart(numBits, '0');
   return Array.from({ length: numBits }, (_, index) => binaryString[index] === '1');
 };
 // ç›‘听设备数据变化
 onMounted(() => {
   eventBus.on('stackerData', eventData => {
       if (Stackers.length == 0) {
         Stackers.push({ deviceName: eventData.deviceName, data: eventData.data });
       }
       else {
         const Stacker = Stackers.find(c => c.deviceName == eventData.deviceName);
         if (Stacker) {
           Stacker.data = eventData.data
         }
         else {
           Stackers.push({ deviceName: eventData.deviceName, data: eventData.data });
         }
       }
   })
 });
 </script>
 <style scoped>
 .Stackerbox {
   width: 550px;
   float: left;
   height: 300px;
 }
 .box1 {
   float: left;
 }
 .card-body {
   text-align: center;
   border-radius: 6%;
 }
 .Stacker {
   background-color: burlywood;
 }
 .lis {
   float: left;
   width: 233px;
 }
 </style>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/Home.vue
@@ -1,14 +1,37 @@
<template>
  <div class="title"></div>
  <el-container>
    <!-- <el-header >运行日志</el-header> -->
    <el-main>
      <el-card v-for="(log, index) in logs" :key="index" class="log-card" :style="{ color: log.color }">
        <div :style="{ color: log.color }">{{ log.logEntry }}</div>
        <div :style="{ color: log.color }">{{ log.time }}</div>
      </el-card>
    </el-main>
  </el-container>
</template>
<script>
import { ref, reactive } from 'vue'
import { ref, onMounted } from 'vue'
import eventBus from "@/uitils/eventBus";
export default {
  setup() {
    return {
    const logs = ref([]);
    onMounted(() => {
      eventBus.on('Logs', eventData => {
        if (logs.value.length > 500) {
          logs.value = [];
        }
        const logEntry = "日志信息:" + eventData.log
        const time = "时间:" + eventData.time
        logs.value.unshift({ logEntry: logEntry, time: time, color: eventData.color });
        // logs.value.unshift(logEntry);
      });
    });
    return {
      logs
    }
  }
}
@@ -21,4 +44,8 @@
  font-size: 28px;
  color: orange;
}
.log-card {
  margin-bottom: 10px;
}
</style>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/Index.vue
@@ -135,6 +135,7 @@
import { useRouter, useRoute } from "vue-router";
import store from "../store/index";
import http from "@/../src/api/http.js";
import useSignalr from '../uitils/signalr.js';
export default defineComponent({
  components: {
    VolMenu,
@@ -520,6 +521,9 @@
          });
        }
        const { startSignalr } = useSignalr()
        startSignalr()
        //当前刷新是不是首页
        if (router.currentRoute.value.path != navigation[0].path) {
          //查找系统菜单
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/Login.vue
@@ -95,9 +95,9 @@
    const loading = ref(false);
    const codeImgSrc = ref('');
    const userInfo = reactive({
      userName: '',
      password: '',
      verificationCode: '',
      userName: 'admin',
      password: '123456',
      verificationCode: '1234',
      UUID: undefined
    });
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/basicinfo/Dt_StationManager.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,204 @@
<template>
  <view-grid ref="grid" :columns="columns" :detail="detail" :editFormFields="editFormFields"
    :editFormOptions="editFormOptions" :searchFormFields="searchFormFields" :searchFormOptions="searchFormOptions"
    :table="table" :extend="extend">
  </view-grid>
</template>
<script>
import extend from "@/extension/basicinfo/Dt_StationManager.js";
import { ref, defineComponent } from "vue";
export default defineComponent({
  setup() {
    const table = ref({
      key: "stationID",
      footer: "Foots",
      cnName: "站台信息",
      name: "Dt_StationManager",
      url: "/Dt_StationManager/",
      sortName: "stationID",
    });
    const editFormFields = ref({
      stationCode: "",
      stationName: "",
      stationMaterial: "",
      stationEnable: "",
      stationArea: "",
      stationRemark: "",
      deviceCode: "",
    });
    const editFormOptions = ref([
      [
        {
          title: "站台编号",
          field: "stationCode",
          type: "int",
        },
        {
          title: "站台名称",
          field: "stationName",
          type: "string",
        },
        {
          title: "站台类型",
          required: true,
          field: "stationMaterial",
          type: "select",
          dataKey: "agvStationEnum",
          data: [],
        },
      ],
      [
        {
          title: "区域",
          required: true,
          field: "stationArea",
          type: "select",
          dataKey: "agvareaEnum",
          data: [],
        },
        {
          title: "是否启用",
          required: true,
          field: "stationEnable",
          type: "select",
          dataKey: "enable",
          data: [],
        },
        {
          title: "备注",
          field: "stationRemark",
          type: "string",
        },
      ], [
        {
          title: "所属设备",
          field: "deviceCode",
          type: "string",
        },
      ]
    ]);
    const searchFormFields = ref({
      stationCode: "",
      stationName: "",
      stationMaterial: "",
      stationEnable: "",
    });
    const searchFormOptions = ref([
      [
        { title: "站台名称", field: "stationName", type: "like" },
        { title: "站台编号", field: "stationCode", type: "like" },
        {
          title: "站台类型",
          field: "stationMaterial",
          type: "select",
          dataKey: "agvStationEnum",
          data: [],
        }
      ],
      [
        { title: "所属设备", field: "deviceCode", type: "like" },
        {
          title: "区域",
          field: "stationArea",
          type: "select",
          dataKey: "agvareaEnum",
          data: [],
        }, {
          title: "是否启用",
          field: "stationEnable",
          type: "select",
          dataKey: "enable",
          data: [],
        },
      ],
    ]);
    const columns = ref([
      {
        field: "stationId",
        title: "stationId",
        type: "int",
        width: 90,
        hidden: true,
        readonly: true,
        require: true,
        align: "left",
        sort: true
      },
      {
        field: "stationCode",
        title: "站台编号",
        type: "string",
        width: 100,
        align: "left",
        sort: true
      },
      {
        field: "stationName",
        title: "站台名称",
        type: "string",
        width: 150,
        align: "left",
        sort: true
      },
      {
        field: "stationMaterial",
        title: "站台类型",
        type: "string",
        width: 150,
        align: "left",
        bind: { key: "agvStationEnum", data: [] },
        sort: true
      },
      {
        field: "stationEnable",
        title: "是否启用",
        type: "string",
        width: 120,
        align: "left",
        bind: { key: "enable", data: [] },
        sort: true
      },
      {
        field: "stationArea",
        title: "区域",
        type: "string",
        width: 120,
        align: "left",
        sort: true,
        bind: { key: "agvareaEnum", data: {} }
      },
      {
        field: "stationRemark",
        title: "备注",
        type: "string",
        width: 120,
        align: "left",
        sort: true
        // link: true,
      },
      {
        field: "deviceCode",
        title: "所属设备",
        type: "string",
        width: 120,
        align: "left",
        sort: true
      },
    ]);
    return {
      table,
      extend,
      editFormFields,
      editFormOptions,
      searchFormFields,
      searchFormOptions,
      columns,
    };
  },
});
</script>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/charts/bigdata.vue
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/quartzJob/deviceInfo.vue
@@ -27,6 +27,7 @@
      sortName: "createDate",
    });
    const editFormFields = ref({
      id:"",
      deviceCode: "",
      deviceName: "",
      deviceType: "",
@@ -94,7 +95,6 @@
      deviceCode: "",
      deviceType: "",
      deviceStatus: "",
      createDate:"",
    });
    const searchFormOptions = ref([
      [
@@ -112,10 +112,6 @@
          type: "select",
          dataKey: "deviceStatus",
          data: [],
        },{
        field: "createDate",
        title: "创建时间",
        type: "datetime",
      },
      ],
    ]);
@@ -165,14 +161,14 @@
        field: "deviceIp",
        title: "设备IP",
        type: "string",
        width: 90,
        width: 150,
        align: "left",
      },
      {
        field: "devicePort",
        title: "设备端口",
        type: "int",
        width: 120,
        width: 100,
        align: "left",
      },
      {
@@ -352,7 +348,7 @@
          align: "left",
        },
      ],
      sortName: "CreateDate",
      sortName: "createDate",
      key: "id",
    });
    return {
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/syslog/txt_log.vue
ÎļþÒÑɾ³ý
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/system/AgvStation.vue
ÎļþÒÑɾ³ý
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/system/Sys_User.vue
@@ -36,6 +36,7 @@
      gender: "",
      remark: "",
      headImageUrl: "",
      roleName:"",
    });
    const editFormOptions = ref([
      [{ title: "帐号", required: true, field: "userName"}],
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/taskinfo/task.vue
@@ -88,19 +88,21 @@
        width: 90,
        align: "left",
      },
      // {
      //   field: "palletCode",
      //   title: "托盘编号",
      //   type: "string",
      //   width: 200,
      //   align: "left",
      // },
      {
        field: "roadway",
        title: "区域",
        type: "string",
        width: 90,
        align: "left",
        bind:{key:"agvareaEnum",data:{}}
      },
      {
        field: "agvName",
        title: "AGV编号",
        type: "string",
        width: 90,
        align: "left",
        bind:{key:"agvareaEnum",data:{}}
      },
      {
        field: "taskType",
@@ -108,7 +110,7 @@
        type: "int",
        width: 90,
        align: "left",
        bind: { key: "agvStationEnum", data: [] },
        bind: { key: "taskType", data: [] },
      },
      {
        field: "taskState",
@@ -124,6 +126,7 @@
        type: "int",
        width: 120,
        align: "left",
        bind: { key: "location", data: [] },
      },
      {
        field: "targetAddress",
@@ -131,6 +134,7 @@
        type: "string",
        width: 120,
        align: "left",
        bind: { key: "location", data: [] },
      },
      {
        field: "currentAddress",
@@ -138,6 +142,8 @@
        type: "string",
        width: 120,
        align: "left",
        bind: { key: "location", data: [] },
        hidden:true,
      },
      {
        field: "nextAddress",
@@ -145,6 +151,8 @@
        type: "string",
        width: 120,
        align: "left",
        bind: { key: "location", data: [] },
        hidden:true,
      },
      {
        field: "exceptionMessage",
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/src/views/taskinfo/task_hty.vue
@@ -80,7 +80,6 @@
        readonly: true,
        require: true,
        align: "left",
        sort:true,
      },
      {
        field: "taskNum",
@@ -88,23 +87,22 @@
        type: "int",
        width: 90,
        align: "left",
        sort:true,
      },
      {
        field: "palletCode",
        title: "托盘编号",
        type: "string",
        width: 200,
        align: "left",
        sort:true,
      },
      {
        field: "roadway",
        title: "巷道号",
        title: "区域",
        type: "string",
        width: 90,
        align: "left",
        sort:true,
        bind:{key:"agvareaEnum",data:{}}
      },
      {
        field: "agvName",
        title: "AGV编号",
        type: "string",
        width: 90,
        align: "left",
        bind:{key:"agvareaEnum",data:{}}
      },
      {
        field: "taskType",
@@ -113,7 +111,6 @@
        width: 90,
        align: "left",
        bind: { key: "taskType", data: [] },
        sort:true,
      },
      {
        field: "taskState",
@@ -122,7 +119,6 @@
        width: 150,
        align: "left",
        bind: { key: "taskState", data: [] },
        sort:true,
      },
      {
        field: "sourceAddress",
@@ -130,6 +126,7 @@
        type: "int",
        width: 120,
        align: "left",
        bind: { key: "location", data: [] },
      },
      {
        field: "targetAddress",
@@ -137,6 +134,7 @@
        type: "string",
        width: 120,
        align: "left",
        bind: { key: "location", data: [] },
      },
      {
        field: "currentAddress",
@@ -144,6 +142,8 @@
        type: "string",
        width: 120,
        align: "left",
        bind: { key: "location", data: [] },
        hidden:true,
      },
      {
        field: "nextAddress",
@@ -151,6 +151,8 @@
        type: "string",
        width: 120,
        align: "left",
        bind: { key: "location", data: [] },
        hidden:true,
      },
      {
        field: "exceptionMessage",
@@ -195,7 +197,6 @@
        type: "datetime",
        width: 150,
        align: "left",
        sort:true,
      },
      {
        field: "modifier",
@@ -210,7 +211,6 @@
        type: "datetime",
        width: 160,
        align: "left",
        sort:true,
      },
      {
        field: "remark",
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Client/yarn.lock
ÎļþÒÑɾ³ý
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/CodeChunks.db
Binary files differ
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/CodeChunks.db-shm
Binary files differ
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/CodeChunks.db-wal
Binary files differ
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/SemanticSymbols.db
Binary files differ
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/SemanticSymbols.db-shm
Binary files differ
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/CopilotIndices/17.13.441.19478/SemanticSymbols.db-wal
Binary files differ
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/FileContentIndex/read.lock
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/DocumentLayout.backup.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,273 @@
{
  "Version": 1,
  "WorkspaceRootPath": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\",
  "Documents": [
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_server\\controllers\\task\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\controllers\\task\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|solutionrelative:wideseawcs_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_taskinfoservice\\taskexecutedetailservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|solutionrelative:wideseawcs_taskinfoservice\\taskexecutedetailservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinejob\\commonconveyorlinejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinejob\\commonconveyorlinejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\stackercranejob\\commonstackercranejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\stackercranejob\\commonstackercranejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{C2D3D138-9109-481B-8BEB-A27597890B2C}|WIDESEAWCS_DTO\\WIDESEAWCS_DTO.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_dto\\enum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{C2D3D138-9109-481B-8BEB-A27597890B2C}|WIDESEAWCS_DTO\\WIDESEAWCS_DTO.csproj|solutionrelative:wideseawcs_dto\\enum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\testjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\testjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{8C2CC25B-DE5D-433E-A550-63864C7A716D}|WIDESEAWCS_IBasicInfoService\\WIDESEAWCS_IBasicInfoService.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_ibasicinfoservice\\idt_stationmanagerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{8C2CC25B-DE5D-433E-A550-63864C7A716D}|WIDESEAWCS_IBasicInfoService\\WIDESEAWCS_IBasicInfoService.csproj|solutionrelative:wideseawcs_ibasicinfoservice\\idt_stationmanagerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinejob\\conveyorlinetaskcommand.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinejob\\conveyorlinetaskcommand.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}|WIDESEAWCS_Model\\WIDESEAWCS_Model.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_model\\models\\basicinfo\\dt_stationmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}|WIDESEAWCS_Model\\WIDESEAWCS_Model.csproj|solutionrelative:wideseawcs_model\\models\\basicinfo\\dt_stationmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\stackercranejob\\stackercranedbname.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\stackercranejob\\stackercranedbname.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}|WIDESEAWCS_Model\\WIDESEAWCS_Model.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_model\\models\\taskinfo\\dt_task.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}|WIDESEAWCS_Model\\WIDESEAWCS_Model.csproj|solutionrelative:wideseawcs_model\\models\\taskinfo\\dt_task.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_server\\controllers\\system\\sys_dictionarycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\controllers\\system\\sys_dictionarycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    }
  ],
  "DocumentGroupContainers": [
    {
      "Orientation": 0,
      "VerticalTabListWidth": 256,
      "DocumentGroups": [
        {
          "DockedWidth": 200,
          "SelectedChildIndex": 2,
          "Children": [
            {
              "$type": "Bookmark",
              "Name": "ST:128:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
            },
            {
              "$type": "Bookmark",
              "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "Title": "TaskController.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Controllers\\Task\\TaskController.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Controllers\\Task\\TaskController.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Controllers\\Task\\TaskController.cs*",
              "RelativeToolTip": "WIDESEAWCS_Server\\Controllers\\Task\\TaskController.cs*",
              "ViewState": "AgIAAAoAAAAAAAAAAAAYwBcAAAA7AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-12T01:30:32.857Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 4,
              "Title": "CommonStackerCraneJob.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "ViewState": "AgIAAGcAAAAAAAAAAADwv1wAAAAnAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T07:20:51.488Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 3,
              "Title": "CommonConveyorLineJob.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineJob\\CommonConveyorLineJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\ConveyorLineJob\\CommonConveyorLineJob.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineJob\\CommonConveyorLineJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\ConveyorLineJob\\CommonConveyorLineJob.cs",
              "ViewState": "AgIAAKAAAAAAAAAAAAAvwKoAAAARAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T00:33:00.02Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 1,
              "Title": "TaskService.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "ViewState": "AgIAAFgAAAAAAAAAAAAgwGkAAAAQAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T02:52:33.157Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 2,
              "Title": "TaskExecuteDetailService.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskExecuteDetailService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\TaskExecuteDetailService.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskExecuteDetailService.cs",
              "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\TaskExecuteDetailService.cs",
              "ViewState": "AgIAAFYAAAAAAAAAAADwv1oAAAANAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T02:54:03.845Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 5,
              "Title": "Program.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Program.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs",
              "RelativeToolTip": "WIDESEAWCS_Server\\Program.cs",
              "ViewState": "AgIAAHgAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T05:42:49.47Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 12,
              "Title": "StackerCraneDBName.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\StackerCraneDBName.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\StackerCraneJob\\StackerCraneDBName.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\StackerCraneDBName.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\StackerCraneJob\\StackerCraneDBName.cs",
              "ViewState": "AgIAAEIAAAAAAAAAAAAAAF0AAAAOAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T09:13:25.087Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 13,
              "Title": "Dt_Task.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Model\\Models\\TaskInfo\\Dt_Task.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Model\\Models\\TaskInfo\\Dt_Task.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Model\\Models\\TaskInfo\\Dt_Task.cs",
              "RelativeToolTip": "WIDESEAWCS_Model\\Models\\TaskInfo\\Dt_Task.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAB8AAAAHAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T08:43:01.804Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 6,
              "Title": "TaskStatusEnum.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_DTO\\Enum\\TaskStatusEnum.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_DTO\\Enum\\TaskStatusEnum.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_DTO\\Enum\\TaskStatusEnum.cs",
              "RelativeToolTip": "WIDESEAWCS_DTO\\Enum\\TaskStatusEnum.cs",
              "ViewState": "AgIAAJUAAAAAAAAAAAAnwJ8AAAAMAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T08:33:01.088Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 8,
              "Title": "IDt_StationManagerService.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_IBasicInfoService\\IDt_StationManagerService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_IBasicInfoService\\IDt_StationManagerService.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_IBasicInfoService\\IDt_StationManagerService.cs",
              "RelativeToolTip": "WIDESEAWCS_IBasicInfoService\\IDt_StationManagerService.cs",
              "ViewState": "AgIAABsAAAAAAAAAAAAnwDIAAAAnAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T01:09:00.319Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 9,
              "Title": "ConveyorLineTaskCommand.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineJob\\ConveyorLineTaskCommand.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\ConveyorLineJob\\ConveyorLineTaskCommand.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineJob\\ConveyorLineTaskCommand.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\ConveyorLineJob\\ConveyorLineTaskCommand.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAuwBwAAAA1AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T01:17:59.023Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 7,
              "Title": "TestJob.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\TestJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\TestJob.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\TestJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\TestJob.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T01:43:47.806Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 10,
              "Title": "Dt_StationManager.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Model\\Models\\BasicInfo\\Dt_StationManager.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Model\\Models\\BasicInfo\\Dt_StationManager.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Model\\Models\\BasicInfo\\Dt_StationManager.cs",
              "RelativeToolTip": "WIDESEAWCS_Model\\Models\\BasicInfo\\Dt_StationManager.cs",
              "ViewState": "AgIAAC8AAAAAAAAAAAAhwD8AAAAgAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T08:42:55.586Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 14,
              "Title": "Sys_DictionaryController.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Controllers\\System\\Sys_DictionaryController.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Controllers\\System\\Sys_DictionaryController.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Controllers\\System\\Sys_DictionaryController.cs",
              "RelativeToolTip": "WIDESEAWCS_Server\\Controllers\\System\\Sys_DictionaryController.cs",
              "ViewState": "AgIAACIBAAAAAAAAAADwv1MBAABEAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T08:32:07.315Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 11,
              "Title": "appsettings.json",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\appsettings.json",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
              "RelativeToolTip": "WIDESEAWCS_Server\\appsettings.json",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAgAAABSAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
              "WhenOpened": "2025-06-10T07:20:02.074Z"
            }
          ]
        }
      ]
    }
  ]
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/DocumentLayout.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,273 @@
{
  "Version": 1,
  "WorkspaceRootPath": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\",
  "Documents": [
    {
      "AbsoluteMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_quartzjob\\stackercrane\\common\\commonstackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{6236BFFF-173D-44A8-9FC3-7C001EA30347}|WIDESEAWCS_QuartzJob\\WIDESEAWCS_QuartzJob.csproj|solutionrelative:wideseawcs_quartzjob\\stackercrane\\common\\commonstackercrane.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\stackercranejob\\commonstackercranejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\stackercranejob\\commonstackercranejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_server\\controllers\\task\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\controllers\\task\\taskcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{83F18A31-5983-4587-A0B2-414BF70E50B5}|WIDESEAWCS_TaskInfoService\\WIDESEAWCS_TaskInfoService.csproj|solutionrelative:wideseawcs_taskinfoservice\\taskservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinejob\\commonconveyorlinejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinejob\\commonconveyorlinejob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{C2D3D138-9109-481B-8BEB-A27597890B2C}|WIDESEAWCS_DTO\\WIDESEAWCS_DTO.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_dto\\enum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{C2D3D138-9109-481B-8BEB-A27597890B2C}|WIDESEAWCS_DTO\\WIDESEAWCS_DTO.csproj|solutionrelative:wideseawcs_dto\\enum\\taskstatusenum.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\testjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\testjob.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{8C2CC25B-DE5D-433E-A550-63864C7A716D}|WIDESEAWCS_IBasicInfoService\\WIDESEAWCS_IBasicInfoService.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_ibasicinfoservice\\idt_stationmanagerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{8C2CC25B-DE5D-433E-A550-63864C7A716D}|WIDESEAWCS_IBasicInfoService\\WIDESEAWCS_IBasicInfoService.csproj|solutionrelative:wideseawcs_ibasicinfoservice\\idt_stationmanagerservice.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\conveyorlinejob\\conveyorlinetaskcommand.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\conveyorlinejob\\conveyorlinetaskcommand.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}|WIDESEAWCS_Model\\WIDESEAWCS_Model.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_model\\models\\basicinfo\\dt_stationmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}|WIDESEAWCS_Model\\WIDESEAWCS_Model.csproj|solutionrelative:wideseawcs_model\\models\\basicinfo\\dt_stationmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_tasks\\stackercranejob\\stackercranedbname.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{294E4915-0241-4C8C-BA99-7588B945863A}|WIDESEAWCS_Tasks\\WIDESEAWCS_Tasks.csproj|solutionrelative:wideseawcs_tasks\\stackercranejob\\stackercranedbname.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}|WIDESEAWCS_Model\\WIDESEAWCS_Model.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_model\\models\\taskinfo\\dt_task.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{7F200FE8-CAF6-4131-BD25-8D438FE0ABAC}|WIDESEAWCS_Model\\WIDESEAWCS_Model.csproj|solutionrelative:wideseawcs_model\\models\\taskinfo\\dt_task.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    },
    {
      "AbsoluteMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|e:\\get\\jiangxijiujiang\\\u9879\u76EE\u4EE3\u7801\\wcs\\wideseawcs_server\\wideseawcs_server\\controllers\\system\\sys_dictionarycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
      "RelativeMoniker": "D:0:0:{487FA45B-EA1A-4ACA-BB5B-0F6708F462C0}|WIDESEAWCS_Server\\WIDESEAWCS_Server.csproj|solutionrelative:wideseawcs_server\\controllers\\system\\sys_dictionarycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
    }
  ],
  "DocumentGroupContainers": [
    {
      "Orientation": 0,
      "VerticalTabListWidth": 256,
      "DocumentGroups": [
        {
          "DockedWidth": 200,
          "SelectedChildIndex": 2,
          "Children": [
            {
              "$type": "Bookmark",
              "Name": "ST:128:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
            },
            {
              "$type": "Bookmark",
              "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
            },
            {
              "$type": "Document",
              "DocumentIndex": 0,
              "Title": "CommonStackerCrane.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\CommonStackerCrane.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\CommonStackerCrane.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\CommonStackerCrane.cs",
              "RelativeToolTip": "WIDESEAWCS_QuartzJob\\StackerCrane\\Common\\CommonStackerCrane.cs",
              "ViewState": "AgIAABcAAAAAAAAAAADwvycAAAAVAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-12T01:50:11.447Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 2,
              "Title": "TaskController.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Controllers\\Task\\TaskController.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Controllers\\Task\\TaskController.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Controllers\\Task\\TaskController.cs",
              "RelativeToolTip": "WIDESEAWCS_Server\\Controllers\\Task\\TaskController.cs",
              "ViewState": "AgIAAAoAAAAAAAAAAAAYwBkAAAAMAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-12T01:30:32.857Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 1,
              "Title": "CommonStackerCraneJob.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\StackerCraneJob\\CommonStackerCraneJob.cs",
              "ViewState": "AgIAACoAAAAAAAAAAAAAADYAAAAiAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T07:20:51.488Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 4,
              "Title": "CommonConveyorLineJob.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineJob\\CommonConveyorLineJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\ConveyorLineJob\\CommonConveyorLineJob.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineJob\\CommonConveyorLineJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\ConveyorLineJob\\CommonConveyorLineJob.cs",
              "ViewState": "AgIAADkBAAAAAAAAAAAiwFcBAAATAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T00:33:00.02Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 3,
              "Title": "TaskService.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "RelativeToolTip": "WIDESEAWCS_TaskInfoService\\TaskService.cs",
              "ViewState": "AgIAAAQCAAAAAAAAAAAAACACAAAIAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T02:52:33.157Z",
              "EditorCaption": ""
            },
            {
              "$type": "Document",
              "DocumentIndex": 5,
              "Title": "Program.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Program.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Program.cs",
              "RelativeToolTip": "WIDESEAWCS_Server\\Program.cs",
              "ViewState": "AgIAAHgAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T05:42:49.47Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 12,
              "Title": "StackerCraneDBName.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\StackerCraneDBName.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\StackerCraneJob\\StackerCraneDBName.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\StackerCraneJob\\StackerCraneDBName.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\StackerCraneJob\\StackerCraneDBName.cs",
              "ViewState": "AgIAAEIAAAAAAAAAAAAAAF0AAAAOAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T09:13:25.087Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 13,
              "Title": "Dt_Task.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Model\\Models\\TaskInfo\\Dt_Task.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Model\\Models\\TaskInfo\\Dt_Task.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Model\\Models\\TaskInfo\\Dt_Task.cs",
              "RelativeToolTip": "WIDESEAWCS_Model\\Models\\TaskInfo\\Dt_Task.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAB8AAAAHAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T08:43:01.804Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 6,
              "Title": "TaskStatusEnum.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_DTO\\Enum\\TaskStatusEnum.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_DTO\\Enum\\TaskStatusEnum.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_DTO\\Enum\\TaskStatusEnum.cs",
              "RelativeToolTip": "WIDESEAWCS_DTO\\Enum\\TaskStatusEnum.cs",
              "ViewState": "AgIAAJUAAAAAAAAAAAAnwJ8AAAAMAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T08:33:01.088Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 8,
              "Title": "IDt_StationManagerService.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_IBasicInfoService\\IDt_StationManagerService.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_IBasicInfoService\\IDt_StationManagerService.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_IBasicInfoService\\IDt_StationManagerService.cs",
              "RelativeToolTip": "WIDESEAWCS_IBasicInfoService\\IDt_StationManagerService.cs",
              "ViewState": "AgIAABsAAAAAAAAAAAAnwDIAAAAnAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T01:09:00.319Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 9,
              "Title": "ConveyorLineTaskCommand.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineJob\\ConveyorLineTaskCommand.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\ConveyorLineJob\\ConveyorLineTaskCommand.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\ConveyorLineJob\\ConveyorLineTaskCommand.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\ConveyorLineJob\\ConveyorLineTaskCommand.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAAAuwBwAAAA1AAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T01:17:59.023Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 7,
              "Title": "TestJob.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\TestJob.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Tasks\\TestJob.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Tasks\\TestJob.cs",
              "RelativeToolTip": "WIDESEAWCS_Tasks\\TestJob.cs",
              "ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-11T01:43:47.806Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 10,
              "Title": "Dt_StationManager.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Model\\Models\\BasicInfo\\Dt_StationManager.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Model\\Models\\BasicInfo\\Dt_StationManager.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Model\\Models\\BasicInfo\\Dt_StationManager.cs",
              "RelativeToolTip": "WIDESEAWCS_Model\\Models\\BasicInfo\\Dt_StationManager.cs",
              "ViewState": "AgIAAC8AAAAAAAAAAAAhwD8AAAAgAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T08:42:55.586Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 14,
              "Title": "Sys_DictionaryController.cs",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Controllers\\System\\Sys_DictionaryController.cs",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\Controllers\\System\\Sys_DictionaryController.cs",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\Controllers\\System\\Sys_DictionaryController.cs",
              "RelativeToolTip": "WIDESEAWCS_Server\\Controllers\\System\\Sys_DictionaryController.cs",
              "ViewState": "AgIAACIBAAAAAAAAAADwv1MBAABEAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
              "WhenOpened": "2025-06-10T08:32:07.315Z"
            },
            {
              "$type": "Document",
              "DocumentIndex": 11,
              "Title": "appsettings.json",
              "DocumentMoniker": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
              "RelativeDocumentMoniker": "WIDESEAWCS_Server\\appsettings.json",
              "ToolTip": "E:\\GET\\JiangXiJiuJiang\\\u9879\u76EE\u4EE3\u7801\\WCS\\WIDESEAWCS_Server\\WIDESEAWCS_Server\\appsettings.json",
              "RelativeToolTip": "WIDESEAWCS_Server\\appsettings.json",
              "ViewState": "AgIAAAAAAAAAAAAAAAAAAAgAAABSAAAAAAAAAA==",
              "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
              "WhenOpened": "2025-06-10T07:20:02.074Z"
            }
          ]
        }
      ]
    }
  ]
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vs/WIDESEAWCS_Server/v17/HierarchyCache.v1.txt
Binary files differ
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/.vscode/launch.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
{
    // ä½¿ç”¨ IntelliSense äº†è§£ç›¸å…³å±žæ€§ã€‚
    // æ‚¬åœä»¥æŸ¥çœ‹çŽ°æœ‰å±žæ€§çš„æè¿°ã€‚
    // æ¬²äº†è§£æ›´å¤šä¿¡æ¯ï¼Œè¯·è®¿é—®: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": []
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoRepository/Dt_StationManagerRepository.cs
ÎļþÃû´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemRepository/AgvStationRepository.cs ÐÞ¸Ä
@@ -21,15 +21,15 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_ISystemRepository;
using WIDESEAWCS_IBasicInfoRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
using WIDESEAWCS_Model.Models.BasicInfo;
namespace WIDESEAWCS_SystemRepository
namespace WIDESEAWCS_BasicInfoRepository
{
    public class AgvStationRepository : RepositoryBase<AGVStation>, IAgvStationRepository
    public class Dt_StationManagerRepository : RepositoryBase<Dt_StationManager>, IDt_StationManagerRepository
    {
        public AgvStationRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        public Dt_StationManagerRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        {
        }
    }
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoRepository/WIDESEAWCS_BasicInfoRepository.csproj
@@ -1,14 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\WIDESEAWCS_IBasicInfoRepository\WIDESEAWCS_IBasicInfoRepository.csproj" />
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/Dt_StationManagerService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,100 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_TaskInfoService
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using AutoMapper;
using Microsoft.AspNetCore.Mvc.RazorPages;
using NetTaste;
using Newtonsoft.Json;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using SqlSugar;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_DTO.Enum;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_IBasicInfoRepository;
using WIDESEAWCS_IBasicInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.BasicInfo;
namespace WIDESEAWCS_BasicInfoService
{
    public class Dt_StationManagerService : ServiceBase<Dt_StationManager, IDt_StationManagerRepository>, IDt_StationManagerService
    {
        public Dt_StationManagerService(IDt_StationManagerRepository BaseDal) : base(BaseDal)
        {
        }
        public class Station_materialList
        {
            /// <summary>
            /// ä¸‹æ–™ä½-》》上料或存放
            /// </summary>
            public static List<int> BoardLoadList = new List<int>() { (int)AgvStationEnum.BoardLoad, (int)AgvStationEnum.PadUse };
            /// <summary>
            /// ä¸Šæ–™ï¼Œä¸‹æ–™ï¼Œåž«æ¿ä½¿ç”¨ï¼Œåž«æ¿å›žæ”¶
            /// </summary>
            public static List<int> UsebitsList = new List<int>() { (int)AgvStationEnum.BoardUnload,(int)AgvStationEnum.PadRecycle};
            public static List<string> StationareaList = new List<string>() {"1003","1004" , "1005","1006","1007" };
        }
        public List<Dt_StationManager> QuerypLatform(string deviceNo,List<string> task)
        {
            return BaseDal.QueryData(x=>x.DeviceCode == deviceNo && x.stationEnable==1 && Station_materialList.UsebitsList.Contains(x.stationMaterial) && !task.Contains(x.stationName)).ToList();
        }
        public List<Dt_StationManager> QuerypLatformarer(string deviceNo)
        {
            return BaseDal.QueryData((x => x.DeviceCode == deviceNo && x.stationEnable == 1 && Station_materialList.BoardLoadList.Contains(x.stationMaterial)), x=>x.stationMaterial).ToList();
        }
        public List<Dt_StationManager> QuerypLatformmaterial(int Station_Area)
        {
            return BaseDal.QueryData(x => x.stationArea == Station_Area && x.stationEnable == 1 && (x.stationMaterial == (int)AgvStationEnum.BoardStore || x.stationMaterial == (int)AgvStationEnum.PadStore) ).ToList();
        }
        public List<Dt_StationManager> QuerypStation_Area(int Station_Area)
        {
            return BaseDal.QueryData(x => x.stationArea == Station_Area && x.stationEnable == 1 && x.stationMaterial == (int)AgvStationEnum.PadStore).ToList();
        }
        public List<Dt_StationManager> QuerypStation_Area2(string Station_remark)
        {
            return BaseDal.QueryData(x => Station_remark.Contains(x.stationRemark) && x.stationEnable == 1 && x.stationMaterial == (int)AgvStationEnum.PadStore).ToList();
        }
        public List<Dt_StationManager> GetAllStationByDeviceCode(string DeviceCode)
        {
            return BaseDal.QueryData(x => x.DeviceCode == DeviceCode && x.stationEnable == 1).ToList();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/WIDESEAWCS_BasicInfoService.csproj
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
@@ -7,12 +7,8 @@
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
    <PackageReference Include="WIDESEAWCS_QuartzJob" Version="2.1.2" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\WIDESEAWCS_IBasicInfoService\WIDESEAWCS_IBasicInfoService.csproj" />
    <ProjectReference Include="..\WIDESEAWCS_QuartzJob\WIDESEAWCS_QuartzJob.csproj" />
  </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/Http/HttpHelper.cs
@@ -1,5 +1,4 @@

using Newtonsoft.Json;
using Newtonsoft.Json;
using System.Net;
using System.Text;
using WIDESEA_Common.Log;
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Common/WIDESEAWCS_Common.csproj
@@ -8,7 +8,6 @@
  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
  </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/BaseCommunicator.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,144 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Communicator
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šåŸºç¡€é€šè®¯æŠ½è±¡ç±»ï¼Œå°è£…连接、断开连接、读取、写入等方法
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using HslCommunication.LogNet;
using System.Diagnostics.CodeAnalysis;
namespace WIDESEAWCS_Communicator
{
    public abstract class BaseCommunicator: IDisposable
    {
        /// <summary>
        /// æž„造函数
        /// </summary>
        protected BaseCommunicator()
        {
        }
        /// <summary>
        /// æ—¥å¿—记录实例对象
        /// </summary>
        public abstract ILogNet LogNet { get; }
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public abstract string Name { get; }
        /// <summary>
        /// èŽ·å–å½“å‰é€šè®¯å™¨æ˜¯å¦å·²è¿žæŽ¥åˆ°PLC。
        /// </summary>
        public abstract bool IsConnected { get; }
        /// <summary>
        /// è¿žæŽ¥åˆ°PLC。
        /// </summary>
        /// <returns>如果连接成功则返回true,否则返回false。</returns>
        public abstract bool Connect();
        /// <summary>
        /// æ–­å¼€ä¸Žå·¥ä¸šè®¾å¤‡çš„连接。
        /// </summary>
        /// <returns>如果成功断开连接则返回true,如果已经是断开状态则返回false。</returns>
        public abstract bool Disconnect();
        /// <summary>
        /// ä»ŽPLC读取数据。
        /// </summary>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="length">要读取的数据长度。</param>
        /// <returns>读取到的数据,如果读取失败则可能返回null或空数组。</returns>
        public abstract byte[] Read(string address, int length);
        /// <summary>
        /// ä»ŽPLC读取数据。
        /// </summary>
        /// <typeparam name="T">读取数据的类型泛型。</typeparam>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <returns>读取到的数据,如果读取失败则可能返回null或抛出异常。</returns>
        public abstract T Read<T>(string address);
        /// <summary>
        /// ä»ŽPLC读取数据。
        /// </summary>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="dataType">数据类型。</param>
        /// <returns>读取到的数据,如果读取失败则可能返回null或抛出异常。</returns>
        public abstract object ReadAsObj(string address, string dataType);
        /// <summary>
        /// å‘PLC写入数据。
        /// </summary>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="data">要写入的数据。</param>
        /// <returns>如果写入成功则返回true,否则抛出异常。</returns>
        public abstract bool Write(string address, byte[] data);
        /// <summary>
        /// å‘PLC写入数据。
        /// </summary>
        /// <typeparam name="T">读取数据的类型泛型。</typeparam>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="value">要写入的数据。</param>
        /// <returns>如果写入成功则返回true,否则抛出异常。</returns>
        public abstract bool Write<T>(string address, T value) where T : notnull;
        /// <summary>
        /// å‘PLC写入数据。
        /// </summary>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="dataType">要写入的数据类型。</param>
        /// <param name="value">要写入的数据。</param>
        /// <returns>如果写入成功则返回true,失败则抛出异常。</returns>
        /// <exception cref="CommunicationException"></exception>
        public abstract bool WriteObj(string address, string dataType, object value);
        /// <summary>
        /// ç­‰å¾…指定地址的泛型类型值为指定的值
        /// </summary>
        /// <typeparam name="T">指定的值的类型泛型。</typeparam>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="readInterval">读取的频率。</param>
        /// <param name="waitTimeout">等待的超时时间,如果超时时间为-1的话,则是无期限等待。</param>
        /// <param name="value">等待检测的值</param>
        /// <returns>是否等待成功的结果对象,一旦通信失败,或是等待超时就返回失败。否则返回成功,并告知调用方等待了多久。</returns>
        public abstract OperateResult<TimeSpan> Wait<T>(string address, int readInterval, int waitTimeout, T value) where T : struct;
        /// <summary>
        /// è¯»å–自定义的数据类型,需要继承自IDataTransfer接口,返回一个新的类型的实例对象。
        /// </summary>
        /// <typeparam name="T">自定义的数据类型泛型。</typeparam>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <returns>成功返回自定义类型数据,失败抛出异常。</returns>
        public abstract T ReadCustomer<T>(string address) where T : IDataTransfer, new();
        /// <summary>
        /// å†™å…¥è‡ªå®šä¹‰ç±»åž‹çš„æ•°æ®ï¼Œè¯¥ç±»åž‹å¿…须继承自IDataTransfer接口。
        /// </summary>
        /// <typeparam name="T">自定义的数据类型泛型。</typeparam>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="value">要写入数据。</param>
        /// <returns>如果写入成功则返回true,失败则抛出异常。</returns>
        public abstract bool WriteCustomer<T>(string address, [NotNull] T value) where T : IDataTransfer, new();
        /// <summary>
        /// é‡Šæ”¾å¯¹è±¡èµ„源的接口。
        /// </summary>
        public abstract void Dispose();
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/CommunicationException.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,188 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Communicator
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè‡ªå®šä¹‰é€šè®¯å¼‚常类,定义了错误类型、错误代码(暂时没定义错误代码表)
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication.LogNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Communicator
{
    /// <summary>
    /// å·¥ä¸šé€šä¿¡é”™è¯¯ç±»ï¼Œå°è£…了与PLC通信时可能发生的错误。
    /// </summary>
    [Serializable] // ç¡®ä¿ç±»æ”¯æŒåºåˆ—化
    public class CommunicationException : Exception
    {
        //public static ILogNet logNet = new LogNetFileSize()
        /// <summary>
        /// é”™è¯¯ä»£ç ã€‚
        /// </summary>
        public int? ErrorCode { get; }
        /// <summary>
        /// é€šä¿¡é”™è¯¯çš„类型。
        /// </summary>
        public CommunicationErrorType ErrorType { get; }
        /// <summary>
        /// é”™è¯¯ä¿¡æ¯
        /// </summary>
        public override string Message => _message;
        private string _message;
        /// <summary>
        /// åˆå§‹åŒ–一个新的 CommunicationException å®žä¾‹ã€‚
        /// </summary>
        /// <param name="message">错误的描述。</param>
        /// <param name="plcErrorCode">错误代码(可选)。</param>
        /// <param name="innerException">导致当前异常的异常(可选)。</param>
        public CommunicationException(string message, CommunicationErrorType errorType, int? plcErrorCode = null, Exception innerException = null)
            : base(message, innerException)
        {
            ErrorCode = plcErrorCode;
            ErrorType = errorType;
            _message = message;
        }
        /// <summary>
        /// æä¾›ä¸€ä¸ªæ›´å‹å¥½çš„字符串表示形式,包含PLC错误代码(如果可用)和任何内部异常信息。
        /// </summary>
        /// <returns>异常的字符串表示形式。</returns>
        public override string ToString()
        {
            //string plcCodeInfo = ErrorCode.HasValue ? $"PLC Error Code: {ErrorCode.Value}" : "No PLC Error Code";
            string innerExceptionInfo = InnerException != null ? $"\nInner Exception: {InnerException.Message}" : "";
            return $"{GetType().Name}: {Message}\n{innerExceptionInfo}";
        }
    }
    /// <summary>
    /// å·¥ä¸šé€šä¿¡é”™è¯¯ç±»åž‹æžšä¸¾ã€‚
    /// </summary>
    public enum CommunicationErrorType
    {
        /// <summary>
        /// IP地址错误
        /// </summary>
        IpAddressError,
        /// <summary>
        /// è¿žæŽ¥PLC错误
        /// </summary>
        ConnectionFailed,
        /// <summary>
        /// æœªçŸ¥ç±»åž‹é”™è¯¯
        /// </summary>
        Unknown,
        /// <summary>
        /// è¯»å–失败
        /// </summary>
        ReadFailed,
        /// <summary>
        /// å†™å…¥å¤±è´¥
        /// </summary>
        WriteFailed,
        /// <summary>
        /// ç±»åž‹é”™è¯¯
        /// </summary>
        TypeError,
        /// <summary>
        /// è¯»å–异常
        /// </summary>
        ReadException
    }
    public class CommunicationExceptionMessage
    {
        /// <summary>
        /// Ip地址错误,参数【IP】
        /// </summary>
        public const string IpAddressErrorException = "Ip地址错误,【{0}】";
        /// <summary>
        /// æ•°æ®è¯»å–失败,参数【数据类型,协议地址,错误信息】
        /// </summary>
        public const string ReadFailedException = "数据读取失败,数据类型:【{0}】,地址:【{1}】,错误信息:【{2}】";
        /// <summary>
        /// æ•°æ®å†™å…¥å¤±è´¥,参数【数据类型,协议地址,写入的数据,错误信息】
        /// </summary>
        public const string WriteFailedException = "数据写入失败,数据类型:【{0}】,地址:【{1}】,写入的数据:【{2}】,错误信息:【{3}】";
        /// <summary>
        /// æ•°æ®ç±»åž‹é”™è¯¯,参数【数据类型,协议地址】
        /// </summary>
        public const string DataTypeErrorException = "数据类型错误,未定义该PLC数据类型:【{0}】,地址:【{1}】";
        /// <summary>
        /// æ•°æ®è¯»å–异常,参数【数据类型,协议地址,错误信息】
        /// </summary>
        public const string ReadException = "数据读取失败,数据类型:【{0}】,地址:【{1}】,错误信息:【{2}】";
        /// <summary>
        /// æ•°æ®è¯»å–失败,参数【数据类型,协议地址,错误信息】
        /// </summary>
        public const string WriteAndReadCheckFaild = "数据写入后读取校验失败,地址:【{0}】,写入的数据:【{1}】,读取的数据:【{2}】";
        /// <summary>
        /// æ•°æ®è¯»å–错误,结果为null,参数【协议地址】
        /// </summary>
        public const string ReadDataIsNull = "数据读取错误,未取到数据结果,地址:【{0}】";
        /// <summary>
        /// è¿žæŽ¥å¤±è´¥,参数【IP,Port,错误信息】
        /// </summary>
        public const string ConnectFaild = "PLC连接失败,IP:【{0}】,Port:【{1}】,错误信息:【{2}】";
        /// <summary>
        /// è¿žæŽ¥å¼‚常,参数【IP,Port,错误信息】
        /// </summary>
        public const string ConnectException = "PLC连接异常,IP:【{0}】,Port:【{1}】,错误信息:【{2}】";
        /// <summary>
        /// æ•°æ®ç±»åž‹è½¬åŒ–错误,参数【数据类型,协议地址,写入的数据,错误信息】
        /// </summary>
        public const string TypeConvertError = "数据类型转换错误,数据类型:【{0}】,地址:【{1}】,写入的数据:【{2}】,错误信息:【{3}】";
    }
    public class CommunicationInfoMessage
    {
        /// <summary>
        /// æ•°æ®å†™å…¥,参数【协议地址,写入的数据】
        /// </summary>
        public const string WriteData = "数据写入,地址:【{0}】,写入的数据:【{1}】";
        /// <summary>
        /// æ•°æ®å†™å…¥åŽè¯»å–,参数【协议地址,读取的数据】
        /// </summary>
        public const string WriteAfterRead = "数据写入后读取,地址:【{0}】,读取的数据:【{1}】";
        /// <summary>
        /// æ•°æ®å†™å…¥åŽè¯»å–校验成功,参数【协议地址,写入的数据,读取的数据】
        /// </summary>
        public const string WriteAndReadCheckSuccess = "数据写入后读取校验成功,地址:【{0}】,写入的数据:【{1}】,读取的数据:【{2}】";
        /// <summary>
        /// è¿žæŽ¥æˆåŠŸ,参数【IP,Port】
        /// </summary>
        public const string ConnectSuccess = "PLC连接成功,IP:【{0}】,Port:【{1}】";
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensDBDataType.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Communicator
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè¥¿é—¨å­PLC的数据类型
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Communicator
{
    /// <summary>
    /// è¥¿é—¨å­PLC的数据类型
    /// </summary>
    public class SiemensDBDataType
    {
        #region <Const>
        /// <summary>
        /// 32位有符号整型
        /// </summary>
        public const string DataType_DInt = "dint";
        /// <summary>
        /// å¸ƒå°”
        /// </summary>
        public const string DataType_Bool = "bool";
        /// <summary>
        /// å­—符串
        /// </summary>
        public const string DataType_String = "string";
        /// <summary>
        /// 16位有符号整型
        /// </summary>
        public const string DataType_Int = "int";
        /// <summary>
        /// å­—节
        /// </summary>
        public const string DataType_Byte = "byte";
        /// <summary>
        /// 32位无符号整型
        /// </summary>
        public const string DataType_DW = "dw";
        /// <summary>
        /// 16位无符号整型
        /// </summary>
        public const string DataType_W = "w";
        /// <summary>
        /// æµ®ç‚¹åž‹
        /// </summary>
        public const string DataType_Float = "float";
        /// <summary>
        /// å­—符
        /// </summary>
        public const string DataType_Char = "char";
        #endregion <Const>
        /// <summary>
        /// æ ¹æ®è¥¿é—¨å­PLC的数据类型获取对应C#的类型编号枚举
        /// </summary>
        /// <param name="dataType">西门子PLC的数据类型</param>
        /// <returns>返回对应C#的类型编号枚举</returns>
        /// <exception cref="CommunicationException"></exception>
        public static TypeCode GetTypeCode(string dataType)
        {
            return dataType.ToLower() switch
            {
                DataType_DInt => TypeCode.Int32,
                DataType_DW => TypeCode.UInt32,
                DataType_Int => TypeCode.Int16,
                DataType_W => TypeCode.UInt16,
                DataType_Float => TypeCode.Single,
                DataType_Bool => TypeCode.Boolean,
                DataType_Byte => TypeCode.Byte,
                DataType_String => TypeCode.String,
                DataType_Char => TypeCode.Char,
                _ => throw new CommunicationException($"数据类型错误:【{dataType}】", CommunicationErrorType.TypeError),
            };
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/Siemens/SiemensS7Communicator.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,711 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_Communicator
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè¥¿é—¨å­S7通讯类的封装,继承BaseCommunicator抽象类
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using HslCommunication.Core;
using HslCommunication.LogNet;
using HslCommunication.Profinet.Siemens;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace WIDESEAWCS_Communicator
{
    /// <summary>
    /// è¥¿é—¨å­S7通讯类
    /// </summary>
    [Description("西门子S7")]
    public class SiemensS7 : BaseCommunicator
    {
        #region Private Member
        /// <summary>
        /// HSLCommunication的西门子的S7协议的通讯类
        /// </summary>
        private SiemensS7Net plc;
        /// <summary>
        /// è®¾å¤‡çš„IP地址。
        /// </summary>
        private string _ipAddress;
        /// <summary>
        /// è¿žæŽ¥ä½¿ç”¨çš„端口号。
        /// </summary>
        private int _port;
        /// <summary>
        /// å½“前通讯器是否已连接到PLC。
        /// </summary>
        private bool _connected;
        /// <summary>
        /// PLC名称
        /// </summary>
        private string _name;
        private ILogNet _logNet;
        private bool _isPing = true;
        #endregion Private Member
        #region Public Member
        /// <summary>
        /// èŽ·å–å½“å‰é€šè®¯å™¨æ˜¯å¦å·²è¿žæŽ¥åˆ°PLC。
        /// </summary>
        public override bool IsConnected => _connected;
        /// <summary>
        /// PLC名称
        /// </summary>
        public override string Name => _name;
        public override ILogNet LogNet => _logNet;
        #endregion Public Member
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
        /// <param name="ipAddress">设备的IP地址</param>
        /// <param name="port">连接使用的端口号</param>
        /// <param name="name">设备名称</param>
        public SiemensS7(string ipAddress, int port, string name)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory + $"Log_PLCReadWrite\\{name}";
            _logNet = new LogNetFileSize(path, 10 * 1024 * 1024, 100);
            bool ipCheck = IPAddress.TryParse(ipAddress, out IPAddress? address);
            if (!ipCheck)
            {
                _logNet.WriteError(name, string.Format(CommunicationExceptionMessage.IpAddressErrorException, ipAddress));
                throw new CommunicationException(string.Format(CommunicationExceptionMessage.IpAddressErrorException, ipAddress), CommunicationErrorType.IpAddressError);
            }
            _ipAddress = ipAddress;//通过构造函数赋值设备的IP地址
            _port = port;//通过构造函数赋值连接使用的端口号
            _name = name;
        }
        #endregion
        #region Private Method
        /// <summary>
        /// ä»ŽOperateResult对象中获取读取的数据。
        /// </summary>
        /// <typeparam name="T">读取的数据类型。</typeparam>
        /// <param name="operateResult">HSLCommunication读取的OperateResult<T>对象</param>
        /// <returns>如果读取成功,返回读取结果,读取失败,抛出自定义通讯异常</returns>
        /// <exception cref="CommunicationException">自定义通讯异常类</exception>
        private object GetContent<T>(OperateResult<T> operateResult, string address)
        {
            try
            {
                if (!operateResult.IsSuccess)
                {
                    throw new CommunicationException(string.Format(CommunicationExceptionMessage.ReadFailedException, typeof(T).Name, address, operateResult.Message), CommunicationErrorType.ReadFailed);
                }
                return operateResult.Content ?? throw new CommunicationException(string.Format(CommunicationExceptionMessage.ReadDataIsNull, address), CommunicationErrorType.ReadFailed);
            }
            catch (Exception ex)
            {
                LogNet.WriteException(Name, ex.Message, ex);
                throw new CommunicationException(ex.Message, CommunicationErrorType.ReadFailed, innerException: ex);
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="operateResult"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <exception cref="CommunicationException"></exception>
        private bool GetResult<T>(OperateResult operateResult, string address, T value) where T : notnull
        {
            StringBuilder stringBuilder = new StringBuilder();
            try
            {
                stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteData, address, value));
                if (!operateResult.IsSuccess)
                {
                    throw new CommunicationException(string.Format(CommunicationExceptionMessage.WriteFailedException, typeof(T).Name, address, value, operateResult.Message), CommunicationErrorType.WriteFailed);
                }
                else
                {
                    //return true;
                    object? obj = null;
                    for (int i = 0; i < 5; i++)
                    {
                        T readValue = Read<T>(address);
                        stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteAfterRead, readValue, value));
                        obj = readValue;
                        if (readValue.Equals(value))
                        {
                            stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteAndReadCheckSuccess, address, value, readValue));
                            return true;
                        }
                        else if (i < 4)
                        {
                            Write(address, value);
                        }
                    }
                    stringBuilder.AppendLine(string.Format(CommunicationExceptionMessage.WriteAndReadCheckFaild, address, value, obj));
                    throw new CommunicationException(stringBuilder.ToString(), CommunicationErrorType.WriteFailed);
                }
            }
            catch (Exception ex)
            {
                LogNet.WriteException(Name, ex.Message, ex);
                throw new CommunicationException(ex.Message, CommunicationErrorType.WriteFailed, innerException: ex);
            }
            finally
            {
                LogNet.WriteInfo(Name, stringBuilder.ToString());
            }
        }
        /// <summary>
        /// å†™å…¥æ•°æ®
        /// </summary>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <exception cref="CommunicationException"></exception>
        private OperateResult Write(string address, object value)
        {
            try
            {
                Type type = value.GetType();
                switch (Type.GetTypeCode(type))
                {
                    case TypeCode.Int32:
                        return plc.Write(address, Convert.ToInt32(value));
                    case TypeCode.UInt32:
                        return plc.Write(address, Convert.ToUInt32(value));
                    case TypeCode.Int16:
                        return plc.Write(address, Convert.ToInt16(value));
                    case TypeCode.UInt16:
                        return plc.Write(address, Convert.ToUInt16(value));
                    case TypeCode.Single:
                        return plc.Write(address, Convert.ToSingle(value));
                    case TypeCode.Boolean:
                        return plc.Write(address, Convert.ToBoolean(value));
                    case TypeCode.Byte:
                        return plc.Write(address, Convert.ToByte(value));
                    case TypeCode.String:
                        return plc.Write(address, Convert.ToString(value));
                    case TypeCode.Char:
                        return plc.Write(address, Convert.ToChar(value));
                    default:
                        throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, type.Name, address), CommunicationErrorType.TypeError);
                }
            }
            catch (CommunicationException ex)
            {
                throw new CommunicationException(ex.Message, ex.ErrorType);
            }
            catch (Exception ex)
            {
                //读取异常时抛出自定义通讯异常类
                throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, address, value), CommunicationErrorType.TypeError, innerException: ex);
            }
        }
        private object Read(string address, TypeCode typeCode)
        {
            try
            {
                switch (typeCode)
                {
                    case TypeCode.Int32:
                        return (int)GetContent(plc.ReadInt32(address), address);
                    case TypeCode.UInt32:
                        return (uint)GetContent(plc.ReadUInt32(address), address);
                    case TypeCode.Int16:
                        return (short)GetContent(plc.ReadInt16(address), address);
                    case TypeCode.UInt16:
                        return (ushort)GetContent(plc.ReadUInt16(address), address);
                    case TypeCode.Single:
                        return (float)GetContent(plc.ReadFloat(address), address);
                    case TypeCode.Boolean:
                        return (bool)GetContent(plc.ReadBool(address), address);
                    case TypeCode.Byte:
                        return (byte)GetContent(plc.ReadByte(address), address);
                    case TypeCode.String:
                        return (string)GetContent(plc.ReadString(address), address);
                    case TypeCode.Char:
                        return (char)GetContent(plc.ReadByte(address), address);
                    default:
                        throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, typeCode.ToString(), address), CommunicationErrorType.TypeError);
                }
            }
            catch (CommunicationException ex)
            {
                //读取异常时抛出自定义通讯异常类
                throw new CommunicationException(ex.Message, ex.ErrorType);
            }
            catch (Exception ex)
            {
                //读取异常时抛出自定义通讯异常类
                throw new CommunicationException($"读取数据异常,错误信息:{ex.Message}", CommunicationErrorType.ReadException, innerException: ex);
            }
        }
        private void Ping()
        {
            Task.Run(() =>
            {
                while (_isPing)
                {
                    try
                    {
                        IPStatus status = plc.IpAddressPing();
                        if (status == IPStatus.Success)
                            _connected = true;
                        else
                            _connected = false;
                    }
                    finally
                    {
                        Thread.Sleep(100);
                    }
                }
            });
        }
        #endregion
        #region Public Method
        /// <summary>
        /// è¿žæŽ¥åˆ°PLC。
        /// </summary>
        /// <returns>如果连接成功则返回true,否则返回false。</returns>
        /// <exception cref="CommunicationException">自定义通讯异常类</exception>
        public override bool Connect()
        {
            try
            {
                //实例化一个西门子的S7协议的通讯对象
                plc = new SiemensS7Net(SiemensPLCS.S1500)
                {
                    IpAddress = _ipAddress,
                    Port = _port
                };
                OperateResult operateResult = plc.ConnectServer();//连接PLC
                _connected = operateResult.IsSuccess;//将连接是否成功赋值给当前通讯器是否已连接到PLC
                if (_connected)
                    LogNet.WriteInfo(Name, string.Format(CommunicationInfoMessage.ConnectSuccess, _ipAddress, _port));
                else
                    LogNet.WriteError(Name, string.Format(CommunicationExceptionMessage.ConnectFaild, _ipAddress, _port, operateResult.Message));
                Ping();
                return operateResult.IsSuccess;
            }
            catch (Exception ex)
            {
                LogNet.WriteException(Name, string.Format(CommunicationExceptionMessage.ConnectFaild, _ipAddress, _port, ex.Message), ex);
                //连接异常时抛出自定义异常类
                throw new CommunicationException(ex.Message, CommunicationErrorType.ConnectionFailed, innerException: ex);
            }
        }
        /// <summary>
        /// æ–­å¼€ä¸Žå·¥ä¸šè®¾å¤‡çš„连接。
        /// </summary>
        /// <returns>如果成功断开连接则返回true,如果已经是断开状态则返回false。</returns>
        public override bool Disconnect()
        {
            try
            {
                if (plc != null)
                {
                    OperateResult operateResult = plc.ConnectClose();//断开与PLC的连接
                    return operateResult.IsSuccess;
                }
                return false;
            }
            catch (Exception ex)
            {
                return false;
            }
            finally
            {
                _connected = false;
            }
        }
        #region Read
        /// <summary>
        /// ä»ŽPLC读取数据。
        /// </summary>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="length">要读取的数据长度。</param>
        /// <returns>读取到的数据,如果读取失败则可能返回null、空数组或抛出自定义通讯异常。</returns>
        /// <exception cref="CommunicationException">自定义通讯异常类</exception>
        public override byte[] Read(string address, int length)
        {
            return (byte[])GetContent(plc.Read(address, (ushort)length), address);
        }
        /// <summary>
        /// ä»ŽPLC读取数据。
        /// </summary>
        /// <typeparam name="T">读取的数据类型。</typeparam>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="length">要读取的数据长度(可选,默认值为1)。</param>
        /// <returns>如果读取成功,返回读取的结果,失败则抛出自定义通讯异常</returns>
        /// <exception cref="CommunicationException">自定义通讯异常类</exception>
        public override T Read<T>(string address)
        {
            Type type = typeof(T);
            return (T)Read(address, Type.GetTypeCode(type));
        }
        /// <summary>
        /// ä»ŽPLC读取数据返回object。
        /// </summary>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="dataType">读取的数据类型。</param>
        /// <returns>如果读取成功,返回读取的结果,失败则抛出自定义通讯异常</returns>
        /// <exception cref="CommunicationException">自定义通讯异常类</exception>
        public override object ReadAsObj(string address, string dataType)
        {
            return Read(address, SiemensDBDataType.GetTypeCode(dataType));
        }
        #endregion
        #region Write
        /// <summary>
        /// å‘PLC写入数据。
        /// </summary>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="data">要写入的数据。</param>
        /// <returns>如果写入成功则返回true,如果写入失败则可能返回false或抛出自定义通讯异常。</returns>
        /// <exception cref="CommunicationException">自定义通讯异常类</exception>
        public override bool Write(string address, byte[] data)
        {
            try
            {
                OperateResult result = plc.Write(address, data);
                if (result.IsSuccess)
                {
                    return result.IsSuccess;
                }
                else
                {
                    //todo å†™å…¥å¤±è´¥
                    return false;
                }
            }
            catch (Exception ex)
            {
                //写入异常时抛出自定义通讯异常类
                throw new CommunicationException($"写入数据异常,地址:【{address}】,错误信息: {ex.Message}", CommunicationErrorType.ReadFailed, innerException: ex);
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public override bool Write<T>(string address, T value)
        {
            return GetResult(Write(address, value), address, value);
        }
        /// <summary>
        /// å‘PLC写入数据。
        /// </summary>
        /// <param name="address">源地址,具体格式取决于使用的工业协议。</param>
        /// <param name="dataType">要写入的数据类型(PLC的数据类型)。</param>
        /// <param name="value">要写入的数据。</param>
        /// <returns>如果写入成功则返回true,失败则抛出自定义通讯异常。</returns>
        /// <exception cref="CommunicationException"></exception>
        public override bool WriteObj(string address, string dataType, [NotNull] object value)
        {
            bool obj = false;
            switch (dataType.ToLower())
            {
                case SiemensDBDataType.DataType_DInt:
                    {
                        int writeVal;
                        try
                        {
                            writeVal = Convert.ToInt32(value);
                        }
                        catch (Exception ex)
                        {
                            throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex);
                        }
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_DW:
                    {
                        uint writeVal;
                        try
                        {
                            writeVal = Convert.ToUInt32(value);
                        }
                        catch (Exception ex)
                        {
                            throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex);
                        }
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Int:
                    {
                        short writeVal;
                        try
                        {
                            writeVal = Convert.ToInt16(value);
                        }
                        catch (Exception ex)
                        {
                            throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex);
                        }
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_W:
                    {
                        ushort writeVal;
                        try
                        {
                            writeVal = Convert.ToUInt16(value);
                        }
                        catch (Exception ex)
                        {
                            throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex);
                        }
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Float:
                    {
                        float writeVal;
                        try
                        {
                            writeVal = Convert.ToSingle(value);
                        }
                        catch (Exception ex)
                        {
                            throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex);
                        }
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Bool:
                    {
                        bool writeVal;
                        try
                        {
                            writeVal = Convert.ToBoolean(value);
                        }
                        catch (Exception ex)
                        {
                            throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex);
                        }
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Byte:
                    {
                        byte writeVal;
                        try
                        {
                            writeVal = Convert.ToByte(value);
                        }
                        catch (Exception ex)
                        {
                            throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex);
                        }
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_String:
                    {
                        string writeVal;
                        try
                        {
                            writeVal = value.ToString();
                        }
                        catch (Exception ex)
                        {
                            throw new CommunicationException(string.Format(CommunicationExceptionMessage.TypeConvertError, dataType, address, value, ex.Message), CommunicationErrorType.TypeError, innerException: ex);
                        }
                        obj = GetResult(Write(address, writeVal), address, writeVal);
                    }
                    break;
                case SiemensDBDataType.DataType_Char:
                    break;
                default:
                    throw new CommunicationException(string.Format(CommunicationExceptionMessage.DataTypeErrorException, dataType, address), CommunicationErrorType.TypeError);
            }
            return obj;
        }
        #endregion
        #region ReadCustomer
        public override T ReadCustomer<T>(string address)
        {
            try
            {
                return plc.ReadCustomer<T>(address).Content;
            }
            catch (Exception ex)
            {
                LogNet.WriteException(Name, $"【{Name}】PLC读取异常,地址:【{address}】,错误信息:【{ex.Message}】", ex);
                throw new CommunicationException(ex.Message, CommunicationErrorType.ReadException, innerException: ex);
            }
        }
        #endregion
        #region WriteCustomer
        public override bool WriteCustomer<T>(string address, [NotNull] T value)
        {
            StringBuilder stringBuilder = new StringBuilder();
            try
            {
                OperateResult operateResult = plc.WriteCustomer(address, value);
                stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteData, address, JsonConvert.SerializeObject(value)));
                if (operateResult.IsSuccess)
                {
                    object? obj = null;
                    for (int i = 0; i < 5; i++)
                    {
                        T readValue = ReadCustomer<T>(address);
                        stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteAfterRead, address, JsonConvert.SerializeObject(readValue)));
                        obj = readValue;
                        PropertyInfo[] propertyInfos = typeof(T).GetProperties();
                        for (int j = 0; j < propertyInfos.Length; j++)
                        {
                            object? writeValueItem = propertyInfos[j].GetValue(value);
                            object? readValueItem = propertyInfos[j].GetValue(readValue);
                            if (writeValueItem.Equals(readValueItem))
                            {
                                stringBuilder.AppendLine(string.Format(CommunicationInfoMessage.WriteAndReadCheckSuccess, address, JsonConvert.SerializeObject(value), JsonConvert.SerializeObject(readValue)));
                            }
                            else
                            {
                                break;
                            }
                            if (j == propertyInfos.Length - 1)
                                return true;
                        }
                        plc.WriteCustomer(address, value);
                    }
                    stringBuilder.AppendLine(string.Format(CommunicationExceptionMessage.WriteAndReadCheckFaild, address, JsonConvert.SerializeObject(value), JsonConvert.SerializeObject(obj)));
                    throw new CommunicationException(string.Format(CommunicationExceptionMessage.WriteAndReadCheckFaild, address, JsonConvert.SerializeObject(value), JsonConvert.SerializeObject(obj)), CommunicationErrorType.WriteFailed);
                }
                else
                {
                    throw new CommunicationException(string.Format(CommunicationExceptionMessage.WriteFailedException, typeof(T).Name, address, JsonConvert.SerializeObject(value), operateResult.Message), CommunicationErrorType.WriteFailed);
                }
            }
            catch (Exception ex)
            {
                LogNet.WriteException(Name, ex.Message, ex);
                throw new CommunicationException(ex.Message, CommunicationErrorType.WriteFailed, innerException: ex);
            }
            finally
            {
                LogNet.WriteInfo(Name, stringBuilder.ToString());
            }
        }
        #endregion
        // æ˜¾å¼å®žçްIDisposable接口以提供垃圾回收时的清理
        public override void Dispose()
        {
            _isPing = false;
            Disconnect();
            plc.Dispose();
            GC.SuppressFinalize(this);
        }
        public override OperateResult<TimeSpan> Wait<T>(string address, int readInterval, int waitTimeout, T value)
        {
            TypeCode typeCode = Type.GetTypeCode(typeof(T));
            switch (typeCode)
            {
                case TypeCode.Byte:
                    DateTime start = DateTime.Now;
                    while (true)
                    {
                        OperateResult<byte> read = plc.ReadByte(address);
                        if (!read.IsSuccess) return OperateResult.CreateFailedResult<TimeSpan>(read);
                        if (read.Content == Convert.ToByte(value)) return OperateResult.CreateSuccessResult(DateTime.Now - start);
                        if (waitTimeout > 0 && (DateTime.Now - start).TotalMilliseconds > waitTimeout)
                        {
                            return new OperateResult<TimeSpan>(StringResources.Language.CheckDataTimeout + waitTimeout);
                        }
                        HslHelper.ThreadSleep(readInterval);
                    }
                case TypeCode.Int16:
                    OperateResult<TimeSpan> operateResultShort = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout);
                    return operateResultShort;
                case TypeCode.Int32:
                    OperateResult<TimeSpan> operateResultInt = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout);
                    return operateResultInt;
                case TypeCode.UInt16:
                    OperateResult<TimeSpan> operateResultUShort = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout);
                    return operateResultUShort;
                case TypeCode.UInt32:
                    OperateResult<TimeSpan> operateResultUInt = plc.Wait(address, Convert.ToInt16(value), readInterval, waitTimeout);
                    return operateResultUInt;
                default:
                    throw new NotSupportedException();
            }
        }
        #endregion
        #region Destruction Function
        /// <summary>
        /// æžæž„函数,确保在不再需要时关闭连接
        /// </summary>
        ~SiemensS7()
        {
            Dispose();
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Communicator/WIDESEAWCS_Communicator.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <Version>1.0.0</Version>
        <Description>工业设备通讯</Description>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="HslCommunication" Version="11.6.4" />
    </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/AOP/LogAOP.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,287 @@
using Castle.DynamicProxy;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;
using StackExchange.Profiling;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.LogHelper;
namespace WIDESEAWCS_Core.AOP
{
    /// <summary>
    /// æ‹¦æˆªå™¨BlogLogAOP ç»§æ‰¿IInterceptor接口
    /// </summary>
    public class LogAOP : IInterceptor
    {
        private readonly IHttpContextAccessor _accessor;
        public LogAOP(IHttpContextAccessor accessor)
        {
            _accessor = accessor;
        }
        /// <summary>
        /// å®žä¾‹åŒ–IInterceptor唯一方法
        /// </summary>
        /// <param name="invocation">包含被拦截方法的信息</param>
        public void Intercept(IInvocation invocation)
        {
            string UserName = _accessor.HttpContext?.User?.Identity?.Name;
            string json;
            try
            {
                if (invocation.Arguments.Any())
                {
                    json = JsonConvert.SerializeObject(invocation.Arguments);
                }
                else
                {
                    json = "无参数";
                }
            }
            catch (Exception ex)
            {
                json = "无法序列化,可能是兰姆达表达式等原因造成,按照框架优化代码" + ex.ToString();
            }
            DateTime startTime = DateTime.Now;
            AOPLogInfo apiLogAopInfo = new AOPLogInfo
            {
                RequestTime = startTime.ToString("yyyy-MM-dd hh:mm:ss fff"),
                OpUserName = "【当前操作用户】:" + UserName,
                RequestMethodName = "【当前执行方法】:" + invocation.Method.Name,
                RequestParamsName = "【携带的参数有】:" + string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()),
                RequestParamsData = json
            };
            var dataIntercept = $"";
            try
            {
                MiniProfiler.Current.Step($"执行{invocation.InvocationTarget}.{invocation.Method.Name}()方法 -> ");
                //在被拦截的方法执行完毕后 ç»§ç»­æ‰§è¡Œå½“前方法,注意是被拦截的是异步的
                invocation.Proceed();
                // å¼‚步获取异常,先执行
                if (IsAsyncMethod(invocation.Method))
                {
                    if (invocation.Method.ReturnType == typeof(Task))
                    {
                        invocation.ReturnValue = InternalAsyncHelper.AwaitTaskWithPostActionAndFinally(
                            (Task)invocation.ReturnValue,
                            async () => await SuccessAction(invocation, apiLogAopInfo, startTime), /*成功时执行*/
                            ex =>
                            {
                                LogEx(ex, apiLogAopInfo);
                            });
                    }
                    else
                    {
                        invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPostActionAndFinallyAndGetResult(
                            invocation.Method.ReturnType.GenericTypeArguments[0],
                            invocation.ReturnValue,
                            async (o) => await SuccessAction(invocation, apiLogAopInfo, startTime, o), /*成功时执行*/
                            ex =>
                            {
                                LogEx(ex, apiLogAopInfo);
                            });
                    }
                }
                else
                {
                    // åŒæ­¥1
                    string jsonResult;
                    try
                    {
                        jsonResult = JsonConvert.SerializeObject(invocation.ReturnValue);
                    }
                    catch (Exception ex)
                    {
                        jsonResult = "无法序列化,可能是兰姆达表达式等原因造成,按照框架优化代码" + ex.ToString();
                    }
                    var type = invocation.Method.ReturnType;
                    var resultProperty = type.GetProperty("Result");
                    DateTime endTime = DateTime.Now;
                    string ResponseTime = (endTime - startTime).Milliseconds.ToString();
                    apiLogAopInfo.ResponseTime = endTime.ToString("yyyy-MM-dd hh:mm:ss fff");
                    apiLogAopInfo.ResponseIntervalTime = ResponseTime + "ms";
                    apiLogAopInfo.ResponseJsonData = jsonResult;
                    Parallel.For(0, 1, e =>
                    {
                        LogLock.OutLogAOP("AOPLog", new string[] { apiLogAopInfo.GetType().ToString(), JsonConvert.SerializeObject(apiLogAopInfo) });
                    });
                }
            }
            catch (Exception ex) // åŒæ­¥2
            {
                LogEx(ex, apiLogAopInfo);
                throw;
            }
        }
        private async Task SuccessAction(IInvocation invocation, AOPLogInfo apiLogAopInfo, DateTime startTime, object o = null)
        {
            DateTime endTime = DateTime.Now;
            string ResponseTime = (endTime - startTime).Milliseconds.ToString();
            apiLogAopInfo.ResponseTime = endTime.ToString("yyyy-MM-dd hh:mm:ss fff");
            apiLogAopInfo.ResponseIntervalTime = ResponseTime + "ms";
            apiLogAopInfo.ResponseJsonData = JsonConvert.SerializeObject(o);
            await Task.Run(() =>
            {
                Parallel.For(0, 1, e =>
                {
                    LogLock.OutLogAOP("AOPLog", new string[] { apiLogAopInfo.GetType().ToString(), JsonConvert.SerializeObject(apiLogAopInfo) });
                });
            });
        }
        private void LogEx(Exception ex, AOPLogInfo dataIntercept)
        {
            if (ex != null)
            {
                //执行的 service ä¸­ï¼Œæ”¶å½•异常
                MiniProfiler.Current.CustomTiming("Errors:", ex.Message);
                //执行的 service ä¸­ï¼Œæ•获异常
                AOPLogExInfo apiLogAopExInfo = new AOPLogExInfo
                {
                    ExMessage = ex.Message,
                    InnerException = "InnerException-内部异常:\r\n" + (ex.InnerException == null ? "" : ex.InnerException.InnerException.ToString()) +
                                     "\r\nStackTrace-堆栈跟踪:\r\n" + (ex.StackTrace == null ? "" : ex.StackTrace.ToString()),
                    ApiLogAopInfo = dataIntercept
                };
                // å¼‚常日志里有详细的堆栈信息
                Parallel.For(0, 1, e =>
                {
                    LogLock.OutLogAOP("AOPLogEx", new string[] { apiLogAopExInfo.GetType().ToString(), JsonConvert.SerializeObject(apiLogAopExInfo) });
                });
            }
        }
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return method.ReturnType == typeof(Task) || method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>);
        }
    }
    internal static class InternalAsyncHelper
    {
        public static async Task AwaitTaskWithPostActionAndFinally(Task actualReturnValue, Func<Task> postAction, Action<Exception> finalAction)
        {
            Exception exception = null;
            try
            {
                await actualReturnValue;
                await postAction();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            finally
            {
                finalAction(exception);
            }
        }
        public static async Task<T> AwaitTaskWithPostActionAndFinallyAndGetResult<T>(Task<T> actualReturnValue, Func<object, Task> postAction,
            Action<Exception> finalAction)
        {
            Exception exception = null;
            try
            {
                var result = await actualReturnValue;
                await postAction(result);
                return result;
            }
            catch (Exception ex)
            {
                exception = ex;
                throw;
            }
            finally
            {
                finalAction(exception);
            }
        }
        public static object CallAwaitTaskWithPostActionAndFinallyAndGetResult(Type taskReturnType, object actualReturnValue,
            Func<object, Task> action, Action<Exception> finalAction)
        {
            return typeof(InternalAsyncHelper)
                .GetMethod(nameof(AwaitTaskWithPostActionAndFinallyAndGetResult), BindingFlags.Public | BindingFlags.Static)
                .MakeGenericMethod(taskReturnType)
                .Invoke(null, new object[] { actualReturnValue, action, finalAction });
        }
    }
    public class AOPLogInfo
    {
        /// <summary>
        /// è¯·æ±‚æ—¶é—´
        /// </summary>
        [Description("请求时间")]
        public string RequestTime { get; set; } = string.Empty;
        /// <summary>
        /// æ“ä½œäººå‘˜
        /// </summary>
        [Description("操作人员")]
        public string OpUserName { get; set; } = string.Empty;
        /// <summary>
        /// è¯·æ±‚方法名
        /// </summary>
        [Description("请求方法名")]
        public string RequestMethodName { get; set; } = string.Empty;
        /// <summary>
        /// è¯·æ±‚参数名
        /// </summary>
        [Description("请求参数名")]
        public string RequestParamsName { get; set; } = string.Empty;
        /// <summary>
        /// è¯·æ±‚参数数据JSON
        /// </summary>
        [Description("请求参数数据JSON")]
        public string RequestParamsData { get; set; } = string.Empty;
        /// <summary>
        /// è¯·æ±‚响应间隔时间
        /// </summary>
        [Description("请求响应间隔时间")]
        public string ResponseIntervalTime { get; set; } = string.Empty;
        /// <summary>
        /// å“åº”æ—¶é—´
        /// </summary>
        [Description("响应时间")]
        public string ResponseTime { get; set; } = string.Empty;
        /// <summary>
        /// å“åº”结果
        /// </summary>
        [Description("响应结果")]
        public string ResponseJsonData { get; set; } = string.Empty;
    }
    public class AOPLogExInfo
    {
        public AOPLogInfo ApiLogAopInfo { get; set; }
        /// <summary>
        /// å¼‚常
        /// </summary>
        [Description("异常")]
        public string InnerException { get; set; } = string.Empty;
        /// <summary>
        /// å¼‚常信息
        /// </summary>
        [Description("异常信息")]
        public string ExMessage { get; set; } = string.Empty;
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/AOP/SqlSugarAop.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,100 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.DB.Models;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.HttpContextUser;
using WIDESEAWCS_Core.Tenants;
namespace WIDESEAWCS_Core.AOP
{
    public static class SqlSugarAop
    {
        public static void DataExecuting(object oldValue, DataFilterModel entityInfo)
        {
            if (entityInfo.EntityValue is BaseEntity baseEntity)
            {
                // æ–°å¢žæ“ä½œ
                if (entityInfo.OperationType == DataFilterType.InsertByObject)
                {
                    if (entityInfo.PropertyName == nameof(BaseEntity.CreateDate))
                    {
                        baseEntity.CreateDate = DateTime.Now;
                    }
                }
                else if (entityInfo.OperationType == DataFilterType.UpdateByObject)
                {
                    baseEntity.ModifyDate = DateTime.Now;
                }
                try
                {
                    if (App.User?.UserId > 0)
                    {
                        switch (entityInfo.OperationType)
                        {
                            case DataFilterType.UpdateByObject:
                                baseEntity.Modifier = App.User.UserName;
                                break;
                            case DataFilterType.InsertByObject:
                                baseEntity.Creater = App.User.UserName;
                                break;
                        }
                    }
                    else
                    {
                        switch (entityInfo.OperationType)
                        {
                            case DataFilterType.UpdateByObject:
                                baseEntity.Modifier = "System";
                                break;
                            case DataFilterType.InsertByObject:
                                baseEntity.Creater = "System";
                                break;
                        }
                    }
                }
                catch (NullReferenceException)
                {
                    switch (entityInfo.OperationType)
                    {
                        case DataFilterType.UpdateByObject:
                            baseEntity.Modifier = "System";
                            break;
                        case DataFilterType.InsertByObject:
                            baseEntity.Creater = "System";
                            break;
                    }
                }
            }
        }
        private static string GetWholeSql(SugarParameter[] paramArr, string sql)
        {
            foreach (var param in paramArr)
            {
                sql = sql.Replace(param.ParameterName, $@"'{param.Value.ObjToString()}'");
            }
            return sql;
        }
        private static string GetParas(SugarParameter[] pars)
        {
            string key = "【SQL参数】:";
            foreach (var param in pars)
            {
                key += $"{param.ParameterName}:{param.Value}\n";
            }
            return key;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/App.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,202 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.HttpContextUser;
namespace WIDESEAWCS_Core
{
    public class App
    {
        static App()
        {
            EffectiveTypes = Assemblies.SelectMany(GetTypes);
        }
        private static bool _isRun;
        /// <summary>是否正在运行</summary>
        public static bool IsBuild { get; set; }
        public static bool IsRun
        {
            get => _isRun;
            set => _isRun = IsBuild = value;
        }
        /// <summary>应用有效程序集</summary>
        public static readonly IEnumerable<Assembly> Assemblies = RuntimeExtension.GetAllAssemblies();
        /// <summary>有效程序集类型</summary>
        public static readonly IEnumerable<Type> EffectiveTypes;
        /// <summary>优先使用App.GetService()手动获取服务</summary>
        public static IServiceProvider RootServices => IsRun || IsBuild ? InternalApp.RootServices : null;
        /// <summary>获取Web主机环境,如,是否是开发环境,生产环境等</summary>
        public static IWebHostEnvironment WebHostEnvironment => InternalApp.WebHostEnvironment;
        /// <summary>获取泛型主机环境,如,是否是开发环境,生产环境等</summary>
        public static IHostEnvironment HostEnvironment => InternalApp.HostEnvironment;
        /// <summary>全局配置选项</summary>
        public static IConfiguration Configuration => InternalApp.Configuration;
        /// <summary>
        /// èŽ·å–è¯·æ±‚ä¸Šä¸‹æ–‡
        /// </summary>
        public static HttpContext HttpContext => RootServices?.GetService<IHttpContextAccessor>()?.HttpContext;
        public static IUser User => GetService<IUser>();
        #region Service
        /// <summary>解析服务提供器</summary>
        /// <param name="serviceType"></param>
        /// <param name="mustBuild"></param>
        /// <param name="throwException"></param>
        /// <returns></returns>
        public static IServiceProvider GetServiceProvider(Type serviceType, bool mustBuild = false, bool throwException = true)
        {
            if (App.HostEnvironment == null || App.RootServices != null &&
                InternalApp.InternalServices
                    .Where((u =>
                        u.ServiceType ==
                        (serviceType.IsGenericType ? serviceType.GetGenericTypeDefinition() : serviceType)))
                    .Any((u => u.Lifetime == ServiceLifetime.Singleton)))
                return App.RootServices;
            //获取请求生存周期的服务
            if (HttpContext?.RequestServices != null)
                return HttpContext.RequestServices;
            if (RootServices != null)
            {
                IServiceScope scope = RootServices.CreateScope();
                return scope.ServiceProvider;
            }
            if (mustBuild)
            {
                if (throwException)
                {
                    throw new ApplicationException("当前不可用,必须要等到 WebApplication Build后");
                }
                return default;
            }
            ServiceProvider serviceProvider = InternalApp.InternalServices.BuildServiceProvider();
            return serviceProvider;
        }
        public static TService GetService<TService>(bool mustBuild = true) where TService : class
        {
            TService test = GetService(typeof(TService), null, mustBuild) as TService;
            return test;
        }
        /// <summary>获取请求生存周期的服务</summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="serviceProvider"></param>
        /// <param name="mustBuild"></param>
        /// <returns></returns>
        public static TService GetService<TService>(IServiceProvider serviceProvider, bool mustBuild = true)
            where TService : class => (serviceProvider ?? App.GetServiceProvider(typeof(TService), mustBuild, false))?.GetService<TService>();
        /// <summary>获取请求生存周期的服务</summary>
        /// <param name="type"></param>
        /// <param name="serviceProvider"></param>
        /// <param name="mustBuild"></param>
        /// <returns></returns>
        public static object GetService(Type type, IServiceProvider serviceProvider = null, bool mustBuild = true)
        {
            object obj = (serviceProvider ?? GetServiceProvider(type, mustBuild, false))?.GetService(type);
            return obj;
        }
        #endregion
        #region private
        /// <summary>加载程序集中的所有类型</summary>
        /// <param name="ass"></param>
        /// <returns></returns>
        private static IEnumerable<Type> GetTypes(Assembly ass)
        {
            Type[] source = Array.Empty<Type>();
            try
            {
                source = ass.GetTypes();
            }
            catch
            {
                //$@"Error load `{ass.FullName}` assembly.".WriteErrorLine();
            }
            return source.Where(u => u.IsPublic);
        }
        #endregion
        #region Options
        /// <summary>获取配置</summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <returns>TOptions</returns>
        public static TOptions GetConfig<TOptions>()
            where TOptions : class, IConfigurableOptions
        {
            TOptions instance = App.Configuration
                .GetSection(ConfigurableOptions.GetConfigurationPath(typeof(TOptions)))
                .Get<TOptions>();
            return instance;
        }
        /// <summary>获取选项</summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <param name="serviceProvider"></param>
        /// <returns>TOptions</returns>
        public static TOptions GetOptions<TOptions>(IServiceProvider serviceProvider = null) where TOptions : class, new()
        {
            IOptions<TOptions> service = App.GetService<IOptions<TOptions>>(serviceProvider ?? App.RootServices, false);
            return service?.Value;
        }
        /// <summary>获取选项</summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <param name="serviceProvider"></param>
        /// <returns>TOptions</returns>
        public static TOptions GetOptionsMonitor<TOptions>(IServiceProvider serviceProvider = null)
            where TOptions : class, new()
        {
            IOptionsMonitor<TOptions> service =
                App.GetService<IOptionsMonitor<TOptions>>(serviceProvider ?? App.RootServices, false);
            return service?.CurrentValue;
        }
        /// <summary>获取选项</summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <param name="serviceProvider"></param>
        /// <returns>TOptions</returns>
        public static TOptions GetOptionsSnapshot<TOptions>(IServiceProvider serviceProvider = null)
            where TOptions : class, new()
        {
            IOptionsSnapshot<TOptions> service = App.GetService<IOptionsSnapshot<TOptions>>(serviceProvider, false);
            return service?.Value;
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Attributes/ModelValidateAttribute.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Attributes
{
    [AttributeUsage(AttributeTargets.Property)]
    public class PropertyValidateAttribute : Attribute
    {
        public int MaxValue { get; set; } = int.MaxValue;
        public int MinValue { get; set; } = int.MinValue;
        public bool NotNullAndEmpty { get; set; } = true;
        public bool IsContainMaxValue { get; set; } = false;
        public bool IsContainMinValue { get; set; } = false;
        public string Description { get; set; }
        public PropertyValidateAttribute(string description)
        {
            if (!string.IsNullOrEmpty(description))
                Description = description;
        }
    }
    [AttributeUsage(AttributeTargets.Class)]
    public class ModelValidateAttribute : Attribute
    {
        public ModelValidateType ModelValidateType { get; } = ModelValidateType.SimpleValidate;
        public ModelValidateAttribute()
        {
        }
    }
    public enum ModelValidateType
    {
        SimpleValidate,
        CustomValidate,
        SimpleAndCustom
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Authorization/AuthorizationResponse.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Const;
namespace WIDESEAWCS_Core.Authorization
{
    public static class AuthorizationResponse
    {
        public static AuthorizationFilterContext FilterResult(
          this AuthorizationFilterContext context,
            HttpStatusCode statusCode,
            string? message = null)
        {
            context.Result = new ContentResult()
            {
                Content = new { message, status = false, code = (int)statusCode }.Serialize(),
                ContentType = "application/json",
                StatusCode = (int)statusCode
            };
            //Logger.Info(LoggerType.ApiAuthorize, message);
            return context;
        }
        public static AuthorizationFilterContext Unauthorized(this AuthorizationFilterContext context, string? message = null)
        {
            return context.FilterResult(HttpStatusCode.Unauthorized, message);
        }
        //不通过JWT验证的,直接将用户信息缓存起来
        public static void AddIdentity(this AuthorizationFilterContext context, int? userId = null)
        {
            int _userId = userId ?? JwtHelper.GetUserId(context.HttpContext.Request.Headers[AppSecret.TokenHeaderName]);
            if (_userId <= 0) return;
            //将用户Id缓存到上下文(或者自定一个对象,通过DI以AddScoped方式注入上下文来管理用户信息)
            var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Jti, _userId.ToString()) };
            context.HttpContext.User.AddIdentity(new ClaimsIdentity(claims));
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Authorization/AuthorizationSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.Authorization
{
    /// <summary>
    /// ç³»ç»Ÿ æŽˆæƒæœåŠ¡ é…ç½®
    /// </summary>
    public static class AuthorizationSetup
    {
        /// <summary>
        /// ç³»ç»Ÿ æŽˆæƒæœåŠ¡ é…ç½®
        /// </summary>
        /// <param name="services"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void AddAuthorizationSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            })
             .AddJwtBearer(options =>
             {
                 options.TokenValidationParameters = new TokenValidationParameters
                 {
                     SaveSigninToken = true,//保存token,后台验证token是否生效(重要)
                     ValidateIssuer = true,//是否验证Issuer
                     ValidateAudience = true,//是否验证Audience
                     ValidateLifetime = true,//是否验证失效时间
                     ValidateIssuerSigningKey = true,//是否验证SecurityKey
                     ValidAudience = AppSecret.Audience,//Audience
                     ValidIssuer = AppSecret.Issuer,//Issuer,这两项和前面签发jwt的设置一致
                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppSecret.JWT))
                 };
                 options.Events = new JwtBearerEvents()
                 {
                     OnChallenge = context =>
                     {
                         context.HandleResponse();
                         context.Response.Clear();
                         context.Response.ContentType = "application/json";
                         context.Response.StatusCode = 401;
                         context.Response.WriteAsync(new { message = "授权未通过", status = false, code = 401 }.Serialize());
                         return Task.CompletedTask;
                     }
                 };
             });
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Authorization/JwtHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,121 @@
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.HttpContextUser;
namespace WIDESEAWCS_Core.Authorization
{
    public class JwtHelper
    {
        /// <summary>
        /// ç”ŸæˆJWT
        /// </summary>
        /// <param name="serInfo"></param>
        /// <returns></returns>
        public static string IssueJwt(TokenModelJwt tokenModel)
        {
            string exp = $"{new DateTimeOffset(DateTime.Now.AddMinutes(/*tokenModel.UserId == 1 ? 43200 : */AppSettings.app("ExpMinutes").ObjToInt())).ToUnixTimeSeconds()}";
            List<Claim> claims = new List<Claim>
                {
                    new Claim(JwtRegisteredClaimNames.Jti, tokenModel.UserId.ToString()),
                    new Claim(JwtRegisteredClaimNames.Iat,  $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                    new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                    //JWT过期时间
                    //默认设置jwt过期时间120分钟
                    new Claim (JwtRegisteredClaimNames.Exp, exp),
                    new Claim(JwtRegisteredClaimNames.Iss, AppSecret.Issuer),
                    new Claim(JwtRegisteredClaimNames.Aud, AppSecret.Audience),
                    new Claim(ClaimTypes.Role, tokenModel.RoleId.ToString()),
                    new Claim(ClaimTypes.Name, tokenModel.UserName),
                    new Claim(nameof(TokenModelJwt.TenantId), tokenModel.TenantId.ToString())
               };
            // å¯ä»¥å°†ä¸€ä¸ªç”¨æˆ·çš„多个角色全部赋予;
            // ä½œè€…:DX æä¾›æŠ€æœ¯æ”¯æŒï¼›
            //秘钥16位
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppSecret.JWT));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            JwtSecurityToken securityToken = new JwtSecurityToken(issuer: AppSecret.Issuer, claims: claims, signingCredentials: creds);
            string jwt = new JwtSecurityTokenHandler().WriteToken(securityToken);
            return jwt;
        }
        /// <summary>
        /// è§£æž
        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static UserInfo SerializeJwt(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
            UserInfo userInfo = new UserInfo
            {
                UserId = Convert.ToInt32(jwtToken.Id),
                RoleId = (jwtToken.Payload[ClaimTypes.Role] ?? 0).ObjToInt(),
            };
            return userInfo;
        }
        /// <summary>
        /// èŽ·å–è¿‡æœŸæ—¶é—´
        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static DateTime GetExp(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
            DateTime expDate = (jwtToken.Payload[JwtRegisteredClaimNames.Exp] ?? 0).ObjToInt().GetTimeSpmpToDate();
            return expDate;
        }
        public static bool IsExp(string jwtStr)
        {
            return GetExp(jwtStr) < DateTime.Now;
        }
        public static int GetUserId(string jwtStr)
        {
            try
            {
                if (jwtStr.IsNullOrEmpty()) return 0;
                jwtStr = jwtStr.Replace("Bearer ", "");
                return new JwtSecurityTokenHandler().ReadJwtToken(jwtStr).Id.ObjToInt();
            }
            catch
            {
                return 0;
            }
        }
    }
    /// <summary>
    /// ä»¤ç‰Œ
    /// </summary>
    public class TokenModelJwt
    {
        /// <summary>
        /// UserId
        /// </summary>
        public long UserId { get; set; }
        /// <summary>
        /// è§’色
        /// </summary>
        public int RoleId { get; set; }
        /// <summary>
        /// èŒèƒ½
        /// </summary>
        public string UserName { get; set; }
        public long TenantId { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseController/ApiBaseController.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,118 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseServices;
namespace WIDESEAWCS_Core.BaseController
{
    [Authorize, ApiController]
    public class ApiBaseController<IService, TEntity> : Controller
    {
        protected IService Service;
        public ApiBaseController(IService service)
        {
            Service = service;
        }
        [HttpPost, Route("GetPageData")]
        public virtual ActionResult GetPageData([FromBody] PageDataOptions options)
        {
            return Json(InvokeService("GetPageData", new object[] { options }));
        }
        [HttpPost, Route("GetDetailPage")]
        public virtual ActionResult GetDetailPage([FromBody] PageDataOptions pageData)
        {
            return Json(InvokeService("GetDetailPage", new object[] { pageData }));
        }
        [HttpPost, Route("AddData")]
        public virtual ActionResult AddData([FromBody] TEntity options)
        {
            return Json(InvokeService("AddData", new object[] { options }));
        }
        [HttpPost, Route("Add")]
        public virtual ActionResult Add([FromBody] SaveModel options)
        {
            return Json(InvokeService("AddData", new object[] { options }));
        }
        [HttpPost, Route("Update")]
        public virtual ActionResult Update([FromBody] SaveModel options)
        {
            return Json(InvokeService("UpdateData", new object[] { options }));
        }
        [HttpPost, Route("UpdateData")]
        public virtual ActionResult UpdateData([FromBody] TEntity options)
        {
            return Json(InvokeService("UpdateData", new object[] { options }));
        }
        [HttpPost, Route("Del")]
        public virtual ActionResult Del([FromBody] object[] key)
        {
            return Json(InvokeService("DeleteData", new object[] { key }));
        }
        [HttpPost, Route("Export")]
        public virtual ActionResult Export([FromBody] PageDataOptions loadData)
        {
            WebResponseContent result = InvokeService("Export", new object[] { loadData }) as WebResponseContent;
            if (result.Status)
                return File(
                       System.IO.File.ReadAllBytes(result.Data.ToString()),
                       System.Net.Mime.MediaTypeNames.Application.Octet,
                       Path.GetFileName(result.Data.ToString())
                   );
            return Json(result);
        }
        [HttpPost,HttpGet, Route("DownLoadTemplate")]
        public virtual ActionResult DownLoadTemplate()
        {
            WebResponseContent result = InvokeService("DownLoadTemplate", new object[] { }) as WebResponseContent;
            if (result.Status)
                return File(
                       System.IO.File.ReadAllBytes(result.Data.ToString()),
                       System.Net.Mime.MediaTypeNames.Application.Octet,
                       Path.GetFileName(result.Data.ToString())
                   );
            return Json(result);
        }
        [HttpPost, Route("Import")]
        public virtual ActionResult Import(List<IFormFile> fileInput)
        {
            return Json(InvokeService("Import", new object[] { fileInput }));
        }
        [HttpPost, Route("ExportSeedData"), AllowAnonymous]
        public ActionResult ExportSeedData()
        {
            return Json(InvokeService("ExportSeedData", new object[] {  }));
        }
        private object InvokeService(string methodName, object[] parameters)
        {
            Type t = Service.GetType();
            List<Type> types = new List<Type>();
            foreach (var param in parameters)
            {
                types.Add(param.GetType());
            }
            MethodInfo method = t.GetMethod(methodName, types.ToArray());
            return method.Invoke(Service, parameters);
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/PageDataOptions.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core
{
    public class PageDataOptions
    {
        public int Page { get; set; }
        public int Rows { get; set; }
        public int Total { get; set; }
        public string TableName { get; set; }
        public string Sort { get; set; }
        /// <summary>
        /// æŽ’序方式
        /// </summary>
        public string Order { get; set; }
        public string Wheres { get; set; }
        public bool Export { get; set; }
        public object Value { get; set; }
        /// <summary>
        /// æŸ¥è¯¢æ¡ä»¶
        /// </summary>
        public List<SearchParameters> Filter { get; set; }
    }
    public class SearchParameters
    {
        public string Name { get; set; }
        public string Value { get; set; }
        //查询类型:LinqExpressionType
        public string DisplayType { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/PageGridData.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core
{
    public class PageGridData<T>
    {
        public int Total { get; set; }
        public List<T> Rows { get; set; }
        public object Summary { get; set; }
        public PageGridData()
        {
        }
        public PageGridData(int total, List<T> rows)
        {
            Total = total;
            Rows = rows;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/Permissions.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core
{
    public class Permissions
    {
        public int MenuId { get; set; }
        public int ParentId { get; set; }
        public string TableName { get; set; }
        public string MenuAuth { get; set; }
        public string UserAuth { get; set; }
        /// <summary>
        /// å½“前用户权限,存储的是权限的值,如:Add,Search等
        /// </summary>
        public string[] UserAuthArr { get; set; }
        /// <summary>
        /// 2022.03.26
        /// èœå•类型1:移动端,0:PC端
        /// </summary>
        public int MenuType { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/SaveModel.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core
{
    public class SaveModel
    {
        public Dictionary<string, object> MainData { get; set; }
        public List<Dictionary<string, object>> DetailData { get; set; }
        public List<object> DelKeys { get; set; }
        /// <summary>
        /// ä»Žå‰å°ä¼ å…¥çš„其他参数(自定义扩展可以使用)
        /// </summary>
        public object Extra { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseModels/WebResponseContent.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core
{
    public class WebResponseContent
    {
        public WebResponseContent()
        {
        }
        public WebResponseContent(bool status)
        {
            Status = status;
        }
        public bool Status { get; set; }
        public int Code { get; set; }
        public string Message { get; set; }
        public object Data { get; set; }
        public string DevMessage { get; set; }
        public WebResponseContent OK()
        {
            Status = true;
            return this;
        }
        public static WebResponseContent Instance
        {
            get { return new WebResponseContent(); }
        }
        public WebResponseContent OK(string message = null, object data = null)
        {
            Status = true;
            Message = message;
            Data = data;
            return this;
        }
        public WebResponseContent Error(string message = null)
        {
            Status = false;
            Message = message;
            return this;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/IRepository.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,418 @@
using Microsoft.Data.SqlClient;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.BaseRepository
{
    public interface IRepository<TEntity> : IDependency where TEntity : class, new()
    {
        /// <summary>
        /// SqlsugarClient实体
        /// </summary>
        ISqlSugarClient Db { get; }
        /// <summary>
        /// é€šè¿‡ä¸»é”®æŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>查询结果</returns>
        TEntity QureyDataById(object id);
        Task<TEntity> QureyDataByIdAsync(object id);
        /// <summary>
        /// é€šè¿‡ä¸»é”®æ•°ç»„查询数据
        /// </summary>
        /// <param name="lstIds">主键数组</param>
        /// <returns>查询结果集合</returns>
        List<TEntity> QureyDataByIds(object[] lstIds);
        Task<List<TEntity>> QureyDataByIdsAsync(object[] lstIds);
        /// <summary>
        /// é€šè¿‡ä¸»é”®é›†åˆæŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="lstIds">主键集合</param>
        /// <returns>查询结果集合</returns>
        List<TEntity> QureyDataByIds(List<object> lstIds);
        Task<List<TEntity>> QureyDataByIdsAsync(List<object> lstIds);
        /// <summary>
        /// æ·»åŠ å•æ¡æ•°æ®
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>影响行数</returns>
        int AddData(TEntity entity);
        Task<int> AddDataAsync(TEntity entity);
        /// <summary>
        /// æ·»åŠ å¤šæ¡æ•°æ®
        /// </summary>
        /// <param name="listEntity"></param>
        /// <returns>影响行数</returns>
        int AddData(List<TEntity> listEntity);
        Task<int> AddDataAsync(List<TEntity> listEntity);
        /// <summary>
        /// é€šè¿‡ä¸»é”®åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>删除结果</returns>
        bool DeleteDataById(object id);
        Task<bool> DeleteDataByIdAsync(object id);
        /// <summary>
        /// é€šè¿‡ä¸»é”®æ•°æ®åˆ é™¤å¤šæ¡æ•°æ®
        /// </summary>
        /// <param name="ids">主键数组</param>
        /// <returns>删除结果</returns>
        bool DeleteDataByIds(object[] ids);
        Task<bool> DeleteDataByIdsAsync(object[] ids);
        /// <summary>
        /// é€šè¿‡å®žä½“数据删除数据
        /// </summary>
        /// <param name="ids">主键数组</param>
        /// <returns>删除结果</returns>
        bool DeleteData(TEntity entity);
        Task<bool> DeleteDataAsync(TEntity entity);
        /// <summary>
        /// é€šè¿‡å®žä½“集合数据删除数据
        /// </summary>
        /// <param name="ids">主键数组</param>
        /// <returns>删除结果</returns>
        bool DeleteData(List<TEntity> listEntity);
        Task<bool> DeleteDataAsync(List<TEntity> listEntity);
        /// <summary>
        /// æ›´æ–°å•条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        bool UpdateData(TEntity entity);
        Task<bool> UpdateDataAsync(TEntity entity);
        /// <summary>
        /// æ›´æ–°å¤šæ¡æ•°æ®
        /// </summary>
        /// <param name="listEntity"></param>
        /// <returns></returns>
        bool UpdateData(List<TEntity> listEntity);
        Task<bool> UpdateDataAsync(List<TEntity> listEntity);
        /// <summary>
        /// æŒ‡å®šåˆ—更新数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="lstColumns"></param>
        /// <param name="lstIgnoreColumns"></param>
        /// <returns></returns>
        bool UpdateData(TEntity entity, List<string> lstColumns, List<string>? lstIgnoreColumns = null);
        Task<bool> UpdateDataAsync(TEntity entity, List<string> lstColumns, List<string>? lstIgnoreColumns = null);
        /// <summary>
        /// æŸ¥è¯¢æ‰€æœ‰æ•°æ®
        /// </summary>
        /// <returns></returns>
        List<TEntity> QueryData();
        Task<List<TEntity>> QueryDataAsync();
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        List<TEntity> QueryData(string where);
        Task<List<TEntity>> QueryDataAsync(string where);
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression);
        Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression);
        TEntity QueryFirst(Expression<Func<TEntity, bool>> whereExpression);
        Task<TEntity> QueryFirstAsync(Expression<Func<TEntity, bool>> whereExpression);
        TResult QueryFirst<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> expression);
        Task<TResult> QueryFirstAsync<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> expression);
        TResult QueryFirst<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> expression, Dictionary<string, OrderByType> orderBy);
        Task<TResult> QueryFirstAsync<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> expression, Dictionary<string, OrderByType> orderBy);
        TEntity QueryFirst(Expression<Func<TEntity, bool>> whereExpression, Dictionary<string, OrderByType> orderBy);
        Task<TEntity> QueryFirstAsync(Expression<Func<TEntity, bool>> whereExpression, Dictionary<string, OrderByType> orderBy);
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®å¹¶æŽ’序
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression, Dictionary<string, OrderByType> orderBy);
        Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression, string orderByFields);
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®å¹¶æŽ’序
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        List<TEntity> QueryData(string where, Dictionary<string, OrderByType> orderBy);
        Task<List<TEntity>> QueryDataAsync(string where, Dictionary<string, OrderByType> orderBy);
        /// <summary>
        /// æŸ¥è¯¢æŒ‡å®šæ•°æ®å¯¹è±¡
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        List<TResult> QueryData<TResult>(Expression<Func<TEntity, TResult>> expression);
        Task<List<TResult>> QueryDataAsync<TResult>(Expression<Func<TEntity, TResult>> expression);
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æŒ‡å®šæ•°æ®å¯¹è±¡
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="expression"></param>
        /// <param name="whereExpression"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        List<TResult> QueryData<TResult>(Expression<Func<TEntity, TResult>> expression, Expression<Func<TEntity, bool>> whereExpression, string orderByFields = "");
        Task<List<TResult>> QueryDataAsync<TResult>(Expression<Func<TEntity, TResult>> expression, Expression<Func<TEntity, bool>> whereExpression, string orderByFields);
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®å¹¶æŽ’序
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="orderByExpression"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderByExpression, bool isAsc = true);
        Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderByExpression, bool isAsc = true);
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®å¹¶æŽ’序
        /// </summary>
        /// <param name="where"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        List<TEntity> QueryData(string where, string orderByFields);
        Task<List<TEntity>> QueryDataAsync(string where, string orderByFields);
        /// <summary>
        /// åŽŸç”ŸSql语句查询数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        List<TEntity> QueryDataBySql(string sql, SugarParameter[]? parameters = null);
        Task<List<TEntity>> QueryDataBySqlAsync(string sql, SugarParameter[]? parameters = null);
        /// <summary>
        /// åŽŸç”ŸSql语句查询数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        List<dynamic> QueryDynamicDataBySql(string sql, SugarParameter[]? parameters = null);
        Task<List<dynamic>> QueryDynamicDataBySqlAsync(string sql, SugarParameter[]? parameters = null);
        List<object> QueryObjectDataBySql(string sql, SugarParameter[]? parameters = null);
        Task<List<object>> QueryObjectDataBySqlAsync(string sql, SugarParameter[]? parameters = null);
        /// <summary>
        /// åŽŸç”ŸSql语句执行操作
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="sqlParameters"></param>
        /// <returns></returns>
        int ExecuteSqlCommand(string sql, params SqlParameter[] sqlParameters);
        Task<int> ExecuteSqlCommandAsync(string sql, params SqlParameter[] sqlParameters);
        /// <summary>
        /// åŽŸç”ŸSql语句查询数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        DataTable QueryTable(string sql, SugarParameter[]? parameters = null);
        Task<DataTable> QueryTableAsync(string sql, SugarParameter[]? parameters = null);
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®æŒ‡å®šæ•°é‡çš„行
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="top"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression, int top, string orderByFields);
        Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression, int top, string orderByFields);
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æŒ‡å®šæ•°é‡çš„行
        /// </summary>
        /// <param name="where"></param>
        /// <param name="top"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        List<TEntity> QueryData(string where, int top, string orderByFields);
        Task<List<TEntity>> QueryDataAsync(string where, int top, string orderByFields);
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression, int pageIndex, int pageSize, string orderByFields);
        Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression, int pageIndex, int pageSize, string orderByFields);
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="where"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        List<TEntity> QueryData(string where, int pageIndex, int pageSize, string orderByFields);
        Task<List<TEntity>> QueryDataAsync(string where, int pageIndex, int pageSize, string orderByFields);
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        PageGridData<TEntity> QueryPage(Expression<Func<TEntity, bool>> whereExpression, int pageIndex, int pageSize, string? orderByFields = null);
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pagesize"></param>
        /// <param name="orderBy"></param>
        /// <returns></returns>
        PageGridData<TEntity> QueryPage(Expression<Func<TEntity, bool>> whereExpression, int pageIndex, int pagesize, Dictionary<string, OrderByType> orderBy);
        PageGridData<TEntity> QueryPage(string where, int pageIndex, int pageSize, Dictionary<string, OrderByType> orderBy);
        /// <summary>
        /// ä¸¤è¡¨è”查
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="joinExpression"></param>
        /// <param name="selectExpression"></param>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        List<TResult> QueryTabs<T, T2, TResult>(
            Expression<Func<T, T2, object[]>> joinExpression,
            Expression<Func<T, T2, TResult>> selectExpression,
           Expression<Func<T,T2, bool>> whereExpressionT1,
            Expression<Func<TResult, bool>> whereExpression);
        Task<List<TResult>> QueryTabsAsync<T, T2, TResult>(
            Expression<Func<T, T2, object[]>> joinExpression,
            Expression<Func<T, T2, TResult>> selectExpression,
            Expression<Func<TResult, bool>> whereExpression);
        /// <summary>
        /// ä¸¤è¡¨è”查-分页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="joinExpression"></param>
        /// <param name="selectExpression"></param>
        /// <param name="whereExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        PageGridData<TResult> QueryTabsPage<T, T2, TResult>(
            Expression<Func<T, T2, object[]>> joinExpression,
            Expression<Func<T, T2, TResult>> selectExpression,
            Expression<Func<TResult, bool>> whereExpression,
            int pageIndex = 1,
            int pageSize = 20,
            string? orderByFields = null);
        /// <summary>
        /// ä¸¤è¡¨è”合查询-分页-分组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="joinExpression"></param>
        /// <param name="selectExpression"></param>
        /// <param name="whereExpression"></param>
        /// <param name="groupExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        PageGridData<TResult> QueryTabsPage<T, T2, TResult>(
            Expression<Func<T, T2, object[]>> joinExpression,
            Expression<Func<T, T2, TResult>> selectExpression,
            Expression<Func<TResult, bool>> whereExpression,
            Expression<Func<T, object>> groupExpression,
            int pageIndex = 1,
            int pageSize = 20,
            string? orderByFields = null);
        //List<TResult> QueryMuch<T, T2, T3, TResult>(
        //    Expression<Func<T, T2, T3, object[]>> joinExpression,
        //    Expression<Func<T, T2, T3, TResult>> selectExpression,
        //    Expression<Func<T, T2, T3, bool>> whereLambda = null) where T : class, new();
        //Task<PageModel<TEntity>> QueryPage(PaginationModel pagination);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/RepositoryBase.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,855 @@
using SqlSugar;
using System.Data;
using System.Linq.Expressions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using WIDESEAWCS_Core.Helper;
using Microsoft.Data.SqlClient;
using System.Drawing.Printing;
using WIDESEAWCS_Core.Tenants;
using WIDESEAWCS_Core.Seed;
using WIDESEAWCS_Core.DB;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.AOP;
using OfficeOpenXml.FormulaParsing.ExpressionGraph;
namespace WIDESEAWCS_Core.BaseRepository
{
    public class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class, new()
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly SqlSugarScope _dbBase;
        private ISqlSugarClient _db
        {
            get
            {
                ISqlSugarClient db = _dbBase;
                //多租户
                var mta = typeof(TEntity).GetCustomAttribute<MultiTenantAttribute>();
                if (mta is { TenantType: TenantTypeEnum.Db })
                {
                    //获取租户信息 ç§Ÿæˆ·ä¿¡æ¯å¯ä»¥æå‰ç¼“存下来
                    if (App.User is { TenantId: > 0 })
                    {
                        dynamic tenant = db.Queryable(MainDb.TenantTableName, "x").Where(MainDb.TenantId, "=", App.User.TenantId).First();
                        if (tenant != null)
                        {
                            var iTenant = db.AsTenant();
                            if (!iTenant.IsAnyConnection(tenant.TenantId))
                            {
                                string conStr = tenant.ConnectionString;
                                ConnectionConfig connectionConfig = new ConnectionConfig()
                                {
                                    ConfigId = tenant.TenantId,
                                    ConnectionString = conStr.DecryptDES(AppSecret.DB),
                                    DbType = (SqlSugar.DbType)tenant.DbType,
                                    IsAutoCloseConnection = true,
                                    AopEvents = new AopEvents()
                                    {
                                        DataExecuting = SqlSugarAop.DataExecuting
                                    }
                                };
                                iTenant.AddConnection(connectionConfig);
                            }
                            return iTenant.GetConnection(tenant.TenantId);
                        }
                    }
                }
                return db;
            }
        }
        /// <summary>
        /// åˆ›å»ºæ•°æ®åº“连接对象
        /// </summary>
        public ISqlSugarClient Db => _db;
        public RepositoryBase(IUnitOfWorkManage unitOfWorkManage)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _dbBase = unitOfWorkManage.GetDbClient();
        }
        /// <summary>
        /// é€šè¿‡ä¸»é”®æŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>查询结果</returns>
        public virtual TEntity QureyDataById(object id)
        {
            return _db.CopyNew().Queryable<TEntity>().In(id).Single();
        }
        /// <summary>
        /// é€šè¿‡ä¸»é”®æ•°ç»„查询数据
        /// </summary>
        /// <param name="lstIds">主键数组</param>
        /// <returns>查询结果集合</returns>
        public virtual List<TEntity> QureyDataByIds(object[] lstIds)
        {
            return _db.CopyNew().Queryable<TEntity>().In(lstIds).ToList();
        }
        /// <summary>
        /// é€šè¿‡ä¸»é”®é›†åˆæŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="lstIds">主键集合</param>
        /// <returns>查询结果集合</returns>
        public virtual List<TEntity> QureyDataByIds(List<object> lstIds)
        {
            return _db.CopyNew().Queryable<TEntity>().In(lstIds).ToList();
        }
        /// <summary>
        /// æ·»åŠ å•æ¡æ•°æ®
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>影响行数</returns>
        public virtual int AddData(TEntity entity)
        {
            IInsertable<TEntity> insert = _db.CopyNew().Insertable(entity);
            return insert.ExecuteReturnIdentity();
        }
        /// <summary>
        /// æ·»åŠ å¤šæ¡æ•°æ®
        /// </summary>
        /// <param name="listEntity"></param>
        /// <returns>影响行数</returns>
        public virtual int AddData(List<TEntity> listEntity)
        {
            IInsertable<TEntity> insert = _db.CopyNew().Insertable(listEntity);
            return insert.ExecuteCommand();
        }
        /// <summary>
        /// é€šè¿‡ä¸»é”®åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>删除结果</returns>
        public virtual bool DeleteDataById(object id)
        {
            return _db.CopyNew().Deleteable<TEntity>().In(id).ExecuteCommandHasChange();
        }
        /// <summary>
        /// é€šè¿‡ä¸»é”®æ•°æ®åˆ é™¤å¤šæ¡æ•°æ®
        /// </summary>
        /// <param name="ids">主键数组</param>
        /// <returns>删除结果</returns>
        public virtual bool DeleteDataByIds(object[] ids)
        {
            return _db.CopyNew().Deleteable<TEntity>().In(ids).ExecuteCommandHasChange();
        }
        /// <summary>
        /// é€šè¿‡å®žä½“数据删除数据
        /// </summary>
        /// <param name="ids">主键数组</param>
        /// <returns>删除结果</returns>
        public virtual bool DeleteData(TEntity entity)
        {
            return _db.CopyNew().Deleteable(entity).ExecuteCommandHasChange();
        }
        /// <summary>
        /// é€šè¿‡å®žä½“集合数据删除数据
        /// </summary>
        /// <param name="ids">主键数组</param>
        /// <returns>删除结果</returns>
        public virtual bool DeleteData(List<TEntity> listEntity)
        {
            return _db.CopyNew().Deleteable(listEntity).ExecuteCommandHasChange();
        }
        /// <summary>
        /// æ›´æ–°å•条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual bool UpdateData(TEntity entity)
        {
            return _db.CopyNew().Updateable(entity).ExecuteCommandHasChange();
        }
        /// <summary>
        /// æ›´æ–°å¤šæ¡æ•°æ®
        /// </summary>
        /// <param name="listEntity"></param>
        /// <returns></returns>
        public virtual bool UpdateData(List<TEntity> listEntity)
        {
            return _db.CopyNew().Updateable(listEntity).ExecuteCommandHasChange();
        }
        /// <summary>
        /// æŒ‡å®šåˆ—更新数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="lstColumns"></param>
        /// <param name="lstIgnoreColumns"></param>
        /// <returns></returns>
        public virtual bool UpdateData(TEntity entity, List<string> lstColumns, List<string>? lstIgnoreColumns = null)
        {
            IUpdateable<TEntity> update = _db.CopyNew().Updateable(entity);
            if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0)
            {
                update = update.IgnoreColumns(lstIgnoreColumns.ToArray());
            }
            if (lstColumns != null && lstColumns.Count > 0)
            {
                update = update.UpdateColumns(lstColumns.ToArray());
            }
            return update.ExecuteCommandHasChange();
        }
        /// <summary>
        /// æŸ¥è¯¢æ‰€æœ‰æ•°æ®
        /// </summary>
        /// <returns></returns>
        public virtual List<TEntity> QueryData()
        {
            return _db.CopyNew().Queryable<TEntity>().ToList();
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(string where)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(!string.IsNullOrEmpty(where), where).ToList();
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).ToList();
        }
        public virtual TEntity QueryFirst(Expression<Func<TEntity, bool>> whereExpression)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).First();
        }
        public virtual TResult QueryFirst<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> expression)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).Select(expression).First();
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®å¹¶æŽ’序
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).OrderBy(orderByModels).ToList();
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®å¹¶æŽ’序
        /// </summary>
        /// <param name="where"></param>
        /// <param name="orderBy"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(string where, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            return _db.CopyNew().Queryable<TEntity>().WhereIF(!string.IsNullOrEmpty(where), where).OrderBy(orderByModels).ToList();
        }
        /// <summary>
        /// æŸ¥è¯¢æŒ‡å®šæ•°æ®å¯¹è±¡
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual List<TResult> QueryData<TResult>(Expression<Func<TEntity, TResult>> expression)
        {
            return _db.CopyNew().Queryable<TEntity>().Select(expression).ToList();
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æŒ‡å®šæ•°æ®å¯¹è±¡
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="expression"></param>
        /// <param name="whereExpression"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual List<TResult> QueryData<TResult>(Expression<Func<TEntity, TResult>> expression, Expression<Func<TEntity, bool>> whereExpression, string orderByFields = "")
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).WhereIF(whereExpression != null, whereExpression).Select(expression).ToList();
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®å¹¶æŽ’序
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="orderByExpression"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderByExpression, bool isAsc = true)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(orderByExpression != null, orderByExpression, isAsc ? OrderByType.Asc : OrderByType.Desc).WhereIF(whereExpression != null, whereExpression).ToList();
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®å¹¶æŽ’序
        /// </summary>
        /// <param name="where"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(string where, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).WhereIF(!string.IsNullOrEmpty(where), where).ToList();
        }
        /// <summary>
        /// åŽŸç”ŸSql语句查询数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryDataBySql(string sql, SugarParameter[]? parameters = null)
        {
            return _db.Ado.SqlQuery<TEntity>(sql, parameters);
        }
        /// <summary>
        /// åŽŸç”ŸSql语句查询数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public virtual List<dynamic> QueryDynamicDataBySql(string sql, SugarParameter[]? parameters = null)
        {
            return _db.Ado.SqlQuery<dynamic>(sql, parameters);
        }
        /// <summary>
        /// åŽŸç”ŸSql语句查询数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public virtual List<object> QueryObjectDataBySql(string sql, SugarParameter[]? parameters = null)
        {
            return _db.Ado.SqlQuery<object>(sql, parameters);
        }
        /// <summary>
        /// åŽŸç”ŸSql语句执行操作
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="sqlParameters"></param>
        /// <returns></returns>
        public virtual int ExecuteSqlCommand(string sql, params SqlParameter[] sqlParameters)
        {
            return _db.Ado.ExecuteCommand(sql, sqlParameters);
        }
        /// <summary>
        /// åŽŸç”ŸSql语句查询数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public virtual DataTable QueryTable(string sql, SugarParameter[]? parameters = null)
        {
            return _db.Ado.GetDataTable(sql, parameters);
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æ•°æ®æŒ‡å®šæ•°é‡çš„行
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="top"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression, int top, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).WhereIF(whereExpression != null, whereExpression).Take(top).ToList();
        }
        /// <summary>
        /// æ¡ä»¶æŸ¥è¯¢æŒ‡å®šæ•°é‡çš„行
        /// </summary>
        /// <param name="where"></param>
        /// <param name="top"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(string where, int top, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).WhereIF(!string.IsNullOrEmpty(where), where).Take(top).ToList();
        }
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(Expression<Func<TEntity, bool>> whereExpression, int pageIndex, int pageSize, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields)
               .WhereIF(whereExpression != null, whereExpression).ToPageList(pageIndex, pageSize);
        }
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="where"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual List<TEntity> QueryData(string where, int pageIndex, int pageSize, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields)
                .WhereIF(!string.IsNullOrEmpty(where), where).ToPageList(pageIndex, pageSize);
        }
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual PageGridData<TEntity> QueryPage(Expression<Func<TEntity, bool>> whereExpression, int pageIndex, int pageSize, string? orderByFields = null)
        {
            int totalCount = 0;
            var list = _db.CopyNew().Queryable<TEntity>()
                .OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields)
                .WhereIF(whereExpression != null, whereExpression)
                .ToPageList(pageIndex, pageSize, ref totalCount);
            return new PageGridData<TEntity> { Rows = list, Total = totalCount };
        }
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderBy"></param>
        /// <returns></returns>
        public virtual PageGridData<TEntity> QueryPage(Expression<Func<TEntity, bool>> whereExpression, int pageIndex, int pageSize, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            int totalCount = 0;
            List<TEntity> list = _db.CopyNew().Queryable<TEntity>()
                .OrderBy(orderByModels)
                .WhereIF(whereExpression != null, whereExpression)
                .ToPageList(pageIndex, pageSize, ref totalCount);
            return new PageGridData<TEntity>(totalCount, list);
        }
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢
        /// </summary>
        /// <param name="where"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual PageGridData<TEntity> QueryPage(string where, int pageIndex, int pageSize, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            int totalCount = 0;
            List<TEntity> list = _db.CopyNew().Queryable<TEntity>()
                .WhereIF(!string.IsNullOrEmpty(where), where).OrderBy(orderByModels).ToPageList(pageIndex, pageSize, ref totalCount);
            return new PageGridData<TEntity>(totalCount, list);
        }
        /// <summary>
        /// ä¸¤è¡¨è”查
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="joinExpression"></param>
        /// <param name="selectExpression"></param>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public virtual List<TResult> QueryTabs<T, T2, TResult>(
           Expression<Func<T, T2, object[]>> joinExpression,
           Expression<Func<T, T2, TResult>> selectExpression,
           Expression<Func<T,T2, bool>> whereExpressionT1,
           Expression<Func<TResult, bool>> whereExpression)
        {
            List<TResult> list = _db.CopyNew().Queryable(joinExpression).WhereIF(whereExpressionT1 != null, whereExpressionT1)
               .Select(selectExpression)
               .WhereIF(whereExpression != null, whereExpression).ToList();
            return list;
        }
        /// <summary>
        /// ä¸¤è¡¨è”查-分页
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="joinExpression"></param>
        /// <param name="selectExpression"></param>
        /// <param name="whereExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        public virtual PageGridData<TResult> QueryTabsPage<T1, T2, TResult>(Expression<Func<T1, T2, object[]>> joinExpression, Expression<Func<T1, T2, TResult>> selectExpression, Expression<Func<TResult, bool>> whereExpression, int pageIndex, int pageSize, string? orderByFields = null)
        {
            int totalCount = 0;
            List<TResult> list = _db.CopyNew().Queryable(joinExpression)
                .Select(selectExpression)
                .OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields)
                .WhereIF(whereExpression != null, whereExpression)
                .ToPageList(pageIndex, pageSize, ref totalCount);
            return new PageGridData<TResult>(totalCount, list);
        }
        /// <summary>
        /// ä¸¤è¡¨è”合查询-分页-分组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="joinExpression"></param>
        /// <param name="selectExpression"></param>
        /// <param name="whereExpression"></param>
        /// <param name="groupExpression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderByFields"></param>
        /// <returns></returns>
        public virtual PageGridData<TResult> QueryTabsPage<T1, T2, TResult>(Expression<Func<T1, T2, object[]>> joinExpression, Expression<Func<T1, T2, TResult>> selectExpression, Expression<Func<TResult, bool>> whereExpression, Expression<Func<T1, object>> groupExpression, int pageIndex, int pageSize, string? orderByFields = null)
        {
            int totalCount = 0;
            List<TResult> list = _db.CopyNew().Queryable(joinExpression).GroupBy(groupExpression)
                .Select(selectExpression)
                .OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields)
                .WhereIF(whereExpression != null, whereExpression)
                .ToPageList(pageIndex, pageSize, ref totalCount);
            return new PageGridData<TResult>(totalCount, list);
        }
        public Task<TEntity> QureyDataByIdAsync(object id)
        {
            return _db.CopyNew().Queryable<TEntity>().In(id).SingleAsync();
        }
        public Task<List<TEntity>> QureyDataByIdsAsync(object[] lstIds)
        {
            return _db.CopyNew().Queryable<TEntity>().In(lstIds).ToListAsync();
        }
        public Task<List<TEntity>> QureyDataByIdsAsync(List<object> lstIds)
        {
            return _db.CopyNew().Queryable<TEntity>().In(lstIds).ToListAsync();
        }
        public Task<int> AddDataAsync(TEntity entity)
        {
            IInsertable<TEntity> insert = _db.CopyNew().Insertable(entity);
            return insert.ExecuteReturnIdentityAsync();
        }
        public Task<int> AddDataAsync(List<TEntity> listEntity)
        {
            IInsertable<TEntity> insert = _db.CopyNew().Insertable(listEntity);
            return insert.ExecuteReturnIdentityAsync();
        }
        public Task<bool> DeleteDataByIdAsync(object id)
        {
            return _db.CopyNew().Deleteable<TEntity>().In(id).ExecuteCommandHasChangeAsync();
        }
        public Task<bool> DeleteDataByIdsAsync(object[] ids)
        {
            return _db.CopyNew().Deleteable<TEntity>().In(ids).ExecuteCommandHasChangeAsync();
        }
        public Task<bool> DeleteDataAsync(TEntity entity)
        {
            return _db.CopyNew().Deleteable(entity).ExecuteCommandHasChangeAsync();
        }
        public Task<bool> DeleteDataAsync(List<TEntity> listEntity)
        {
            return _db.CopyNew().Deleteable(listEntity).ExecuteCommandHasChangeAsync();
        }
        public Task<bool> UpdateDataAsync(TEntity entity)
        {
            return _db.CopyNew().Updateable(entity).ExecuteCommandHasChangeAsync();
        }
        public Task<bool> UpdateDataAsync(List<TEntity> listEntity)
        {
            return _db.CopyNew().Updateable(listEntity).ExecuteCommandHasChangeAsync();
        }
        public Task<bool> UpdateDataAsync(TEntity entity, List<string> lstColumns, List<string>? lstIgnoreColumns = null)
        {
            IUpdateable<TEntity> update = _db.CopyNew().Updateable(entity);
            if (lstIgnoreColumns != null && lstIgnoreColumns.Count > 0)
            {
                update = update.IgnoreColumns(lstIgnoreColumns.ToArray());
            }
            if (lstColumns != null && lstColumns.Count > 0)
            {
                update = update.UpdateColumns(lstColumns.ToArray());
            }
            return update.ExecuteCommandHasChangeAsync();
        }
        public Task<List<TEntity>> QueryDataAsync()
        {
            return _db.CopyNew().Queryable<TEntity>().ToListAsync();
        }
        public Task<List<TEntity>> QueryDataAsync(string where)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(!string.IsNullOrEmpty(where), where).ToListAsync();
        }
        public Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }
        public Task<TEntity> QueryFirstAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).FirstAsync();
        }
        public Task<TResult> QueryFirstAsync<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> expression)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).Select(expression).FirstAsync();
        }
        public TResult QueryFirst<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> expression, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).OrderBy(orderByModels).Select(expression).First();
        }
        public Task<TResult> QueryFirstAsync<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> expression, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).OrderBy(orderByModels).Select(expression).FirstAsync();
        }
        public TEntity QueryFirst(Expression<Func<TEntity, bool>> whereExpression, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).OrderBy(orderByModels).First();
        }
        public Task<TEntity> QueryFirstAsync(Expression<Func<TEntity, bool>> whereExpression, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).OrderBy(orderByModels).FirstAsync();
        }
        public Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().WhereIF(whereExpression != null, whereExpression).OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).ToListAsync();
        }
        public Task<List<TEntity>> QueryDataAsync(string where, Dictionary<string, OrderByType> orderBy)
        {
            List<OrderByModel> orderByModels = new List<OrderByModel>();
            foreach (var item in orderBy)
            {
                OrderByModel orderByModel = new OrderByModel()
                {
                    FieldName = item.Key,
                    OrderByType = item.Value
                };
                orderByModels.Add(orderByModel);
            }
            return _db.CopyNew().Queryable<TEntity>().WhereIF(!string.IsNullOrEmpty(where), where).OrderBy(orderByModels).ToListAsync();
        }
        public Task<List<TResult>> QueryDataAsync<TResult>(Expression<Func<TEntity, TResult>> expression)
        {
            return _db.CopyNew().Queryable<TEntity>().Select(expression).ToListAsync();
        }
        public Task<List<TResult>> QueryDataAsync<TResult>(Expression<Func<TEntity, TResult>> expression, Expression<Func<TEntity, bool>> whereExpression, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).WhereIF(whereExpression != null, whereExpression).Select(expression).ToListAsync();
        }
        public Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, object>> orderByExpression, bool isAsc = true)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(orderByExpression != null, orderByExpression, isAsc ? OrderByType.Asc : OrderByType.Desc).WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }
        public Task<List<TEntity>> QueryDataAsync(string where, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).WhereIF(!string.IsNullOrEmpty(where), where).ToListAsync();
        }
        public Task<List<TEntity>> QueryDataBySqlAsync(string sql, SugarParameter[]? parameters = null)
        {
            return _db.Ado.SqlQueryAsync<TEntity>(sql, parameters);
        }
        public Task<List<dynamic>> QueryDynamicDataBySqlAsync(string sql, SugarParameter[]? parameters = null)
        {
            return _db.Ado.SqlQueryAsync<dynamic>(sql, parameters);
        }
        public Task<List<object>> QueryObjectDataBySqlAsync(string sql, SugarParameter[]? parameters = null)
        {
            return _db.Ado.SqlQueryAsync<object>(sql, parameters);
        }
        public Task<int> ExecuteSqlCommandAsync(string sql, params SqlParameter[] sqlParameters)
        {
            return _db.Ado.ExecuteCommandAsync(sql, sqlParameters);
        }
        public Task<DataTable> QueryTableAsync(string sql, SugarParameter[]? parameters = null)
        {
            return _db.Ado.GetDataTableAsync(sql, parameters);
        }
        public Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression, int top, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).WhereIF(whereExpression != null, whereExpression).Take(top).ToListAsync();
        }
        public Task<List<TEntity>> QueryDataAsync(string where, int top, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields).WhereIF(!string.IsNullOrEmpty(where), where).Take(top).ToListAsync();
        }
        public Task<List<TEntity>> QueryDataAsync(Expression<Func<TEntity, bool>> whereExpression, int pageIndex, int pageSize, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields)
              .WhereIF(whereExpression != null, whereExpression).ToPageListAsync(pageIndex, pageSize);
        }
        public Task<List<TEntity>> QueryDataAsync(string where, int pageIndex, int pageSize, string orderByFields)
        {
            return _db.CopyNew().Queryable<TEntity>().OrderByIF(!string.IsNullOrEmpty(orderByFields), orderByFields)
                .WhereIF(!string.IsNullOrEmpty(where), where).ToPageListAsync(pageIndex, pageSize);
        }
        public Task<List<TResult>> QueryTabsAsync<T, T2, TResult>(Expression<Func<T, T2, object[]>> joinExpression, Expression<Func<T, T2, TResult>> selectExpression, Expression<Func<TResult, bool>> whereExpression)
        {
            return _db.CopyNew().Queryable(joinExpression)
             .Select(selectExpression)
             .WhereIF(whereExpression != null, whereExpression).ToListAsync();
        }
        //List<TResult> QueryMuch<T, T2, T3, TResult>(
        //    Expression<Func<T, T2, T3, object[]>> joinExpression,
        //    Expression<Func<T, T2, T3, TResult>> selectExpression,
        //    Expression<Func<T, T2, T3, bool>> whereLambda = null) where T : class, new(){throw new NotImplementedException();}
        //Task<PageModel<TEntity>> QueryPage(PaginationModel pagination){throw new NotImplementedException();}
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/IUnitOfWorkManage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.BaseRepository
{
    public interface IUnitOfWorkManage
    {
        SqlSugarScope GetDbClient();
        int TranCount { get; }
        UnitOfWork CreateUnitOfWork();
        void BeginTran();
        void BeginTran(MethodInfo method);
        void CommitTran();
        void CommitTran(MethodInfo method);
        void RollbackTran();
        void RollbackTran(MethodInfo method);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/UnitOfWork.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,55 @@
using Microsoft.Extensions.Logging;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.BaseRepository
{
    public class UnitOfWork : IDisposable
    {
        public ILogger Logger { get; set; }
        public ISqlSugarClient Db { get; internal set; }
        public ITenant Tenant { get; internal set; }
        public bool IsTran { get; internal set; }
        public bool IsCommit { get; internal set; }
        public bool IsClose { get; internal set; }
        public void Dispose()
        {
            if (IsTran && !IsCommit)
            {
                Logger.LogDebug("UnitOfWork RollbackTran");
                this.Tenant.RollbackTran();
            }
            if (this.Db.Ado.Transaction != null || this.IsClose)
                return;
            this.Db.Close();
        }
        public bool Commit()
        {
            if (this.IsTran && !this.IsCommit)
            {
                Logger.LogDebug("UnitOfWork CommitTran");
                this.Tenant.CommitTran();
                this.IsCommit = true;
            }
            if (this.Db.Ado.Transaction == null && !this.IsClose)
            {
                this.Db.Close();
                this.IsClose = true;
            }
            return this.IsCommit;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseRepository/UnitOfWorks/UnitOfWorkManage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,194 @@
using Microsoft.Extensions.Logging;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.BaseRepository
{
    public class UnitOfWorkManage : IUnitOfWorkManage
    {
        private readonly ILogger<UnitOfWorkManage> _logger;
        private readonly ISqlSugarClient _sqlSugarClient;
        private int _tranCount { get; set; }
        public int TranCount => _tranCount;
        public readonly ConcurrentStack<string> TranStack = new();
        public UnitOfWorkManage(ISqlSugarClient sqlSugarClient, ILogger<UnitOfWorkManage> logger)
        {
            _sqlSugarClient = sqlSugarClient;
            _logger = logger;
            _tranCount = 0;
        }
        /// <summary>
        /// èŽ·å–DB,保证唯一性
        /// </summary>
        /// <returns></returns>
        public SqlSugarScope GetDbClient()
        {
            // å¿…须要as,后边会用到切换数据库操作
            return _sqlSugarClient as SqlSugarScope;
        }
        public UnitOfWork CreateUnitOfWork()
        {
            UnitOfWork uow = new UnitOfWork();
            uow.Logger = _logger;
            uow.Db = _sqlSugarClient;
            uow.Tenant = (ITenant)_sqlSugarClient;
            uow.IsTran = true;
            uow.Db.Open();
            uow.Tenant.BeginTran();
            _logger.LogDebug("UnitOfWork Begin");
            return uow;
        }
        public void BeginTran()
        {
            lock (this)
            {
                _tranCount++;
                GetDbClient().BeginTran();
            }
        }
        public void BeginTran(MethodInfo method)
        {
            lock (this)
            {
                GetDbClient().BeginTran();
                TranStack.Push(method.GetFullName());
                _tranCount = TranStack.Count;
            }
        }
        public WebResponseContent BeginTran(Func<WebResponseContent> func)
        {
            lock (this)
            {
                BeginTran();
                try
                {
                    WebResponseContent content = func();
                    if (content.Status)
                    {
                        CommitTran();
                    }
                    else
                    {
                        RollbackTran();
                    }
                    return content;
                }
                catch(Exception ex)
                {
                    RollbackTran();
                    return WebResponseContent.Instance.Error(ex.Message);
                }
            }
        }
        public void CommitTran()
        {
            lock (this)
            {
                _tranCount--;
                if (_tranCount == 0)
                {
                    try
                    {
                        GetDbClient().CommitTran();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        GetDbClient().RollbackTran();
                    }
                }
            }
        }
        public void CommitTran(MethodInfo method)
        {
            lock (this)
            {
                string result = "";
                while (!TranStack.IsEmpty && !TranStack.TryPeek(out result))
                {
                    Thread.Sleep(1);
                }
                if (result == method.GetFullName())
                {
                    try
                    {
                        GetDbClient().CommitTran();
                        _logger.LogDebug($"Commit Transaction");
                        Console.WriteLine($"Commit Transaction");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        GetDbClient().RollbackTran();
                        _logger.LogDebug($"Commit Error , Rollback Transaction");
                    }
                    finally
                    {
                        while (!TranStack.TryPop(out _))
                        {
                            Thread.Sleep(1);
                        }
                        _tranCount = TranStack.Count;
                    }
                }
            }
        }
        public void RollbackTran()
        {
            lock (this)
            {
                _tranCount--;
                GetDbClient().RollbackTran();
            }
        }
        public void RollbackTran(MethodInfo method)
        {
            lock (this)
            {
                string result = "";
                while (!TranStack.IsEmpty && !TranStack.TryPeek(out result))
                {
                    Thread.Sleep(1);
                }
                if (result == method.GetFullName())
                {
                    GetDbClient().RollbackTran();
                    _logger.LogDebug($"Rollback Transaction");
                    Console.WriteLine($"Rollback Transaction");
                    while (!TranStack.TryPop(out _))
                    {
                        Thread.Sleep(1);
                    }
                    _tranCount = TranStack.Count;
                }
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseServices/IService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
using Microsoft.AspNetCore.Http;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.BaseServices
{
    public interface IService<TEntity>: IDependency where TEntity : class
    {
        ISqlSugarClient Db { get; }
        /// <summary>
        /// åˆ†é¡µæŸ¥è¯¢æ•°æ®
        /// </summary>
        /// <param name="options"></param>
        /// <returns></returns>
        PageGridData<TEntity> GetPageData(PageDataOptions options);
        object GetDetailPage(PageDataOptions pageData);
        /// <summary>
        /// æ·»åŠ æ•°æ®
        /// </summary>
        /// <param name="entity">单个实体</param>
        /// <returns></returns>
        WebResponseContent AddData(TEntity entity);
        /// <summary>
        /// æ·»åŠ æ•°æ®
        /// </summary>
        /// <param name="entities">实体集合</param>
        /// <returns></returns>
        WebResponseContent AddData(List<TEntity> entities);
        /// <summary>
        /// æ·»åŠ æ•°æ®
        /// </summary>
        /// <param name="saveModel"></param>
        /// <returns></returns>
        WebResponseContent AddData(SaveModel saveModel);
        /// <summary>
        /// ä¿®æ”¹æ•°æ®
        /// </summary>
        /// <param name="entity">单个实体</param>
        /// <returns></returns>
        WebResponseContent UpdateData(TEntity entity);
        /// <summary>
        /// ä¿®æ”¹æ•°æ®
        /// </summary>
        /// <param name="entities">实体集合</param>
        /// <returns></returns>
        WebResponseContent UpdateData(List<TEntity> entities);
        /// <summary>
        /// ä¿®æ”¹æ•°æ®
        /// </summary>
        /// <param name="saveModel"></param>
        /// <returns></returns>
        WebResponseContent UpdateData(SaveModel saveModel);
        /// <summary>
        /// åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="key">主键</param>
        /// <returns></returns>
        WebResponseContent DeleteData(object key);
        /// <summary>
        /// åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="keys">主键数组</param>
        /// <returns></returns>
        WebResponseContent DeleteData(object[] keys);
        /// <summary>
        /// åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="entity">单个实体</param>
        /// <returns></returns>
        WebResponseContent DeleteData(TEntity entity);
        /// <summary>
        /// åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="entities">实体集合</param>
        /// <returns></returns>
        WebResponseContent DeleteData(List<TEntity> entities);
        /// <summary>
        /// å¯¼å‡ºæ•°æ®
        /// </summary>
        /// <param name="pageData"></param>
        /// <returns></returns>
        WebResponseContent Export(PageDataOptions pageData);
        /// <summary>
        /// å¯¼å…¥æ•°æ®
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        WebResponseContent Import(List<IFormFile> files);
        /// <summary>
        /// ä¸Šä¼ æ–‡ä»¶
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        WebResponseContent Upload(List<IFormFile> files);
        /// <summary>
        /// æ¨¡æ¿ä¸‹è½½
        /// </summary>
        /// <returns></returns>
        WebResponseContent DownLoadTemplate();
        WebResponseContent ExportSeedData();
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseServices/ServiceBase.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,808 @@
using Magicodes.ExporterAndImporter.Core;
using Magicodes.ExporterAndImporter.Core.Models;
using Magicodes.ExporterAndImporter.Excel;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using SqlSugar;
using System.Drawing.Drawing2D;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Utilities;
using static OfficeOpenXml.ExcelErrorValue;
namespace WIDESEAWCS_Core.BaseServices
{
    public class ServiceBase<TEntity, TRepository> : ServiceFunFilter<TEntity>, IService<TEntity>
         where TEntity : class, new()
         where TRepository : IRepository<TEntity>
    {
        public ServiceBase(TRepository BaseDal)
        {
            this.BaseDal = BaseDal;
        }
        public TRepository BaseDal { get; set; } //通过在子类的构造函数中注入,这里是基类,不用构造函数
        public ISqlSugarClient Db => BaseDal.Db;
        private PropertyInfo[] _propertyInfo { get; set; } = null;
        private PropertyInfo[] TProperties
        {
            get
            {
                if (_propertyInfo != null)
                {
                    return _propertyInfo;
                }
                _propertyInfo = typeof(TEntity).GetProperties();
                return _propertyInfo;
            }
        }
        public virtual PageGridData<TEntity> GetPageData(PageDataOptions options)
        {
            string wheres = ValidatePageOptions(options);
            //获取排序字段
            Dictionary<string, OrderByType> orderbyDic = GetPageDataSort(options, TProperties);
            PageGridData<TEntity> pageGridData = new PageGridData<TEntity>();
            pageGridData = BaseDal.QueryPage(wheres, options.Page, options.Rows, orderbyDic);
            return pageGridData;
        }
        //protected string ValidatePageOptions(PageDataOptions options)
        //{
        //    options = options ?? new PageDataOptions();
        //    string where = "";
        //    List<SearchParameters> searchParametersList = new List<SearchParameters>();
        //    if (options.Filter != null && options.Filter.Count > 0)
        //    {
        //        searchParametersList.AddRange(options.Filter);
        //    }
        //    else if (!string.IsNullOrEmpty(options.Wheres))
        //    {
        //        try
        //        {
        //            searchParametersList = options.Wheres.DeserializeObject<List<SearchParameters>>();
        //            options.Filter = searchParametersList;
        //        }
        //        catch { }
        //    }
        //    QueryRelativeList?.Invoke(searchParametersList);
        //    for (int i = 0; i < searchParametersList.Count; i++)
        //    {
        //        if (string.IsNullOrEmpty(searchParametersList[i].Value))
        //        {
        //            continue;
        //        }
        //        PropertyInfo property = TProperties.Where(c => c.Name.ToUpper() == searchParametersList[i].Name.ToUpper()).FirstOrDefault();
        //        if (property == null) continue;
        //        List<(bool, string, object)> results = property.ValidationValueForDbType(searchParametersList[i].Value.Split(',')).ToList();
        //        if (results == null || results.Count() == 0)
        //        {
        //            continue;
        //        }
        //        for (int j = 0; j < results.Count(); j++)
        //        {
        //            if (j == 0)
        //            {
        //                where += "(";
        //            }
        //            LinqExpressionType expressionType = searchParametersList[i].DisplayType.GetLinqCondition();
        //            if (expressionType == LinqExpressionType.Equal)
        //            {
        //                where += $"{searchParametersList[i].Name} like '%{results[j].Item3}%'";
        //            }
        //            else
        //            {
        //                where += $"{searchParametersList[i].Name} {searchParametersList[i].DisplayType} '{results[j].Item3}'";
        //            }
        //            if (j == results.Count() - 1)
        //            {
        //                where += ")";
        //            }
        //            else
        //            {
        //                where += " or ";
        //            }
        //        }
        //        if (i < searchParametersList.Count - 1)
        //            where += " and ";
        //    }
        //    return where;
        //}
        protected string ValidatePageOptions(PageDataOptions options)
        {
            options = options ?? new PageDataOptions();
            string where = "";
            List<SearchParameters> searchParametersList = new List<SearchParameters>();
            if (options.Filter != null && options.Filter.Count > 0)
            {
                searchParametersList.AddRange(options.Filter);
            }
            else if (!string.IsNullOrEmpty(options.Wheres))
            {
                try
                {
                    searchParametersList = options.Wheres.DeserializeObject<List<SearchParameters>>();
                    options.Filter = searchParametersList;
                }
                catch { }
            }
            QueryRelativeList?.Invoke(searchParametersList);
            for (int i = 0; i < searchParametersList.Count; i++)
            {
                if (string.IsNullOrEmpty(searchParametersList[i].Value))
                {
                    continue;
                }
                PropertyInfo property = TProperties.Where(c => c.Name.ToUpper() == searchParametersList[i].Name.ToUpper()).FirstOrDefault();
                if (property == null) continue;
                (bool, string, object) result = property.ValidationVal(searchParametersList[i].Value);
                if (!result.Item1)
                {
                    continue;
                }
                LinqExpressionType expressionType = searchParametersList[i].DisplayType.GetLinqCondition();
                if (expressionType == LinqExpressionType.Equal)
                {
                    if (string.IsNullOrEmpty(where))
                    {
                        // é’ˆå¯¹å­—符串类型的字段使用模糊查询
                        //where += $"{searchParametersList[i].Name} like '%{searchParametersList[i].Value}%'";
                        if (searchParametersList[i].Value.ToLower() == "true" || searchParametersList[i].Value.ToLower() == "false")
                        {
                            where += $" {searchParametersList[i].Name} = '{searchParametersList[i].Value.ToLower()}'";
                        }
                        else
                        {
                            where += $"{searchParametersList[i].Name} like '%{searchParametersList[i].Value}%'";
                        }
                    }
                    else
                    {
                        // é’ˆå¯¹å¸ƒå°”类型字段进行精确查询
                        if (searchParametersList[i].Value.ToLower() == "true" || searchParametersList[i].Value.ToLower() == "false")
                        {
                            where += $" and {searchParametersList[i].Name} = '{searchParametersList[i].Value.ToLower()}'";
                        }
                        else
                        {
                            where += $" and {searchParametersList[i].Name} like '%{searchParametersList[i].Value}%'";
                        }
                    }
                }
                else
                {
                    if (string.IsNullOrEmpty(where))
                        where += $"{searchParametersList[i].Name} {searchParametersList[i].DisplayType} '{searchParametersList[i].Value}'";
                    else
                        where += $" and {searchParametersList[i].Name} {searchParametersList[i].DisplayType} '{searchParametersList[i].Value}'";
                }
            }
            return where;
        }
        /// <summary>
        /// èŽ·å–æŽ’åºå­—æ®µ
        /// </summary>
        /// <param name="pageData"></param>
        /// <param name="propertyInfo"></param>
        /// <returns></returns>
        private Dictionary<string, OrderByType> GetPageDataSort(PageDataOptions pageData, PropertyInfo[] propertyInfo)
        {
            if (!string.IsNullOrEmpty(pageData.Sort))
            {
                if (pageData.Sort.Contains(","))
                {
                    List<string> sortArr = pageData.Sort.Split(",").Where(x => propertyInfo.Any(p => p.Name == x)).ToList();
                    Dictionary<string, OrderByType> sortDic = new Dictionary<string, OrderByType>();
                    foreach (var item in sortArr)
                    {
                        sortDic[item] = pageData.Order?.ToLower() == OrderByType.Asc.ToString() ? OrderByType.Asc : OrderByType.Desc;
                    }
                    return sortDic;
                }
                else if (propertyInfo.Any(x => x.Name == pageData.Sort.FirstLetterToLower() || x.Name == pageData.Sort.FirstLetterToUpper()))
                {
                    return new Dictionary<string, OrderByType> {
                        {
                            pageData.Sort,pageData.Order?.ToLower() == OrderByType.Asc.ToString() ? OrderByType.Asc : OrderByType.Desc
                        } };
                }
            }
            return new Dictionary<string, OrderByType> { { "CreateDate", pageData.Order?.ToLower() == OrderByType.Asc.ToString() ? OrderByType.Asc : OrderByType.Desc } };
        }
        public virtual object GetDetailPage(PageDataOptions pageData)
        {
            Type t = typeof(TEntity);
            if (pageData.Value == null) return new PageGridData<object>(total: 0, null);
            string keyName = t.GetKeyName();
            ////生成查询条件
            //Expression<Func<TEntity, bool>> whereExpression = keyName.CreateExpression<TEntity>(pageData.Value, LinqExpressionType.Equal);
            int totalCount = 0;
            PropertyInfo propertyInfo = t.GetProperties().FirstOrDefault(x => x.GetCustomAttribute<Navigate>() != null);
            if (propertyInfo != null)
            {
                Type detailType = propertyInfo.PropertyType.GetGenericArguments()[0];
                Navigate navigate = propertyInfo.GetCustomAttribute<Navigate>();
                List<ExpandoObject> list = BaseDal.Db.Queryable(detailType.Name, "detail").Where(navigate.GetName(), "=", pageData.Value).ToPageList(pageData.Page, pageData.Rows, ref totalCount);
                return new PageGridData<ExpandoObject>(totalCount, list);
            }
            return new PageGridData<object>(total: 0, null);
        }
        /// <summary>
        /// æ·»åŠ æ•°æ®
        /// </summary>
        /// <param name="entity">单个实体</param>
        /// <returns></returns>
        public virtual WebResponseContent AddData(TEntity entity)
        {
            try
            {
                return BaseDal.AddData(entity) > 0 ? WebResponseContent.Instance.OK() : WebResponseContent.Instance.Error();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// æ·»åŠ æ•°æ®
        /// </summary>
        /// <param name="entities">实体集合</param>
        /// <returns></returns>
        public virtual WebResponseContent AddData(List<TEntity> entities)
        {
            try
            {
                return BaseDal.AddData(entities) > 0 ? WebResponseContent.Instance.OK() : WebResponseContent.Instance.Error();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// æ·»åŠ æ•°æ®
        /// </summary>
        /// <param name="saveModel"></param>
        /// <returns></returns>
        public virtual WebResponseContent AddData(SaveModel saveModel)
        {
            try
            {
                if (saveModel == null || saveModel.MainData == null || saveModel.MainData.Count == 0)//判断参数是否传入
                {
                    return WebResponseContent.Instance.Error("传参错误,参数不能为空");
                }
                var x = saveModel.MainData;
                string validResult = typeof(TEntity).ValidateDicInEntity(x, true, TProperties);
                if (!string.IsNullOrEmpty(validResult))
                {
                    return WebResponseContent.Instance.Error(validResult);
                }
                PropertyInfo keyPro = typeof(TEntity).GetKeyProperty();
                if (keyPro == null)
                {
                    return WebResponseContent.Instance.Error("请先设置主键");
                }
                if (keyPro.PropertyType == typeof(Guid))
                {
                    saveModel.MainData.Add(keyPro.Name, Guid.NewGuid());
                }
                else if (keyPro.PropertyType == typeof(int) || keyPro.PropertyType == typeof(long))
                {
                    SugarColumn sugarColumn = keyPro.GetCustomAttribute<SugarColumn>();
                    if (sugarColumn.IsIdentity)
                    {
                        saveModel.MainData.Remove(keyPro.Name.FirstLetterToUpper());
                        saveModel.MainData.Remove(keyPro.Name.FirstLetterToLower());
                    }
                }
                TEntity entity = saveModel.MainData.DicToModel<TEntity>();
                if (saveModel.DetailData == null || saveModel.DetailData.Count == 0)
                {
                    BaseDal.AddData(entity);
                    return WebResponseContent.Instance.OK();
                }
                if (typeof(TEntity).GetNavigatePro() == null)
                {
                    return WebResponseContent.Instance.Error("未配置导航属性");
                }
                Type detailType = typeof(TEntity).GetDetailType();
                MethodInfo? methodInfo = GetType().GetMethod(nameof(AddDataIncludesDetail));
                methodInfo = methodInfo?.MakeGenericMethod(new Type[] { detailType });
                object? obj = methodInfo?.Invoke(this, new object[] { entity, detailType, saveModel.DetailData });
                return obj as WebResponseContent;
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        public WebResponseContent AddDataIncludesDetail<TDetail>(TEntity entity, Type detailType, List<Dictionary<string, object>> detailDics) where TDetail : class, new()
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                string name = typeof(TEntity).GetMainIdByDetail();
                string reslut = detailType.ValidateDicInEntity(detailDics, true, new string[] { name });
                if (reslut != string.Empty)
                    return WebResponseContent.Instance.Error(reslut);
                List<TDetail> list = detailDics.DicToIEnumerable<TDetail>();
                ((SqlSugarScope)BaseDal.Db).BeginTran();
                int id = BaseDal.Db.Insertable(entity).ExecuteReturnIdentity();
                for (int i = 0; i < list.Count; i++)
                {
                    TDetail detail = list[i];
                    typeof(TDetail).SetDetailId(detail, id, name);
                }
                BaseDal.Db.Insertable(list).ExecuteCommand();
                ((SqlSugarScope)BaseDal.Db).CommitTran();
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                ((SqlSugarScope)BaseDal.Db).RollbackTran();
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// ä¿®æ”¹æ•°æ®
        /// </summary>
        /// <param name="entity">单个实体</param>
        /// <returns></returns>
        public virtual WebResponseContent UpdateData(TEntity entity)
        {
            try
            {
                return BaseDal.UpdateData(entity) ? WebResponseContent.Instance.OK() : WebResponseContent.Instance.Error();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// ä¿®æ”¹æ•°æ®
        /// </summary>
        /// <param name="entities">实体集合</param>
        /// <returns></returns>
        public virtual WebResponseContent UpdateData(List<TEntity> entities)
        {
            try
            {
                return BaseDal.UpdateData(entities) ? WebResponseContent.Instance.OK() : WebResponseContent.Instance.Error();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// ä¿®æ”¹æ•°æ®
        /// </summary>
        /// <param name="saveModel"></param>
        /// <returns></returns>
        public virtual WebResponseContent UpdateData(SaveModel saveModel)
        {
            try
            {
                List<string>? list = UpdateIgnoreColOnExecute?.Invoke(saveModel);
                if (saveModel == null || saveModel.MainData == null || saveModel.MainData.Count == 0)//判断参数是否传入
                {
                    return WebResponseContent.Instance.Error("传参错误,参数不能为空");
                }
                string validResult = typeof(TEntity).ValidateDicInEntity(saveModel.MainData, false, TProperties, list?.ToArray());
                if (!string.IsNullOrEmpty(validResult))
                {
                    return WebResponseContent.Instance.Error(validResult);
                }
                PropertyInfo keyPro = typeof(TEntity).GetKeyProperty();
                if (keyPro == null)
                {
                    return WebResponseContent.Instance.Error("请先设置主键");
                }
                TEntity entity = saveModel.MainData.DicToModel<TEntity>();
                //List<string> listCol = new List<string>();
                //foreach (var item in saveModel.MainData)
                //{
                //    PropertyInfo propertyInfo = typeof(TEntity).GetProperty(item.Key);
                //    if (propertyInfo == null)
                //    {
                //        propertyInfo = typeof(TEntity).GetProperty(item.Key.FirstLetterToLower());
                //        if (propertyInfo == null)
                //        {
                //            propertyInfo = typeof(TEntity).GetProperty(item.Key.FirstLetterToUpper());
                //        }
                //    }
                //    listCol.Add(propertyInfo?.Name);
                //}
                if (saveModel.DetailData == null || saveModel.DetailData.Count == 0)
                {
                    //if (list != null)
                    //    listCol = listCol.Where(x => !list.Contains(x)).ToList();
                    bool result = BaseDal.UpdateData(entity);
                    return WebResponseContent.Instance.OK();
                }
                if (typeof(TEntity).GetNavigatePro() == null)
                {
                    return WebResponseContent.Instance.Error("未配置导航属性");
                }
                Type detailType = typeof(TEntity).GetDetailType();
                MethodInfo? methodInfo = GetType().GetMethod(nameof(UpdateDataInculdesDetail));
                methodInfo = methodInfo?.MakeGenericMethod(new Type[] { detailType });
                object? obj = methodInfo?.Invoke(this, new object[] { entity, detailType, saveModel.DetailData, saveModel.DelKeys });
                return obj as WebResponseContent;
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        public WebResponseContent UpdateDataInculdesDetail<TDetail>(TEntity entity, Type detailType, List<Dictionary<string, object>> detailDics, List<object> delKeys) where TDetail : class, new()
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                string name = typeof(TEntity).GetMainIdByDetail();
                string reslut = detailType.ValidateDicInEntity(detailDics, true, new string[] { name });
                if (reslut != string.Empty)
                    return WebResponseContent.Instance.Error(reslut);
                List<TDetail> list = detailDics.DicToIEnumerable<TDetail>();
                List<object> dynamicDelKeys = new List<object>();
                if (delKeys != null)
                {
                    for (int i = 0; i < delKeys.Count; i++)
                    {
                        dynamicDelKeys.Add(delKeys[i]);
                    }
                }
                List<TDetail> updateRows = new List<TDetail>();
                List<TDetail> addRows = new List<TDetail>();
                for (int i = 0; i < list.Count; i++)
                {
                    object detailId = typeof(TDetail).GetPropertyValue(list[i], typeof(TDetail).GetKeyName());
                    if (detailId != null)
                    {
                        if (detailId.ToString() != "0")
                        {
                            updateRows.Add(list[i]);
                        }
                        else
                        {
                            addRows.Add(list[i]);
                        }
                    }
                }
                object mainId = typeof(TEntity).GetPropertyValue(entity, typeof(TEntity).GetKeyName());
                if (mainId != null)
                {
                    ((SqlSugarScope)BaseDal.Db).BeginTran();
                    if (dynamicDelKeys.Count > 0)
                        BaseDal.Db.Deleteable<object>().AS(detailType.Name).Where($"{detailType.GetKeyName()} in (@id)", new { id = dynamicDelKeys.ToArray() }).ExecuteCommandHasChange();
                    BaseDal.Db.Updateable(entity).ExecuteCommandHasChange();
                    BaseDal.Db.Updateable(updateRows).ExecuteCommand();
                    for (int i = 0; i < addRows.Count; i++)
                    {
                        TDetail detail = addRows[i];
                        typeof(TDetail).SetDetailId(detail, mainId, name);
                    }
                    BaseDal.Db.Insertable(addRows).ExecuteCommand();
                    ((SqlSugarScope)BaseDal.Db).CommitTran();
                    content = WebResponseContent.Instance.OK();
                }
                else
                {
                    content = WebResponseContent.Instance.Error("未找到主表主键值");
                }
            }
            catch (Exception ex)
            {
                ((SqlSugarScope)BaseDal.Db).RollbackTran();
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="key">主键</param>
        /// <returns></returns>
        public virtual WebResponseContent DeleteData(object key)
        {
            try
            {
                return BaseDal.DeleteDataById(key) ? WebResponseContent.Instance.OK() : WebResponseContent.Instance.Error();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="keys">主键数组</param>
        /// <returns></returns>
        public virtual WebResponseContent DeleteData(object[] keys)
        {
            try
            {
                if (typeof(TEntity).GetNavigatePro() == null)
                    return BaseDal.DeleteDataByIds(keys) ? WebResponseContent.Instance.OK() : WebResponseContent.Instance.Error();
                else
                {
                    if (keys != null)
                    {
                        Type detailType = typeof(TEntity).GetDetailType();
                        string name = typeof(TEntity).GetMainIdByDetail();
                        List<object> dynamicDelKeys = new List<object>();
                        for (int i = 0; i < keys.Length; i++)
                        {
                            dynamicDelKeys.Add(keys[i]);
                        }
                        ((SqlSugarScope)BaseDal.Db).BeginTran();
                        if (dynamicDelKeys.Count > 0)
                            BaseDal.Db.Deleteable<object>().AS(detailType.Name).Where($"{name} in (@id)", new { id = dynamicDelKeys.ToArray() }).ExecuteCommandHasChange();
                        BaseDal.DeleteDataByIds(keys);
                        ((SqlSugarScope)BaseDal.Db).CommitTran();
                        return WebResponseContent.Instance.OK();
                    }
                    else
                    {
                        return WebResponseContent.Instance.Error("参数错误");
                    }
                }
            }
            catch (Exception ex)
            {
                ((SqlSugarScope)BaseDal.Db).RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="entity">单个实体</param>
        /// <returns></returns>
        public virtual WebResponseContent DeleteData(TEntity entity)
        {
            try
            {
                return BaseDal.DeleteData(entity) ? WebResponseContent.Instance.OK() : WebResponseContent.Instance.Error();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// åˆ é™¤æ•°æ®
        /// </summary>
        /// <param name="entities">实体集合</param>
        /// <returns></returns>
        public virtual WebResponseContent DeleteData(List<TEntity> entities)
        {
            try
            {
                return BaseDal.DeleteData(entities) ? WebResponseContent.Instance.OK() : WebResponseContent.Instance.Error();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// å¯¼å‡ºæ•°æ®
        /// </summary>
        /// <param name="pageData"></param>
        /// <returns></returns>
        public virtual WebResponseContent Export(PageDataOptions options)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Type t = typeof(TEntity);
                string savePath = AppDomain.CurrentDomain.BaseDirectory + $"ExcelExport";
                IExporter exporter = new ExcelExporter();
                string wheres = ValidatePageOptions(options);
                //获取排序字段
                Dictionary<string, OrderByType> orderbyDic = GetPageDataSort(options, TProperties);
                List<TEntity> entities = BaseDal.QueryData(wheres, orderbyDic);
                byte[] data = exporter.ExportAsByteArray(entities).Result;
                string fileName = "";
                SugarTable sugarTable = t.GetCustomAttribute<SugarTable>();
                if (sugarTable != null)
                {
                    fileName = sugarTable.TableDescription + ".xlsx";
                }
                else
                {
                    fileName = nameof(TEntity) + ".xlsx";
                }
                FileHelper.WriteFile(savePath, fileName, data);
                content = WebResponseContent.Instance.OK(data: savePath + "\\" + fileName);
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// å¯¼å…¥æ•°æ®
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        public virtual WebResponseContent Import(List<IFormFile> files)
        {
            try
            {
                if (files == null || files.Count == 0)
                    return new WebResponseContent { Status = true, Message = "请选择上传的文件" };
                Microsoft.AspNetCore.Http.IFormFile formFile = files[0];
                string dicPath = AppDomain.CurrentDomain.BaseDirectory + $"ExcelImprot/{DateTime.Now.ToString("yyyMMdd")}/{typeof(TEntity).Name}/";
                if (!Directory.Exists(dicPath)) Directory.CreateDirectory(dicPath);
                string fileName = $"{Guid.NewGuid()}_{formFile.FileName}";
                dicPath = $"{dicPath}{fileName}";
                using (FileStream stream = new FileStream(dicPath, FileMode.Create))
                {
                    formFile.CopyTo(stream);
                }
                ExcelImporter importer = new ExcelImporter();
                ImportResult<TEntity> importResult = importer.Import<TEntity>(dicPath, "").Result;
                if (importResult.HasError)
                {
                    return WebResponseContent.Instance.Error(importResult.TemplateErrors.Serialize());
                }
                BaseDal.AddData(importResult.Data.ToList());
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// ä¸Šä¼ æ–‡ä»¶
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        public virtual WebResponseContent Upload(List<IFormFile> files)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// æ¨¡æ¿ä¸‹è½½
        /// </summary>
        /// <returns></returns>
        public virtual WebResponseContent DownLoadTemplate()
        {
            WebResponseContent content = new WebResponseContent();
            Type t = typeof(TEntity);
            IExporter exporter = new ExcelExporter();
            byte[] data = exporter.ExportHeaderAsByteArray(new TEntity()).Result;
            string fileName = "";
            SugarTable sugarTable = t.GetCustomAttribute<SugarTable>();
            if (sugarTable != null)
            {
                fileName = sugarTable.TableDescription + "导入模板.xlsx";
            }
            else
            {
                fileName = nameof(TEntity) + "导入模板.xlsx";
            }
            string savePath = AppDomain.CurrentDomain.BaseDirectory + $"ExcelImprotTemplate";
            FileHelper.WriteFile(savePath, fileName, data);
            content = WebResponseContent.Instance.OK(data: savePath + "\\" + fileName);
            return content;
        }
        public WebResponseContent ExportSeedData()
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                string seedDataFolder = $"WIDESEAWCS_DB.DBSeed.Json/{typeof(TEntity).Name}.tsv";
                List<TEntity> deviceInfos = BaseDal.QueryData();
                string str = JsonConvert.SerializeObject(deviceInfos, Formatting.Indented);
                List<Dictionary<string, object>> keyValuePairs = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(str);
                FileHelper.WriteFileAndDelOldFile($"{AppDomain.CurrentDomain.BaseDirectory}wwwroot/{seedDataFolder}", str);
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/BaseServices/ServiceFunFilter.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,234 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.BaseServices
{
    public abstract class ServiceFunFilter<T> where T : class
    {
        /// <summary>
        /// 2020.08.15是否开启多租户功能
        /// ä½¿ç”¨æ–¹æ³•见文档或SellOrderService.cs
        /// </summary>
        protected bool IsMultiTenancy { get; set; }
        /// <summary>
        /// æŸ¥è¯¢ç•Œé¢table ç»Ÿè®¡ã€æ±‚和、平均值等
        /// å®žçŽ°æ–¹å¼
        ///SummaryExpress = (IQueryable<App_TransactionAvgPrice> queryable) =>
        //                {
        //                return queryable.GroupBy(x => 1).Select(x => new
        //                {
        //                    AvgPrice = x.Average(o => o.AvgPrice),
        //                    Enable = x.Sum(o => o.Enable)
        //            }).FirstOrDefault();
        //};
        /// </summary>
        //   protected Func<IGrouping<T, T>, object> SummaryExpress = null;
        protected Func<IQueryable<T>, object> SummaryExpress = null;
        /// <summary>
        /// æ˜Žç»†table ç»Ÿè®¡ã€æ±‚和、平均值等
        /// </summary>
        /// <typeparam name="Detail"></typeparam>
        /// <param name="queryeable"></param>
        /// <returns></returns>
        //protected abstract object GetDetailSummary<Detail>(IQueryable<Detail> queryeable);
        /// <summary>
        /// æ˜¯å¦å¼€å¯ç”¨æˆ·æ•°æ®æƒé™,true=用户只能操作自己(及下级角色)创建的数据,如:查询、删除、修改等操作
        /// æ³¨æ„ï¼šéœ€è¦åœ¨ä»£ç ç”Ÿæˆå™¨ç•Œé¢é€‰æ‹©ã€æ˜¯ã€‘及生成Model才会生效)
        /// </summary>
        protected bool LimitCurrentUserPermission { get; set; } = false;
        ///默认导出最大表数量:0不限制
        protected int Limit { get; set; } = 0;
        /// <summary>
        /// é»˜è®¤ä¸Šä¼ æ–‡ä»¶å¤§å°é™åˆ¶3M
        /// </summary>
        protected int LimitUpFileSizee { get; set; } = 3;
        /// <summary>
        /// 2020.08.15添加自定义原生查询sql,这个对于不想写表达式关联或者复杂查询非常有用
        /// ä¾‹ï¼šQuerySql=$"select * from tb1 as a where  a.name='xxxx' x.id in (select b.id from tb2 b)";
        ///  select * è¿™é‡Œå¯ä»¥è‡ªå®šä¹‰ï¼Œä½†select å¿…须返回表所有的列,不能少
        /// </summary>
        protected string QuerySql = null;
        /// <summary>
        /// æŸ¥è¯¢å‰,对现在有的查询字符串条件增加或删除
        /// </summary>
        protected Action<List<SearchParameters>> QueryRelativeList { get; set; }
        //查询前,在现有的查询条件上通过表达式修改查询条件
        protected Func<IQueryable<T>, IQueryable<T>> QueryRelativeExpression { get; set; }
        /// <summary>
        /// æŒ‡å®šæŸ¥è¯¢çš„列,格式:Expression<Func<T, object>> exp = x => new { x.字段1, x.字段2 }(暂时未启用)
        /// </summary>
        protected Expression<Func<T, object>> Columns { get; set; }
        /// <summary>
        /// è®¾ç½®æŸ¥è¯¢æŽ’序参数及方式,参数格式为:
        ///  Expression<Func<T, Dictionary<object, bool>>> orderBy = x => new Dictionary<object, QueryOrderBy>()
        ///            {{ x.ID, QueryOrderBy.Asc },{ x.DestWarehouseName, QueryOrderBy.Desc } };
        /// è¿”回的是new Dictionary<object, bool>(){{}}key为排序字段,QueryOrderBy为排序方式
        /// </summary>
        protected Expression<Func<T, Dictionary<object, OrderByType>>> OrderByExpression;
        /// <summary>
        /// è®¾ç½®æŸ¥è¯¢çš„表名(已弃用)
        /// </summary>
        protected string TableName { get; set; }
        /// <summary>
        /// é¡µé¢æŸ¥è¯¢æˆ–导出,从数据库查询出来的结果
        /// </summary>
        protected Action<PageGridData<T>> GetPageDataOnExecuted;
        /// <summary>
        /// è°ƒç”¨æ–°å»ºå¤„理前(SaveModel为传入的原生数据)
        /// </summary>
        protected Func<SaveModel, WebResponseContent> AddOnExecute;
        /// <summary>
        /// è°ƒç”¨æ–°å»ºä¿å­˜æ•°æ®åº“前处理(已将提交的原生数据转换成了对象)
        ///  Func<T, object,ResponseData>  T为主表数据,object为明细数据(如果需要使用明细对象,请用 object as List<T>转换)
        /// </summary>
        protected Func<T, object, WebResponseContent> AddOnExecuting;
        /// <summary>
        /// è°ƒç”¨æ–°å»ºä¿å­˜æ•°æ®åº“后处理。
        /// **实现当前方法时,内部默认已经开启事务,如果实现的方法操作的是同一数据库,则不需要在AddOnExecuted中事务
        ///  Func<T, object,ResponseData>  T为主表数据,object为明细数据(如果需要使用明细对象,请用 object as List<T>转换)
        ///  æ­¤å¤„已开启了DbContext事务(重点),如果还有其他业务处事,直接在这里写EF代码,不需要再开启事务
        /// å¦‚果执行的是手写sql请用repository.DbContext.Database.ExecuteSqlCommand()或 repository.DbContext.Set<T>().FromSql执行具体sql语句
        /// </summary>
        protected Func<T, object, WebResponseContent> AddOnExecuted;
        /// <summary>
        /// è¿›å…¥å®¡æ‰¹æµç¨‹æ–¹æ³•之前
        /// </summary>
        protected Func<T, bool> AddWorkFlowExecuting;
        /// <summary>
        /// å†™å…¥å®¡æ‰¹æµç¨‹æ•°æ®ä¹‹åŽ
        /// list:审批的人id
        /// </summary>
        protected Action<T, List<int>> AddWorkFlowExecuted;
        /// <summary>
        /// è°ƒç”¨æ›´æ–°æ–¹æ³•前处理(SaveModel为传入的原生数据)
        /// </summary>
        protected Func<SaveModel, WebResponseContent> UpdateOnExecute;
        /// <summary>
        /// è°ƒç”¨æ›´æ–°æ–¹æ³•前处理(SaveModel为传入的原生数据)
        /// </summary>
        protected Func<SaveModel, List<string>> UpdateIgnoreColOnExecute;
        /// <summary>
        ///  è°ƒç”¨æ›´æ–°æ–¹æ³•保存数据库前处理
        ///  (已将提交的原生数据转换成了对象,将明细新增、修改、删除的数据分别用object1/2/3标识出来 )
        ///  T=更新的主表对象
        ///  object1=为新增明细的对象,使用时将object as List<T>转换一下
        ///  object2=为更新明细的对象
        ///  List<object>=为删除的细的对象Key
        /// </summary>
        protected Func<T, object, object, List<object>, WebResponseContent> UpdateOnExecuting;
        /// <summary>
        ///  è°ƒç”¨æ›´æ–°æ–¹æ³•保存数据库后处理
        ///   **实现当前方法时,内部默认已经开启事务,如果实现的方法操作的是同一数据库,则不需要在UpdateOnExecuted中事务
        ///  (已将提交的原生数据转换成了对象,将明细新增、修改、删除的数据分别用object1/2/3标识出来 )
        ///  T=更新的主表对象
        ///  object1=为新增明细的对象,使用时将object as List<T>转换一下
        ///  object2=为更新明细的对象
        ///  List<object>=为删除的细的对象Key
        /// æ­¤å¤„已开启了DbContext事务(重点),如果还有其他业务处事,直接在这里写EF代码,不需要再开启事务
        /// å¦‚果执行的是手写sql请用repository.DbContext.Database.ExecuteSqlCommand()或 repository.DbContext.Set<T>().FromSql执行具体sql语句
        /// </summary>
        protected Func<T, object, object, List<object>, WebResponseContent> UpdateOnExecuted;
        /// <summary>
        /// åˆ é™¤å‰å¤„理,object[]准备删除的主键
        /// </summary>
        protected Func<object[], WebResponseContent> DelOnExecuting;
        /// <summary>
        /// åˆ é™¤åŽå¤„理,object[]已删除的主键,此处已开启了DbContext事务(重点),如果还有其他业务处事,直接在这里写EF代码,不需要再开启事务
        /// å¦‚果执行的是手写sql请用repository.DbContext.Database.ExecuteSqlCommand()或 repository.DbContext.Set<T>().FromSql执行具体sql语句
        /// </summary>
        protected Func<object[], WebResponseContent> DelOnExecuted;
        /// <summary>
        /// å®¡æ ¸å‰å¤„理
        /// </summary>
        protected Func<List<T>, WebResponseContent> AuditOnExecuting;
        /// <summary>
        /// å®¡æ ¸åŽå¤„理
        /// </summary>
        protected Func<List<T>, WebResponseContent> AuditOnExecuted;
        /// <summary>
        ///导出前处理,DataTable导出的表数据
        ///List<T>导出的数据, List<string>忽略不需要导出的字段
        ///此方法不建议使用,由下面ExportColumns委托替代2020.05.07
        /// </summary>
        protected Func<List<T>, List<string>, WebResponseContent> ExportOnExecuting;
        /// <summary>
        /// 2020.05.07
        /// å¯¼å‡ºè¡¨æ•°æ®(界面上导出操作),指定要导出的列,格式:Expression<Func<T, object>> exp = x => new { x.字段1, x.字段2 }
        /// </summary>
        protected Expression<Func<T, object>> ExportColumns { get; set; }
        /// <summary>
        /// 2020.05.07
        /// å¯¼å‡ºä¸‹è½½æ¨¡æ¿ï¼ŒæŒ‡å®šè¦å¯¼å‡ºçš„æ¨¡æ¿åˆ—,格式:Expression<Func<T, object>> exp = x => new { x.字段1, x.字段2 }
        /// </summary>
        protected Expression<Func<T, object>> DownLoadTemplateColumns { get; set; }
        /// <summary>
        /// å¯¼å…¥ä¿å­˜åŽ
        /// </summary>
        protected Func<List<T>, WebResponseContent> ImportOnExecuted;
        /// <summary>
        /// å¯¼å…¥ä¿å­˜å‰
        /// </summary>
        protected Func<List<T>, WebResponseContent> ImportOnExecuting;
        /// <summary>
        /// å¯¼å…¥æ—¶ä¸éªŒè¯ä¸‹æ‹‰æ¡†æ•°æ®æºçš„字段值2023.05.03
        /// </summary>
        protected Expression<Func<T, object>> ImportIgnoreSelectValidationColumns;
        /// <summary>
        /// 2022.06.20增加原生excel读取方法(导入时可以自定义读取excel内容)
        /// string=当前读取的excel单元格的值
        /// ExcelWorksheet=excel对象
        /// ExcelRange当前excel单元格对象
        /// int=当前读取的第几数
        /// int=当前读取的第几列
        /// string=返回的值
        /// </summary>
        //protected Func<string, ExcelWorksheet, ExcelRange, int, int, string> ImportOnReadCellValue;
        /// <summary>
        /// è‡ªå®šä¹‰ä¸Šä¼ æ–‡ä»¶å¤¹(2022.10.07)
        /// </summary>
        protected string UploadFolder = null;
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/Caching.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,351 @@
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
namespace WIDESEAWCS_Core.Caches
{
    /// <summary>
    /// å®žä¾‹åŒ–缓存接口ICaching
    /// </summary>
    public class Caching : ICaching
    {
        private readonly IDistributedCache _cache;
        public Caching(IDistributedCache cache)
        {
            _cache = cache;
        }
        private byte[] GetBytes<T>(T source)
        {
            return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(source));
        }
        public IDistributedCache Cache => _cache;
        public void AddCacheKey(string cacheKey)
        {
            var res = _cache.GetString(CacheConst.KeyAll);
            var allkeys = string.IsNullOrWhiteSpace(res) ? new List<string>() : JsonConvert.DeserializeObject<List<string>>(res);
            if (!allkeys.Any(m => m == cacheKey))
            {
                allkeys.Add(cacheKey);
                _cache.SetString(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
            }
        }
        /// <summary>
        /// å¢žåŠ ç¼“å­˜Key
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public async Task AddCacheKeyAsync(string cacheKey)
        {
            var res = await _cache.GetStringAsync(CacheConst.KeyAll);
            var allkeys = string.IsNullOrWhiteSpace(res) ? new List<string>() : JsonConvert.DeserializeObject<List<string>>(res);
            if (!allkeys.Any(m => m == cacheKey))
            {
                allkeys.Add(cacheKey);
                await _cache.SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
            }
        }
        public void DelByPattern(string key)
        {
            var allkeys = GetAllCacheKeys();
            if (allkeys == null) return;
            var delAllkeys = allkeys.Where(u => u.Contains(key)).ToList();
            delAllkeys.ForEach(u => { _cache.Remove(u); });
            // æ›´æ–°æ‰€æœ‰ç¼“存键
            allkeys = allkeys.Where(u => !u.Contains(key)).ToList();
            _cache.SetString(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
        }
        /// <summary>
        /// åˆ é™¤æŸç‰¹å¾å…³é”®å­—缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task DelByPatternAsync(string key)
        {
            var allkeys = await GetAllCacheKeysAsync();
            if (allkeys == null) return;
            var delAllkeys = allkeys.Where(u => u.Contains(key)).ToList();
            delAllkeys.ForEach(u => { _cache.Remove(u); });
            // æ›´æ–°æ‰€æœ‰ç¼“存键
            allkeys = allkeys.Where(u => !u.Contains(key)).ToList();
            await _cache.SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
        }
        public void DelCacheKey(string cacheKey)
        {
            var res = _cache.GetString(CacheConst.KeyAll);
            var allkeys = string.IsNullOrWhiteSpace(res) ? new List<string>() : JsonConvert.DeserializeObject<List<string>>(res);
            if (allkeys.Any(m => m == cacheKey))
            {
                allkeys.Remove(cacheKey);
                _cache.SetString(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
            }
        }
        /// <summary>
        /// åˆ é™¤ç¼“å­˜
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public async Task DelCacheKeyAsync(string cacheKey)
        {
            var res = await _cache.GetStringAsync(CacheConst.KeyAll);
            var allkeys = string.IsNullOrWhiteSpace(res) ? new List<string>() : JsonConvert.DeserializeObject<List<string>>(res);
            if (allkeys.Any(m => m == cacheKey))
            {
                allkeys.Remove(cacheKey);
                await _cache.SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
            }
        }
        public bool Exists(string cacheKey)
        {
            var res = _cache.Get(cacheKey);
            return res != null;
        }
        /// <summary>
        /// æ£€æŸ¥ç»™å®š key æ˜¯å¦å­˜åœ¨
        /// </summary>
        /// <param name="cacheKey">键</param>
        /// <returns></returns>
        public async Task<bool> ExistsAsync(string cacheKey)
        {
            var res = await _cache.GetAsync(cacheKey);
            return res != null;
        }
        public List<string> GetAllCacheKeys()
        {
            var res = _cache.GetString(CacheConst.KeyAll);
            return string.IsNullOrWhiteSpace(res) ? null : JsonConvert.DeserializeObject<List<string>>(res);
        }
        /// <summary>
        /// èŽ·å–æ‰€æœ‰ç¼“å­˜åˆ—è¡¨
        /// </summary>
        /// <returns></returns>
        public async Task<List<string>> GetAllCacheKeysAsync()
        {
            var res = await _cache.GetStringAsync(CacheConst.KeyAll);
            return string.IsNullOrWhiteSpace(res) ? null : JsonConvert.DeserializeObject<List<string>>(res);
        }
        public T Get<T>(string cacheKey)
        {
            var res = _cache.Get(cacheKey);
            return res == null ? default : JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(res));
        }
        /// <summary>
        /// èŽ·å–ç¼“å­˜
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public async Task<T> GetAsync<T>(string cacheKey)
        {
            var res = await _cache.GetAsync(cacheKey);
            return res == null ? default : JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(res));
        }
        public object Get(Type type, string cacheKey)
        {
            var res = _cache.Get(cacheKey);
            return res == null ? default : JsonConvert.DeserializeObject(Encoding.UTF8.GetString(res), type);
        }
        public async Task<object> GetAsync(Type type, string cacheKey)
        {
            var res = await _cache.GetAsync(cacheKey);
            return res == null ? default : JsonConvert.DeserializeObject(Encoding.UTF8.GetString(res), type);
        }
        public string GetString(string cacheKey)
        {
            return _cache.GetString(cacheKey);
        }
        /// <summary>
        /// èŽ·å–ç¼“å­˜
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public async Task<string> GetStringAsync(string cacheKey)
        {
            return await _cache.GetStringAsync(cacheKey);
        }
        public void Remove(string key)
        {
            _cache.Remove(key);
            DelCacheKey(key);
        }
        /// <summary>
        /// åˆ é™¤ç¼“å­˜
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task RemoveAsync(string key)
        {
            await _cache.RemoveAsync(key);
            await DelCacheKeyAsync(key);
        }
        public void RemoveAll()
        {
            var catches = GetAllCacheKeys();
            foreach (var @catch in catches) Remove(@catch);
            catches.Clear();
            _cache.SetString(CacheConst.KeyAll, JsonConvert.SerializeObject(catches));
        }
        public async Task RemoveAllAsync()
        {
            var catches = await GetAllCacheKeysAsync();
            foreach (var @catch in catches) await RemoveAsync(@catch);
            catches.Clear();
            await _cache.SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(catches));
        }
        public void Set<T>(string cacheKey, T value, TimeSpan? expire = null)
        {
            _cache.Set(cacheKey, GetBytes(value),
                expire == null
                    ? new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6) }
                    : new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = expire });
            AddCacheKey(cacheKey);
        }
        /// <summary>
        /// å¢žåŠ å¯¹è±¡ç¼“å­˜
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task SetAsync<T>(string cacheKey, T value)
        {
            await _cache.SetAsync(cacheKey, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)),
                new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6) });
            await AddCacheKeyAsync(cacheKey);
        }
        /// <summary>
        /// å¢žåŠ å¯¹è±¡ç¼“å­˜,并设置过期时间
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="value"></param>
        /// <param name="expire"></param>
        /// <returns></returns>
        public async Task SetAsync<T>(string cacheKey, T value, TimeSpan expire)
        {
            await _cache.SetAsync(cacheKey, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)),
                new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = expire });
            await AddCacheKeyAsync(cacheKey);
        }
        public void SetPermanent<T>(string cacheKey, T value)
        {
            _cache.Set(cacheKey, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)));
            AddCacheKey(cacheKey);
        }
        public async Task SetPermanentAsync<T>(string cacheKey, T value)
        {
            await _cache.SetAsync(cacheKey, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value)));
            await AddCacheKeyAsync(cacheKey);
        }
        public void SetString(string cacheKey, string value, TimeSpan? expire = null)
        {
            if (expire == null)
                _cache.SetString(cacheKey, value, new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6) });
            else
                _cache.SetString(cacheKey, value, new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = expire });
            AddCacheKey(cacheKey);
        }
        /// <summary>
        /// å¢žåŠ å­—ç¬¦ä¸²ç¼“å­˜
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public async Task SetStringAsync(string cacheKey, string value)
        {
            await _cache.SetStringAsync(cacheKey, value, new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6) });
            await AddCacheKeyAsync(cacheKey);
        }
        /// <summary>
        /// å¢žåŠ å­—ç¬¦ä¸²ç¼“å­˜,并设置过期时间
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="value"></param>
        /// <param name="expire"></param>
        /// <returns></returns>
        public async Task SetStringAsync(string cacheKey, string value, TimeSpan expire)
        {
            await _cache.SetStringAsync(cacheKey, value, new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = expire });
            await AddCacheKeyAsync(cacheKey);
        }
        /// <summary>
        /// ç¼“存最大角色数据范围
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="dataScopeType"></param>
        /// <returns></returns>
        public async Task SetMaxDataScopeType(long userId, int dataScopeType)
        {
            var cacheKey = CacheConst.KeyMaxDataScopeType + userId;
            await SetStringAsync(cacheKey, dataScopeType.ToString());
            await AddCacheKeyAsync(cacheKey);
        }
        /// <summary>
        ///  æ ¹æ®çˆ¶é”®æ¸…空
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task DelByParentKeyAsync(string key)
        {
            var allkeys = await GetAllCacheKeysAsync();
            if (allkeys == null) return;
            var delAllkeys = allkeys.Where(u => u.StartsWith(key)).ToList();
            delAllkeys.ForEach(Remove);
            // æ›´æ–°æ‰€æœ‰ç¼“存键
            allkeys = allkeys.Where(u => !u.StartsWith(key)).ToList();
            await SetStringAsync(CacheConst.KeyAll, JsonConvert.SerializeObject(allkeys));
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICacheService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Caches
{
    public interface ICacheService : IDisposable
    {
        /// <summary>
        /// éªŒè¯ç¼“存项是否存在
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        bool Exists(string key);
        /// <summary>
        /// æ·»åŠ ç¼“å­˜
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">缓存Value</param>
        /// <param name="expiresIn">缓存时长</param>
        /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) //new TimeSpan(0, 60, 0);</param>
        /// <returns></returns>
        bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false);
        bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false);
        void AddOrUpdate(string key, string value, int expireSeconds = -1, bool isSliding = false);
        /// <summary>
        /// åˆ é™¤ç¼“å­˜
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        bool Remove(string key);
        /// <summary>
        /// æ‰¹é‡åˆ é™¤ç¼“å­˜
        /// </summary>
        /// <param name="key">缓存Key集合</param>
        /// <returns></returns>
        void Remove(IEnumerable<string> keys);
        /// <summary>
        /// èŽ·å–ç¼“å­˜
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        T Get<T>(string key) where T : class;
        /// <summary>
        /// èŽ·å–ç¼“å­˜
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        string Get(string key);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/ICaching.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Caches
{
    /// <summary>
    /// ç¼“存抽象接口,基于IDistributedCache封装
    /// </summary>
    public interface ICaching
    {
        public IDistributedCache Cache { get; }
        void AddCacheKey(string cacheKey);
        Task AddCacheKeyAsync(string cacheKey);
        void DelByPattern(string key);
        Task DelByPatternAsync(string key);
        void DelCacheKey(string cacheKey);
        Task DelCacheKeyAsync(string cacheKey);
        bool Exists(string cacheKey);
        Task<bool> ExistsAsync(string cacheKey);
        List<string> GetAllCacheKeys();
        Task<List<string>> GetAllCacheKeysAsync();
        T Get<T>(string cacheKey);
        Task<T> GetAsync<T>(string cacheKey);
        object Get(Type type, string cacheKey);
        Task<object> GetAsync(Type type, string cacheKey);
        string GetString(string cacheKey);
        Task<string> GetStringAsync(string cacheKey);
        void Remove(string key);
        Task RemoveAsync(string key);
        void RemoveAll();
        Task RemoveAllAsync();
        void Set<T>(string cacheKey, T value, TimeSpan? expire = null);
        Task SetAsync<T>(string cacheKey, T value);
        Task SetAsync<T>(string cacheKey, T value, TimeSpan expire);
        void SetPermanent<T>(string cacheKey, T value);
        Task SetPermanentAsync<T>(string cacheKey, T value);
        void SetString(string cacheKey, string value, TimeSpan? expire = null);
        Task SetStringAsync(string cacheKey, string value);
        Task SetStringAsync(string cacheKey, string value, TimeSpan expire);
        Task DelByParentKeyAsync(string key);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Caches/MemoryCacheService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,113 @@
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Caches
{
    public class MemoryCacheService : ICacheService
    {
        protected IMemoryCache _cache;
        public MemoryCacheService(IMemoryCache cache)
        {
            _cache = cache;
        }
        public bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false)
        {
            return AddObject(key, value, expireSeconds, isSliding);
        }
        public bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false)
        {
            if (expireSeconds != -1)
            {
                _cache.Set(key,
                    value,
                    new MemoryCacheEntryOptions()
                    .SetSlidingExpiration(new TimeSpan(0, 0, expireSeconds))
                    );
            }
            else
            {
                _cache.Set(key, value);
            }
            return true;
        }
        public void AddOrUpdate(string key, string value, int expireSeconds = -1, bool isSliding = false)
        {
            if (!string.IsNullOrEmpty(Get(key)))
            {
                Remove(key);
                Add(key, value, expireSeconds, isSliding);
            }
            else
            {
                Add(key, value, expireSeconds, isSliding);
            }
        }
        public void Dispose()
        {
            if (_cache != null)
                _cache.Dispose();
            GC.SuppressFinalize(this);
        }
        public bool Exists(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            return _cache.Get(key) != null;
        }
        public T Get<T>(string key) where T : class
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            return _cache.Get(key) as T;
        }
        public string Get(string key)
        {
            try
            {
                return _cache.Get(key)?.ToString();
            }
            catch
            {
                return string.Empty;
            }
        }
        public bool Remove(string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }
            _cache.Remove(key);
            return !Exists(key);
        }
        public void Remove(IEnumerable<string> keys)
        {
            if (keys == null)
            {
                throw new ArgumentNullException(nameof(keys));
            }
            keys.ToList().ForEach(item => _cache.Remove(item));
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/AppSecret.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Const
{
    /// <summary>
    /// ç§˜é’¥é…ç½®
    /// </summary>
    public struct AppSecret
    {
        public const string JWT = "BB3647441FFA4B5DB4E64A29B53CE525";
        public const string Audience = "WIDESEAWCS_WMS";
        public const string Issuer = "WIDESEAWCS_WMS_Owner";
        public const string TokenHeaderName = "Authorization";
        public const string User = "C5ABA9E202D94C43A3CA66002BF77FAF";
        public const string DB = "3F8B7B38AD3D484A89ACA513CBD79F36";
        //连接字符串
        //Data Source=.;Initial Catalog=WIDESEAWCS_DB_2;User ID=sa;Password=P@ssw0rd;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/CacheConst.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Const
{
    /// <summary>
    /// ç¼“存相关常量
    /// </summary>
    public class CacheConst
    {
        /// <summary>
        /// ç”¨æˆ·ç¼“å­˜
        /// </summary>
        public const string KeyUser = "user:";
        /// <summary>
        /// ç”¨æˆ·éƒ¨é—¨ç¼“å­˜
        /// </summary>
        public const string KeyUserDepart = "userDepart:";
        /// <summary>
        /// èœå•缓存
        /// </summary>
        public const string KeyMenu = "menu:";
        /// <summary>
        /// èœå•
        /// </summary>
        public const string KeyPermissions = "permissions";
        /// <summary>
        /// æƒé™ç¼“å­˜
        /// </summary>
        public const string KeyPermission = "permission:";
        /// <summary>
        /// æŽ¥å£è·¯ç”±
        /// </summary>
        public const string KeyModules = "modules";
        /// <summary>
        /// ç³»ç»Ÿé…ç½®
        /// </summary>
        public const string KeySystemConfig = "sysConfig";
        /// <summary>
        /// æŸ¥è¯¢è¿‡æ»¤å™¨ç¼“å­˜
        /// </summary>
        public const string KeyQueryFilter = "queryFilter:";
        /// <summary>
        /// æœºæž„Id集合缓存
        /// </summary>
        public const string KeyOrgIdList = "org:";
        /// <summary>
        /// æœ€å¤§è§’色数据范围缓存
        /// </summary>
        public const string KeyMaxDataScopeType = "maxDataScopeType:";
        /// <summary>
        /// éªŒè¯ç ç¼“å­˜
        /// </summary>
        public const string KeyVerCode = "verCode:";
        /// <summary>
        /// æ‰€æœ‰ç¼“存关键字集合
        /// </summary>
        public const string KeyAll = "keys";
        /// <summary>
        /// å®šæ—¶ä»»åŠ¡ç¼“å­˜
        /// </summary>
        public const string KeyTimer = "timer:";
        /// <summary>
        /// åœ¨çº¿ç”¨æˆ·ç¼“å­˜
        /// </summary>
        public const string KeyOnlineUser = "onlineuser:";
        /// <summary>
        /// å¸¸é‡ä¸‹æ‹‰æ¡†
        /// </summary>
        public const string KeyConstSelector = "selector:";
        /// <summary>
        /// swagger登录缓存
        /// </summary>
        public const string SwaggerLogin = "swaggerLogin:";
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/ErrorMsgConst.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Const
{
    public class ErrorMsgConst
    {
        public const string ParamIsNull = "参数无效";
        public const string EntityValueIsNull = "为必须提交项";
        public const string SugarColumnIsNull = "请配置SugarColumn属性";
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/HtmlElementType.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Const
{
    public struct HtmlElementType
    {
        public const string drop = "drop";
        public const string droplist = "droplist";
        public const string select = "select";
        public const string selectlist = "selectlist";
        public const string checkbox = "checkbox";
        public const string textarea = "textarea";
        public const string thanorequal = "thanorequal";
        public const string lessorequal = "lessorequal";
        public const string gt = "gt";
        public const string lt = "lt";
        public const string GT = ">";
        public const string LT = "<";
        public const string like = "like";
        public const string ThanOrEqual = ">=";
        public const string LessOrequal = "<=";
        public const string Contains = "in";
        public const string Equal = "=";
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/SqlDbTypeName.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Const
{
    public struct SqlDbTypeName
    {
        public const string NVarChar = "nvarchar";
        public const string VarChar = "varchar";
        public const string NChar = "nchar";
        public const string Char = "char";
        public const string Text = "text";
        public const string Int = "int";
        public const string BigInt = "bigint";
        public const string DateTime = "datetime";
        public const string Date = "date";
        public const string SmallDateTime = "smalldatetime";
        public const string SmallDate = "smalldate";
        public const string Float = "float";
        public const string Decimal = "decimal";
        public const string Double = "double";
        public const string Bit = "bit";
        public const string Bool = "bool";
        public const string UniqueIdentifier = "uniqueidentifier";
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/TenantConst.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Const
{
    public class TenantConst
    {
        public const string DBConStr = "Data Source={0};Initial Catalog={1};User ID={2};Password={3};Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Const/TenantStatus.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Const
{
    public struct TenantStatus
    {
        public const int Enable = 1;
        public const int Disable = 2;
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Core/ConfigurableOptions.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Core
{
    public static class ConfigurableOptions
    {
        /// <summary>添加选项配置</summary>
        /// <typeparam name="TOptions">选项类型</typeparam>
        /// <param name="services">服务集合</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddConfigurableOptions<TOptions>(this IServiceCollection services)
            where TOptions : class, IConfigurableOptions
        {
            Type optionsType = typeof(TOptions);
            string path = GetConfigurationPath(optionsType);
            services.Configure<TOptions>(App.Configuration.GetSection(path));
            return services;
        }
        public static IServiceCollection AddConfigurableOptions(this IServiceCollection services, Type type)
        {
            string path = GetConfigurationPath(type);
            var config = App.Configuration.GetSection(path);
            Type iOptionsChangeTokenSource = typeof(IOptionsChangeTokenSource<>);
            Type iConfigureOptions = typeof(IConfigureOptions<>);
            Type configurationChangeTokenSource = typeof(ConfigurationChangeTokenSource<>);
            Type namedConfigureFromConfigurationOptions = typeof(NamedConfigureFromConfigurationOptions<>);
            iOptionsChangeTokenSource = iOptionsChangeTokenSource.MakeGenericType(type);
            iConfigureOptions = iConfigureOptions.MakeGenericType(type);
            configurationChangeTokenSource = configurationChangeTokenSource.MakeGenericType(type);
            namedConfigureFromConfigurationOptions = namedConfigureFromConfigurationOptions.MakeGenericType(type);
            services.AddOptions();
            services.AddSingleton(iOptionsChangeTokenSource,
                Activator.CreateInstance(configurationChangeTokenSource, Options.DefaultName, config) ?? throw new InvalidOperationException());
            return services.AddSingleton(iConfigureOptions,
                Activator.CreateInstance(namedConfigureFromConfigurationOptions, Options.DefaultName, config) ?? throw new InvalidOperationException());
        }
        /// <summary>获取配置路径</summary>
        /// <param name="optionsType">选项类型</param>
        /// <returns></returns>
        public static string GetConfigurationPath(Type optionsType)
        {
            var endPath = new[] { "Option", "Options" };
            var configurationPath = optionsType.Name;
            foreach (var s in endPath)
            {
                if (configurationPath.EndsWith(s))
                {
                    return configurationPath[..^s.Length];
                }
            }
            return configurationPath;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Core/IConfigurableOptions.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Core
{
    public interface IConfigurableOptions
    {
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Core/InternalApp.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Core
{
    public static class InternalApp
    {
        internal static IServiceCollection InternalServices;
        /// <summary>根服务</summary>
        internal static IServiceProvider RootServices;
        /// <summary>获取Web主机环境</summary>
        internal static IWebHostEnvironment WebHostEnvironment;
        /// <summary>获取泛型主机环境</summary>
        internal static IHostEnvironment HostEnvironment;
        /// <summary>配置对象</summary>
        internal static IConfiguration Configuration;
        public static void ConfigureApplication(this WebApplicationBuilder wab)
        {
            HostEnvironment = wab.Environment;
            WebHostEnvironment = wab.Environment;
            InternalServices = wab.Services;
        }
        public static void ConfigureApplication(this IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public static void ConfigureApplication(this IHost app)
        {
            RootServices = app.Services;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/DB/BaseDBConfig.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,121 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Tenants;
namespace WIDESEAWCS_Core.DB
{
    public class BaseDBConfig
    {
        /* ä¹‹å‰çš„单库操作已经删除,如果想要之前的代码,可以查看我的GitHub的历史记录
         * ç›®å‰æ˜¯å¤šåº“操作,默认加载的是appsettings.json设置为true的第一个db连接。
         */
        public static List<MutiDBOperate> MutiConnectionString => MutiInitConn();
        private static string DifDBConnOfSecurity(params string[] conn)
        {
            foreach (var item in conn)
            {
                try
                {
                    if (File.Exists(item))
                    {
                        return File.ReadAllText(item).Trim();
                    }
                }
                catch (System.Exception)
                {
                }
            }
            return conn[conn.Length - 1];
        }
        public static List<MutiDBOperate> MutiInitConn()
        {
            SqlSugarScope sqlSugarClient = new SqlSugarScope(new ConnectionConfig
            {
                ConfigId = MainDb.CurrentDbConnId,
                ConnectionString = AppSettings.app(MainDb.ConnectionString).DecryptDES(AppSecret.DB),
                IsAutoCloseConnection = true,
                DbType = MainDb.DbType,
                AopEvents = new AopEvents
                {
                    OnError = x =>
                    {
                        Console.WriteLine(x.Sql);
                    }
                }
            });
            List<ExpandoObject> list = sqlSugarClient.Queryable(MainDb.TenantTableName, "x").Where(MainDb.TenantStatus, "=", TenantStatus.Enable).Select(TenantUtil.GetTenantSelectModels()).ToList();
            List<MutiDBOperate> listdatabaseSlaveDB = new List<MutiDBOperate>();
            MutiDBOperate mainDb = new MutiDBOperate()
            {
                Connection = AppSettings.app(MainDb.ConnectionString).DecryptDES(AppSecret.DB),
                ConnId = MainDb.CurrentDbConnId,
                DbType = DataBaseType.SqlServer
            };
            listdatabaseSlaveDB.Add(mainDb);
            for (int i = 0; i < list.Count; i++)
            {
                dynamic data = list[i];
                MutiDBOperate mutiDBOperate = new MutiDBOperate()
                {
                    Connection = data.ConnectionString,
                    ConnId = data.TenantId + "",
                    DbType = (DataBaseType)data.DbType,
                };
                mutiDBOperate.Connection = mutiDBOperate.Connection.DecryptDES(AppSecret.DB);
                listdatabaseSlaveDB.Add(mutiDBOperate);
            }
            return listdatabaseSlaveDB;
        }
    }
    public enum DataBaseType
    {
        MySql = 0,
        SqlServer = 1,
        Sqlite = 2,
        Oracle = 3,
        PostgreSQL = 4,
        Dm = 5,
        Kdbndp = 6,
    }
    public class MutiDBOperate
    {
        /// <summary>
        /// è¿žæŽ¥å¯ç”¨å¼€å…³
        /// </summary>
        public bool Enabled { get; set; }
        /// <summary>
        /// è¿žæŽ¥ID
        /// </summary>
        public string ConnId { get; set; }
        /// <summary>
        /// ä»Žåº“执行级别,越大越先执行
        /// </summary>
        public int HitRate { get; set; }
        /// <summary>
        /// è¿žæŽ¥å­—符串
        /// </summary>
        public string Connection { get; set; }
        /// <summary>
        /// æ•°æ®åº“类型
        /// </summary>
        public DataBaseType DbType { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/DB/MainDb.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.DB
{
    public static class MainDb
    {
        public const string CurrentDbConnId = "WIDESEA";
        public const string ConnectionStringsEncryption = "ConnectionStringsEncryption";
        public const string ConnectionString = "ConnectionString";
        public const string TenantTableName = "Sys_Tenant";
        public const string TenantStatus = "Status";
        public const string TenantId = "TenantId";
        public const string TenantName = "TenantName";
        public const string EntityNameSpace = "WIDESEAWCS_Model.Models";
        public const string TenantDbType = "DbType";
        public const string AssemblyName = "WIDESEAWCS_Model.dll";
        public static DbType DbType = DbType.SqlServer;
        public const string UserTableName = "Sys_User";
        public const string RoleId = "Role_Id";
        public const string UserName = "UserName";
        public const string UserId = "User_Id";
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/DB/Models/BaseEntity.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
using Magicodes.ExporterAndImporter.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.DB.Models
{
    public class BaseEntity
    {
        #region æ•°æ®çŠ¶æ€ç®¡ç†
        /// <summary>
        /// çŠ¶æ€ <br/>
        /// ä¸­ç«‹å­—段,某些表可使用某些表不使用
        /// </summary>
        //public bool Enabled { get; set; } = true;
        /// <summary>
        /// ä¸­ç«‹å­—段,某些表可使用某些表不使用   <br/>
        /// é€»è¾‘上的删除,非物理删除  <br/>
        /// ä¾‹å¦‚:单据删除并非直接删除
        /// </summary>
        //public bool IsDeleted { get; set; }
        /// <summary>
        /// ä¸­ç«‹å­—段 <br/>
        /// æ˜¯å¦å†…置数据
        /// </summary>
        //public bool IsInternal { get; set; }
        #endregion
        #region åˆ›å»º
        /// <summary>
        /// åˆ›å»ºè€…
        /// </summary>
        [ImporterHeader(IsIgnore = true)]
        [ExporterHeader(DisplayName = "创建者")]
        [SugarColumn(IsNullable = false, IsOnlyIgnoreUpdate = true, ColumnDescription = "创建者")]
        public string Creater { get; set; }
        /// <summary>
        /// åˆ›å»ºæ—¶é—´
        /// </summary>
        [ImporterHeader(IsIgnore = true)]
        [ExporterHeader(DisplayName = "创建时间")]
        [SugarColumn(IsNullable = false, IsOnlyIgnoreUpdate = true, ColumnDescription = "创建时间")]
        public DateTime CreateDate { get; set; } = DateTime.Now;
        #endregion
        #region ä¿®æ”¹
        /// <summary>
        /// æ›´æ–°è€…
        /// </summary>
        [ImporterHeader(IsIgnore = true)]
        [ExporterHeader(DisplayName = "修改人")]
        [SugarColumn(IsNullable = true, IsOnlyIgnoreInsert = true, ColumnDescription = "修改人")]
        public string Modifier { get; set; }
        /// <summary>
        /// ä¿®æ”¹æ—¥æœŸ
        /// </summary>
        [ImporterHeader(IsIgnore = true)]
        [ExporterHeader(DisplayName = "修改日期")]
        [SugarColumn(IsNullable = true, IsOnlyIgnoreInsert = true, ColumnDescription = "修改日期")]
        public DateTime? ModifyDate { get; set; }
        /// <summary>
        /// æ•°æ®ç‰ˆæœ¬
        /// </summary>
        //[SugarColumn(DefaultValue = "0", IsEnableUpdateVersionValidation = true)] //标识版本字段
        //public long Version { get; set; }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/DB/RepositorySetting.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
using WIDESEAWCS_Core.Tenants;
namespace WIDESEAWCS_Core.DB
{
    public class RepositorySetting
    {
        private static readonly Lazy<IEnumerable<Type>> AllEntitys = new(() =>
        {
            var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
            var referencedAssemblies = System.IO.Directory.GetFiles(path, MainDb.AssemblyName).Select(Assembly.LoadFrom).FirstOrDefault();
            return referencedAssemblies
                .GetTypes()
                .Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(BaseEntity)))
                .Where(it => it.FullName != null && it.FullName.StartsWith(MainDb.EntityNameSpace));
        });
        public static IEnumerable<Type> Entitys => AllEntitys.Value;
        /// <summary>
        /// é…ç½®å®žä½“软删除过滤器<br/>
        /// ç»Ÿä¸€è¿‡æ»¤ è½¯åˆ é™¤ æ— éœ€è‡ªå·±å†™æ¡ä»¶
        /// </summary>
        public static void SetDeletedEntityFilter(SqlSugarScopeProvider db)
        {
            //db.QueryFilter.AddTableFilter<IDeleteFilter>(it => it.IsDeleted == false);
        }
        /// <summary>
        /// é…ç½®ç§Ÿæˆ·
        /// </summary>
        public static void SetTenantEntityFilter(SqlSugarScopeProvider db)
        {
            if (App.User is not { UserId: > 0, TenantId: > 0 })
            {
                return;
            }
            //多租户 å•表
            //db.QueryFilter.AddTableFilter<ITenantEntity>(it => it.TenantId == App.User.TenantId || it.TenantId == 0);
            //多租户 å¤šè¡¨
            //db.SetTenantTable(App.User.TenantId.ToString());
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Enums/EnumHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,118 @@
using System.ComponentModel;
using System.Reflection;
namespace WIDESEA_Core.Enums
{
    public static class EnumHelper
    {
        /// <summary>
        /// æžšä¸¾è½¬å­—典集合
        /// </summary>
        /// <typeparam name="T">枚举类名称</typeparam>
        /// <param name="keyDefault">默认key值</param>
        /// <param name="valueDefault">默认value值</param>
        /// <returns>返回生成的字典集合</returns>
        public static Dictionary<string, object> EnumListDic<T>(string keyDefault, string valueDefault = "")
        {
            Dictionary<string, object> dicEnum = new Dictionary<string, object>();
            Type enumType = typeof(T);
            if (!enumType.IsEnum)
            {
                return dicEnum;
            }
            if (!string.IsNullOrEmpty(keyDefault)) //判断是否添加默认选项
            {
                dicEnum.Add(keyDefault, valueDefault);
            }
            string[] fieldstrs = Enum.GetNames(enumType); //获取枚举字段数组
            foreach (var item in fieldstrs)
            {
                string description = string.Empty;
                var field = enumType.GetField(item);
                object[] arr = field.GetCustomAttributes(typeof(DescriptionAttribute), true); //获取属性字段数组
                if (arr != null && arr.Length > 0)
                {
                    description = ((DescriptionAttribute)arr[0]).Description;   //属性描述
                }
                else
                {
                    description = item;  //描述不存在取字段名称
                }
                dicEnum.Add(description, (int)Enum.Parse(enumType, item));  //不用枚举的value值作为字典key值的原因从枚举例子能看出来,其实这边应该判断他的值不存在,默认取字段名称
            }
            return dicEnum;
        }
        /// <summary>
        /// èŽ·å–æžšä¸¾é¡¹æè¿°ä¿¡æ¯ ä¾‹å¦‚GetEnumDesc(Days.Sunday)
        /// </summary>
        /// <param name="en">枚举项 å¦‚Days.Sunday</param>
        /// <returns></returns>
        public static string GetIntegralRuleTypeEnumDesc(this Enum en)
        {
            Type type = en.GetType();
            MemberInfo[] memInfo = type.GetMember(en.ToString());
            if (memInfo != null && memInfo.Length > 0)
            {
                object[] attrs = memInfo[0].GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
                if (attrs != null && attrs.Length > 0)
                    return ((DescriptionAttribute)attrs[0]).Description;
            }
            return en.ToString();
        }
        /// <summary>
        /// èŽ·å–æžšä¸¾é›†åˆ
        /// </summary>
        /// <typeparam name="T">枚举类名称</typeparam>
        /// <returns></returns>
        public static IEnumerable<EnumModel> GetEnumList<T>()
        {
            var model = default(T);
            FieldInfo[] fieldinfo = typeof(T).GetFields();
            List<EnumModel> result = new List<EnumModel>();
            foreach (FieldInfo field in fieldinfo)
            {
                EnumModel enumModel = new EnumModel();
                if (!(Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attribute))
                {
                    enumModel.Desc = field.GetValue(model).ToString();
                }
                else
                {
                    enumModel.Desc = attribute.Description;
                }
                enumModel.Value = field.GetValue(model).GetHashCode();
                enumModel.Key = field.GetValue(model) as ValueType;
                if (field.GetValue(model).ToString() != "0")
                {
                    result.Add(enumModel);
                }
            }
            return result;
        }
        public static int GetEnumMaxValue(this Enum @enum)
        {
            Type type = @enum.GetType();
            MemberInfo[] memInfo = type.GetMember(@enum.ToString());
            return 0;
        }
    }
    public class EnumModel
    {
        /// <summary>
        /// Enum的值
        /// </summary>
        public int Value { get; set; }
        /// <summary>
        /// Enum的key
        /// </summary>
        public ValueType Key { get; set; }
        /// <summary>
        /// Enum描述
        /// </summary>
        public string Desc { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Enums/LinqExpressionType.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Enums
{
    public enum LinqExpressionType
    {
        Equal = 0,//=
        NotEqual = 1,//!=
        GreaterThan,//>
        LessThan,//<
        ThanOrEqual,//>=
        LessThanOrEqual,//<=
        In,
        Contains,//Contains
        NotContains//NotContains
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Enums/RouterInOutType.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Enums
{
    public enum RouterInOutType
    {
        /// <summary>
        /// å…¥åº“路由
        /// </summary>
        [Description("入库路由")]
        In = 1,
        /// <summary>
        /// å‡ºåº“路由
        /// </summary>
        [Description("出库路由")]
        Out = 2,
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/AllOptionRegister.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Core;
namespace WIDESEAWCS_Core.Extensions
{
    public static class AllOptionRegister
    {
        public static void AddAllOptionRegister(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            foreach (var optionType in App.EffectiveTypes.Where(s =>
                         !s.IsInterface && typeof(IConfigurableOptions).IsAssignableFrom(s)))
            {
                services.AddConfigurableOptions(optionType);
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/ApplicationSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Extensions
{
    public static class ApplicationSetup
    {
        public static void UseApplicationSetup(this WebApplication app)
        {
            app.Lifetime.ApplicationStarted.Register(() =>
            {
                App.IsRun = true;
            });
            app.Lifetime.ApplicationStopped.Register(() =>
            {
                App.IsRun = false;
                //清除日志
                //Log.CloseAndFlush();
            });
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/AutofacModuleRegister.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
using Autofac;
using Autofac.Extras.DynamicProxy;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.AOP;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.LogHelper;
namespace WIDESEAWCS_Core.Extensions
{
    public class AutofacModuleRegister : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            var basePath = AppContext.BaseDirectory;
            var cacheType = new List<Type>();
            //builder.RegisterType<LogAOP>();
            //cacheType.Add(typeof(LogAOP));
            builder.RegisterGeneric(typeof(RepositoryBase<>)).As(typeof(IRepository<>)).InstancePerDependency();//注册仓储
            builder.RegisterGeneric(typeof(ServiceBase<,>)).As(typeof(IService<>)).InstancePerDependency();//注册服务
            Type baseType = typeof(IDependency);
            List<RuntimeLibrary> compilationLibrary = DependencyContext.Default
                    .RuntimeLibraries
                    .Where(x => !x.Serviceable
                    && x.Type == "project")
                    .ToList();
            List<Assembly> assemblyList = new List<Assembly>();
            foreach (var library in compilationLibrary)
            {
                try
                {
                    string path = Path.Combine(basePath, $"{library.Name}.dll");
                    if (!File.Exists(path))
                    {
                        var msg = $"{library.Name}.dll丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin æ–‡ä»¶å¤¹ï¼Œå¹¶æ‹·è´ã€‚";
                        //log.Error(msg);
                        throw new Exception(msg);
                    }
                    assemblyList.Add(Assembly.LoadFrom(path));
                }
                catch (Exception ex)
                {
                    Console.WriteLine(library.Name + ex.Message);
                }
            }
            builder.RegisterAssemblyTypes(assemblyList.ToArray()).Where(x => !x.IsInterface && !x.IsAbstract && baseType.IsAssignableFrom(x))
                        .AsImplementedInterfaces()
                        .PropertiesAutowired()
                        .InstancePerDependency().
                        EnableInterfaceInterceptors()
                        .InterceptedBy(cacheType.ToArray());
            builder.RegisterType<UnitOfWorkManage>().As<IUnitOfWorkManage>()
               .AsImplementedInterfaces()
               .InstancePerLifetimeScope()
               .PropertiesAutowired();
            builder.RegisterType<RequestLogModel>().InstancePerLifetimeScope();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/CorsSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.Extensions
{
    /// <summary>
    /// Cors è·¨åŸŸ
    /// </summary>
    public static class CorsSetup
    {
        /// <summary>
        /// è·¨åŸŸ
        /// </summary>
        /// <param name="services"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void AddCorsSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            services.AddCors(c =>
            {
                if (!AppSettings.app(new string[] { "Cors", "EnableAllIPs" }).ObjToBool())
                {
                    c.AddPolicy(AppSettings.app(new string[] {"Cors", "PolicyName" }),
                        policy =>
                        {
                            policy
                            .WithOrigins(AppSettings.app(new string[] { "Cors", "IPs" }).Split(','))
                            .AllowAnyHeader()//Ensures that the policy allows any header.
                            .AllowAnyMethod();
                        });
                }
                else
                {
                    //允许任意跨域请求
                    c.AddPolicy(AppSettings.app(new string[] { "Cors", "PolicyName" }),
                        policy =>
                        {
                            policy
                            .SetIsOriginAllowed((host) => true)
                            .AllowAnyMethod()
                            .AllowAnyHeader()
                            .AllowCredentials();
                        });
                }
            });
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/DbSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Seed;
namespace WIDESEAWCS_Core
{
    /// <summary>
    /// Db å¯åŠ¨æœåŠ¡
    /// </summary>
    public static class DbSetup
    {
        public static void AddDbSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            services.AddScoped<DBSeed>();
            services.AddScoped<DBContext>();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/HttpContextSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.HttpContextUser;
namespace WIDESEAWCS_Core.Extensions
{
    /// <summary>
    /// HttpContext ç›¸å…³æœåŠ¡
    /// </summary>
    public static class HttpContextSetup
    {
        /// <summary>
        ///  HttpContext ç›¸å…³æœåŠ¡
        /// </summary>
        /// <param name="services"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void AddHttpContextSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddScoped<IUser, AspNetUser>();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/InitializationHostServiceSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Extensions
{
    public static class InitializationHostServiceSetup
    {
        /// <summary>
        /// åº”用初始化服务注入
        /// </summary>
        /// <param name="services"></param>
        public static void AddInitializationHostServiceSetup(this IServiceCollection services)
        {
            if (services is null)
            {
                ArgumentNullException.ThrowIfNull(nameof(services));
            }
            services.AddHostedService<SeedDataHostedService>();
            //services.AddHostedService<QuartzJobHostedService>();
            //services.AddHostedService<ConsulHostedService>();
            //services.AddHostedService<EventBusHostedService>();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/IpPolicyRateLimitSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Extensions
{
    /// <summary>
    /// IPLimit限流 å¯åŠ¨æœåŠ¡
    /// </summary>
    public static class IpPolicyRateLimitSetup
    {
        public static void AddIpPolicyRateLimitSetup(this IServiceCollection services, IConfiguration Configuration)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            // needed to store rate limit counters and ip rules
            //services.AddMemoryCache();
            //load general configuration from appsettings.json
            //services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
            // inject counter and rules stores
            //services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
            //services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
            //services.AddSingleton<IProcessingStrategy, AsyncKeyLockProcessingStrategy>();
            // inject counter and rules distributed cache stores
            //services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>();
            //services.AddSingleton<IRateLimitCounterStore, DistributedCacheRateLimitCounterStore>();
            // the clientId/clientIp resolvers use it.
            //services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            // configuration (resolvers, counter key builders)
            //services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/MemoryCacheSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using WIDESEAWCS_Core.Caches;
namespace WIDESEAWCS_Core.Extensions
{
    /// <summary>
    /// Memory缓存 å¯åŠ¨æœåŠ¡
    /// </summary>
    public static class MemoryCacheSetup
    {
        public static void AddMemoryCacheSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            services.AddSingleton<ICacheService, MemoryCacheService>();
            services.AddMemoryCache();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/MiniProfilerSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.Extensions
{
    /// <summary>
    /// MiniProfiler æ€§èƒ½åˆ†æž
    /// </summary>
    public static class MiniProfilerSetup
    {
        /// <summary>
        /// æ€§èƒ½åˆ†æž
        /// </summary>
        /// <param name="services"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void AddMiniProfilerSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            //if (AppSettings.app(new string[] { "Startup", "MiniProfiler", "Enabled" }).ObjToBool())
            //{
            services.AddMiniProfiler(options =>
            {
                options.RouteBasePath = "/profiler";
            });
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/SqlsugarSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,146 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using StackExchange.Profiling;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.AOP;
using WIDESEAWCS_Core.DB;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_Core.Seed;
namespace WIDESEAWCS_Core
{
    /// <summary>
    /// SqlSugar å¯åŠ¨æœåŠ¡
    /// </summary>
    public static class SqlsugarSetup
    {
        private static readonly MemoryCache Cache = new MemoryCache(new MemoryCacheOptions());
        public static void AddSqlsugarSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            // é»˜è®¤æ·»åŠ ä¸»æ•°æ®åº“è¿žæŽ¥
            //MainDb.CurrentDbConnId = AppSettings.app(new string[] { "MainDB" });
            services.AddHttpContextAccessor();
            // SqlSugarScope是线程安全,可使用单例注入
            // å‚考:https://www.donet5.com/Home/Doc?typeId=1181
            services.AddSingleton<ISqlSugarClient>(o =>
            {
                var memoryCache = o.GetRequiredService<IMemoryCache>();
                // è¿žæŽ¥å­—符串
                var listConfig = new List<ConnectionConfig>
                {
                    new ConnectionConfig
                    {
                        ConfigId = MainDb.CurrentDbConnId,
                        ConnectionString = DBContext.GetMainConnectionDb().Connection,
                        IsAutoCloseConnection = true,
                        DbType = MainDb.DbType,
                        AopEvents = new AopEvents
                        {
                            OnLogExecuting = (sql, p) =>
                            {
                                  Parallel.For(0, 1, e =>
                                  {
                                        MiniProfiler.Current.CustomTiming("SQL:", GetParas(p) + "【SQL语句】:" + sql);
                                  });
                                //Console.Out.WriteLine(GetParas(p));
                                //Console.Out.WriteLine(sql);
                                //Console.Out.WriteLine();
                            }
                        },
                    }
                };
                #region ä»Žåº“
                //var listConfig_Slave = new List<SlaveConnectionConfig>();
                //BaseDBConfig.MutiConnectionString.ForEach(s =>
                //{
                //    if(s.ConnId != MainDb.CurrentDbConnId)
                //    {
                //        listConfig_Slave.Add(new SlaveConnectionConfig()
                //        {
                //            HitRate = s.HitRate,
                //            ConnectionString = s.Connection
                //        });
                //    }
                //});
                //BaseDBConfig.MutiConnectionString.ForEach(m =>
                //{
                //    listConfig.Add(new ConnectionConfig()
                //    {
                //        ConfigId = m.ConnId.ObjToString().ToLower(),
                //        ConnectionString = m.Connection,
                //        DbType = (DbType)m.DbType,
                //        IsAutoCloseConnection = true,
                //        MoreSettings = new ConnMoreSettings()
                //        {
                //            //IsWithNoLockQuery = true,
                //            IsAutoRemoveDataCache = true
                //        },
                //        // ä»Žåº“
                //        //SlaveConnectionConfigs = listConfig_Slave,
                //        // è‡ªå®šä¹‰ç‰¹æ€§
                //        ConfigureExternalServices = new ConfigureExternalServices()
                //        {
                //            DataInfoCacheService = new SqlSugarMemoryCacheService(memoryCache),
                //            EntityService = (property, column) =>
                //            {
                //                if (column.IsPrimarykey && property.PropertyType == typeof(int))
                //                {
                //                    column.IsIdentity = true;
                //                }
                //            }
                //        },
                //        InitKeyType = InitKeyType.Attribute,
                //        AopEvents = new AopEvents()
                //        {
                //            OnError = x =>
                //            {
                //                Console.WriteLine(x.Sql);
                //            }
                //        }
                //    }
                //   );
                //});
                #endregion
                SqlSugarScope sqlSugarClient = new SqlSugarScope(listConfig, db =>
                {
                    db.Aop.DataExecuting = SqlSugarAop.DataExecuting;
                });
                return sqlSugarClient;
            });
        }
        private static string GetWholeSql(SugarParameter[] paramArr, string sql)
        {
            foreach (var param in paramArr)
            {
                sql.Replace(param.ParameterName, param.Value.ObjToString());
            }
            return sql;
        }
        private static string GetParas(SugarParameter[] pars)
        {
            string key = "【SQL参数】:";
            foreach (var param in pars)
            {
                key += $"{param.ParameterName}:{param.Value}\n";
            }
            return key;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Extensions/SwaggerSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,131 @@

using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
using static WIDESEAWCS_Core.Extensions.CustomApiVersion;
using Swashbuckle.AspNetCore.Filters;
using Microsoft.Extensions.Logging;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
namespace WIDESEAWCS_Core.Extensions
{
    /// <summary>
    /// Swagger
    /// </summary>
    public static class SwaggerSetup
    {
        /// <summary>
        /// Swagger
        /// </summary>
        /// <param name="services"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void AddSwaggerSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            var basePath = AppContext.BaseDirectory;
            //var basePath2 = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
            var ApiName = AppSettings.app(new string[] { "ApiName" });
            services.AddSwaggerGen(c =>
            {
                //遍历出全部的版本,做文档信息展示
                typeof(ApiVersions).GetEnumNames().ToList().ForEach(version =>
                {
                    c.SwaggerDoc(version, new OpenApiInfo
                    {
                        Version = version,
                        Title = $"{ApiName} æŽ¥å£æ–‡æ¡£â€”—{RuntimeInformation.FrameworkDescription}",
                        Description = $"{ApiName} HTTP API " + version,
                    });
                    c.OrderActionsBy(o => o.RelativePath);
                });
                c.UseInlineDefinitionsForEnums();
                try
                {
                    //这个就是刚刚配置的xml文件名
                    //var xmlPath = Path.Combine(basePath, "WIDESEAWCS_Server.xml");
                    //默认的第二个参数是false,这个是controller的注释,记得修改
                    //c.IncludeXmlComments(xmlPath, true);
                    //这个就是Model层的xml文件名
                    //var xmlModelPath = Path.Combine(basePath, "WIDESEAWCS_Server.Model.xml");
                    //c.IncludeXmlComments(xmlModelPath);
                }
                catch (Exception ex)
                {
                    //log.Error("Blog.Core.xml和Blog.Core.Model.xml ä¸¢å¤±ï¼Œè¯·æ£€æŸ¥å¹¶æ‹·è´ã€‚\n" + ex.Message);
                }
                // å¼€å¯åŠ æƒå°é”
                c.OperationFilter<AddResponseHeadersFilter>();
                c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
                // åœ¨header中添加token,传递到后台
                c.OperationFilter<SecurityRequirementsOperationFilter>();
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "JWT授权token前面需要加上字段Bearer与一个空格,如Bearer token",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        new string[] { }
                    }
                });
            }).AddControllers()
            .ConfigureApiBehaviorOptions(options =>
            {
                options.SuppressConsumesConstraintForFormFileParameters = true;
                options.SuppressInferBindingSourcesForParameters = true;
                options.SuppressModelStateInvalidFilter = true;
                options.SuppressMapClientErrors = true;
                options.ClientErrorMapping[404].Link =
                    "https://*/404";
            });
            //services.AddSwaggerGenNewtonsoftSupport();
        }
    }
    /// <summary>
    /// è‡ªå®šä¹‰ç‰ˆæœ¬
    /// </summary>
    public class CustomApiVersion
    {
        /// <summary>
        /// Api接口版本 è‡ªå®šä¹‰
        /// </summary>
        public enum ApiVersions
        {
            /// <summary>
            /// V1 ç‰ˆæœ¬
            /// </summary>
            V1 = 1,
            /// <summary>
            /// V2 ç‰ˆæœ¬
            /// </summary>
            V2 = 2,
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/ActionExecuteFilter.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Filter
{
    public class ActionExecuteFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            //throw new NotImplementedException();
        }
        public void OnActionExecuting(ActionExecutingContext context)
        {
            //throw new NotImplementedException();
            //foreach (KeyValuePair<string, object?> item in context.ActionArguments)
            //{
            //    if (item.Value != null)
            //    {
            //        string name = item.Value.GetType().Name;
            //        Console.Out.WriteLine(name);
            //    }
            //    else
            //    {
            //        context.Result = new JsonResult(new { Status = false, Message = "参数不能为空" });
            //        return;
            //    }
            //}
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/ApiAuthorizeFilter.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,117 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Runtime;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Authorization;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.Filter
{
    /// <summary>
    /// åˆ¤æ–­token是否正确
    /// </summary>
    public class ApiAuthorizeFilter : IAuthorizationFilter
    {
        private static readonly string replaceTokenPath = "/api/User/replaceToken";
        private static readonly string loginPath = "/api/User/login";
        private static readonly string vierificationCodePath = "/api/User/getVierificationCode";
        public ApiAuthorizeFilter()
        {
        }
        /// <summary>
        /// åªåˆ¤æ–­token是否正确,不判断权限
        /// å¦‚果需要判断权限的在Action上加上ApiActionPermission属性标识权限类别,ActionPermissionFilter作权限处理
        ///(string,string,string)1、请求参数,2、返回消息,3,异常消息,4状态
        /// </summary>
        /// <param name="context"></param>
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            //if (!App.HostEnvironment.IsProduction() || context.HttpContext.Request.Path.Value == loginPath || context.HttpContext.Request.Path.Value == vierificationCodePath)
            {
                if (context.ActionDescriptor.EndpointMetadata.Any(item => item is IAllowAnonymous))
                {
                    //如果使用了固定Token不过期,直接对token的合法性及token是否存在进行验证
                    //if (context.Filters
                    //   .Where(item => item is IFixedTokenFilter)
                    //   .FirstOrDefault() is IFixedTokenFilter tokenFilter)
                    //{
                    //    tokenFilter.OnAuthorization(context);
                    //    return;
                    //}
                    //匿名并传入了token,需要将用户的ID缓存起来,保证UserHelper里能正确获取到用户信息
                    if (!context.HttpContext.User.Identity?.IsAuthenticated ?? false
                        && !string.IsNullOrEmpty(context.HttpContext.Request.Headers[AppSecret.TokenHeaderName]))
                    {
                        context.AddIdentity();
                    }
                    return;
                }
            }
            //else
            //{
            //    if (!context.HttpContext.User.Identity.IsAuthenticated
            //            || !context.HttpContext.Request.Headers.ContainsKey(AppSecret.TokenHeaderName))
            //    {
            //        context.Unauthorized("未授权");
            //        return;
            //    }
            //}
            #region å•点登录
            if (string.IsNullOrEmpty(App.User.Token))
            {
                if (!string.IsNullOrEmpty(context.HttpContext.Request.Headers[AppSecret.TokenHeaderName].ObjToString().Replace("Bearer ", "")))
                {
                    DateTime? expDate = context.HttpContext.User.Claims.Where(x => x.Type == JwtRegisteredClaimNames.Exp).Select(x => x.Value).FirstOrDefault()?.GetTimeSpmpToDate();
                    //动态标识刷新token(2021.05.01)
                    int ExpMinutes = AppSettings.app("ExpMinutes").ObjToInt();
                    if ((expDate.GetValueOrDefault() - DateTime.Now).TotalMinutes > ExpMinutes)
                    {
                        context.Unauthorized("登陆已过期");
                        return;
                    }
                    else
                    {
                        App.User.UpdateToke(context.HttpContext.Request.Headers[AppSecret.TokenHeaderName].ObjToString().Replace("Bearer ", ""));
                    }
                }
                else
                {
                    context.Unauthorized("登陆已过期");
                    return;
                }
            }
            else
            {
                if (App.User.Token != ((ClaimsIdentity?)context.HttpContext.User.Identity)?.BootstrapContext?.ToString())
                {
                    context.Unauthorized("登陆已过期");
                    return;
                }
            }
            #endregion
            {
                DateTime? expDate = context.HttpContext.User.Claims.Where(x => x.Type == JwtRegisteredClaimNames.Exp)
               .Select(x => x.Value).FirstOrDefault()?.GetTimeSpmpToDate();
                //动态标识刷新token(2021.05.01)
                int ExpMinutes = AppSettings.app("ExpMinutes").ObjToInt();
                if ((expDate.GetValueOrDefault() - DateTime.Now).TotalMinutes < ExpMinutes / 3 && context.HttpContext.Request.Path != replaceTokenPath)
                {
                    context.HttpContext.Response.Headers.Add("wideseawcs_exp", "1");
                }
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/ExporterHeaderFilter.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
using Magicodes.ExporterAndImporter.Core.Filters;
using Magicodes.ExporterAndImporter.Core.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Filter
{
    public class ExporterHeaderFilter : IExporterHeaderFilter
    {
        /// <summary>
        /// è¡¨å¤´ç­›é€‰å™¨ï¼ˆä¿®æ”¹åç§°ï¼‰
        /// </summary>
        /// <param name="exporterHeaderInfo"></param>
        /// <returns></returns>
        public ExporterHeaderInfo Filter(ExporterHeaderInfo exporterHeaderInfo)
        {
            return exporterHeaderInfo;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/GlobalExceptionsFilter.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using StackExchange.Profiling;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
using System.Reflection.Metadata;
using WIDESEAWCS_Core.LogHelper;
namespace WIDESEAWCS_Core.Filter
{
    /// <summary>
    /// å…¨å±€å¼‚常错误日志
    /// </summary>
    public class GlobalExceptionsFilter : IExceptionFilter
    {
        private readonly IWebHostEnvironment _env;
        private readonly ILogger<GlobalExceptionsFilter> _loggerHelper;
        public GlobalExceptionsFilter(IWebHostEnvironment env, ILogger<GlobalExceptionsFilter> loggerHelper)
        {
            _env = env;
            _loggerHelper = loggerHelper;
        }
        public void OnException(ExceptionContext context)
        {
            var json = new WebResponseContent();
            json.Message = context.Exception.Message;//错误信息
            json.Code = 500;//500异常
            var errorAudit = "Unable to resolve service for";
            if (!string.IsNullOrEmpty(json.Message) && json.Message.Contains(errorAudit))
            {
                json.Message = json.Message.Replace(errorAudit, $"(若新添加服务,需要重新编译项目){errorAudit}");
            }
            if (_env.EnvironmentName.ObjToString().Equals("Development"))
            {
                json.DevMessage = context.Exception.StackTrace;//堆栈信息
            }
            var res = new ContentResult();
            res.Content = json.Serialize();
            context.Result = res;
            MiniProfiler.Current.CustomTiming("Errors:", json.Message);
            LogLock.OutLogAOP("全局异常错误日志", new string[] { json.Message + WriteLog(json.Message, context.Exception) });
            //采用log4net è¿›è¡Œé”™è¯¯æ—¥å¿—记录
            //_loggerHelper.LogError(json.Message + WriteLog(json.Message, context.Exception));
        }
        /// <summary>
        /// è‡ªå®šä¹‰è¿”回格式
        /// </summary>
        /// <param name="throwMsg"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        public string WriteLog(string throwMsg, Exception ex)
        {
            return string.Format("\r\n【自定义错误】:{0} \r\n【异常类型】:{1} \r\n【异常信息】:{2} \r\n【堆栈调用】:{3}", new object[] { throwMsg,
                ex.GetType().Name, ex.Message, ex.StackTrace });
        }
    }
    public class InternalServerErrorObjectResult : ObjectResult
    {
        public InternalServerErrorObjectResult(object value) : base(value)
        {
            StatusCode = StatusCodes.Status500InternalServerError;
        }
    }
    //返回错误信息
    public class JsonErrorResponse
    {
        /// <summary>
        /// ç”Ÿäº§çŽ¯å¢ƒçš„æ¶ˆæ¯
        /// </summary>
        public string Message { get; set; }
        /// <summary>
        /// å¼€å‘环境的消息
        /// </summary>
        public string DevelopmentMessage { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Filter/UseServiceDIAttribute.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Filter
{
    public class UseServiceDIAttribute : ActionFilterAttribute
    {
        protected readonly ILogger<UseServiceDIAttribute> _logger;
        //private readonly IBlogArticleServices _blogArticleServices;
        private readonly string _name;
        public UseServiceDIAttribute(ILogger<UseServiceDIAttribute> logger/*, IBlogArticleServices blogArticleServices*/, string Name = "")
        {
            _logger = logger;
            /*_blogArticleServices = blogArticleServices;*/
            _name = Name;
        }
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            //var dd =await _blogArticleServices.Query();
            base.OnActionExecuted(context);
            DeleteSubscriptionFiles();
        }
        private void DeleteSubscriptionFiles()
        {
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/AppSettings.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,88 @@
using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    /// <summary>
    /// appsettings.json操作类
    /// </summary>
    public class AppSettings
    {
        public static IConfiguration Configuration { get; set; }
        static string contentPath { get; set; }
        public AppSettings(string contentPath)
        {
            string Path = "appsettings.json";
            //如果你把配置文件 æ˜¯ æ ¹æ®çŽ¯å¢ƒå˜é‡æ¥åˆ†å¼€äº†ï¼Œå¯ä»¥è¿™æ ·å†™
            //Path = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json";
            Configuration = new ConfigurationBuilder()
               .SetBasePath(contentPath)
               .Add(new JsonConfigurationSource { Path = Path, Optional = false, ReloadOnChange = true })//这样的话,可以直接读目录里的json文件,而不是 bin æ–‡ä»¶å¤¹ä¸‹çš„,所以不用修改复制属性
               .Build();
        }
        public AppSettings(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        /// <summary>
        /// å°è£…要操作的字符
        /// </summary>
        /// <param name="sections">节点配置</param>
        /// <returns></returns>
        public static string app(params string[] sections)
        {
            try
            {
                if (sections.Any())
                {
                    return Configuration[string.Join(":", sections)];
                }
            }
            catch (Exception) { }
            return "";
        }
        /// <summary>
        /// é€’归获取配置信息数组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sections"></param>
        /// <returns></returns>
        public static List<T> app<T>(params string[] sections)
        {
            List<T> list = new List<T>();
            // å¼•用 Microsoft.Extensions.Configuration.Binder åŒ…
            Configuration.Bind(string.Join(":", sections), list);
            return list;
        }
        /// <summary>
        /// æ ¹æ®è·¯å¾„  configuration["App:Name"];
        /// </summary>
        /// <param name="sectionsPath"></param>
        /// <returns></returns>
        public static string GetValue(string sectionsPath)
        {
            try
            {
                return Configuration[sectionsPath];
            }
            catch (Exception) { }
            return "";
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/ConsoleHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    public static class ConsoleHelper
    {
        private static readonly object _objLock = new();
        /// <summary>
        /// åœ¨æŽ§åˆ¶å°è¾“出
        /// </summary>
        /// <param name="str">文本</param>
        /// <param name="color">前颜色</param>
        public static void WriteColorLine(string str, ConsoleColor color)
        {
            lock (_objLock)
            {
                ConsoleColor currentForeColor = Console.ForegroundColor;
                Console.ForegroundColor = color;
                Console.WriteLine(str);
                Console.ForegroundColor = currentForeColor;
            }
        }
        /// <summary>
        /// åœ¨æŽ§åˆ¶å°è¾“出
        /// </summary>
        /// <param name="str">文本</param>
        /// <param name="color">前颜色</param>
        public static void WriteColorLine(object str, ConsoleColor color)
        {
            lock (_objLock)
            {
                ConsoleColor currentForeColor = Console.ForegroundColor;
                Console.ForegroundColor = color;
                Console.WriteLine(str);
                Console.ForegroundColor = currentForeColor;
            }
        }
        /// <summary>
        /// æ‰“印错误信息
        /// </summary>
        /// <param name="str">待打印的字符串</param>
        /// <param name="color">想要打印的颜色</param>
        public static void WriteErrorLine(this string str, ConsoleColor color = ConsoleColor.Red) => WriteColorLine(str, color);
        /// <summary>
        /// æ‰“印警告信息
        /// </summary>
        /// <param name="str">待打印的字符串</param>
        /// <param name="color">想要打印的颜色</param>
        public static void WriteWarningLine(this string str, ConsoleColor color = ConsoleColor.Yellow) => WriteColorLine(str, color);
        /// <summary>
        /// æ‰“印正常信息
        /// </summary>
        /// <param name="str">待打印的字符串</param>
        /// <param name="color">想要打印的颜色</param>
        public static void WriteInfoLine(this string str, ConsoleColor color = ConsoleColor.White) => WriteColorLine(str, color);
        /// <summary>
        /// æ‰“印成功的信息
        /// </summary>
        /// <param name="str">待打印的字符串</param>
        /// <param name="color">想要打印的颜色</param>
        public static void WriteSuccessLine(this string str, ConsoleColor color = ConsoleColor.Green) => WriteColorLine(str, color);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/ExportHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,106 @@
using Magicodes.ExporterAndImporter.Core;
using Magicodes.ExporterAndImporter.Excel;
using Magicodes.IE.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    public static class ExportHelper
    {
        public static Type CreateDynamicClass(this PropertyInfo[] propertyInfos)
        {
            string className = "DynamicClass";
            AssemblyName assemblyName = new AssemblyName("WIDESEAWCS_Model.Models");
            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);//定义具有指定名称和访问权限的动态程序集
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");//在此程序集中定义命名的暂时动态模块
            TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public);//TypeBuilder:在运行时定义并创建类的新实例
            Type attributeType1 = typeof(ExcelExporterAttribute);
            MethodInfo [] methodInfos = attributeType1.GetMethods(BindingFlags.Public);
            ConstructorInfo[] constructorInfos2 = attributeType1.GetConstructors();
            ConstructorInfo constructorInfo2 = constructorInfos2[0];
            CustomAttributeBuilder customAttributeBuilder2 = new CustomAttributeBuilder(constructorInfo2, new object[] { });
            typeBuilder.SetCustomAttribute(customAttributeBuilder2);
            foreach (var property in propertyInfos)
            {
                string propertyName = property.Name;
                Type propertyType = property.PropertyType;
                FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
                PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
                SugarColumn sugarColumn = property.GetCustomAttribute<SugarColumn>();
                if (sugarColumn != null)
                {
                    Type attributeType = typeof(ExporterHeaderAttribute);
                    ConstructorInfo[] constructorInfos = attributeType.GetConstructors();
                    ConstructorInfo constructorInfo = constructorInfos[0];
                    CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(constructorInfo, new object[] { sugarColumn.ColumnDescription, 11f, null, false, true, true, 0, KnownColor.Empty });
                    propertyBuilder.SetCustomAttribute(customAttributeBuilder);
                }
                MethodAttributes getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
                MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + propertyName, getSetAttributes, propertyType, Type.EmptyTypes);
                ILGenerator getIL = getMethodBuilder.GetILGenerator();
                getIL.Emit(OpCodes.Ldarg_0);
                getIL.Emit(OpCodes.Ldfld, fieldBuilder);
                getIL.Emit(OpCodes.Ret);
                MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_" + propertyName, getSetAttributes, null, new Type[] { propertyType });
                ILGenerator setIL = setMethodBuilder.GetILGenerator();
                setIL.Emit(OpCodes.Ldarg_0);
                setIL.Emit(OpCodes.Ldarg_1);
                setIL.Emit(OpCodes.Stfld, fieldBuilder);
                setIL.Emit(OpCodes.Ret);
                propertyBuilder.SetGetMethod(getMethodBuilder);
                propertyBuilder.SetSetMethod(setMethodBuilder);
            }
            Type generatedType = typeBuilder.CreateType();
            return generatedType;
        }
        public static void SetProperty(object instance, string propertyName, object value)
        {
            Type type = instance.GetType();
            PropertyInfo propertyInfo = type.GetProperty(propertyName);
            propertyInfo.SetValue(instance, value);
        }
        public static object GetProperty(object instance, string propertyName)
        {
            Type type = instance.GetType();
            PropertyInfo propertyInfo = type.GetProperty(propertyName);
            return propertyInfo.GetValue(instance);
        }
        public static void SetValue<T>(object instance, T value)
        {
            Type type = instance.GetType();
            PropertyInfo[] propertyInfos = typeof(T).GetProperties();
            for (int j = 0; j < propertyInfos.Length; j++)
            {
                PropertyInfo propertyInfo = type.GetProperty(propertyInfos[j].Name);
                object obj = propertyInfos[j].GetValue(value);
                propertyInfo.SetValue(instance, obj);
                ExporterHeaderAttribute exporterHeaderAttribute = propertyInfo.GetCustomAttribute<ExporterHeaderAttribute>();
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/FileHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,451 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    public class FileHelper : IDisposable
    {
        private bool _alreadyDispose = false;
        #region æž„造函数
        public FileHelper()
        {
        }
        ~FileHelper()
        {
            Dispose(); ;
        }
        protected virtual void Dispose(bool isDisposing)
        {
            if (_alreadyDispose) return;
            _alreadyDispose = true;
        }
        #endregion
        #region IDisposable æˆå‘˜
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
        #region å–得文件后缀名
        /****************************************
          * å‡½æ•°åç§°ï¼šGetPostfixStr
          * åŠŸèƒ½è¯´æ˜Žï¼šå–å¾—æ–‡ä»¶åŽç¼€å
          * å‚     æ•°ï¼šfilename:文件名称
          * è°ƒç”¨ç¤ºåˆ—:
          *            string filename = "aaa.aspx";
          *            string s = EC.FileObj.GetPostfixStr(filename);
         *****************************************/
        /// <summary>
        /// å–后缀名
        /// </summary>
        /// <param name="filename">文件名</param>
        /// <returns>.gif|.html格式</returns>
        public static string GetPostfixStr(string filename)
        {
            int start = filename.LastIndexOf(".");
            int length = filename.Length;
            string postfix = filename.Substring(start, length - start);
            return postfix;
        }
        #endregion
        #region æ ¹æ®æ–‡ä»¶å¤§å°èŽ·å–æŒ‡å®šå‰ç¼€çš„å¯ç”¨æ–‡ä»¶å
        /// <summary>
        /// æ ¹æ®æ–‡ä»¶å¤§å°èŽ·å–æŒ‡å®šå‰ç¼€çš„å¯ç”¨æ–‡ä»¶å
        /// </summary>
        /// <param name="folderPath">文件夹</param>
        /// <param name="prefix">文件前缀</param>
        /// <param name="size">文件大小(1m)</param>
        /// <param name="ext">文件后缀(.log)</param>
        /// <returns>可用文件名</returns>
        public static string GetAvailableFileWithPrefixOrderSize(string folderPath, string prefix, int size = 1 * 1024 * 1024, string ext = ".log")
        {
            var allFiles = new DirectoryInfo(folderPath);
            var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(prefix.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d => d.Name).ToList();
            if (selectFiles.Count > 0)
            {
                return selectFiles.FirstOrDefault().FullName;
            }
            return Path.Combine(folderPath, $@"{prefix}_{DateTime.Now.DateToTimeStamp()}.log");
        }
        public static string GetAvailableFileNameWithPrefixOrderSize(string _contentRoot, string prefix, int size = 1 * 1024 * 1024, string ext = ".log")
        {
            var folderPath = Path.Combine(_contentRoot, "Log");
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }
            var allFiles = new DirectoryInfo(folderPath);
            var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(prefix.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d => d.Name).ToList();
            if (selectFiles.Count > 0)
            {
                return selectFiles.FirstOrDefault().Name.Replace(".log", "");
            }
            return $@"{prefix}_{DateTime.Now.DateToTimeStamp()}";
        }
        #endregion
        #region å†™æ–‡ä»¶
        /****************************************
          * å‡½æ•°åç§°ï¼šWriteFile
          * åŠŸèƒ½è¯´æ˜Žï¼šå†™æ–‡ä»¶,会覆盖掉以前的内容
          * å‚     æ•°ï¼šPath:文件路径,Strings:文本内容
          * è°ƒç”¨ç¤ºåˆ—:
          *            string Path = Server.MapPath("Default2.aspx");
          *            string Strings = "这是我写的内容啊";
          *            EC.FileObj.WriteFile(Path,Strings);
         *****************************************/
        /// <summary>
        /// å†™æ–‡ä»¶
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <param name="Strings">文件内容</param>
        public static void WriteFile(string Path, string Strings)
        {
            if (!File.Exists(Path))
            {
                FileStream f = File.Create(Path);
                f.Close();
            }
            StreamWriter f2 = new StreamWriter(Path, false, System.Text.Encoding.UTF8);
            f2.Write(Strings);
            f2.Close();
            f2.Dispose();
        }
        /// <summary>
        /// å†™æ–‡ä»¶
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <param name="Strings">文件内容</param>
        public static void WriteFileAndDelOldFile(string Path, string Strings)
        {
            if (!File.Exists(Path))
            {
                FileStream f = File.Create(Path);
                f.Close();
            }
            else
            {
                File.Delete(Path);
            }
            StreamWriter f2 = new StreamWriter(Path, false, System.Text.Encoding.UTF8);
            f2.Write(Strings);
            f2.Close();
            f2.Dispose();
        }
        /// <summary>
        /// å†™æ–‡ä»¶
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <param name="Strings">文件内容</param>
        public static void WriteFile(string Path, byte[] buf)
        {
            if (!File.Exists(Path))
            {
                FileStream f = File.Create(Path);
                f.Close();
            }
            FileStream f2 = new FileStream(Path, FileMode.Create, FileAccess.Write);
            f2.Write(buf, 0, buf.Length);
            f2.Close();
            f2.Dispose();
        }
        public static void WriteFile(string Path, string fileName, byte[] buf)
        {
            if (!Directory.Exists(Path))
            {
                Directory.CreateDirectory(Path);
            }
            if (!File.Exists(Path + "\\" + fileName))
            {
                FileStream f = File.Create(Path + "\\" + fileName);
                f.Close();
            }
            FileStream f2 = new FileStream(Path + "\\" + fileName, FileMode.Create, FileAccess.Write);
            f2.Write(buf, 0, buf.Length);
            f2.Close();
            f2.Dispose();
        }
        /// <summary>
        /// å†™æ–‡ä»¶
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <param name="Strings">文件内容</param>
        /// <param name="encode">编码格式</param>
        public static void WriteFile(string Path, string Strings, Encoding encode)
        {
            if (!File.Exists(Path))
            {
                FileStream f = File.Create(Path);
                f.Close();
            }
            StreamWriter f2 = new StreamWriter(Path, false, encode);
            f2.Write(Strings);
            f2.Close();
            f2.Dispose();
        }
        #endregion
        #region è¯»æ–‡ä»¶
        /****************************************
          * å‡½æ•°åç§°ï¼šReadFile
          * åŠŸèƒ½è¯´æ˜Žï¼šè¯»å–æ–‡æœ¬å†…å®¹
          * å‚     æ•°ï¼šPath:文件路径
          * è°ƒç”¨ç¤ºåˆ—:
          *            string Path = Server.MapPath("Default2.aspx");
          *            string s = EC.FileObj.ReadFile(Path);
         *****************************************/
        /// <summary>
        /// è¯»æ–‡ä»¶
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <returns></returns>
        public static string ReadFile(string Path)
        {
            string s = "";
            if (!File.Exists(Path))
                s = "不存在相应的目录";
            else
            {
                StreamReader f2 = new StreamReader(Path, System.Text.Encoding.GetEncoding("gb2312"));
                s = f2.ReadToEnd();
                f2.Close();
                f2.Dispose();
            }
            return s;
        }
        /// <summary>
        /// è¯»æ–‡ä»¶
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <param name="encode">编码格式</param>
        /// <returns></returns>
        public static string ReadFile(string Path, Encoding encode)
        {
            string s = "";
            if (!File.Exists(Path))
                s = "不存在相应的目录";
            else
            {
                StreamReader f2 = new StreamReader(Path, encode);
                s = f2.ReadToEnd();
                f2.Close();
                f2.Dispose();
            }
            return s;
        }
        #endregion
        #region è¿½åŠ æ–‡ä»¶
        /****************************************
          * å‡½æ•°åç§°ï¼šFileAdd
          * åŠŸèƒ½è¯´æ˜Žï¼šè¿½åŠ æ–‡ä»¶å†…å®¹
          * å‚     æ•°ï¼šPath:文件路径,strings:内容
          * è°ƒç”¨ç¤ºåˆ—:
          *            string Path = Server.MapPath("Default2.aspx");
          *            string Strings = "新追加内容";
          *            EC.FileObj.FileAdd(Path, Strings);
         *****************************************/
        /// <summary>
        /// è¿½åŠ æ–‡ä»¶
        /// </summary>
        /// <param name="Path">文件路径</param>
        /// <param name="strings">内容</param>
        public static void FileAdd(string Path, string strings)
        {
            StreamWriter sw = File.AppendText(Path);
            sw.Write(strings);
            sw.Flush();
            sw.Close();
        }
        #endregion
        #region æ‹·è´æ–‡ä»¶
        /****************************************
          * å‡½æ•°åç§°ï¼šFileCoppy
          * åŠŸèƒ½è¯´æ˜Žï¼šæ‹·è´æ–‡ä»¶
          * å‚     æ•°ï¼šOrignFile:原始文件,NewFile:新文件路径
          * è°ƒç”¨ç¤ºåˆ—:
          *            string orignFile = Server.MapPath("Default2.aspx");
          *            string NewFile = Server.MapPath("Default3.aspx");
          *            EC.FileObj.FileCoppy(OrignFile, NewFile);
         *****************************************/
        /// <summary>
        /// æ‹·è´æ–‡ä»¶
        /// </summary>
        /// <param name="OrignFile">原始文件</param>
        /// <param name="NewFile">新文件路径</param>
        public static void FileCoppy(string orignFile, string NewFile)
        {
            File.Copy(orignFile, NewFile, true);
        }
        #endregion
        #region åˆ é™¤æ–‡ä»¶
        /****************************************
          * å‡½æ•°åç§°ï¼šFileDel
          * åŠŸèƒ½è¯´æ˜Žï¼šåˆ é™¤æ–‡ä»¶
          * å‚     æ•°ï¼šPath:文件路径
          * è°ƒç”¨ç¤ºåˆ—:
          *            string Path = Server.MapPath("Default3.aspx");
          *            EC.FileObj.FileDel(Path);
         *****************************************/
        /// <summary>
        /// åˆ é™¤æ–‡ä»¶
        /// </summary>
        /// <param name="Path">路径</param>
        public static void FileDel(string Path)
        {
            File.Delete(Path);
        }
        #endregion
        #region ç§»åŠ¨æ–‡ä»¶
        /****************************************
          * å‡½æ•°åç§°ï¼šFileMove
          * åŠŸèƒ½è¯´æ˜Žï¼šç§»åŠ¨æ–‡ä»¶
          * å‚     æ•°ï¼šOrignFile:原始路径,NewFile:新文件路径
          * è°ƒç”¨ç¤ºåˆ—:
          *             string orignFile = Server.MapPath("../说明.txt");
          *             string NewFile = Server.MapPath("http://www.cnblogs.com/说明.txt");
          *             EC.FileObj.FileMove(OrignFile, NewFile);
         *****************************************/
        /// <summary>
        /// ç§»åŠ¨æ–‡ä»¶
        /// </summary>
        /// <param name="OrignFile">原始路径</param>
        /// <param name="NewFile">新路径</param>
        public static void FileMove(string orignFile, string NewFile)
        {
            File.Move(orignFile, NewFile);
        }
        #endregion
        #region åœ¨å½“前目录下创建目录
        /****************************************
          * å‡½æ•°åç§°ï¼šFolderCreate
          * åŠŸèƒ½è¯´æ˜Žï¼šåœ¨å½“å‰ç›®å½•ä¸‹åˆ›å»ºç›®å½•
          * å‚     æ•°ï¼šOrignFolder:当前目录,NewFloder:新目录
          * è°ƒç”¨ç¤ºåˆ—:
          *            string orignFolder = Server.MapPath("test/");
          *            string NewFloder = "new";
          *            EC.FileObj.FolderCreate(OrignFolder, NewFloder);
         *****************************************/
        /// <summary>
        /// åœ¨å½“前目录下创建目录
        /// </summary>
        /// <param name="OrignFolder">当前目录</param>
        /// <param name="NewFloder">新目录</param>
        public static void FolderCreate(string orignFolder, string NewFloder)
        {
            Directory.SetCurrentDirectory(orignFolder);
            Directory.CreateDirectory(NewFloder);
        }
        #endregion
        #region é€’归删除文件夹目录及文件
        /****************************************
          * å‡½æ•°åç§°ï¼šDeleteFolder
          * åŠŸèƒ½è¯´æ˜Žï¼šé€’å½’åˆ é™¤æ–‡ä»¶å¤¹ç›®å½•åŠæ–‡ä»¶
          * å‚     æ•°ï¼šdir:文件夹路径
          * è°ƒç”¨ç¤ºåˆ—:
          *            string dir = Server.MapPath("test/");
          *            EC.FileObj.DeleteFolder(dir);
         *****************************************/
        /// <summary>
        /// é€’归删除文件夹目录及文件
        /// </summary>
        /// <param name="dir"></param>
        /// <returns></returns>
        public static void DeleteFolder(string dir)
        {
            if (Directory.Exists(dir)) //如果存在这个文件夹删除之
            {
                foreach (string d in Directory.GetFileSystemEntries(dir))
                {
                    if (File.Exists(d))
                        File.Delete(d); //直接删除其中的文件
                    else
                        DeleteFolder(d); //递归删除子文件夹
                }
                Directory.Delete(dir); //删除已空文件夹
            }
        }
        #endregion
        #region å°†æŒ‡å®šæ–‡ä»¶å¤¹ä¸‹é¢çš„æ‰€æœ‰å†…容copy到目标文件夹下面 æžœç›®æ ‡æ–‡ä»¶å¤¹ä¸ºåªè¯»å±žæ€§å°±ä¼šæŠ¥é”™ã€‚
        /****************************************
          * å‡½æ•°åç§°ï¼šCopyDir
          * åŠŸèƒ½è¯´æ˜Žï¼šå°†æŒ‡å®šæ–‡ä»¶å¤¹ä¸‹é¢çš„æ‰€æœ‰å†…å®¹copy到目标文件夹下面 æžœç›®æ ‡æ–‡ä»¶å¤¹ä¸ºåªè¯»å±žæ€§å°±ä¼šæŠ¥é”™ã€‚
          * å‚     æ•°ï¼šsrcPath:原始路径,aimPath:目标文件夹
          * è°ƒç”¨ç¤ºåˆ—:
          *            string srcPath = Server.MapPath("test/");
          *            string aimPath = Server.MapPath("test1/");
          *            EC.FileObj.CopyDir(srcPath,aimPath);
         *****************************************/
        /// <summary>
        /// æŒ‡å®šæ–‡ä»¶å¤¹ä¸‹é¢çš„æ‰€æœ‰å†…容copy到目标文件夹下面
        /// </summary>
        /// <param name="srcPath">原始路径</param>
        /// <param name="aimPath">目标文件夹</param>
        public static void CopyDir(string srcPath, string aimPath)
        {
            try
            {
                // æ£€æŸ¥ç›®æ ‡ç›®å½•是否以目录分割字符结束如果不是则添加之
                if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar)
                    aimPath += Path.DirectorySeparatorChar;
                // åˆ¤æ–­ç›®æ ‡ç›®å½•是否存在如果不存在则新建之
                if (!Directory.Exists(aimPath))
                    Directory.CreateDirectory(aimPath);
                // å¾—到源目录的文件列表,该里面是包含文件以及目录路径的一个数组
                //如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法
                //string[] fileList = Directory.GetFiles(srcPath);
                string[] fileList = Directory.GetFileSystemEntries(srcPath);
                //遍历所有的文件和目录
                foreach (string file in fileList)
                {
                    //先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
                    if (Directory.Exists(file))
                        CopyDir(file, aimPath + Path.GetFileName(file));
                    //否则直接Copy文件
                    else
                        File.Copy(file, aimPath + Path.GetFileName(file), true);
                }
            }
            catch (Exception ee)
            {
                throw new Exception(ee.ToString());
            }
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpContextHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    public static class HttpContextHelper
    {
        public static string GetUserIp(this HttpContext context)
        {
            string realIP = null;
            string forwarded = null;
            string remoteIpAddress = context.Connection.RemoteIpAddress.ToString();
            if (context.Request.Headers.ContainsKey("X-Real-IP"))
            {
                realIP = context.Request.Headers["X-Real-IP"].ToString();
                if (realIP != remoteIpAddress)
                {
                    remoteIpAddress = realIP;
                }
            }
            if (context.Request.Headers.ContainsKey("X-Forwarded-For"))
            {
                forwarded = context.Request.Headers["X-Forwarded-For"].ToString();
                if (forwarded != remoteIpAddress)
                {
                    remoteIpAddress = forwarded;
                }
            }
            return remoteIpAddress;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/HttpHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,149 @@
using AngleSharp.Dom;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    public class HttpHelper
    {
        public static async Task<string> GetAsync(string serviceAddress, Dictionary<string, object> parameters, string contentType = "application/json", Dictionary<string, string>? headers = null)
        {
            try
            {
                string result = string.Empty;
                using HttpClient httpClient = new HttpClient();
                httpClient.Timeout = new TimeSpan(0, 0, 60);
                // å°†å‚数拼接到URL中
                string queryString = string.Join("&", parameters.Select(x => $"{x.Key}={x.Value}"));
                serviceAddress += "?" + queryString;
                if (headers != null)
                {
                    foreach (var header in headers)
                        httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
                result = await httpClient.GetAsync(serviceAddress).Result.Content.ReadAsStringAsync();
                return result;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            return null;
        }
        // ç”¨äºŽè¿½è¸ªæ¯ä¸ªè¯·æ±‚的调用次数和最后请求时间。
        private static readonly Dictionary<string, (int Count, DateTime LastRequestTime)> requestTracker = new();
        public static async Task<string> PostAsync(string serviceAddress, string requestJson = null, string contentType = "application/json", Dictionary<string, string>? headers = null)
        {
            try
            {
                if (serviceAddress.Contains("http://c24-cellmi3:12020"))
                {
                    // å°† JSON å­—符串转换为字典
                    var parameters = JsonConvert.DeserializeObject<Dictionary<string, object>>(requestJson);
                    // åˆ›å»ºä¸€ä¸ªæ–°çš„字典,排除 RequestTime å’Œ SessionId
                    var filteredParameters = parameters.Where(p => p.Key != "RequestTime" && p.Key != "SessionId").ToDictionary(p => p.Key, p => p.Value);
                    string requestKey = $"{serviceAddress}:{JsonConvert.SerializeObject(filteredParameters)}";
                    // æ£€æŸ¥è¯·æ±‚次数和时间限制
                    if (requestTracker.TryGetValue(requestKey, out var requestInfo))
                    {
                        if (requestInfo.Count >= 5 && DateTime.Now < requestInfo.LastRequestTime.AddMinutes(3))
                        {
                            // å¦‚果请求次数超过限制且未超过10分钟,抛出异常
                            throw new InvalidOperationException("请求次数已达到限制,请稍后再试。");
                        }
                    }
                    // æ›´æ–°è¯·æ±‚跟踪信息
                    if (requestTracker.ContainsKey(requestKey))
                    {
                        requestTracker[requestKey] = (requestInfo.Count + 1, DateTime.Now);
                    }
                    else
                    {
                        requestTracker[requestKey] = (1, DateTime.Now);
                    }
                }
                string result = string.Empty;
                using (HttpContent httpContent = new StringContent(requestJson))
                {
                    httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    using HttpClient httpClient = new HttpClient();
                    httpClient.Timeout = new TimeSpan(0, 0, 60);
                    if (headers != null)
                    {
                        foreach (var header in headers)
                            httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                    }
                    result = await httpClient.PostAsync(serviceAddress, httpContent).Result.Content.ReadAsStringAsync();
                }
                return result;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            return null;
        }
        public static string Get(string serviceAddress, string contentType = "application/json", Dictionary<string, string>? headers = null)
        {
            try
            {
                string result = string.Empty;
                using HttpClient httpClient = new HttpClient();
                httpClient.Timeout = new TimeSpan(0, 0, 60);
                foreach (var header in headers)
                    httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                result = httpClient.GetStringAsync(serviceAddress).Result;
                return result;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            return null;
        }
        public static string Post(string serviceAddress, string requestJson = null, string contentType = "application/json", Dictionary<string, string>? headers = null)
        {
            try
            {
                string result = string.Empty;
                using (HttpContent httpContent = new StringContent(requestJson))
                {
                    httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    using HttpClient httpClient = new HttpClient();
                    httpClient.Timeout = new TimeSpan(0, 0, 60);
                    foreach (var header in headers)
                        httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                    result = httpClient.PostAsync(serviceAddress, httpContent).Result.Content.ReadAsStringAsync().Result;
                }
                return result;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            return null;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/MethodInfoExtensions.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    public static class MethodInfoExtensions
    {
        public static string GetFullName(this MethodInfo method)
        {
            if (method.DeclaringType == null)
            {
                return $@"{method.Name}";
            }
            return $"{method.DeclaringType.FullName}.{method.Name}";
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/ObjectExtension.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    public static class ObjectExtension
    {
        public static List<T> DicToIEnumerable<T>(this List<Dictionary<string, object>> dicList)
        {
            List<T> list = new List<T>();
            foreach (Dictionary<string, object> dic in dicList)
            {
                list.Add(dic.DicToModel<T>());
            }
            return list;
        }
        public static T DicToModel<T>(this Dictionary<string, object> dic)
        {
            //T model = Activator.CreateInstance<T>();
            //PropertyInfo[] propertyInfos = typeof(T).GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance);
            //Dictionary<string, object> upperDic = dic.ToDictionary(k => k.Key.ToUpper(), v => v.Value);
            //foreach (var property in propertyInfos)
            //{
            //    object value = null;
            //    if (!upperDic.TryGetValue(property.Name.ToUpper(), out value))
            //    {
            //        continue;
            //    }
            //    property.SetValue(model, value?.ToString().ChangeType(property.PropertyType));
            //}
            //return model;
            T model = Activator.CreateInstance<T>();
            PropertyInfo[] propertyInfos = typeof(T).GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in propertyInfos)
            {
                object value = null;
                if (!dic.TryGetValue(property.Name, out value))
                {
                    if (!dic.TryGetValue(property.Name.FirstLetterToUpper(), out value))
                    {
                        if (!dic.TryGetValue(property.Name.FirstLetterToLower(), out value))
                        {
                            continue;
                        }
                    }
                }
                ;
                property.SetValue(model, value?.ToString().ChangeType(property.PropertyType));
            }
            return model;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/RuntimeExtension.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@

using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Helper
{
    public static class RuntimeExtension
    {
        /// <summary>
        /// èŽ·å–é¡¹ç›®ç¨‹åºé›†ï¼ŒæŽ’é™¤æ‰€æœ‰çš„ç³»ç»Ÿç¨‹åºé›†(Microsoft.***、System.***等)、Nuget下载包
        /// </summary>
        /// <returns></returns>
        public static IList<Assembly> GetAllAssemblies()
        {
            var list = new List<Assembly>();
            var deps = DependencyContext.Default;
            //只加载项目中的程序集
            var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type == "project"); //排除所有的系统程序集、Nuget下载包
            foreach (var lib in libs)
            {
                try
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                    list.Add(assembly);
                }
                catch (Exception e)
                {
                    //Log.Debug(e, "GetAllAssemblies Exception:{ex}", e.Message);
                }
            }
            return list;
        }
        public static Assembly GetAssembly(string assemblyName)
        {
            return GetAllAssemblies().FirstOrDefault(assembly => assembly.FullName.Contains(assemblyName));
        }
        public static IList<Type> GetAllTypes()
        {
            var list = new List<Type>();
            foreach (var assembly in GetAllAssemblies())
            {
                var typeInfos = assembly.DefinedTypes;
                foreach (var typeInfo in typeInfos)
                {
                    list.Add(typeInfo.AsType());
                }
            }
            return list;
        }
        public static IList<Type> GetTypesByAssembly(string assemblyName)
        {
            var list = new List<Type>();
            var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));
            var typeInfos = assembly.DefinedTypes;
            foreach (var typeInfo in typeInfos)
            {
                list.Add(typeInfo.AsType());
            }
            return list;
        }
        public static Type GetImplementType(string typeName, Type baseInterfaceType)
        {
            return GetAllTypes().FirstOrDefault(t =>
            {
                if (t.Name == typeName &&
                    t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name))
                {
                    var typeInfo = t.GetTypeInfo();
                    return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType;
                }
                return false;
            });
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/SecurityEncDecryptHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.DB;
namespace WIDESEAWCS_Core.Helper
{
    public static class SecurityEncDecryptHelper
    {
        private static byte[] Keys = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
        /// <summary>
        /// DES加密字符串
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <param name="encryptKey">加密密钥,要求为16位</param>
        /// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
        public static string EncryptDES(this string encryptString, string encryptKey)
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 16));
                byte[] rgbIV = Keys;
                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
                using (var DCSP = Aes.Create())
                {
                    using (MemoryStream mStream = new MemoryStream())
                    {
                        using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
                        {
                            cStream.Write(inputByteArray, 0, inputByteArray.Length);
                            cStream.FlushFinalBlock();
                            return Convert.ToBase64String(mStream.ToArray()).Replace('+', '_').Replace('/', '~');
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("密码加密异常" + ex.Message);
            }
        }
        /// <summary>
        /// DES解密字符串
        /// </summary>
        /// <param name="decryptString">待解密的字符串</param>
        /// <param name="decryptKey">解密密钥,要求为16位,和加密密钥相同</param>
        /// <returns>解密成功返回解密后的字符串,失败返源串</returns>
        public static string DecryptDES(this string decryptString, string decryptKey)
        {
            if (decryptKey == AppSecret.DB && !AppSettings.app(MainDb.ConnectionStringsEncryption).ObjToBool())
                return decryptString;
            byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 16));
            byte[] rgbIV = Keys;
            byte[] inputByteArray = Convert.FromBase64String(decryptString.Replace('_', '+').Replace('~', '/'));
            using (var DCSP = Aes.Create())
            {
                using (MemoryStream mStream = new MemoryStream())
                {
                    using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
                    {
                        byte[] inputByteArrays = new byte[inputByteArray.Length];
                        cStream.Write(inputByteArray, 0, inputByteArray.Length);
                        cStream.FlushFinalBlock();
                        return Encoding.UTF8.GetString(mStream.ToArray());
                    }
                }
            }
        }
        public static bool TryDecryptDES(this string decryptString, string decryptKey, out string result)
        {
            result = "";
            try
            {
                result = DecryptDES(decryptString, decryptKey);
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Helper/UtilConvert.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,438 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.Enums;
namespace WIDESEAWCS_Core.Helper
{
    public static class UtilConvert
    {
        private static DateTime dateStart = new DateTime(1970, 1, 1, 8, 0, 0);
        private static long longTime = 621355968000000000;
        private static int samllTime = 10000000;
        /// <summary>
        /// æ—¶é—´æˆ³è½¬æ¢æˆæ—¥æœŸ
        /// </summary>
        /// <param name="timeStamp"></param>
        /// <returns></returns>
        public static DateTime GetTimeSpmpToDate(this object timeStamp)
        {
            if (timeStamp == null) return dateStart;
            DateTime dateTime = new DateTime(longTime + Convert.ToInt64(timeStamp) * samllTime, DateTimeKind.Utc).ToLocalTime();
            return dateTime;
        }
        public static string Serialize(this object obj, JsonSerializerSettings formatDate = null)
        {
            if (obj == null) return null;
            formatDate = formatDate ?? new JsonSerializerSettings
            {
                DateFormatString = "yyyy-MM-dd HH:mm:ss"
            };
            return JsonConvert.SerializeObject(obj, formatDate);
        }
        public static T DeserializeObject<T>(this string json)
        {
            if (string.IsNullOrEmpty(json))
            {
                return default(T);
            }
            if (json == "{}")
            {
                json = "[]";
            }
            return JsonConvert.DeserializeObject<T>(json);
        }
        public static string FirstLetterToLower(this string thisValue)
        {
            if (string.IsNullOrEmpty(thisValue)) return string.Empty;
            string result = thisValue.Substring(0, 1).ToLower() + thisValue.Substring(1, thisValue.Length - 1);
            return result;
        }
        public static string FirstLetterToUpper(this string thisValue)
        {
            if (string.IsNullOrEmpty(thisValue)) return string.Empty;
            string result = thisValue.Substring(0, 1).ToUpper() + thisValue.Substring(1, thisValue.Length - 1);
            return result;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static int ObjToInt(this object thisValue)
        {
            int reval = 0;
            if (thisValue == null) return 0;
            if (thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return reval;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static int DoubleToInt(this double thisValue)
        {
            int reval = 0;
            return Convert.ToInt32(thisValue);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <param name="errorValue"></param>
        /// <returns></returns>
        public static int ObjToInt(this object thisValue, int errorValue)
        {
            int reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }
        public static long ObjToLong(this object thisValue)
        {
            long reval = 0;
            if (thisValue == null) return 0;
            if (thisValue != DBNull.Value && long.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return reval;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static double ObjToMoney(this object thisValue)
        {
            double reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return 0;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <param name="errorValue"></param>
        /// <returns></returns>
        public static double ObjToMoney(this object thisValue, double errorValue)
        {
            double reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static string ObjToString(this object thisValue)
        {
            if (thisValue != null) return thisValue.ToString().Trim();
            return "";
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static bool IsNotEmptyOrNull(this object thisValue)
        {
            return ObjToString(thisValue) != "" && ObjToString(thisValue) != "undefined" && ObjToString(thisValue) != "null";
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <param name="errorValue"></param>
        /// <returns></returns>
        public static string ObjToString(this object thisValue, string errorValue)
        {
            if (thisValue != null) return thisValue.ToString().Trim();
            return errorValue;
        }
        public static bool IsNullOrEmpty(this object thisValue) => thisValue == null || thisValue == DBNull.Value || string.IsNullOrWhiteSpace(thisValue.ToString());
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static Decimal ObjToDecimal(this object thisValue)
        {
            Decimal reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return 0;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <param name="errorValue"></param>
        /// <returns></returns>
        public static Decimal ObjToDecimal(this object thisValue, decimal errorValue)
        {
            Decimal reval = 0;
            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static DateTime ObjToDate(this object thisValue)
        {
            DateTime reval = DateTime.MinValue;
            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
            {
                reval = Convert.ToDateTime(thisValue);
            }
            return reval;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <param name="errorValue"></param>
        /// <returns></returns>
        public static DateTime ObjToDate(this object thisValue, DateTime errorValue)
        {
            DateTime reval = DateTime.MinValue;
            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static bool ObjToBool(this object thisValue)
        {
            bool reval = false;
            if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return reval;
        }
        /// <summary>
        /// èŽ·å–å½“å‰æ—¶é—´çš„æ—¶é—´æˆ³
        /// </summary>
        /// <param name="thisValue"></param>
        /// <returns></returns>
        public static string DateToTimeStamp(this DateTime thisValue)
        {
            TimeSpan ts = thisValue - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }
        public static object ChangeType(this object value, Type type)
        {
            if (value == null && type.IsGenericType) return Activator.CreateInstance(type);
            if (value == null) return null;
            if (type == value.GetType()) return value;
            if (type.IsEnum)
            {
                if (value is string)
                    return Enum.Parse(type, value as string);
                else
                    return Enum.ToObject(type, value);
            }
            if (!type.IsInterface && type.IsGenericType)
            {
                Type innerType = type.GetGenericArguments()[0];
                object innerValue = ChangeType(value, innerType);
                return Activator.CreateInstance(type, new object[] { innerValue });
            }
            if (value is string && type == typeof(Guid)) return new Guid(value as string);
            if (value is string && type == typeof(Version)) return new Version(value as string);
            if (!(value is IConvertible)) return value;
            return Convert.ChangeType(value, type);
        }
        public static object ChangeTypeList(this object value, Type type)
        {
            if (value == null) return default;
            var gt = typeof(List<>).MakeGenericType(type);
            dynamic lis = Activator.CreateInstance(gt);
            var addMethod = gt.GetMethod("Add");
            string values = value.ToString();
            if (values != null && values.StartsWith("(") && values.EndsWith(")"))
            {
                string[] splits;
                if (values.Contains("\",\""))
                {
                    splits = values.Remove(values.Length - 2, 2)
                        .Remove(0, 2)
                        .Split("\",\"");
                }
                else
                {
                    splits = values.Remove(0, 1)
                        .Remove(values.Length - 2, 1)
                        .Split(",");
                }
                foreach (var split in splits)
                {
                    var str = split;
                    if (split.StartsWith("\"") && split.EndsWith("\""))
                    {
                        str = split.Remove(0, 1)
                            .Remove(split.Length - 2, 1);
                    }
                    addMethod.Invoke(lis, new object[] { ChangeType(str, type) });
                }
            }
            return lis;
        }
        public static string ToJson(this object value)
        {
            return JsonConvert.SerializeObject(value);
        }
        public static bool IsInt(this object obj)
        {
            if (obj == null)
                return false;
            bool reslut = Int32.TryParse(obj.ToString(), out int _number);
            return reslut;
        }
        public static bool IsDate(this object str)
        {
            return str.IsDate(out _);
        }
        public static bool IsDate(this object str, out DateTime dateTime)
        {
            dateTime = DateTime.Now;
            if (str == null || str.ToString() == "")
            {
                return false;
            }
            return DateTime.TryParse(str.ToString(), out dateTime);
        }
        /// <summary>
        /// æ ¹æ®ä¼ å…¥æ ¼å¼åˆ¤æ–­æ˜¯å¦ä¸ºå°æ•°
        /// </summary>
        /// <param name="str"></param>
        /// <param name="formatString">18,5</param>
        /// <returns></returns>
        public static bool IsNumber(this string str, string formatString)
        {
            if (string.IsNullOrEmpty(str)) return false;
            return Regex.IsMatch(str, @"^[+-]?\d*[.]?\d*$");
        }
        public static bool IsGuid(this string guid)
        {
            Guid newId;
            return guid.GetGuid(out newId);
        }
        public static bool GetGuid(this string guid, out Guid outId)
        {
            Guid emptyId = Guid.Empty;
            return Guid.TryParse(guid, out outId);
        }
        public static LinqExpressionType GetLinqCondition(this string stringType)
        {
            LinqExpressionType linqExpression;
            switch (stringType)
            {
                case HtmlElementType.Contains:
                    linqExpression = LinqExpressionType.In;
                    break;
                case HtmlElementType.ThanOrEqual:
                    linqExpression = LinqExpressionType.ThanOrEqual;
                    break;
                case HtmlElementType.LessOrequal:
                    linqExpression = LinqExpressionType.LessThanOrEqual;
                    break;
                case HtmlElementType.GT:
                    linqExpression = LinqExpressionType.GreaterThan;
                    break;
                case HtmlElementType.lt:
                    linqExpression = LinqExpressionType.LessThan;
                    break;
                case HtmlElementType.like:
                    linqExpression = LinqExpressionType.Contains;
                    break;
                default:
                    linqExpression = LinqExpressionType.Equal;
                    break;
            }
            return linqExpression;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/HostedService/SeedDataHostedService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Seed;
namespace WIDESEAWCS_Core
{
    public sealed class SeedDataHostedService : IHostedService
    {
        private readonly DBContext _dbContext;
        private readonly ILogger<SeedDataHostedService> _logger;
        private readonly string _webRootPath;
        private readonly IServiceProvider _serviceProvider;
        public SeedDataHostedService(
            IServiceProvider serviceProvider,
            IWebHostEnvironment webHostEnvironment,
            ILogger<SeedDataHostedService> logger)
        {
            _serviceProvider = serviceProvider;
            _logger = logger;
            _webRootPath = webHostEnvironment.WebRootPath;
            using var scope = _serviceProvider.CreateScope();
            var dbContext = scope.ServiceProvider.GetService<DBContext>();
            //dbContext.Db.Aop.DataExecuting = SqlSugarAop.DataExecuting;
            _dbContext = dbContext;
        }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Start Initialization Db Seed Service!");
            await DoWork();
        }
        private async Task DoWork()
        {
            try
            {
                //if (AppSettings.app("AppSettings", "SeedDBEnabled").ObjToBool() || AppSettings.app("AppSettings", "SeedDBDataEnabled").ObjToBool())
                {
                    // ä½¿ç”¨ myScopedService æ‰§è¡Œä»»åŠ¡
                    await DBSeed.SeedAsync(_dbContext, _webRootPath);
                    //多租户 åŒæ­¥
                    //await DBSeed.TenantSeedAsync(_dbContext);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error occured seeding the Database.");
                throw;
            }
        }
        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Stop Initialization Db Seed Service!");
            return Task.CompletedTask;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/HttpContextUser/AspNetUser.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,142 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.DB;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Seed;
using ICacheService = WIDESEAWCS_Core.Caches.ICacheService;
namespace WIDESEAWCS_Core.HttpContextUser
{
    public class AspNetUser : IUser
    {
        private readonly IHttpContextAccessor _accessor;
        private readonly ICacheService _cacheService;
        //private readonly ILogger<AspNetUser> _logger;
        public AspNetUser(IHttpContextAccessor accessor, ICacheService cacheService)
        {
            _accessor = accessor;
            _cacheService = cacheService;
            /*_logger = logger;*/
        }
        public string UserName => GetUserInfoFromToken(ClaimTypes.Name).FirstOrDefault() ?? "";
        public int UserId => GetClaimValueByType(JwtRegisteredClaimNames.Jti) == null ? 0 : GetClaimValueByType(JwtRegisteredClaimNames.Jti).FirstOrDefault()?.ObjToInt() ?? 0;
        public long TenantId => GetUserInfoFromToken(nameof(TenantId)).FirstOrDefault()?.ObjToLong() ?? -1;
        public int RoleId => GetUserInfoFromToken(ClaimTypes.Role).FirstOrDefault()?.ObjToInt() ?? 0;
        public string Token => GetToken();
        public int MenuType => (_accessor.HttpContext?.Request.Headers.ContainsKey("uniapp") ?? false) ? 1 : 0;
        public bool IsAuthenticated()
        {
            return _accessor.HttpContext?.User?.Identity?.IsAuthenticated ?? false;
        }
        public string GetToken()
        {
            string token = _cacheService.Get(UserId.ToString());
            if (!string.IsNullOrEmpty(token)) { return token; }
            return string.Empty;
            //return _accessor.HttpContext?.Request?.Headers["Authorization"].ObjToString().Replace("Bearer ", "") ?? "";
        }
        public void UpdateToke(string token)
        {
            _cacheService.AddOrUpdate(UserId.ToString(), token);
        }
        public bool IsSuperAdmin => IsRoleIdSuperAdmin(RoleId);
        public List<string> GetUserInfoFromToken(string ClaimType)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            var token = "";
            token = GetToken();
            // token校验
            if (token.IsNotEmptyOrNull() && jwtHandler.CanReadToken(token))
            {
                JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(token);
                return (from item in jwtToken.Claims
                        where item.Type == ClaimType
                        select item.Value).ToList();
            }
            return new List<string>() { };
        }
        public IEnumerable<Claim> GetClaimsIdentity()
        {
            if (_accessor.HttpContext != null)
            {
                var claims = _accessor.HttpContext.User.Claims.ToList();
                var headers = _accessor.HttpContext.Request.Headers;
                foreach (var header in headers)
                {
                    claims.Add(new Claim(header.Key, header.Value));
                }
                return claims;
            }
            return ArraySegment<Claim>.Empty;
        }
        public List<string> GetClaimValueByType(string ClaimType)
        {
            return (from item in GetClaimsIdentity()
                    where item.Type == ClaimType
                    select item.Value).ToList();
        }
        public bool IsRoleIdSuperAdmin(int roleId)
        {
            return roleId == 1;
        }
    }
    public class UserInfo
    {
        public long TenantId { get; set; }
        public int RoleId { get; set; }
        public string UserName { get; set; }
        public int UserId { get; set; }
        public string UserTrueName { get; set; }
        public string HeadImageUrl { get; set; }
        /// <summary>
        /// ä½¿ç”¨ä¸‹é¢çš„DeptIds字段
        /// </summary>
        [Obsolete]
        public int DeptId { get; set; }
        public List<Guid> DeptIds { get; set; }
        public string Token { get; set; }
        public string Token_ID { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/HttpContextUser/IUser.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.HttpContextUser
{
    public interface IUser
    {
        /// <summary>
        /// åç§°
        /// </summary>
        string UserName { get; }
        /// <summary>
        /// UserId
        /// </summary>
        int UserId { get; }
        /// <summary>
        /// ç§Ÿæˆ·ID
        /// </summary>
        long TenantId { get; }
        int RoleId { get; }
        string Token { get; }
        int MenuType { get; }
        void UpdateToke(string token);
        /// <summary>
        /// æ˜¯å¦è®¤è¯
        /// </summary>
        /// <returns></returns>
        bool IsAuthenticated();
        IEnumerable<Claim> GetClaimsIdentity();
        List<string> GetClaimValueByType(string ClaimType);
        string GetToken();
        List<string> GetUserInfoFromToken(string ClaimType);
        bool IsSuperAdmin { get; }
        bool IsRoleIdSuperAdmin(int roleId);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/IDependency.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core
{
    public interface IDependency
    {
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/LogLock.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.LogHelper
{
    public class LogLock
    {
        static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
        static int WritedCount = 0;
        static int FailedCount = 0;
        static string _contentRoot = string.Empty;
        public LogLock(string contentPath)
        {
            _contentRoot = contentPath;
        }
        public static void OutLogAOP(string prefix, string[] dataParas, bool IsHeader = true)
        {
            OutSql2LogToFile(prefix, dataParas, IsHeader);
        }
        public static void OutSql2LogToFile(string prefix, string[] dataParas, bool IsHeader = true, bool isWrt = false)
        {
            try
            {
                //设置读写锁为写入模式独占资源,其他写入请求需要等待本次写入结束之后才能继续写入
                //注意:长时间持有读线程锁或写线程锁会使其他线程发生饥饿 (starve)。 ä¸ºäº†å¾—到最好的性能,需要考虑重新构造应用程序以将写访问的持续时间减少到最小。
                //      ä»Žæ€§èƒ½æ–¹é¢è€ƒè™‘,请求进入写入模式应该紧跟文件操作之前,在此处进入写入模式仅是为了降低代码复杂度
                //      å› è¿›å…¥ä¸Žé€€å‡ºå†™å…¥æ¨¡å¼åº”在同一个try finally语句块内,所以在请求进入写入模式之前不能触发异常,否则释放次数大于请求次数将会触发异常
                LogWriteLock.EnterWriteLock();
                var folderPath = Path.Combine(_contentRoot, "Log");
                if (!Directory.Exists(folderPath))
                {
                    Directory.CreateDirectory(folderPath);
                }
                //string logFilePath = Path.Combine(path, $@"{filename}.log");
                var logFilePath = FileHelper.GetAvailableFileWithPrefixOrderSize(folderPath, prefix);
                var now = DateTime.Now;
                string logContent = String.Join("\r\n", dataParas);
                if (IsHeader)
                {
                    logContent = (
                       "--------------------------------\r\n" +
                       DateTime.Now + "|\r\n" +
                       String.Join("\r\n", dataParas) + "\r\n"
                       );
                }
                else
                {
                    logContent = (
                       dataParas[1] + ",\r\n"
                       );
                }
                //if (logContent.IsNotEmptyOrNull() && logContent.Length > 500)
                //{
                //    logContent = logContent.Substring(0, 500) + "\r\n";
                //}
                if (isWrt)
                {
                    System.IO.File.WriteAllText(logFilePath, logContent);
                }
                else
                {
                    System.IO.File.AppendAllText(logFilePath, logContent);
                }
                WritedCount++;
            }
            catch (Exception e)
            {
                //Console.Write(e.Message);
                FailedCount++;
            }
            finally
            {
                //退出写入模式,释放资源占用
                //注意:一次请求对应一次释放
                //      è‹¥é‡Šæ”¾æ¬¡æ•°å¤§äºŽè¯·æ±‚次数将会触发异常[写入锁定未经保持即被释放]
                //      è‹¥è¯·æ±‚处理完成后未释放将会触发异常[此模式不下允许以递归方式获取写入锁定]
                LogWriteLock.ExitWriteLock();
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/Logger.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,164 @@
using Microsoft.AspNetCore.Http;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.HttpContextUser;
using WIDESEAWCS_Core.Seed;
namespace WIDESEAWCS_Core.LogHelper
{
    public static class Logger
    {
        public static ConcurrentQueue<dynamic> loggerQueueData = new ConcurrentQueue<dynamic>();
        static Logger()
        {
            Task.Run(() =>
            {
                StartWriteLog();
            });
        }
        static void StartWriteLog()
        {
            DataTable queueTable = CreateEmptyTable();
            while (true)
            {
                try
                {
                    if (loggerQueueData.Count() > 0 && queueTable.Rows.Count < 500)
                    {
                        DequeueToTable(queueTable); continue;
                    }
                    //每5秒写一次数据
                    Thread.Sleep(5000);
                    if (queueTable.Rows.Count == 0) { continue; }
                    SqlSugarScope sugarClient = new SqlSugarScope(new ConnectionConfig()
                    {
                        ConnectionString = DBContext.GetMainConnectionDb().Connection,
                        IsAutoCloseConnection = true,
                        DbType = MainDb.DbType,
                    });
                    int rows = sugarClient.Fastest<DataTable>().AS("Sys_Log").BulkCopy(queueTable);
                    queueTable.Clear();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }
        private static void DequeueToTable(DataTable queueTable)
        {
            loggerQueueData.TryDequeue(out dynamic log);
            if (log != null)
            {
                DataRow row = queueTable.NewRow();
                if (log.BeginDate == null || log.BeginDate?.Year < 2010)
                {
                    log.BeginDate = DateTime.Now;
                }
                if (log.EndDate == null)
                {
                    log.EndDate = DateTime.Now;
                }
                //  row["Id"] = log.Id;
                row["RequestParam"] = log.RequestParam?.Replace("\r\n", "");
                row["ResponseParam"] = log.ResponseParam?.Replace("\r\n", "");
                //row["Success"] = log.Success ?? -1;
                row["BeginDate"] = log.BeginDate;
                row["EndDate"] = log.EndDate;
                row["ElapsedTime"] = ((DateTime)log.EndDate - (DateTime)log.BeginDate).TotalMilliseconds;
                row["UserIP"] = log.UserIP;
                row["Url"] = log.Url;
                row["UserId"] = log.UserId ?? -1;
                row["UserName"] = log.UserName;
                queueTable.Rows.Add(row);
            }
        }
        private static DataTable CreateEmptyTable()
        {
            DataTable queueTable = new DataTable();
            queueTable.Columns.Add("BeginDate", Type.GetType("System.DateTime"));
            queueTable.Columns.Add("ElapsedTime", Type.GetType("System.Int32"));
            queueTable.Columns.Add("EndDate", Type.GetType("System.DateTime"));
            queueTable.Columns.Add("RequestParam", typeof(string));
            queueTable.Columns.Add("ResponseParam", typeof(string));
            //queueTable.Columns.Add("Success", Type.GetType("System.Int32"));
            queueTable.Columns.Add("Url", typeof(string));
            queueTable.Columns.Add("UserIP", typeof(string));
            queueTable.Columns.Add("UserName", typeof(string));
            queueTable.Columns.Add("UserId", Type.GetType("System.Int32"));
            //queueTable.Columns.Add("LogType", typeof(string));
            //queueTable.Columns.Add("ExceptionInfo", typeof(string));
            //queueTable.Columns.Add("ServiceIP", typeof(string));
            //queueTable.Columns.Add("BrowserType", typeof(string));
            //queueTable.Columns.Add("Role_Id", Type.GetType("System.Int32"));
            return queueTable;
        }
        public static void Add(string requestParameter, string responseParameter)
        {
            dynamic log = null;
            try
            {
                HttpContext context = App.HttpContext;
                if (context == null)
                {
                    return;
                }
                if (context.Request.Method == "OPTIONS") return;
                RequestLogModel logModel = (context.RequestServices.GetService(typeof(RequestLogModel)) as RequestLogModel) ?? new RequestLogModel { RequestDate = DateTime.Now };
                IUser user = App.User;
                log = new
                {
                    BeginDate = logModel.RequestDate,
                    EndDate = DateTime.Now,
                    RequestParam = requestParameter,
                    ResponseParam = responseParameter,
                    Url = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase + context.Request.Path,
                    UserIP = GetClientIP(context) ?.Replace("::ffff:", ""),
                    UserId = user.UserId,
                    UserName = user.UserName
                };
            }
            catch (Exception exception)
            {
                log = log ?? new
                {
                    BeginDate = DateTime.Now,
                    EndDate = DateTime.Now,
                    RequestParam = requestParameter,
                    ResponseParam = responseParameter,
                };
            }
            //添加系统日志
            loggerQueueData.Enqueue(log);
        }
        public static string GetClientIP(HttpContext context)
        {
            var ip = context.Request.Headers["X-Forwarded-For"].ObjToString();
            if (string.IsNullOrEmpty(ip))
            {
                ip = context.Connection.RemoteIpAddress.ObjToString();
            }
            return ip;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/QuartzLogger.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.LogHelper
{
    public class QuartzLogger
    {
        static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
        static string folderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Log\\{DateTime.Now.ToString("yyyy-MM-dd")}");
        public static void WriteLogToFile(string fileName, string log)
        {
            try
            {
                LogWriteLock.EnterWriteLock();
                if (!Directory.Exists(folderPath))
                {
                    Directory.CreateDirectory(folderPath);
                }
                string logFilePath = Path.Combine(folderPath, GetLastAccessFileName(fileName));
                DateTime now = DateTime.Now;
                string logContent = $"【{now}】{Environment.NewLine}{log}";
                File.AppendAllText(logFilePath, logContent);
            }
            catch { }
            finally
            {
                LogWriteLock.ExitWriteLock();
            }
        }
        static int size = 10 * 1024 * 1024;
        static string ext = ".log";
        private static string GetLogFilePath(string folderPath, string fileName)
        {
            var allFiles = new DirectoryInfo(folderPath);
            var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(fileName.ToLower()) && fi.Extension.ToLower() == ext.ToLower() && fi.Length < size).OrderByDescending(d => d.Name).ToList();
            if (selectFiles.Count > 0)
            {
                return selectFiles.FirstOrDefault().FullName;
            }
            return Path.Combine(folderPath, $@"{fileName}_{DateTime.Now.ToString("HH-mm-ss")}.log");
        }
        private static string GetLastAccessFileName(string fileName)
        {
            foreach (var m in GetExistLogFileNames(fileName))
            {
                FileInfo fileInfo = new FileInfo(m);
                if (fileInfo.Length < size)
                {
                    return m;
                }
            }
            // è¿”回一个新的默认当前时间的日志名称
            return $@"{fileName}_{DateTime.Now.ToString("HH-mm-ss")}.log";
        }
        public static string[] GetExistLogFileNames(string fileName)
        {
            string[] fileNames = Directory.GetFiles(folderPath, fileName + "*.log");
            return fileNames;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/LogHelper/RequestLogModel.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.LogHelper
{
    public class RequestLogModel
    {
        public DateTime RequestDate {  get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/ApiLogMiddleware.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,112 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.LogHelper;
namespace WIDESEAWCS_Core.Middlewares
{
    /// <summary>
    /// è®°å½•请求和响应数据
    /// </summary>
    public class ApiLogMiddleware
    {
        /// <summary>
        ///
        /// </summary>
        private readonly RequestDelegate _next;
        private readonly ILogger<ApiLogMiddleware> _logger;
        public ApiLogMiddleware(RequestDelegate next, ILogger<ApiLogMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }
        //todo
        public async Task InvokeAsync(HttpContext context)
        {
            // è¿‡æ»¤ï¼Œåªæœ‰æŽ¥å£
            if (context.Request.Path.Value?.Contains("api") ?? false)
            {
                context.Request.EnableBuffering();
                Stream originalBody = context.Response.Body;
                string requestParam = string.Empty;
                string responseParam = string.Empty;
                try
                {
                    (context.RequestServices.GetService(typeof(RequestLogModel)) as RequestLogModel).RequestDate = DateTime.Now;
                    try
                    {
                        // å­˜å‚¨è¯·æ±‚数据
                        requestParam = RequestDataLog(context);
                        context.Request.Body.Position = 0;
                    }
                    catch { }
                    using MemoryStream ms = new();
                    context.Response.Body = ms;
                    await _next(context);
                    try
                    {
                        // å­˜å‚¨å“åº”数据
                        responseParam = ResponseDataLog(context.Response);
                    }
                    catch { }
                    ms.Position = 0;
                    await ms.CopyToAsync(originalBody);
                    if (!(context.Request.Path.Value?.Contains("Get") ?? false))
                        Logger.Add(requestParam, responseParam);
                }
                catch (Exception ex)
                {
                    // è®°å½•异常
                }
                finally
                {
                    context.Response.Body = originalBody;
                }
            }
            else
            {
                await _next(context);
            }
        }
        private string RequestDataLog(HttpContext context)
        {
            var request = context.Request;
            var sr = new StreamReader(request.Body);
            object obj = new
            {
                QueryString = request.QueryString.ToString(),
                BodyData = sr.ReadToEndAsync().Result
            };
            string data = JsonConvert.SerializeObject(obj);
            request.Body.Position = 0;
            return data;
        }
        private string ResponseDataLog(HttpResponse response)
        {
            response.Body.Position = 0;
            using StreamReader stream = new StreamReader(response.Body, leaveOpen: true);
            string body = stream.ReadToEnd();
            response.Body.Position = 0;
            return body;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/ExceptionHandlerMiddleware.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.DirectoryServices.Protocols;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Middlewares
{
    public class ExceptionHandlerMiddleware
    {
        private readonly RequestDelegate _next;
        public ExceptionHandlerMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                await HandleExceptionAsync(context, ex);
            }
        }
        private async Task HandleExceptionAsync(HttpContext context, Exception e)
        {
            if (e == null) return;
            await WriteExceptionAsync(context, e).ConfigureAwait(false);
        }
        private static async Task WriteExceptionAsync(HttpContext context, Exception e)
        {
            var message = e.Message;
            switch (e)
            {
                case UnauthorizedAccessException:
                    context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                    break;
                default:
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    break;
            }
            context.Response.ContentType = "application/json";
            await context.Response
                .WriteAsync(JsonConvert.SerializeObject(WebResponseContent.Instance.Error(message)))
                .ConfigureAwait(false);
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/HttpRequestMiddleware.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Middlewares
{
    public class HttpRequestMiddleware
    {
        private readonly RequestDelegate _next;
        public HttpRequestMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            context.Response.Headers.Add("Access-Control-Expose-Headers", "wideseawcs_exp");
            await _next(context);
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/IpLimitMiddleware.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@

using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.Middlewares
{
    /// <summary>
    /// ip é™æµ
    /// </summary>
    public static class IpLimitMiddleware
    {
        /// <summary>
        /// ip限流
        /// </summary>
        /// <param name="app"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void UseIpLimitMiddle(this IApplicationBuilder app)
        {
            if (app == null) throw new ArgumentNullException(nameof(app));
            //try
            //{
            //    if (AppSettings.app("Middleware", "IpRateLimit", "Enabled").ObjToBool())
            //    {
            //        app.UseIpRateLimiting();
            //    }
            //}
            //catch (Exception e)
            //{
            //    Log.Error($"Error occured limiting ip rate.\n{e.Message}");
            //    throw;
            //}
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/JwtTokenAuthMiddleware.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,94 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Authorization;
using WIDESEAWCS_Core.HttpContextUser;
namespace WIDESEAWCS_Core.Middlewares
{
    /// <summary>
    /// ä¸­é—´ä»¶
    /// åŽŸåšä¸ºè‡ªå®šä¹‰æŽˆæƒä¸­é—´ä»¶
    /// å…ˆåšæ£€æŸ¥ header token的使用
    /// </summary>
    public class JwtTokenAuthMiddleware
    {
        /// <summary>
        ///
        /// </summary>
        private readonly RequestDelegate _next;
        /// <summary>
        ///
        /// </summary>
        /// <param name="next"></param>
        public JwtTokenAuthMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        private void PreProceed(HttpContext next)
        {
            //Console.WriteLine($"{DateTime.Now} middleware invoke preproceed");
            //...
        }
        private void PostProceed(HttpContext next)
        {
            //Console.WriteLine($"{DateTime.Now} middleware invoke postproceed");
            //....
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public Task Invoke(HttpContext httpContext)
        {
            PreProceed(httpContext);
            //检测是否包含'Authorization'请求头
            if (!httpContext.Request.Headers.ContainsKey("Authorization"))
            {
                PostProceed(httpContext);
                return _next(httpContext);
            }
            //var tokenHeader = httpContext.Request.Headers["Authorization"].ToString();
            var tokenHeader = httpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
            try
            {
                if (tokenHeader.Length >= 128)
                {
                    //Console.WriteLine($"{DateTime.Now} token :{tokenHeader}");
                    UserInfo tm = JwtHelper.SerializeJwt(tokenHeader);
                    //授权
                    //var claimList = new List<Claim>();
                    //var claim = new Claim(ClaimTypes.Role, tm.Role);
                    //claimList.Add(claim);
                    //var identity = new ClaimsIdentity(claimList);
                    //var principal = new ClaimsPrincipal(identity);
                    //httpContext.User = principal;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"{DateTime.Now} middleware wrong:{e.Message}");
            }
            PostProceed(httpContext);
            return _next(httpContext);
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/MiddlewareHelpers.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Middlewares
{
    public static class MiddlewareHelpers
    {
        /// <summary>
        /// è¯·æ±‚响应中间件
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseApiLogMiddleware(this IApplicationBuilder app)
        {
            return app.UseMiddleware<ApiLogMiddleware>();
        }
        /// <summary>
        /// è‡ªå®šä¹‰æŽˆæƒä¸­é—´ä»¶
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseJwtTokenAuth(this IApplicationBuilder app)
        {
            return app.UseMiddleware<JwtTokenAuthMiddleware>();
        }
        /// <summary>
        /// å¼‚常处理中间件
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseExceptionHandlerMiddle(this IApplicationBuilder app)
        {
            return app.UseMiddleware<ExceptionHandlerMiddleware>();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/SwaggerAuthMiddleware.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Middlewares
{
    public class SwaggerAuthMiddleware
    {
        private readonly RequestDelegate next;
        public SwaggerAuthMiddleware(RequestDelegate next)
        {
            this.next = next;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            // ä¹Ÿå¯ä»¥æ ¹æ®æ˜¯å¦æ˜¯æœ¬åœ°åšåˆ¤æ–­ IsLocalRequest
            if (context.Request.Path.Value.ToLower().Contains("index.html"))
            {
                // åˆ¤æ–­æƒé™æ˜¯å¦æ­£ç¡®
                if (IsAuthorized(context))
                {
                    await next.Invoke(context);
                    return;
                }
                // æ— æƒé™ï¼Œè·³è½¬swagger登录页
                context.Response.Redirect("/swg-login.html");
            }
            else
            {
                await next.Invoke(context);
            }
        }
        public bool IsAuthorized(HttpContext context)
        {
            // ä½¿ç”¨session模式
            // å¯ä»¥ä½¿ç”¨å…¶ä»–çš„
            return context.Session.GetString("swagger-code") == "success";
        }
        /// <summary>
        /// åˆ¤æ–­æ˜¯ä¸æ˜¯æœ¬åœ°è®¿é—®
        /// æœ¬åœ°ä¸ç”¨swagger拦截
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public bool IsLocalRequest(HttpContext context)
        {
            if (context.Connection.RemoteIpAddress == null && context.Connection.LocalIpAddress == null)
            {
                return true;
            }
            if (context.Connection.RemoteIpAddress.Equals(context.Connection.LocalIpAddress))
            {
                return true;
            }
            if (IPAddress.IsLoopback(context.Connection.RemoteIpAddress))
            {
                return true;
            }
            return false;
        }
    }
    public static class SwaggerAuthorizeExtensions
    {
        public static IApplicationBuilder UseSwaggerAuthorized(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<SwaggerAuthMiddleware>();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Middlewares/SwaggerMiddleware.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@

using Microsoft.AspNetCore.Builder;
using Swashbuckle.AspNetCore.SwaggerUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
using static WIDESEAWCS_Core.Extensions.CustomApiVersion;
namespace WIDESEAWCS_Core.Middlewares
{
    /// <summary>
    /// Swagger中间件
    /// </summary>
    public static class SwaggerMiddleware
    {
        public static void UseSwaggerMiddle(this IApplicationBuilder app, Func<Stream> streamHtml)
        {
            if (app == null) throw new ArgumentNullException(nameof(app));
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                //根据版本名称倒序 éåŽ†å±•ç¤º
                var apiName = AppSettings.app(new string[] { "ApiName" });
                typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
                {
                    c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{apiName} {version}");
                });
                //c.SwaggerEndpoint("/swagger/v1/swagger.json", "WIDESEA.Core后台Api");
                //c.SwaggerEndpoint($"https://petstore.swagger.io/v2/swagger.json", $"{apiName} pet");
                // å°†swagger首页,设置成我们自定义的页面,记得这个字符串的写法:{项目名.index.html}
                if (streamHtml.Invoke() == null)
                {
                    var msg = "index.html的属性,必须设置为嵌入的资源";
                    //Log.Error(msg);
                    throw new Exception(msg);
                }
                c.IndexStream = streamHtml;
                c.DocExpansion(DocExpansion.None); //->修改界面打开时自动折叠
                //if (Permissions.IsUseIds4)
                //{
                //    c.OAuthClientId("blogadminjs");
                //}
                // è·¯å¾„配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc";
                c.RoutePrefix = "";
            });
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Seed/DBContext.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,216 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.DB;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.Seed
{
    public class DBContext
    {
        private static MutiDBOperate connectObject => GetMainConnectionDb();
        private static string _connectionString = connectObject.Connection;
        private static DbType _dbType = (DbType)connectObject.DbType;
        public static string ConnId = connectObject.ConnId;
        private SqlSugarScope _db;
        /// <summary>
        /// è¿žæŽ¥å­—符串
        /// </summary>
        public static MutiDBOperate GetMainConnectionDb()
        {
            MutiDBOperate mainDb = new MutiDBOperate()
            {
                Connection = AppSettings.app(MainDb.ConnectionString).DecryptDES(AppSecret.DB),
                ConnId = MainDb.CurrentDbConnId,
                DbType = DataBaseType.SqlServer
            };
            return mainDb;
        }
        /// <summary>
        /// è¿žæŽ¥å­—符串
        /// </summary>
        public static string ConnectionString
        {
            get { return _connectionString; }
            set { _connectionString = value; }
        }
        /// <summary>
        /// æ•°æ®åº“类型
        /// </summary>
        public static DbType DbType
        {
            get { return _dbType; }
            set { _dbType = value; }
        }
        /// <summary>
        /// æ•°æ®è¿žæŽ¥å¯¹è±¡
        /// </summary>
        public SqlSugarScope Db
        {
            get { return _db; }
            private set { _db = value; }
        }
        //public SqlSugarScope DbClient
        //{
        //    get { return _dbClient; }
        //    private set { _dbClient = value; }
        //}
        /// <summary>
        /// åŠŸèƒ½æè¿°:构造函数
        /// </summary>
        public DBContext(ISqlSugarClient sqlSugarClient)
        {
            if (string.IsNullOrEmpty(_connectionString))
                throw new ArgumentNullException("数据库连接字符串为空");
            _db = sqlSugarClient as SqlSugarScope;
            //_db.Aop.DataExecuting = SqlSugarAop.DataExecuting;
        }
        #region å®žä¾‹æ–¹æ³•
        /// <summary>
        /// åŠŸèƒ½æè¿°:获取数据库处理对象
        /// </summary>
        /// <returns>返回值</returns>
        public SimpleClient<T> GetEntityDB<T>() where T : class, new()
        {
            return new SimpleClient<T>(_db);
        }
        /// <summary>
        /// åŠŸèƒ½æè¿°:获取数据库处理对象
        /// </summary>
        /// <param name="db">db</param>
        /// <returns>返回值</returns>
        //public SimpleClient<T> GetEntityDB<T>(SqlSugarClient db) where T : class, new()
        //{
        //    return new SimpleClient<T>(db);
        //}
        #endregion
        #region æ ¹æ®å®žä½“类生成数据库表
        /// <summary>
        /// åŠŸèƒ½æè¿°:根据实体类生成数据库表
        /// </summary>
        /// <param name="blnBackupTable">是否备份表</param>
        /// <param name="lstEntitys">指定的实体</param>
        public void CreateTableByEntity<T>(bool blnBackupTable, params T[] lstEntitys) where T : class, new()
        {
            Type[] lstTypes = null;
            if (lstEntitys != null)
            {
                lstTypes = new Type[lstEntitys.Length];
                for (int i = 0; i < lstEntitys.Length; i++)
                {
                    T t = lstEntitys[i];
                    lstTypes[i] = typeof(T);
                }
            }
            CreateTableByEntity(blnBackupTable, lstTypes);
        }
        /// <summary>
        /// åŠŸèƒ½æè¿°:根据实体类生成数据库表
        /// </summary>
        /// <param name="blnBackupTable">是否备份表</param>
        /// <param name="lstEntitys">指定的实体</param>
        public void CreateTableByEntity(bool blnBackupTable, params Type[] lstEntitys)
        {
            if (blnBackupTable)
            {
                _db.CodeFirst.BackupTable().InitTables(lstEntitys); //change entity backupTable
            }
            else
            {
                _db.CodeFirst.InitTables(lstEntitys);
            }
        }
        #endregion
        #region é™æ€æ–¹æ³•
        ///// <summary>
        ///// åŠŸèƒ½æè¿°:获得一个DbContext
        ///// </summary>
        ///// <returns></returns>
        //public static MyContext GetDbContext()
        //{
        //    return new MyContext();
        //}
        /// <summary>
        /// åŠŸèƒ½æè¿°:设置初始化参数
        /// </summary>
        /// <param name="strConnectionString">连接字符串</param>
        /// <param name="enmDbType">数据库类型</param>
        public static void Init(string strConnectionString, DbType enmDbType = SqlSugar.DbType.SqlServer)
        {
            _connectionString = strConnectionString;
            _dbType = enmDbType;
        }
        /// <summary>
        /// åŠŸèƒ½æè¿°:创建一个链接配置
        /// </summary>
        /// <param name="blnIsAutoCloseConnection">是否自动关闭连接</param>
        /// <param name="blnIsShardSameThread">是否夸类事务</param>
        /// <returns>ConnectionConfig</returns>
        public static ConnectionConfig GetConnectionConfig(bool blnIsAutoCloseConnection = true, bool blnIsShardSameThread = false)
        {
            ConnectionConfig config = new ConnectionConfig()
            {
                ConnectionString = _connectionString,
                DbType = _dbType,
                IsAutoCloseConnection = blnIsAutoCloseConnection,
                ConfigureExternalServices = new ConfigureExternalServices()
                {
                    //DataInfoCacheService = new HttpRuntimeCache()
                },
                //IsShardSameThread = blnIsShardSameThread
            };
            return config;
        }
        /// <summary>
        /// åŠŸèƒ½æè¿°:获取一个自定义的DB
        /// </summary>
        /// <param name="config">config</param>
        /// <returns>返回值</returns>
        public static SqlSugarScope GetCustomDB(ConnectionConfig config)
        {
            return new SqlSugarScope(config);
        }
        /// <summary>
        /// åŠŸèƒ½æè¿°:获取一个自定义的数据库处理对象
        /// </summary>
        /// <param name="sugarClient">sugarClient</param>
        /// <returns>返回值</returns>
        //public static SqlSugarScope<T> GetCustomEntityDB<T>(SqlSugarScope sugarClient) where T : class, new()
        //{
        //    return new SqlSugarScope<T>(sugarClient);
        //}
        /// <summary>
        /// åŠŸèƒ½æè¿°:获取一个自定义的数据库处理对象
        /// </summary>
        /// <param name="config">config</param>
        /// <returns>返回值</returns>
        //public static SimpleClient<T> GetCustomEntityDB<T>(ConnectionConfig config) where T : class, new()
        //{
        //    SqlSugarScope sugarClient = GetCustomDB(config);
        //    return GetCustomEntityDB<T>(sugarClient);
        //}
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Seed/DBSeed.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,321 @@
using Castle.Components.DictionaryAdapter.Xml;
using Microsoft.AspNetCore.Mvc.Rendering;
using Newtonsoft.Json;
using SkiaSharp;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.DB;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Tenants;
namespace WIDESEAWCS_Core.Seed
{
    public class DBSeed
    {
        private static string SeedDataFolder = "WIDESEAWCS_DB.DBSeed.Json/{0}.tsv";
        /// <summary>
        /// å¼‚步添加种子数据
        /// </summary>
        /// <param name="myContext"></param>
        /// <param name="WebRootPath"></param>
        /// <returns></returns>
        public static async Task SeedAsync(DBContext dbContext, string WebRootPath)
        {
            try
            {
                if (string.IsNullOrEmpty(WebRootPath))
                {
                    throw new Exception("获取wwwroot路径时,异常!");
                }
                SeedDataFolder = Path.Combine(WebRootPath, SeedDataFolder);
                Console.WriteLine("************ WIDESEA DataBase Set *****************");
                //Console.WriteLine($"Master DB ConId: {DBContext.ConnId}");
                Console.WriteLine($"Master DB Type: {DBContext.DbType}");
                //Console.WriteLine($"Master DB ConnectString: {DBContext.ConnectionString}");
                Console.WriteLine();
                // åˆ›å»ºæ•°æ®åº“
                Console.WriteLine($"Create Database(The Db Id:{DBContext.ConnId})...");
                if (DBContext.DbType != SqlSugar.DbType.Oracle)
                {
                    dbContext.Db.DbMaintenance.CreateDatabase();
                    ConsoleHelper.WriteSuccessLine($"Database Created Successfully!");
                }
                else
                {
                    //Oracle æ•°æ®åº“不支持该操作
                    ConsoleHelper.WriteSuccessLine($"Oracle æ•°æ®åº“不支持该操作,可手动创建Oracle数据库!");
                }
                // åˆ›å»ºæ•°æ®åº“表,遍历指定命名空间下的class,
                // æ³¨æ„ä¸è¦æŠŠå…¶ä»–命名空间下的也添加进来。
                Console.WriteLine("Create Tables...");
                var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
                var referencedAssemblies = System.IO.Directory.GetFiles(path, MainDb.AssemblyName).Select(Assembly.LoadFrom).ToArray();
                var modelTypes = referencedAssemblies
                    .SelectMany(a => a.DefinedTypes)
                    .Select(type => type.AsType())
                    .Where(x => x.IsClass && x.Namespace is MainDb.EntityNameSpace && x.GetCustomAttribute<SugarTable>() != null)
                    .ToList();
                modelTypes.ForEach(t =>
                {
                    //var diffString = dbContext.Db.CodeFirst.GetDifferenceTables(t).ToDiffString();
                    // è¿™é‡Œåªæ”¯æŒæ·»åŠ è¡¨ï¼Œä¸æ”¯æŒåˆ é™¤
                    // å¦‚果想要删除,数据库直接右键删除,或者联系SqlSugar作者;
                    IDbMaintenance dbMaintenance = dbContext.Db.DbMaintenance;
                    if (!dbMaintenance.IsAnyTable(t.Name, false))
                    {
                        ConsoleHelper.WriteSuccessLine($"Table [{t.Name}] Created Successfully");
                        dbContext.Db.CodeFirst.InitTables(t);
                        string seedData = FileHelper.ReadFile(string.Format(SeedDataFolder, t.Name), Encoding.UTF8);
                        #region AddSeedData
                        if (seedData != "不存在相应的目录")
                        {
                            List<Dictionary<string, object>> dicFile = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(seedData);
                            if (dicFile.Count > 0)
                            {
                                List<Dictionary<string, object>> dic = new List<Dictionary<string, object>>();
                                List<string> columnNames = dbContext.Db.DbMaintenance.GetColumnInfosByTableName(t.Name, false).Select(x => x.DbColumnName).ToList();
                                var a = t.GetProperties().FirstOrDefault(x => !columnNames.Contains(x.Name));
                                List<PropertyInfo> propertyInfos = t.GetProperties().Where(x => columnNames.Contains(x.Name)).ToList();
                                for (int j = 0; j < dicFile.Count; j++)
                                {
                                    Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
                                    for (int i = 0; i < propertyInfos.Count; i++)
                                    {
                                        PropertyInfo propertyInfo = propertyInfos[i];
                                        SugarColumn sugarColumn = propertyInfo.GetCustomAttribute<SugarColumn>();
                                        if (sugarColumn != null)
                                        {
                                            if (!sugarColumn.IsIgnore)
                                            {
                                                keyValuePairs.Add(propertyInfo.Name, dicFile[j][propertyInfo.Name]);
                                            }
                                        }
                                    }
                                    dic.Add(keyValuePairs);
                                }
                                if (dic.Count > 0)
                                {
                                    for (int i = 0; i < dic.Count; i++)
                                    {
                                        if (dic[i].ContainsKey("CreateDate"))
                                            dic[i]["CreateDate"] = DateTime.Now;
                                        else
                                            dic[i].Add("CreateDate", DateTime.Now);
                                    }
                                    string str = $"SET IDENTITY_INSERT {t.Name} ON;";
                                    str += dbContext.Db.Insertable(dic).AS(t.Name).ToSqlString();
                                    str += ($"SET IDENTITY_INSERT {t.Name} OFF;");
                                    dbContext.Db.Ado.ExecuteCommand(str);
                                    ConsoleHelper.WriteSuccessLine($"Table [{t.Name}] SeedData Added Successfully");
                                }
                            }
                        }
                        #endregion
                    }
                    else
                    {
                        List<string> columnNames = dbContext.Db.DbMaintenance.GetColumnInfosByTableName(t.Name, false).Select(x => x.DbColumnName).ToList();
                        if (t.GetProperties().FirstOrDefault(x => !columnNames.Contains(x.Name)) != null)
                        {
                            bool isChange = true;
                            List<PropertyInfo> propertyInfos = t.GetProperties().Where(x => !columnNames.Contains(x.Name)).ToList();
                            for (int i = 0; i < propertyInfos.Count; i++)
                            {
                                PropertyInfo propertyInfo = propertyInfos[i];
                                SugarColumn sugarColumn = propertyInfo.GetCustomAttribute<SugarColumn>();
                                if (sugarColumn != null)
                                {
                                    if (!sugarColumn.IsIgnore)
                                    {
                                        if (!sugarColumn.IsNullable)
                                        {
                                            isChange = false;
                                            break;
                                        }
                                    }
                                }
                            }
                            if (isChange)
                                dbContext.Db.CodeFirst.InitTables(t);
                        }
                    }
                });
                ConsoleHelper.WriteSuccessLine($"Tables Created Successfully!");
                Console.WriteLine();
            }
            catch (Exception ex)
            {
                // 1、若是Mysql,查看常见问题:https://github.com/anjoy8/Blog.Core/issues/148#issue-776281770
                //2、若是Oracle,查看常见问题:https://github.com/anjoy8/Blog.Core/issues/148#issuecomment-752340231
                throw new Exception("错误:" + ex.Message);
            }
        }
        /// <summary>
        /// åˆå§‹åŒ– å¤šç§Ÿæˆ·
        /// </summary>
        /// <param name="dbContext"></param>
        /// <returns></returns>
        public static async Task TenantSeedAsync(DBContext dbContext)
        {
            if (BaseDBConfig.MutiConnectionString.Where(x => x.ConnId != MainDb.CurrentDbConnId).Any())
            {
                Console.WriteLine($@"Init Multi Tenant Db");
                foreach (MutiDBOperate tenant in BaseDBConfig.MutiConnectionString.Where(x => x.ConnId != MainDb.CurrentDbConnId))
                {
                    Console.WriteLine($@"Init Multi Tenant Db : {tenant.ConnId}");
                    ConnectionConfig connectionConfig = new ConnectionConfig()
                    {
                        ConfigId = tenant.ConnId,
                        ConnectionString = tenant.Connection,
                        IsAutoCloseConnection = true,
                        MoreSettings = new ConnMoreSettings()
                        {
                            IsAutoRemoveDataCache = true
                        },
                        DbType = (DbType)tenant.DbType,
                    };
                    await InitTenantSeedAsync(dbContext.Db.AsTenant(), connectionConfig);
                }
                Console.WriteLine(DateTime.Now + $@"Init Multi Tenant Db Finish");
            }
            //tenants = await myContext.Db.Queryable<SysTenant>().Where(s => s.TenantType == TenantTypeEnum.Tables).ToListAsync();
            //if (tenants.Any())
            //{
            //    await InitTenantSeedAsync(myContext, tenants);
            //}
        }
        #region å¤šç§Ÿæˆ· å¤šåº“ åˆå§‹åŒ–
        /// <summary>
        /// åˆå§‹åŒ–多库
        /// </summary>
        /// <param name="itenant"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public static async Task InitTenantSeedAsync(ITenant itenant, ConnectionConfig config)
        {
            Console.WriteLine(DateTime.Now + $@"Init Multi Tenant Db");
            //itenant.RemoveConnection(config.ConfigId);
            itenant.AddConnection(config);
            var db = itenant.GetConnectionScope(config.ConfigId);
            db.DbMaintenance.CreateDatabase();
            ConsoleHelper.WriteSuccessLine($"Init Multi Tenant Db : {config.ConfigId} Database created successfully!");
            Console.WriteLine($@"Init Multi Tenant Db : {config.ConfigId}  Create Tables");
            // èŽ·å–æ‰€æœ‰å®žä½“è¡¨-初始化租户业务表
            var entityTypes = TenantUtil.GetTenantEntityTypes(TenantTypeEnum.Db);
            if (!entityTypes.Any()) return;
            foreach (var entityType in entityTypes)
            {
                //var splitTable = entityType.GetCustomAttribute<SplitTableAttribute>();
                //if (splitTable == null)
                db.CodeFirst.InitTables(entityType);
                //else
                //    db.CodeFirst.SplitTables().InitTables(entityType);
                Console.WriteLine(entityType.Name);
            }
            Console.WriteLine(DateTime.Now + $@"Init Multi Tenant Db Finish");
            //多租户初始化种子数据
            //await TenantSeedDataAsync(db, TenantTypeEnum.Db);
        }
        #endregion
        //private static async Task TenantSeedDataAsync(ISqlSugarClient db, TenantTypeEnum tenantType)
        //{
        //    // èŽ·å–æ‰€æœ‰ç§å­é…ç½®-初始化数据
        //    var seedDataTypes = AssemblysExtensions.GetAllAssemblies().SelectMany(s => s.DefinedTypes)
        //        .Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass)
        //        .Where(u =>
        //        {
        //            var esd = u.GetInterfaces().FirstOrDefault(i => i.HasImplementedRawGeneric(typeof(IEntitySeedData<>)));
        //            if (esd is null)
        //            {
        //                return false;
        //            }
        //            var eType = esd.GenericTypeArguments[0];
        //            return eType.IsTenantEntity(tenantType);
        //        });
        //    if (!seedDataTypes.Any()) return;
        //    foreach (var seedType in seedDataTypes)
        //    {
        //        dynamic instance = Activator.CreateInstance(seedType);
        //        //初始化数据
        //        {
        //            var seedData = instance.InitSeedData();
        //            if (seedData != null && Enumerable.Any(seedData))
        //            {
        //                var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
        //                var entity = db.EntityMaintenance.GetEntityInfo(entityType);
        //                if (!await db.Queryable(entity.DbTableName, "").AnyAsync())
        //                {
        //                    await db.Insertable(Enumerable.ToList(seedData)).ExecuteCommandAsync();
        //                    Console.WriteLine($"Table:{entity.DbTableName} init success!");
        //                }
        //            }
        //        }
        //        //种子数据
        //        {
        //            var seedData = instance.SeedData();
        //            if (seedData != null && Enumerable.Any(seedData))
        //            {
        //                var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
        //                var entity = db.EntityMaintenance.GetEntityInfo(entityType);
        //                await db.Storageable(Enumerable.ToList(seedData)).ExecuteCommandAsync();
        //                Console.WriteLine($"Table:{entity.DbTableName} seedData success!");
        //            }
        //        }
        //        //自定义处理
        //        {
        //            await instance.CustomizeSeedData(db);
        //        }
        //    }
        //}
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Seed/FrameSeed.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,582 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Seed
{
    public class FrameSeed
    {
        /// <summary>
        /// ç”ŸæˆController层
        /// </summary>
        /// <param name="sqlSugarClient">sqlsugar实例</param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="tableNames">数据库表名数组,默认空,生成所有表</param>
        /// <param name="isMuti"></param>
        /// <returns></returns>
        public static bool CreateControllers(SqlSugarScope sqlSugarClient, string ConnId = null, bool isMuti = false, string[] tableNames = null)
        {
            Create_Controller_ClassFileByDBTalbe(sqlSugarClient, ConnId, $@"C:\my-file\Blog.Core.Api.Controllers", "Blog.Core.Api.Controllers", tableNames, "", isMuti);
            return true;
        }
        /// <summary>
        /// ç”ŸæˆModel层
        /// </summary>
        /// <param name="sqlSugarClient">sqlsugar实例</param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="tableNames">数据库表名数组,默认空,生成所有表</param>
        /// <param name="isMuti"></param>
        /// <returns></returns>
        public static bool CreateModels(SqlSugarScope sqlSugarClient, string ConnId, bool isMuti = false, string[] tableNames = null)
        {
            Create_Model_ClassFileByDBTalbe(sqlSugarClient, ConnId, $@"C:\my-file\Blog.Core.Model", "Blog.Core.Model.Models", tableNames, "", isMuti);
            return true;
        }
        /// <summary>
        /// ç”ŸæˆIRepository层
        /// </summary>
        /// <param name="sqlSugarClient">sqlsugar实例</param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="isMuti"></param>
        /// <param name="tableNames">数据库表名数组,默认空,生成所有表</param>
        /// <returns></returns>
        public static bool CreateIRepositorys(SqlSugarScope sqlSugarClient, string ConnId, bool isMuti = false, string[] tableNames = null)
        {
            Create_IRepository_ClassFileByDBTalbe(sqlSugarClient, ConnId, $@"C:\my-file\Blog.Core.IRepository", "Blog.Core.IRepository", tableNames, "", isMuti);
            return true;
        }
        /// <summary>
        /// ç”Ÿæˆ IService å±‚
        /// </summary>
        /// <param name="sqlSugarClient">sqlsugar实例</param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="isMuti"></param>
        /// <param name="tableNames">数据库表名数组,默认空,生成所有表</param>
        /// <returns></returns>
        public static bool CreateIServices(SqlSugarScope sqlSugarClient, string ConnId, bool isMuti = false, string[] tableNames = null)
        {
            Create_IServices_ClassFileByDBTalbe(sqlSugarClient, ConnId, $@"C:\my-file\Blog.Core.IServices", "Blog.Core.IServices", tableNames, "", isMuti);
            return true;
        }
        /// <summary>
        /// ç”Ÿæˆ Repository å±‚
        /// </summary>
        /// <param name="sqlSugarClient">sqlsugar实例</param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="isMuti"></param>
        /// <param name="tableNames">数据库表名数组,默认空,生成所有表</param>
        /// <returns></returns>
        public static bool CreateRepository(SqlSugarScope sqlSugarClient, string ConnId, bool isMuti = false, string[] tableNames = null)
        {
            Create_Repository_ClassFileByDBTalbe(sqlSugarClient, ConnId, $@"C:\my-file\Blog.Core.Repository", "Blog.Core.Repository", tableNames, "", isMuti);
            return true;
        }
        /// <summary>
        /// ç”Ÿæˆ Service å±‚
        /// </summary>
        /// <param name="sqlSugarClient">sqlsugar实例</param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="isMuti"></param>
        /// <param name="tableNames">数据库表名数组,默认空,生成所有表</param>
        /// <returns></returns>
        public static bool CreateServices(SqlSugarScope sqlSugarClient, string ConnId, bool isMuti = false, string[] tableNames = null)
        {
            Create_Services_ClassFileByDBTalbe(sqlSugarClient, ConnId, $@"C:\my-file\Blog.Core.Services", "Blog.Core.Services", tableNames, "", isMuti);
            return true;
        }
        #region æ ¹æ®æ•°æ®åº“表生产Controller层
        /// <summary>
        /// åŠŸèƒ½æè¿°:根据数据库表生产Controller层
        /// ä½œã€€ã€€è€…:Blog.Core
        /// </summary>
        /// <param name="sqlSugarClient"></param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="strPath">实体类存放路径</param>
        /// <param name="strNameSpace">命名空间</param>
        /// <param name="lstTableNames">生产指定的表</param>
        /// <param name="strInterface">实现接口</param>
        /// <param name="isMuti"></param>
        /// <param name="blnSerializable">是否序列化</param>
        private static void Create_Controller_ClassFileByDBTalbe(
          SqlSugarScope sqlSugarClient,
          string ConnId,
          string strPath,
          string strNameSpace,
          string[] lstTableNames,
          string strInterface,
          bool isMuti = false,
          bool blnSerializable = false)
        {
            var IDbFirst = sqlSugarClient.DbFirst;
            if (lstTableNames != null && lstTableNames.Length > 0)
            {
                IDbFirst = IDbFirst.Where(lstTableNames);
            }
            var ls = IDbFirst.IsCreateDefaultValue().IsCreateAttribute()
                 .SettingClassTemplate(p => p =
@"using Blog.Core.IServices;
using Blog.Core.Model;
using Blog.Core.Model.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace " + strNameSpace + @"
{
    [Route(""api/[controller]/[action]"")]
    [ApiController]
    [Authorize(Permissions.Name)]
     public class {ClassName}Controller : ControllerBase
    {
            /// <summary>
            /// æœåŠ¡å™¨æŽ¥å£ï¼Œå› ä¸ºæ˜¯æ¨¡æ¿ç”Ÿæˆï¼Œæ‰€ä»¥é¦–å­—æ¯æ˜¯å¤§å†™çš„ï¼Œè‡ªå·±å¯ä»¥é‡æž„ä¸‹
            /// </summary>
            private readonly I{ClassName}Services _{ClassName}Services;
            public {ClassName}Controller(I{ClassName}Services {ClassName}Services)
            {
                _{ClassName}Services = {ClassName}Services;
            }
            [HttpGet]
            public async Task<MessageModel<PageModel<{ClassName}>>> Get(int page = 1, string key = """",int intPageSize = 50)
            {
                if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key))
                {
                    key = """";
                }
                Expression<Func<{ClassName}, bool>> whereExpression = a => true;
                return new MessageModel<PageModel<{ClassName}>>()
                {
                    msg = ""获取成功"",
                    success = true,
                    response = await _{ClassName}Services.QueryPage(whereExpression, page, intPageSize)
                };
            }
            [HttpGet(""{id}"")]
            public async Task<MessageModel<{ClassName}>> Get(string id)
            {
                return new MessageModel<{ClassName}>()
                {
                    msg = ""获取成功"",
                    success = true,
                    response = await _{ClassName}Services.QueryById(id)
                };
            }
            [HttpPost]
            public async Task<MessageModel<string>> Post([FromBody] {ClassName} request)
            {
                var data = new MessageModel<string>();
                var id = await _{ClassName}Services.Add(request);
                data.success = id > 0;
                if (data.success)
                {
                    data.response = id.ObjToString();
                    data.msg = ""添加成功"";
                }
                return data;
            }
            [HttpPut]
            public async Task<MessageModel<string>> Put([FromBody] {ClassName} request)
            {
                var data = new MessageModel<string>();
                data.success = await _{ClassName}Services.Update(request);
                if (data.success)
                {
                    data.msg = ""更新成功"";
                    data.response = request?.id.ObjToString();
                }
                return data;
            }
            [HttpDelete]
            public async Task<MessageModel<string>> Delete(int id)
            {
                var data = new MessageModel<string>();
                var model = await _{ClassName}Services.QueryById(id);
                model.IsDeleted = true;
                data.success = await _departmentServices.Update(model);
                if (data.success)
                {
                    data.msg = ""删除成功"";
                    data.response = model?.Id.ObjToString();
                }
                return data;
            }
    }
}")
                  .ToClassStringList(strNameSpace);
            Dictionary<string, string> newdic = new Dictionary<string, string>();
            //循环处理 é¦–字母小写 å¹¶æ’入新的 Dictionary
            foreach (KeyValuePair<string, string> item in ls)
            {
                string newkey = "_" + item.Key.First().ToString().ToLower() + item.Key.Substring(1);
                string newvalue = item.Value.Replace("_" + item.Key, newkey);
                newdic.Add(item.Key, newvalue);
            }
            CreateFilesByClassStringList(newdic, strPath, "{0}Controller");
        }
        #endregion
        #region æ ¹æ®æ•°æ®åº“表生产Model层
        /// <summary>
        /// åŠŸèƒ½æè¿°:根据数据库表生产Model层
        /// ä½œã€€ã€€è€…:Blog.Core
        /// </summary>
        /// <param name="sqlSugarClient"></param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="strPath">实体类存放路径</param>
        /// <param name="strNameSpace">命名空间</param>
        /// <param name="lstTableNames">生产指定的表</param>
        /// <param name="strInterface">实现接口</param>
        /// <param name="isMuti"></param>
        /// <param name="blnSerializable">是否序列化</param>
        private static void Create_Model_ClassFileByDBTalbe(
          SqlSugarScope sqlSugarClient,
          string ConnId,
          string strPath,
          string strNameSpace,
          string[] lstTableNames,
          string strInterface,
          bool isMuti = false,
          bool blnSerializable = false)
        {
            //多库文件分离
            if (isMuti)
            {
                strPath = strPath + @"\Models\" + ConnId;
                strNameSpace = strNameSpace + "." + ConnId;
            }
            var IDbFirst = sqlSugarClient.DbFirst;
            if (lstTableNames != null && lstTableNames.Length > 0)
            {
                IDbFirst = IDbFirst.Where(lstTableNames);
            }
            var ls = IDbFirst.IsCreateDefaultValue().IsCreateAttribute()
                  .SettingClassTemplate(p => p =
@"{using}
namespace " + strNameSpace + @"
{
{ClassDescription}
    [SugarTable( ""{ClassName}"", """ + ConnId + @""")]" + (blnSerializable ? "\n    [Serializable]" : "") + @"
    public class {ClassName}" + (string.IsNullOrEmpty(strInterface) ? "" : (" : " + strInterface)) + @"
    {
           public {ClassName}()
           {
           }
{PropertyName}
    }
}")
                  //.SettingPropertyDescriptionTemplate(p => p = string.Empty)
                  .SettingPropertyTemplate(p => p =
@"{SugarColumn}
           public {PropertyType} {PropertyName} { get; set; }")
                   //.SettingConstructorTemplate(p => p = "              this._{PropertyName} ={DefaultValue};")
                   .ToClassStringList(strNameSpace);
            CreateFilesByClassStringList(ls, strPath, "{0}");
        }
        #endregion
        #region æ ¹æ®æ•°æ®åº“表生产IRepository层
        /// <summary>
        /// åŠŸèƒ½æè¿°:根据数据库表生产IRepository层
        /// ä½œã€€ã€€è€…:Blog.Core
        /// </summary>
        /// <param name="sqlSugarClient"></param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="strPath">实体类存放路径</param>
        /// <param name="strNameSpace">命名空间</param>
        /// <param name="lstTableNames">生产指定的表</param>
        /// <param name="strInterface">实现接口</param>
        /// <param name="isMuti"></param>
        private static void Create_IRepository_ClassFileByDBTalbe(
          SqlSugarScope sqlSugarClient,
          string ConnId,
          string strPath,
          string strNameSpace,
          string[] lstTableNames,
          string strInterface,
          bool isMuti = false
            )
        {
            //多库文件分离
            if (isMuti)
            {
                strPath = strPath + @"\" + ConnId;
                strNameSpace = strNameSpace + "." + ConnId;
            }
            var IDbFirst = sqlSugarClient.DbFirst;
            if (lstTableNames != null && lstTableNames.Length > 0)
            {
                IDbFirst = IDbFirst.Where(lstTableNames);
            }
            var ls = IDbFirst.IsCreateDefaultValue().IsCreateAttribute()
                 .SettingClassTemplate(p => p =
@"using Blog.Core.IRepository.Base;
using Blog.Core.Model.Models" + (isMuti ? "." + ConnId + "" : "") + @";
namespace " + strNameSpace + @"
{
    /// <summary>
    /// I{ClassName}Repository
    /// </summary>
    public interface I{ClassName}Repository : IBaseRepository<{ClassName}>" + (string.IsNullOrEmpty(strInterface) ? "" : (" , " + strInterface)) + @"
    {
    }
}")
                  .ToClassStringList(strNameSpace);
            CreateFilesByClassStringList(ls, strPath, "I{0}Repository");
        }
        #endregion
        #region æ ¹æ®æ•°æ®åº“表生产IServices层
        /// <summary>
        /// åŠŸèƒ½æè¿°:根据数据库表生产IServices层
        /// ä½œã€€ã€€è€…:Blog.Core
        /// </summary>
        /// <param name="sqlSugarClient"></param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="strPath">实体类存放路径</param>
        /// <param name="strNameSpace">命名空间</param>
        /// <param name="lstTableNames">生产指定的表</param>
        /// <param name="strInterface">实现接口</param>
        /// <param name="isMuti"></param>
        private static void Create_IServices_ClassFileByDBTalbe(
          SqlSugarScope sqlSugarClient,
          string ConnId,
          string strPath,
          string strNameSpace,
          string[] lstTableNames,
          string strInterface,
          bool isMuti = false)
        {
            //多库文件分离
            if (isMuti)
            {
                strPath = strPath + @"\" + ConnId;
                strNameSpace = strNameSpace + "." + ConnId;
            }
            var IDbFirst = sqlSugarClient.DbFirst;
            if (lstTableNames != null && lstTableNames.Length > 0)
            {
                IDbFirst = IDbFirst.Where(lstTableNames);
            }
            var ls = IDbFirst.IsCreateDefaultValue().IsCreateAttribute()
                  .SettingClassTemplate(p => p =
@"using Blog.Core.IServices.BASE;
using Blog.Core.Model.Models" + (isMuti ? "." + ConnId + "" : "") + @";
namespace " + strNameSpace + @"
{
    /// <summary>
    /// I{ClassName}Services
    /// </summary>
    public interface I{ClassName}Services :IBaseServices<{ClassName}>" + (string.IsNullOrEmpty(strInterface) ? "" : (" , " + strInterface)) + @"
    {
    }
}")
                   .ToClassStringList(strNameSpace);
            CreateFilesByClassStringList(ls, strPath, "I{0}Services");
        }
        #endregion
        #region æ ¹æ®æ•°æ®åº“表生产 Repository å±‚
        /// <summary>
        /// åŠŸèƒ½æè¿°:根据数据库表生产 Repository å±‚
        /// ä½œã€€ã€€è€…:Blog.Core
        /// </summary>
        /// <param name="sqlSugarClient"></param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="strPath">实体类存放路径</param>
        /// <param name="strNameSpace">命名空间</param>
        /// <param name="lstTableNames">生产指定的表</param>
        /// <param name="strInterface">实现接口</param>
        /// <param name="isMuti"></param>
        private static void Create_Repository_ClassFileByDBTalbe(
          SqlSugarScope sqlSugarClient,
          string ConnId,
          string strPath,
          string strNameSpace,
          string[] lstTableNames,
          string strInterface,
          bool isMuti = false)
        {
            //多库文件分离
            if (isMuti)
            {
                strPath = strPath + @"\" + ConnId;
                strNameSpace = strNameSpace + "." + ConnId;
            }
            var IDbFirst = sqlSugarClient.DbFirst;
            if (lstTableNames != null && lstTableNames.Length > 0)
            {
                IDbFirst = IDbFirst.Where(lstTableNames);
            }
            var ls = IDbFirst.IsCreateDefaultValue().IsCreateAttribute()
                  .SettingClassTemplate(p => p =
@"using Blog.Core.IRepository" + (isMuti ? "." + ConnId + "" : "") + @";
using Blog.Core.IRepository.UnitOfWork;
using Blog.Core.Model.Models" + (isMuti ? "." + ConnId + "" : "") + @";
using Blog.Core.Repository.Base;
namespace " + strNameSpace + @"
{
    /// <summary>
    /// {ClassName}Repository
    /// </summary>
    public class {ClassName}Repository : BaseRepository<{ClassName}>, I{ClassName}Repository" + (string.IsNullOrEmpty(strInterface) ? "" : (" , " + strInterface)) + @"
    {
        public {ClassName}Repository(IUnitOfWork unitOfWork) : base(unitOfWork)
        {
        }
    }
}")
                  .ToClassStringList(strNameSpace);
            CreateFilesByClassStringList(ls, strPath, "{0}Repository");
        }
        #endregion
        #region æ ¹æ®æ•°æ®åº“表生产 Services å±‚
        /// <summary>
        /// åŠŸèƒ½æè¿°:根据数据库表生产 Services å±‚
        /// ä½œã€€ã€€è€…:Blog.Core
        /// </summary>
        /// <param name="sqlSugarClient"></param>
        /// <param name="ConnId">数据库链接ID</param>
        /// <param name="strPath">实体类存放路径</param>
        /// <param name="strNameSpace">命名空间</param>
        /// <param name="lstTableNames">生产指定的表</param>
        /// <param name="strInterface">实现接口</param>
        /// <param name="isMuti"></param>
        private static void Create_Services_ClassFileByDBTalbe(
          SqlSugarScope sqlSugarClient,
          string ConnId,
          string strPath,
          string strNameSpace,
          string[] lstTableNames,
          string strInterface,
          bool isMuti = false)
        {
            //多库文件分离
            if (isMuti)
            {
                strPath = strPath + @"\" + ConnId;
                strNameSpace = strNameSpace + "." + ConnId;
            }
            var IDbFirst = sqlSugarClient.DbFirst;
            if (lstTableNames != null && lstTableNames.Length > 0)
            {
                IDbFirst = IDbFirst.Where(lstTableNames);
            }
            var ls = IDbFirst.IsCreateDefaultValue().IsCreateAttribute()
                  .SettingClassTemplate(p => p =
@"
using Blog.Core.IServices" + (isMuti ? "." + ConnId + "" : "") + @";
using Blog.Core.Model.Models" + (isMuti ? "." + ConnId + "" : "") + @";
using Blog.Core.Services.BASE;
using Blog.Core.IRepository.Base;
namespace " + strNameSpace + @"
{
    public class {ClassName}Services : BaseServices<{ClassName}>, I{ClassName}Services" + (string.IsNullOrEmpty(strInterface) ? "" : (" , " + strInterface)) + @"
    {
        private readonly IBaseRepository<{ClassName}> _dal;
        public {ClassName}Services(IBaseRepository<{ClassName}> dal)
        {
            this._dal = dal;
            base.BaseDal = dal;
        }
    }
}")
                  .ToClassStringList(strNameSpace);
            CreateFilesByClassStringList(ls, strPath, "{0}Services");
        }
        #endregion
        #region æ ¹æ®æ¨¡æ¿å†…容批量生成文件
        /// <summary>
        /// æ ¹æ®æ¨¡æ¿å†…容批量生成文件
        /// </summary>
        /// <param name="ls">类文件字符串list</param>
        /// <param name="strPath">生成路径</param>
        /// <param name="fileNameTp">文件名格式模板</param>
        private static void CreateFilesByClassStringList(Dictionary<string, string> ls, string strPath, string fileNameTp)
        {
            foreach (var item in ls)
            {
                var fileName = $"{string.Format(fileNameTp, item.Key)}.cs";
                var fileFullPath = Path.Combine(strPath, fileName);
                if (!Directory.Exists(strPath))
                {
                    Directory.CreateDirectory(strPath);
                }
                File.WriteAllText(fileFullPath, item.Value, Encoding.UTF8);
            }
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Tenants/ITenantEntity.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Tenants
{
    /// <summary>
    /// ç§Ÿæˆ·æ¨¡åž‹æŽ¥å£
    /// </summary>
    public interface ITenantEntity
    {
        /// <summary>
        /// ç§Ÿæˆ·Id
        /// </summary>
        [SugarColumn(DefaultValue = "0")]
        public long TenantId { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Tenants/MultiTenantAttribute.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Tenants
{
    /// <summary>
    /// æ ‡è¯† å¤šç§Ÿæˆ· çš„业务表 <br/>
    /// é»˜è®¤è®¾ç½®æ˜¯å¤šåº“       <br/>
    /// å…¬å…±è¡¨æ— éœ€åŒºåˆ† ç›´æŽ¥ä½¿ç”¨ä¸»åº“ å„自业务在各自库中 <br/>
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class MultiTenantAttribute : Attribute
    {
        public MultiTenantAttribute()
        {
        }
        public MultiTenantAttribute(TenantTypeEnum tenantType)
        {
            TenantType = tenantType;
        }
        public TenantTypeEnum TenantType { get; set; } = TenantTypeEnum.Db;
    }
    /// <summary>
    /// ç§Ÿæˆ·éš”离方案
    /// </summary>
    public enum TenantTypeEnum
    {
        None = 0,
        /// <summary>
        /// Id隔离
        /// </summary>
        [Description("Id隔离")]
        Id = 1,
        /// <summary>
        /// åº“隔离
        /// </summary>
        [Description("库隔离")]
        Db = 2,
        /// <summary>
        /// è¡¨éš”离
        /// </summary>
        [Description("表隔离")]
        Tables = 3,
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Tenants/TenantUtil.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,127 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB;
namespace WIDESEAWCS_Core.Tenants
{
    public static class TenantUtil
    {
        //public static SysTenant DefaultTenantConfig(this SysTenant tenant)
        //{
        //    tenant.DbType ??= DbType.Sqlite;
        //    //如果没有配置连接
        //    if (tenant.Connection.IsNullOrEmpty())
        //    {
        //        //此处默认配置 Sqlite åœ°å€
        //        //实际业务中 ä¹Ÿä¼šæœ‰è¿ç»´ã€ç³»ç»Ÿç®¡ç†å‘˜ç­‰æ¥ç»´æŠ¤
        //        switch (tenant.DbType.Value)
        //        {
        //            case DbType.Sqlite:
        //                tenant.Connection = $"DataSource={Path.Combine(Environment.CurrentDirectory, tenant.ConfigId)}.db";
        //                break;
        //        }
        //    }
        //    return tenant;
        //}
        //public static ConnectionConfig GetConnectionConfig(this SysTenant tenant)
        //{
        //    if (tenant.DbType is null)
        //    {
        //        throw new ArgumentException("Tenant DbType Must");
        //    }
        //    return new ConnectionConfig()
        //    {
        //        ConfigId = tenant.ConfigId,
        //        DbType = tenant.DbType.Value,
        //        ConnectionString = tenant.Connection,
        //        IsAutoCloseConnection = true,
        //        MoreSettings = new ConnMoreSettings()
        //        {
        //            IsAutoRemoveDataCache = true
        //        },
        //    };
        //}
        public static List<Type> GetTenantEntityTypes(TenantTypeEnum? tenantType = null)
        {
            List<Type> types = RepositorySetting.Entitys.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass).ToList();
            List<Type> returnTypes = types.Where(s => IsTenantEntity(s, tenantType)).ToList();
            return returnTypes;
        }
        public static bool IsTenantEntity(this Type u, TenantTypeEnum? tenantType = null)
        {
            var mta = u.GetCustomAttribute<MultiTenantAttribute>();
            if (mta is null)
            {
                return false;
            }
            if (tenantType != null)
            {
                if (mta.TenantType != tenantType)
                {
                    return false;
                }
            }
            return true;
        }
        public static string GetTenantTableName(this Type type, ISqlSugarClient db, string id)
        {
            var entityInfo = db.EntityMaintenance.GetEntityInfo(type);
            return $@"{entityInfo.DbTableName}_{id}";
        }
        //public static string GetTenantTableName(this Type type, ISqlSugarClient db, SysTenant tenant)
        //{
        //    return GetTenantTableName(type, db, tenant.Id.ToString());
        //}
        public static void SetTenantTable(this ISqlSugarClient db, string id)
        {
            var types = GetTenantEntityTypes(TenantTypeEnum.Tables);
            foreach (var type in types)
            {
                db.MappingTables.Add(type.Name, type.GetTenantTableName(db, id));
            }
        }
        public static List<SelectModel> GetTenantSelectModels()
        {
            List<SelectModel> selectModels = new List<SelectModel>()
            {
                new SelectModel
                {
                    FieldName = MainDb.TenantId
                },
                //new SelectModel
                //{
                //    FieldName = MainDb.TenantName
                //},
                new SelectModel
                {
                    FieldName = MainDb.ConnectionString,
                },
                new SelectModel
                {
                    FieldName = MainDb.TenantDbType
                }
            };
            return selectModels;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Utilities/EntityProperties.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,364 @@
using SqlSugar;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Const;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.Utilities
{
    public static class EntityProperties
    {
        /// <summary>
        /// éªŒè¯æ•°æ®åº“字段类型与值是否正确,
        /// </summary>
        /// <param name="dbType">数据库字段类型(如varchar,nvarchar,decimal,不要带后面长度如:varchar(50))</param>
        /// <param name="value">值</param>
        /// <param name="propertyInfo">要验证的类的属性,若不为null,则会判断字符串的长度是否正确</param>
        /// <returns>(bool, string, object)bool成否校验成功,string校验失败信息,object,当前校验的值</returns>
        public static (bool, string, object) ValidationVal(this PropertyInfo propertyInfo, object value)
        {
            string dbType = "";
            SugarColumn sugarColumn = null;
            if (propertyInfo != null)
            {
                sugarColumn = propertyInfo.GetCustomAttribute<SugarColumn>();
                dbType = propertyInfo.PropertyType != null ? propertyInfo.GetProperWithDbType() : SqlDbTypeName.NVarChar;
            }
            dbType = dbType.ToLower();
            string val = value?.ToString();
            //验证长度
            string reslutMsg = string.Empty;
            if (dbType == SqlDbTypeName.Int)
            {
                if (!value.IsInt())
                    reslutMsg = "只能为有效整数";
            }  //2021.10.12增加属性校验long类型的支持
            else if (dbType == SqlDbTypeName.BigInt)
            {
                if (!long.TryParse(val, out _))
                {
                    reslutMsg = "只能为有效整数";
                }
            }
            else if (dbType == SqlDbTypeName.DateTime
                || dbType == SqlDbTypeName.Date
                || dbType == SqlDbTypeName.SmallDateTime
                || dbType == SqlDbTypeName.SmallDate
                )
            {
                if (!value.IsDate())
                    reslutMsg = "必须为日期格式";
            }
            else if (dbType == SqlDbTypeName.Float || dbType == SqlDbTypeName.Decimal || dbType == SqlDbTypeName.Double)
            {
                if (!val.IsNumber(null))
                {
                    reslutMsg = "不是有效数字";
                }
            }
            else if (dbType == SqlDbTypeName.UniqueIdentifier)
            {
                if (!val.IsGuid())
                {
                    reslutMsg = propertyInfo.Name + "Guid不正确";
                }
            }
            else if (propertyInfo != null
                && (dbType == SqlDbTypeName.VarChar
                || dbType == SqlDbTypeName.NVarChar
                || dbType == SqlDbTypeName.NChar
                || dbType == SqlDbTypeName.Char
                || dbType == SqlDbTypeName.Text))
            {
                //默认nvarchar(max) ã€text é•¿åº¦ä¸èƒ½è¶…过20000
                if (val.Length > 200000)
                {
                    reslutMsg = $"字符长度最多【200000】";
                }
                else
                {
                    int length = sugarColumn.Length;
                    if (length == 0) { return (true, null, null); }
                    //判断双字节与单字段
                    else if (length < 8000 &&
                        ((dbType.Substring(0, 1) != "n"
                        && Encoding.UTF8.GetBytes(val.ToCharArray()).Length > length)
                         || val.Length > length)
                         )
                    {
                        reslutMsg = $"最多只能【{length}】个字符。";
                    }
                }
            }
            if (!string.IsNullOrEmpty(reslutMsg) && propertyInfo != null)
            {
                reslutMsg = sugarColumn.ColumnDescription + reslutMsg;
            }
            return (reslutMsg == "" ? true : false, reslutMsg, value);
        }
        public static List<(bool, string, object)> ValidationValueForDbType(this PropertyInfo propertyInfo, params object[] values)
        {
            List<(bool, string, object)> result = new List<(bool, string, object)>();
            foreach (object value in values)
            {
                result.Add(propertyInfo.ValidationVal(value));
            }
            return result;
        }
        private static readonly Dictionary<Type, string> ProperWithDbType = new Dictionary<Type, string>() {
            {  typeof(string),SqlDbTypeName.NVarChar },
            { typeof(DateTime),SqlDbTypeName.DateTime},
            {typeof(long),SqlDbTypeName.BigInt },
            {typeof(int),SqlDbTypeName.Int},
            { typeof(decimal),SqlDbTypeName.Decimal },
            { typeof(float),SqlDbTypeName.Float },
            { typeof(double),SqlDbTypeName.Double },
            {  typeof(byte),SqlDbTypeName.Int },//类型待完
            { typeof(Guid),SqlDbTypeName.UniqueIdentifier}
        };
        public static string GetProperWithDbType(this PropertyInfo propertyInfo)
        {
            bool result = ProperWithDbType.TryGetValue(propertyInfo.PropertyType, out string value);
            if (result)
            {
                return value;
            }
            return SqlDbTypeName.NVarChar;
        }
        /// <summary>
        /// åˆ¤æ–­hash的列是否为对应的实体,并且值是否有效
        /// </summary>
        /// <param name="typeinfo"></param>
        /// <param name="dic"></param>
        /// <param name="removeNotContains">移除不存在字段</param>
        /// <param name="removerKey">移除主键</param>
        /// <returns></returns>
        //public static string ValidateDicInEntity(this Type typeinfo, Dictionary<string, object> dic, bool removerKey, PropertyInfo[] propertyInfo, string[] ignoreFields = null)
        //{
        //    if (dic == null || dic.Count == 0) { return "参数无效"; }
        //    // ä¸å­˜åœ¨çš„字段直接移除
        //    dic.Where(x => !propertyInfo.Any(p => p.Name.ToUpper() == x.Key.ToUpper())).Select(s => s.Key).ToList().ForEach(f =>
        //    {
        //        dic.Remove(f);
        //    });
        //    string keyName = typeinfo.GetKeyName();
        //    //移除主键
        //    if (removerKey)
        //        dic.Remove(keyName);
        //    //else
        //    //{
        //    //    if (!dic.ContainsKey(keyName))
        //    //        return "请传入主键参数";
        //    //}
        //    foreach (PropertyInfo property in propertyInfo)
        //    {
        //        SugarColumn sugarColumn = property.GetCustomAttribute<SugarColumn>();
        //        if (sugarColumn == null)
        //            return "请配置SugarColumn属性";
        //        //忽略与主键的字段不做验证
        //        if (property.Name.ToUpper() == keyName.ToUpper() || (ignoreFields != null && ignoreFields.Contains(property.Name)) || sugarColumn.IsOnlyIgnoreInsert || sugarColumn.IsOnlyIgnoreUpdate || sugarColumn.IsIgnore)
        //            continue;
        //        //不在编辑中的列,是否也要必填
        //        if (!dic.ContainsKey(property.Name.ToUpper()))
        //        {
        //            if (!sugarColumn.IsNullable)
        //            {
        //                if (sugarColumn.DefaultValue == null)
        //                    return sugarColumn.ColumnDescription + "为必须提交项";
        //                continue;
        //            }
        //            continue;
        //        }
        //        if(dic[property.Name.ToUpper()] != null)
        //        {
        //            string str = dic[property.Name.ToUpper()].ToString();
        //            //将所有空值设置为null
        //            if (str == string.Empty)
        //                dic[property.Name.ToUpper()] = null;
        //        }
        //    }
        //    return string.Empty;
        //}
        public static string ValidateDicInEntity(this Type typeinfo, Dictionary<string, object> dic, bool removerKey, PropertyInfo[] propertyInfo, string[] ignoreFields = null)
        {
            if (dic == null || dic.Count == 0) { return "参数无效"; }
            // ä¸å­˜åœ¨çš„字段直接移除
            dic.Where(x => !propertyInfo.Any(p => p.Name.ToUpper() == x.Key.ToUpper())).Select(s => s.Key).ToList().ForEach(f =>
            {
                dic.Remove(f);
            });
            string keyName = typeinfo.GetKeyName();
            //移除主键
            if (removerKey)
                dic.Remove(keyName);
            //else
            //{
            //    if (!dic.ContainsKey(keyName))
            //        return "请传入主键参数";
            //}
            foreach (PropertyInfo property in propertyInfo)
            {
                SugarColumn sugarColumn = property.GetCustomAttribute<SugarColumn>();
                if (sugarColumn == null)
                    return "请配置SugarColumn属性";
                //忽略与主键的字段不做验证
                if (property.Name == keyName.FirstLetterToUpper() || (ignoreFields != null && ignoreFields.Contains(property.Name)) || sugarColumn.IsOnlyIgnoreInsert || sugarColumn.IsOnlyIgnoreUpdate || sugarColumn.IsIgnore)
                    continue;
                //不在编辑中的列,是否也要必填
                if (!dic.ContainsKey(property.Name.FirstLetterToLower()))
                {
                    if (!sugarColumn.IsNullable)
                    {
                        if (sugarColumn.DefaultValue == null)
                            return sugarColumn.ColumnDescription + "为必须提交项";
                        continue;
                    }
                    continue;
                }
                if (dic[property.Name.FirstLetterToLower()] != null)
                {
                    string str = dic[property.Name.FirstLetterToLower()].ToString();
                    //将所有空值设置为null
                    if (str == string.Empty)
                        dic[property.Name.FirstLetterToLower()] = null;
                }
            }
            return string.Empty;
        }
        public static string ValidateDicInEntity(this Type typeinfo, List<Dictionary<string, object>> dicList, bool removerKey, string[] ignoreFields = null)
        {
            PropertyInfo[] propertyInfo = typeinfo.GetProperties();
            string reslutMsg = string.Empty;
            foreach (Dictionary<string, object> dic in dicList)
            {
                reslutMsg = typeinfo.ValidateDicInEntity(dic, removerKey, propertyInfo, ignoreFields);
                if (!string.IsNullOrEmpty(reslutMsg))
                    return reslutMsg;
            }
            return reslutMsg;
        }
        public static string GetKeyName(this Type typeinfo)
        {
            return typeinfo.GetProperties().GetKeyName();
        }
        public static string GetKeyName(this PropertyInfo[] properties)
        {
            foreach (PropertyInfo property in properties)
            {
                SugarColumn sugarColumn = property.GetCustomAttribute<SugarColumn>();
                if (sugarColumn.IsPrimaryKey)
                    return property.Name;
            }
            return null;
        }
        public static PropertyInfo GetKeyProperty(this Type typeinfo)
        {
            PropertyInfo[] properties = typeinfo.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                SugarColumn sugarColumn = property.GetCustomAttribute<SugarColumn>();
                if (sugarColumn?.IsPrimaryKey ?? false)
                {
                    return property;
                }
            }
            return null;
        }
        public static Type GetDetailType(this Type typeinfo)
        {
            PropertyInfo[] properties = typeinfo.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                Navigate? navigate = property.GetCustomAttribute<Navigate>();
                if (navigate is not null)
                {
                    if (navigate.GetNavigateType() == NavigateType.OneToOne)
                        return property.PropertyType;
                    else
                        return property.PropertyType.GenericTypeArguments[0];
                }
            }
            return null;
        }
        public static string GetMainIdByDetail(this Type typeinfo)
        {
            PropertyInfo[] properties = typeinfo.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                Navigate? navigate = property.GetCustomAttribute<Navigate>();
                if (navigate is not null)
                {
                    return navigate.GetName();
                }
            }
            return null;
        }
        public static void SetDetailId<T>(this Type typeinfo, T enetiy, object id, string name)
        {
            PropertyInfo property = typeinfo.GetProperty(name);
            if (property != null)
            {
                property.SetValue(enetiy, id);
            }
        }
        public static PropertyInfo? GetNavigatePro(this Type typeinfo)
        {
            PropertyInfo[] properties = typeinfo.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                Navigate? navigate = property.GetCustomAttribute<Navigate>();
                if (navigate is not null)
                {
                    return property;
                }
            }
            return null;
        }
        public static object GetPropertyValue<T>(this Type typeinfo, T data, string propertyName)
        {
            if (typeinfo != typeof(T))
                return null;
            PropertyInfo? property = typeinfo.GetProperty(propertyName);
            if (property != null)
            {
                return property.GetValue(data);
            }
            return null;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Utilities/LambdaExtensions.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_Core.Helper;
namespace WIDESEAWCS_Core.Utilities
{
    public static class LambdaExtensions
    {
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="propertyName">字段名</param>
        /// <param name="propertyValue">表达式的值</param>
        /// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
        /// p=>p.propertyName.Contains(propertyValue)</param>
        /// <returns></returns>
        public static Expression<Func<T, bool>> CreateExpression<T>(this string propertyName, object propertyValue, LinqExpressionType expressionType)
        {
            return propertyName.CreateExpression<T>(propertyValue, null, expressionType);
        }
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="propertyName">字段名</param>
        /// <param name="propertyValue">表达式的值</param>
        /// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
        /// p=>p.propertyName.Contains(propertyValue)</param>
        /// <returns></returns>
        private static Expression<Func<T, bool>> CreateExpression<T>(
          this string propertyName,
          object propertyValue,
          ParameterExpression parameter,
          LinqExpressionType expressionType)
        {
            Type proType = null;
            PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
            if (propertyInfo != null)
                proType = propertyInfo.PropertyType;
            else
            {
                propertyInfo = typeof(T).GetProperty(propertyName.FirstLetterToLower());
                if (propertyInfo != null)
                    proType = propertyInfo.PropertyType;
                else
                {
                    propertyInfo = typeof(T).GetProperty(propertyName.FirstLetterToUpper());
                    if (propertyInfo != null)
                        proType = propertyInfo.PropertyType;
                    else
                    {
                        throw new Exception($"未找到该属性,type:{typeof(T)}");
                    }
                }
            }
            //创建节点变量如p=>的节点p
            //  parameter ??= Expression.Parameter(typeof(T), "p");//创建参数p
            parameter = parameter ?? Expression.Parameter(typeof(T), "p");
            //创建节点的属性p=>p.name å±žæ€§name
            MemberExpression memberProperty = Expression.PropertyOrField(parameter, propertyName);
            if (expressionType == LinqExpressionType.In)
            {
                if (!(propertyValue is System.Collections.IList list) || list.Count == 0) throw new Exception("属性值类型不正确");
                bool isStringValue = true;
                List<object> objList = new List<object>();
                if (proType.ToString() != "System.String")
                {
                    isStringValue = false;
                    foreach (var value in list)
                    {
                        objList.Add(value.ToString().ChangeType(proType));
                    }
                    list = objList;
                }
                if (isStringValue)
                {
                    //string ç±»åž‹çš„字段,如果值带有'单引号,EF会默认变成''两个单引号
                    MethodInfo method = typeof(System.Collections.IList).GetMethod("Contains");
                    //创建集合常量并设置为常量的值
                    ConstantExpression constantCollection = Expression.Constant(list);
                    //创建一个表示调用带参数的方法的:new string[]{"1","a"}.Contains("a");
                    MethodCallExpression methodCall = Expression.Call(constantCollection, method, memberProperty);
                    return Expression.Lambda<Func<T, bool>>(methodCall, parameter);
                }
                //非string字段,按上面方式处理报异常Null TypeMapping in Sql Tree
                BinaryExpression body = null;
                foreach (var value in list)
                {
                    ConstantExpression constantExpression = Expression.Constant(value);
                    UnaryExpression unaryExpression = Expression.Convert(memberProperty, constantExpression.Type);
                    body = body == null
                        ? Expression.Equal(unaryExpression, constantExpression)
                        : Expression.OrElse(body, Expression.Equal(unaryExpression, constantExpression));
                }
                return Expression.Lambda<Func<T, bool>>(body, parameter);
            }
            //  object value = propertyValue;
            ConstantExpression constant = proType.ToString() == "System.String"
                ? Expression.Constant(propertyValue) : Expression.Constant(propertyValue.ToString().ChangeType(proType));
            // DateTime只选择了日期的时候自动在结束日期加一天,修复DateTime类型使用日期区间查询无法查询到结束日期的问题
            if ((proType == typeof(DateTime) || proType == typeof(DateTime?)) && expressionType == LinqExpressionType.LessThanOrEqual && propertyValue.ToString().Length == 10)
            {
                constant = Expression.Constant(Convert.ToDateTime(propertyValue.ToString()).AddDays(1));
            }
            UnaryExpression member = Expression.Convert(memberProperty, constant.Type);
            Expression<Func<T, bool>> expression;
            switch (expressionType)
            {
                //p=>p.propertyName == propertyValue
                case LinqExpressionType.Equal:
                    expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter);
                    break;
                //p=>p.propertyName != propertyValue
                case LinqExpressionType.NotEqual:
                    expression = Expression.Lambda<Func<T, bool>>(Expression.NotEqual(member, constant), parameter);
                    break;
                //   p => p.propertyName > propertyValue
                case LinqExpressionType.GreaterThan:
                    expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(member, constant), parameter);
                    break;
                //   p => p.propertyName < propertyValue
                case LinqExpressionType.LessThan:
                    expression = Expression.Lambda<Func<T, bool>>(Expression.LessThan(member, constant), parameter);
                    break;
                // p => p.propertyName >= propertyValue
                case LinqExpressionType.ThanOrEqual:
                    expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(member, constant), parameter);
                    break;
                // p => p.propertyName <= propertyValue
                case LinqExpressionType.LessThanOrEqual:
                    expression = Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(member, constant), parameter);
                    break;
                //   p => p.propertyName.Contains(propertyValue)
                // p => !p.propertyName.Contains(propertyValue)
                case LinqExpressionType.Contains:
                case LinqExpressionType.NotContains:
                    MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                    constant = Expression.Constant(propertyValue, typeof(string));
                    if (expressionType == LinqExpressionType.Contains)
                    {
                        expression = Expression.Lambda<Func<T, bool>>(Expression.Call(member, method, constant), parameter);
                    }
                    else
                    {
                        expression = Expression.Lambda<Func<T, bool>>(Expression.Not(Expression.Call(member, method, constant)), parameter);
                    }
                    break;
                default:
                    // p => p.false
                    expression = False<T>();
                    break;
            }
            return expression;
        }
        /// <summary>
        /// åˆ›å»ºlambda表达式:p=>false
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Expression<Func<T, bool>> False<T>()
        {
            return p => false;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Utilities/ModelValidate.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Attributes;
namespace WIDESEAWCS_Core.Utilities
{
    public class ModelValidate
    {
        /// <summary>
        /// éªŒè¯å®žä½“参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        public static (bool, string, object?) ValidateModelData<T>(T data) where T : class, new()
        {
            Type modelType = typeof(T);
            if (data == null) return (false, "传入参数不可为null", data);
            ModelValidateAttribute? modelAttribute = modelType.GetCustomAttribute<ModelValidateAttribute>();
            if (modelAttribute == null) return (false, $"{modelType.Name}未定义【ModelValidateAttribute】特性", data);
            PropertyInfo[] propertyInfos = modelType.GetProperties();
            return SimpleValidate(propertyInfos, data);
        }
        public static (bool, string, object?) ValidateModelData<T>(List<T> datas) where T : class, new()
        {
            Type modelType = typeof(T);
            if (datas == null) return (false, "传入参数不可为null", datas);
            if (datas.Count == 0) return (false, "集合个数不可等于0", datas);
            foreach (T data in datas)
            {
                if (data == null) return (false, "传入参数不可为null", data);
                ModelValidateAttribute? modelAttribute = modelType.GetCustomAttribute<ModelValidateAttribute>();
                if (modelAttribute == null) return (false, $"{modelType.Name}未定义【ModelValidateAttribute】特性", data);
                PropertyInfo[] propertyInfos = modelType.GetProperties();
                (bool, string, object?) result = SimpleValidate(propertyInfos, data);
                if (!result.Item1) return result;
            }
            return (true, $"成功", datas);
        }
        //private static (bool, string, object?) CustomMethodValidate<T>(ModelValidateAttribute modelAttribute, T data) where T : class, new()
        //{
        //    try
        //    {
        //        if (modelAttribute.CustomValidateMethodTypeName == null) return (false, $"自定义验证方法需要提供方法所在类的类型对象", data);
        //        if (modelAttribute.CustomValidateMethodName == null) return (false, $"自定义验证方法需要提供方法名", data);
        //        string path = Path.Combine(AppContext.BaseDirectory, $"{modelAttribute.CustomValidateAssemblyName}.dll");
        //        Assembly assembly = Assembly.LoadFrom(path);
        //        Type t = assembly.GetType(modelAttribute.CustomValidateAssemblyName + "." + modelAttribute.CustomValidateMethodTypeName);
        //        object bbb = App.GetService(t);
        //        MethodInfo? methodInfo = t.GetMethod(modelAttribute.CustomValidateMethodName);
        //        var result = methodInfo.Invoke(bbb, new object[] { data });
        //        //MethodInfo? methodInfo = modelAttribute.CustomValidateMethodType.GetMethod(modelAttribute.CustomValidateMethodName);
        //        //if (methodInfo == null) return (false, $"未在该类型对象【{modelAttribute.CustomValidateMethodType.Name}】中找到该方法【{modelAttribute.CustomValidateMethodName}】", data);
        //        //methodInfo.GetGenericArguments()
        //        return (true, "成功", data);
        //    }
        //    catch(Exception ex)
        //    {
        //        throw new Exception();
        //    }
        //}
        private static (bool, string, object?) SimpleValidate<T>(PropertyInfo[] propertyInfos, T data) where T : class, new()
        {
            try
            {
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    PropertyValidateAttribute? propertyAttribute = propertyInfo.GetCustomAttribute<PropertyValidateAttribute>();
                    if (propertyAttribute == null) continue;
                    object? value = propertyInfo.GetValue(data, null);
                    if (propertyAttribute.NotNullAndEmpty)
                    {
                        if (value == null) return (false, $"{(string.IsNullOrEmpty(propertyAttribute.Description) ? propertyInfo.Name : propertyAttribute.Description)}不可为null", data);
                        if (string.IsNullOrEmpty(value.ToString())) return (false, $"{(string.IsNullOrEmpty(propertyAttribute.Description) ? propertyInfo.Name : propertyAttribute.Description)}不可为空字符串", data);
                    }
                    if (propertyAttribute.MinValue > int.MinValue)
                    {
                        if (value == null) return (false, $"{(string.IsNullOrEmpty(propertyAttribute.Description) ? propertyInfo.Name : propertyAttribute.Description)}不可为null", data);
                        if (propertyAttribute.IsContainMinValue)
                        {
                            if (Convert.ToInt32(value.ToString()) < propertyAttribute.MinValue) return (false, $"{(string.IsNullOrEmpty(propertyAttribute.Description) ? propertyInfo.Name : propertyAttribute.Description)}的值【{value}】不可小于【{propertyAttribute.MinValue}】", data);
                        }
                        else
                        {
                            if (Convert.ToInt32(value.ToString()) <= propertyAttribute.MinValue) return (false, $"{(string.IsNullOrEmpty(propertyAttribute.Description) ? propertyInfo.Name : propertyAttribute.Description)}的值【{value}】要大于【{propertyAttribute.MinValue}】", data);
                        }
                    }
                    if (propertyAttribute.MaxValue < int.MaxValue)
                    {
                        if (value == null) return (false, $"{(string.IsNullOrEmpty(propertyAttribute.Description) ? propertyInfo.Name : propertyAttribute.Description)}不可为null", data);
                        if (propertyAttribute.IsContainMaxValue)
                        {
                            if (Convert.ToInt32(value.ToString()) >= propertyAttribute.MaxValue) return (false, $"{(string.IsNullOrEmpty(propertyAttribute.Description) ? propertyInfo.Name : propertyAttribute.Description)}的值【{value}】不可大于【{propertyAttribute.MaxValue}】", data);
                        }
                        else
                        {
                            if (Convert.ToInt32(value.ToString()) > propertyAttribute.MaxValue) return (false, $"{(string.IsNullOrEmpty(propertyAttribute.Description) ? propertyInfo.Name : propertyAttribute.Description)}的值【{value}】要小于【{propertyAttribute.MaxValue}】", data);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                return (false, $"数据验证异常,异常信息:{ex.Message}", data);
            }
            return (true, "验证成功", data);
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/Utilities/VierificationCode.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,122 @@
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_Core.Utilities
{
    public static class VierificationCode
    {
        private static readonly string[] _chars = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
        private static readonly SKColor[] colors = { SKColors.Black, SKColors.Green, SKColors.Brown };
        private static readonly string[] fonts = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" };
        public static string RandomText()
        {
            string code = "";//产生的随机数
            int temp = -1;
            Random rand = new Random();
            for (int i = 1; i < 5; i++)
            {
                if (temp != -1)
                {
                    rand = new Random(i * temp * unchecked((int)DateTime.Now.Ticks));
                }
                int t = rand.Next(61);
                if (temp != -1 && temp == t)
                {
                    return RandomText();
                }
                temp = t;
                code += _chars[t];
            }
            return code;
        }
        public static string CreateBase64Imgage(string code)
        {
            var random = new Random();
            var info = new SKImageInfo((int)code.Length * 18, 32);
            using var bitmap = new SKBitmap(info);
            using var canvas = new SKCanvas(bitmap);
            canvas.Clear(SKColors.White);
            using var pen = new SKPaint();
            pen.FakeBoldText = true;
            pen.Style = SKPaintStyle.Fill;
            pen.TextSize = 20;// 0.6f * info.Width * pen.TextSize / pen.MeasureText(code);
            //绘制随机字符
            for (int i = 0; i < code.Length; i++)
            {
                pen.Color = random.GetRandom(colors);//随机颜色索引值
                pen.Typeface = SKTypeface.FromFamilyName(random.GetRandom(fonts), 700, 20, SKFontStyleSlant.Italic);//配置字体
                var point = new SKPoint()
                {
                    X = i * 16,
                    Y = 22// info.Height - ((i + 1) % 2 == 0 ? 2 : 4),
                };
                canvas.DrawText(code.Substring(i, 1), point, pen);//绘制一个验证字符
            }
            // ç»˜åˆ¶å™ªç‚¹
            var points = Enumerable.Range(0, 100).Select(
                _ => new SKPoint(random.Next(bitmap.Width), random.Next(bitmap.Height))
            ).ToArray();
            canvas.DrawPoints(
                SKPointMode.Points,
                points,
                pen);
            //绘制贝塞尔线条
            for (int i = 0; i < 2; i++)
            {
                var p1 = new SKPoint(0, 0);
                var p2 = new SKPoint(0, 0);
                var p3 = new SKPoint(0, 0);
                var p4 = new SKPoint(0, 0);
                var touchPoints = new SKPoint[] { p1, p2, p3, p4 };
                using var bPen = new SKPaint();
                bPen.Color = random.GetRandom(colors);
                bPen.Style = SKPaintStyle.Stroke;
                using var path = new SKPath();
                path.MoveTo(touchPoints[0]);
                path.CubicTo(touchPoints[1], touchPoints[2], touchPoints[3]);
                canvas.DrawPath(path, bPen);
            }
            return bitmap.ToBase64String(SKEncodedImageFormat.Png);
        }
        public static T GetRandom<T>(this Random random, T[] tArray)
        {
            if (random == null) random = new Random();
            return tArray[random.Next(tArray.Length)];
        }
        /// <summary>
        /// SKBitmap转Base64String
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static string ToBase64String(this SKBitmap bitmap, SKEncodedImageFormat format)
        {
            using var memStream = new MemoryStream();
            using var wstream = new SKManagedWStream(memStream);
            bitmap.Encode(wstream, format, 32);
            memStream.TryGetBuffer(out ArraySegment<byte> buffer);
            return $"{Convert.ToBase64String(buffer.Array, 0, (int)memStream.Length)}";
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/WIDESEAWCS_Core - Backup.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <Version>1.0.2</Version>
        <Description>更新接口访问授权问题</Description>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Autofac" Version="8.0.0" />
        <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
        <PackageReference Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
        <PackageReference Include="AutoMapper" Version="13.0.1" />
        <PackageReference Include="Magicodes.IE.EPPlus" Version="2.7.5.1" />
        <PackageReference Include="Magicodes.IE.Excel" Version="2.7.5.1" />
        <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.29" />
        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
        <PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.3.8" />
        <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
        <PackageReference Include="OfficeOpenXml.Core.ExcelPackage" Version="1.0.0" />
        <PackageReference Include="SkiaSharp" Version="2.88.8" />
        <PackageReference Include="SqlSugarCore" Version="5.1.4.152" />
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
        <PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.5" />
        <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.5.0" />
        <PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.0" />
        <PackageReference Include="System.Net.Http" Version="4.3.4" />
        <PackageReference Include="System.Security.Cryptography.Pkcs" Version="6.0.3" />
        <PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
    </ItemGroup>
    <ItemGroup>
        <Folder Include="ServiceExtensions\" />
    </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Core/WIDESEAWCS_Core.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <Version>1.0.4</Version>
        <Description>添加单点登录;
修复单表数据修改-修改人修改时间问题</Description>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Autofac" Version="8.0.0" />
        <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
        <PackageReference Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
        <PackageReference Include="AutoMapper" Version="13.0.1" />
        <PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.5" />
        <PackageReference Include="Magicodes.IE.EPPlus" Version="2.7.5.1" />
        <PackageReference Include="Magicodes.IE.Excel" Version="2.7.5.1" />
        <PackageReference Include="Masuit.Tools.Core" Version="2024.5.0" />
        <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.29" />
        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2" />
        <PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.3.8" />
        <PackageReference Include="MoYu.Pure" Version="4.9.5.5" />
        <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
        <PackageReference Include="OfficeOpenXml.Core.ExcelPackage" Version="1.0.0" />
        <PackageReference Include="SkiaSharp" Version="2.88.8" />
        <PackageReference Include="SqlSugarCore" Version="5.1.4.152" />
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.2" />
        <PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.5" />
        <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.5.0" />
        <PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.0" />
        <PackageReference Include="System.Net.Http" Version="4.3.4" />
        <PackageReference Include="System.Security.Cryptography.Pkcs" Version="6.0.3" />
        <PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
    </ItemGroup>
    <ItemGroup>
        <Folder Include="ServiceExtensions\" />
    </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/Enum/TaskEnumHelper.cs
@@ -26,6 +26,10 @@
            {
                return TaskTypeGroup.InboundGroup;
            }
            else if (!int.TryParse(Enum.Parse<AGVTaskStatusEnum>(taskType.ToString()).ToString(), out result))
            {
                return TaskTypeGroup.AGVGroup;
            }
            else if (!int.TryParse(Enum.Parse<TaskRelocationTypeEnum>(taskType.ToString()).ToString(), out result))
            {
                return TaskTypeGroup.RelocationGroup;
@@ -54,6 +58,10 @@
            {
                return type.GetEnumIndexList().Where(x => x > currentStatus && x < (int)TaskOutStatusEnum.OutFinish).OrderBy(x => x).FirstOrDefault();
            }
            else if (type == typeof(AGVTaskStatusEnum))
            {
                return type.GetEnumIndexList().Where(x => x > currentStatus && x < (int)AGVTaskStatusEnum.AGVFinish).OrderBy(x => x).FirstOrDefault();
            }
            else
            {
                throw new NotImplementedException();
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/Enum/TaskStatusEnum.cs
@@ -144,4 +144,43 @@
        [Description("出库任务异常")]
        OutException = 199,
    }
    public enum AGVTaskStatusEnum
    {
        /// <summary>
        /// æ–°å»ºAGV任务
        /// </summary>
        [Description("新建AGV任务")]
        AGVNew = 400,
        /// <summary>
        /// AGV执行中
        /// </summary>
        [Description("AGV任务执行中")]
        AGV_Executing = 410,
        /// <summary>
        /// AGV任务完成
        /// </summary>
        [Description("AGV任务搬运完成")]
        AGVFinish = 490,
        /// <summary>
        /// å‡ºåº“任务挂起
        /// </summary>
        [Description("出库任务挂起")]
        AGVPending = 497,
        /// <summary>
        /// å‡ºåº“任务取消
        /// </summary>
        [Description("出库任务取消")]
        AGVCancel = 498,
        /// <summary>
        /// å‡ºåº“任务异常
        /// </summary>
        [Description("出库任务异常")]
        AGVException = 499,
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/Enum/TaskTypeEnum.cs
@@ -69,6 +69,15 @@
        RelocationIn = 301
    }
    public enum AGVTaskTypeEnum
    {
        /// <summary>
        /// AGV搬运
        /// </summary>
        [Description("AGV搬运")]
        AGVCarry =400
    }
    public enum TaskOtherTypeEnum
    {
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/Enum/TaskTypeGroup.cs
@@ -9,6 +9,7 @@
    public enum TaskTypeGroup
    {
        InboundGroup,
        AGVGroup,
        OutbondGroup,
        RelocationGroup,
        OtherGroup
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_DTO/WIDESEAWCS_DTO.csproj
@@ -14,8 +14,4 @@
      <Folder Include="BasicInfo\" />
    </ItemGroup>
    <ItemGroup>
      <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
    </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoRepository/IDt_StationManagerRepository.cs
ÎļþÃû´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs ÐÞ¸Ä
@@ -22,11 +22,11 @@
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
using WIDESEAWCS_Model.Models.BasicInfo;
namespace WIDESEAWCS_ISystemRepository
namespace WIDESEAWCS_IBasicInfoRepository
{
    public interface IAgvStationRepository : IRepository<AGVStation>
    public interface IDt_StationManagerRepository : IRepository<Dt_StationManager>
    {
    }
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoRepository/WIDESEAWCS_IBasicInfoRepository.csproj
@@ -7,10 +7,6 @@
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\WIDESEAWCS_DTO\WIDESEAWCS_DTO.csproj" />
  </ItemGroup>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/IDt_StationManagerService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_ITaskInfoService
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.BasicInfo;
namespace WIDESEAWCS_IBasicInfoService
{
    public interface IDt_StationManagerService : IService<Dt_StationManager>
    {
        public List<Dt_StationManager> QuerypLatform(string deviceNo, List<string> _Task);
        public List<Dt_StationManager> QuerypLatformarer(string deviceNo);
        public List<Dt_StationManager> QuerypLatformmaterial(int Station_Area);
        public List<Dt_StationManager> QuerypStation_Area(int Station_Area);
        public List<Dt_StationManager> QuerypStation_Area2(string Station_remark);
        /// <summary>
        /// æ ¹æ®PLC设备获取当前设备下的所有启用的站台
        /// </summary>
        /// <param name="DeviceCode"></param>
        /// <returns></returns>
        List<Dt_StationManager> GetAllStationByDeviceCode(string DeviceCode);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_IBasicInfoService/WIDESEAWCS_IBasicInfoService.csproj
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
@@ -7,11 +7,8 @@
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\WIDESEAWCS_BasicInfoRepository\WIDESEAWCS_BasicInfoRepository.csproj" />
    <ProjectReference Include="..\WIDESEAWCS_ISystemServices\WIDESEAWCS_ISystemServices.csproj" />
  </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/WIDESEAWCS_ISystemRepository.csproj
@@ -7,10 +7,6 @@
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
    </ItemGroup>
    <ItemGroup>
        <ProjectReference Include="..\WIDESEAWCS_DTO\WIDESEAWCS_DTO.csproj" />
    </ItemGroup>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemServices/IAgvStationService.cs
ÎļþÒÑɾ³ý
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemServices/WIDESEAWCS_ISystemServices.csproj
@@ -7,10 +7,6 @@
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
    </ItemGroup>
    <ItemGroup>
        <ProjectReference Include="..\WIDESEAWCS_SystemRepository\WIDESEAWCS_SystemRepository.csproj" />
    </ItemGroup>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/ITaskRepository.cs
@@ -27,6 +27,6 @@
{
    public interface ITaskRepository : IRepository<Dt_Task>
    {
        Task<int> GetTaskNo();
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoRepository/WIDESEAWCS_ITaskInfoRepository.csproj
@@ -7,10 +7,6 @@
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
    </ItemGroup>
    <ItemGroup>
      <ProjectReference Include="..\WIDESEAWCS_DTO\WIDESEAWCS_DTO.csproj" />
    </ItemGroup>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs
@@ -54,7 +54,7 @@
        /// </summary>
        /// <param name="taskDTOs">WMS任务对象集合</param>
        /// <returns>返回处理结果</returns>
        WebResponseContent ReceiveWMSTask(Dt_Task taskDTOs);
        WebResponseContent ReceiveWMSTask([NotNull] List<Dt_Task> taskDTOs);
        
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号、当前地址查询输送线未执行的任务
@@ -70,11 +70,6 @@
        /// <param name="currentAddress"></param>
        /// <returns></returns>
        List<string> QueryConveyorLineTaskSourceAddress();
        /// <summary>
        /// æŸ¥æ‰¾ä»»åŠ¡æ˜¯å¦éœ€è¦åœ°å€
        /// </summary>
        /// <returns></returns>
        Dt_Task QueryConveyorLineTaskRoadway(int agvarea);
        /// <summary>
        /// æŸ¥æ‰¾è¯¥åœ°å€æ˜¯å¦æœ‰èµ·ç‚¹è´§ç»ˆç‚¹ä»»åŠ¡
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/WIDESEAWCS_ITaskInfoService.csproj
@@ -7,10 +7,6 @@
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
    </ItemGroup>
    <ItemGroup>
        <ProjectReference Include="..\WIDESEAWCS_TaskInfoRepository\WIDESEAWCS_TaskInfoRepository.csproj" />
    </ItemGroup>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/BasicInfo/Dt_StationManager.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
using Magicodes.ExporterAndImporter.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
using WIDESEAWCS_Core.Tenants;
namespace WIDESEAWCS_Model.Models.BasicInfo
{
    public class Dt_StationManager: BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [ImporterHeader(Name = "主键")]
        [ExporterHeader(DisplayName = "主键")]
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true,IsNullable =false, ColumnDescription = "主键")]
        public int stationID { get; set; }
        /// <summary>
        /// ç«™å°ç¼–号
        /// </summary>
        [SugarColumn( ColumnDescription = "站台编号")]
        public string stationCode { get; set; }
        /// <summary>
        /// ç«™å°åç§°remark
        /// </summary>
        [SugarColumn(Length = 50, ColumnDescription = "站台名称")]
        public string stationName { get; set; }
        /// <summary>
        /// ç±»åž‹
        /// </summary>
        [SugarColumn( ColumnDescription = "站台类型")]
        public int stationMaterial { get; set; }
        /// <summary>
        /// æ˜¯å¦å¯ç”¨
        /// </summary>
        [SugarColumn( ColumnDescription = "是否启用")]
        public int stationEnable { get; set; }
        /// <summary>
        /// åŒºåŸŸ
        /// </summary>
        [SugarColumn( ColumnDescription = "区域")]
        public int stationArea { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [SugarColumn( Length = 50, ColumnDescription = "备注")]
        public string stationRemark { get; set; }
        /// <summary>
        /// ç«™å°æ‰€å±žè®¾å¤‡
        /// </summary>
        [SugarColumn(Length = 50, IsNullable = false, ColumnDescription = "站台所属设备")]
        public string DeviceCode { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/System/AGVStation.cs
ÎļþÒÑɾ³ý
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/Dt_Task.cs
@@ -51,7 +51,7 @@
        [ImporterHeader(Name = "托盘编号")]
        [ExporterHeader(DisplayName = "托盘编号")]
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "托盘编号")]
        public string PalletCode { get; set; }
        public string AGVName { get; set; }
        /// <summary>
        /// åŒºåŸŸå·
@@ -126,14 +126,6 @@
        public int Grade { get; set; }
        /// <summary>
        /// WMS任务主键
        /// </summary>
        [ImporterHeader(Name = "WMS任务主键")]
        [ExporterHeader(DisplayName = "WMS任务主键")]
        [SugarColumn(IsNullable = false, ColumnDescription = "WMS任务主键")]
        public int WMSId { get; set; }
        /// <summary>
        /// ä»»åŠ¡ä¸‹å‘æ—¶é—´
        /// </summary>
        [ImporterHeader(Name = "任务下发时间")]
@@ -149,26 +141,5 @@
        [SugarColumn(IsNullable = true, Length = 255, ColumnDescription = "备注")]
        public string Remark { get; set; }
        /// <summary>
        /// æ‰˜ç›˜æ•°é‡
        /// </summary>
        [ImporterHeader(Name = "托盘数量")]
        [ExporterHeader(DisplayName = "托盘数量")]
        [SugarColumn(IsNullable = true, ColumnDescription = "托盘数量")]
        public int PalletCodequantity { get; set; }
        /// <summary>
        /// åŽŸææ–™åŽ»å‘
        /// </summary>
        [ImporterHeader(Name = "原材料去向")]
        [ExporterHeader(DisplayName = "原材料去向")]
        [SugarColumn(IsNullable = false, ColumnDescription = "原材料去向")]
        public int PLCTo { get; set; }
        /// <summary>
        /// ç‰©æ–™ç±»åž‹
        /// </summary>
        [ExporterHeader(DisplayName = "物料类型")]
        [SugarColumn(IsNullable = false, ColumnDescription = "物料类型")]
        public int MaterialType { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/Models/TaskInfo/Dt_Task_hty.cs
@@ -51,7 +51,7 @@
        [ImporterHeader(Name = "托盘编号")]
        [ExporterHeader(DisplayName = "托盘编号")]
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "托盘编号")]
        public string PalletCode { get; set; }
        public string AGVName { get; set; }
        /// <summary>
        /// å··é“号
@@ -126,14 +126,6 @@
        public int Grade { get; set; }
        /// <summary>
        /// WMS任务主键
        /// </summary>
        [ImporterHeader(Name = "WMS任务主键")]
        [ExporterHeader(DisplayName = "WMS任务主键")]
        [SugarColumn(IsNullable = false, ColumnDescription = "WMS任务主键")]
        public int WMSId { get; set; }
        /// <summary>
        /// ä»»åŠ¡ä¸‹å‘æ—¶é—´
        /// </summary>
        [ImporterHeader(Name = "任务下发时间")]
@@ -148,26 +140,6 @@
        [ExporterHeader(DisplayName = "备注")]
        [SugarColumn(IsNullable = true, Length = 255, ColumnDescription = "备注")]
        public string Remark { get; set; }
        /// <summary>
        /// æ‰˜ç›˜æ•°é‡
        /// </summary>
        [ImporterHeader(Name = "托盘数量")]
        [ExporterHeader(DisplayName = "托盘数量")]
        [SugarColumn(IsNullable = false, ColumnDescription = "托盘数量")]
        public int PalletCodequantity { get; set; }
        /// <summary>
        /// åŽŸææ–™åŽ»å‘
        /// </summary>
        [ImporterHeader(Name = "原材料去向")]
        [ExporterHeader(DisplayName = "原材料去向")]
        [SugarColumn(IsNullable = false, ColumnDescription = "原材料去向")]
        public int PLCTo { get; set; }
        /// <summary>
        /// ç‰©æ–™ç±»åž‹PalletCodequantity
        /// </summary>
        [ExporterHeader(DisplayName = "物料类型")]
        [SugarColumn(IsNullable = false, ColumnDescription = "物料类型")]
        public int MaterialType { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_Model/WIDESEAWCS_Model.csproj
@@ -8,15 +8,11 @@
    <ItemGroup>
        <PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
        <PackageReference Include="WIDESEAWCS_Core" Version="1.0.7" />
    </ItemGroup>
    <ItemGroup>
        <ProjectReference Include="..\WIDESEAWCS_Common\WIDESEAWCS_Common.csproj" />
    </ItemGroup>
    <ItemGroup>
      <Folder Include="Models\BasicInfo\" />
        <ProjectReference Include="..\WIDESEAWCS_Core\WIDESEAWCS_Core.csproj" />
    </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/CommonConveyorLine.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,343 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šä¸€èˆ¬è¾“送线实现类
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.ConveyorLine.Enum;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.StackerCrane.Enum;
namespace WIDESEAWCS_QuartzJob
{
    [Description("输送线")]
    public class CommonConveyorLine : IConveyorLine
    {
        #region Private Member
        /// <summary>
        /// å †åž›æœºé€šè®¯å¯¹è±¡
        /// </summary>
        private readonly BaseCommunicator _communicator;
        /// <summary>
        /// å †åž›æœºåè®®ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProDTO> _deviceProDTOs;
        /// <summary>
        /// å †åž›æœºåè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProtocolDetailDTO> _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public readonly string _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public readonly string _deviceName;
        private bool _heartStatr = true;
        private bool _isConnected = true;
        #endregion
        #region Public Member
        /// <summary>
        /// è¾“送线通讯对象
        /// </summary>
        public BaseCommunicator Communicator => _communicator;
        /// <summary>
        /// è¾“送线协议信息
        /// </summary>
        public List<DeviceProDTO> DeviceProDTOs => _deviceProDTOs;
        /// <summary>
        /// è¾“送线协议明细信息
        /// </summary>
        public List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public string DeviceCode => _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName => _deviceName;
        /// <summary>
        /// æ˜¯å¦æœ‰æ•…éšœ
        /// </summary>
        public bool IsFault => false;
        /// <summary>
        /// é€šè®¯æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        public bool IsConnected => Communicator.IsConnected && _isConnected;
        /// <summary>
        /// è®¾å¤‡çŠ¶æ€
        /// </summary>
        public DeviceStatus Status => DeviceStatus.Offline;
        #endregion
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
        /// <param name="communicator">堆垛机通讯对象</param>
        /// <param name="deviceProDTOs">堆垛机协议信息</param>
        /// <param name="deviceProtocolDetailDTOs">堆垛机协议明细信息</param>
        /// <param name="deviceCode">设备编号</param>
        /// <param name="deviceName">设备名称</param>
        public CommonConveyorLine(BaseCommunicator communicator, List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs, string deviceCode, string deviceName)
        {
            _communicator = communicator;
            _deviceProDTOs = deviceProDTOs;
            _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs;
            _deviceCode = deviceCode;
            _deviceName = deviceName;
            CheckConnect();
        }
        #endregion
        #region Private Method
        private void CheckConnect()
        {
            Task.Run(() =>
            {
                while (_heartStatr)
                {
                    try
                    {
                        DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault();
                        if (devicePro == null)
                            _isConnected = false;
                        else
                            Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                        _isConnected = true;
                    }
                    catch (Exception ex)
                    {
                        _isConnected = false;
                    }
                    Thread.Sleep(500);
                }
            });
        }
        #endregion
        #region Public Method
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TRsult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        public TRsult GetValue<TEnum, TRsult>(TEnum value, string deviceChildCode) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络【 {DeviceName} ã€‘");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : (TRsult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// ä¸Žè®¾å¤‡çš„心跳
        /// </summary>
        public void Heartbeat()
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="command"></param>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool SendCommand<T>(T command, string deviceChildCode) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络【{DeviceName}】");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == nameof(DeviceCommand) && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                return false;
            }
            if (Communicator.WriteCustomer(devicePro.DeviceProAddress, command))
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// è¯»å–PLC数据,返回自定义对象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="deviceChildCode">子设备编号</param>
        /// <returns>返回自定义对象或抛出异常</returns>
        /// <exception cref="Exception"></exception>
        public T ReadCustomer<T>(string deviceChildCode) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络【{DeviceName}】");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == "ReadDeviceCommand" && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                throw new Exception("未找到协议信息:" + deviceChildCode);
            }
            else
            {
                return Communicator.ReadCustomer<T>(devicePro.DeviceProAddress);
            }
        }
        /// <summary>
        /// è¯»å–PLC数据,返回自定义对象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="deviceChildCode">子设备编号</param>
        /// <param name="deviceProParamType">参数类型</param>
        /// <returns>返回自定义对象或抛出异常</returns>
        /// <exception cref="Exception"></exception>
        public T ReadCustomer<T>(string deviceChildCode, string deviceProParamType) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络【{DeviceName}】");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == deviceProParamType && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                throw new Exception("未找到协议信息:" + deviceChildCode);
            }
            else
            {
                return Communicator.ReadCustomer<T>(devicePro.DeviceProAddress);
            }
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络【 {DeviceName} ã€‘");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        /// <summary>
        /// æ£€æµ‹ç«™å°æ˜¯å¦æœ‰è´§
        /// </summary>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool IsOccupied(string deviceChildCode)
        {
            if (Communicator.IsConnected)
            {
                List<DeviceProDTO> devicePros = _deviceProDTOs.Where(x => x.DeviceProParamType == ConveyorLineStatus.IsOccupied.ToString()).ToList();
                if (devicePros.Count == 0)
                {
                    //todo åè®®ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                    throw new Exception();
                }
                for (int i = 0; i < devicePros.Count; i++)
                {
                    object readStatus = Communicator.ReadAsObj(devicePros[i].DeviceProAddress, devicePros[i].DeviceDataType);
                    //todo åè®®æ˜Žç»†ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                    DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePros[i].DeviceProParamName) ?? throw new Exception();
                    deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePros[i].DeviceProParamType && x.ProtocalDetailValue.Equals(readStatus.ToString()));
                    if (deviceProtocolDetail != null)
                    {
                        return true;
                    }
                    return false;
                }
            }
            //todo é€šè®¯æœªè¿žæŽ¥æ—¶æŠ›å‡ºå¼‚常
            return false;
        }
        /// <summary>
        /// æ£€æµ‹ç«™å°æ˜¯å¦æœ‰è´§
        /// </summary>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool IsOccupiedx(string deviceChildCode)
        {
            if (Communicator.IsConnected)
            {
                var device = _deviceProDTOs.Where(x => x.DeviceChildCode == deviceChildCode && x.DeviceProParamName == "InteractiveSignal").FirstOrDefault();
                object readStatus = Communicator.ReadAsObj(device.DeviceProAddress, device.DeviceDataType);
                //todo åè®®æ˜Žç»†ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                if (readStatus.ToString() != "2")
                {
                    return true;
                }
                return false;
            }
            //todo é€šè®¯æœªè¿žæŽ¥æ—¶æŠ›å‡ºå¼‚常
            return false;
        }
        public void Dispose()
        {
            _heartStatr = false;
            _communicator.Dispose();
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/CommonConveyorLine_After.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,342 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šä¸€èˆ¬è¾“送线实现类
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.ConveyorLine.Enum;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.StackerCrane.Enum;
namespace WIDESEAWCS_QuartzJob
{
    [Description("输送线")]
    public class CommonConveyorLine_After : IConveyorLine
    {
        #region Private Member
        /// <summary>
        /// å †åž›æœºé€šè®¯å¯¹è±¡
        /// </summary>
        private readonly BaseCommunicator _communicator;
        /// <summary>
        /// å †åž›æœºåè®®ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProDTO> _deviceProDTOs;
        /// <summary>
        /// å †åž›æœºåè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProtocolDetailDTO> _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public readonly string _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public readonly string _deviceName;
        private bool _heartStatr = true;
        private bool _isConnected = true;
        #endregion
        #region Public Member
        /// <summary>
        /// è¾“送线通讯对象
        /// </summary>
        public BaseCommunicator Communicator => _communicator;
        /// <summary>
        /// è¾“送线协议信息
        /// </summary>
        public List<DeviceProDTO> DeviceProDTOs => _deviceProDTOs;
        /// <summary>
        /// è¾“送线协议明细信息
        /// </summary>
        public List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public string DeviceCode => _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName => _deviceName;
        /// <summary>
        /// æ˜¯å¦æœ‰æ•…éšœ
        /// </summary>
        public bool IsFault => false;
        /// <summary>
        /// é€šè®¯æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        public bool IsConnected => Communicator.IsConnected && _isConnected;
        /// <summary>
        /// è®¾å¤‡çŠ¶æ€
        /// </summary>
        public DeviceStatus Status => DeviceStatus.Offline;
        #endregion
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
        /// <param name="communicator">堆垛机通讯对象</param>
        /// <param name="deviceProDTOs">堆垛机协议信息</param>
        /// <param name="deviceProtocolDetailDTOs">堆垛机协议明细信息</param>
        /// <param name="deviceCode">设备编号</param>
        /// <param name="deviceName">设备名称</param>
        public CommonConveyorLine_After(BaseCommunicator communicator, List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs, string deviceCode, string deviceName)
        {
            _communicator = communicator;
            _deviceProDTOs = deviceProDTOs;
            _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs;
            _deviceCode = deviceCode;
            _deviceName = deviceName;
            CheckConnect();
        }
        #endregion
        #region Private Method
        private void CheckConnect()
        {
            Task.Run(() =>
            {
                while (_heartStatr)
                {
                    try
                    {
                        DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault();
                        if (devicePro == null)
                            _isConnected = false;
                        else
                            Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                        _isConnected = true;
                    }
                    catch (Exception ex)
                    {
                        _isConnected = false;
                    }
                    Thread.Sleep(500);
                }
            });
        }
        #endregion
        #region Public Method
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TRsult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        public TRsult GetValue<TEnum, TRsult>(TEnum value, string deviceChildCode) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : (TRsult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// ä¸Žè®¾å¤‡çš„心跳
        /// </summary>
        public void Heartbeat()
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="command"></param>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool SendCommand<T>(T command, string deviceChildCode) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == nameof(DeviceCommand) && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                return false;
            }
            if (Communicator.WriteCustomer(devicePro.DeviceProAddress, command))
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// è¯»å–PLC数据,返回自定义对象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="deviceChildCode">子设备编号</param>
        /// <returns>返回自定义对象或抛出异常</returns>
        /// <exception cref="Exception"></exception>
        public T ReadCustomer<T>(string deviceChildCode) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == "DeviceCommand" && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                throw new Exception("未找到协议信息");
            }
            else
            {
                return Communicator.ReadCustomer<T>(devicePro.DeviceProAddress);
            }
        }
        /// <summary>
        /// è¯»å–PLC数据,返回自定义对象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="deviceChildCode">子设备编号</param>
        /// <param name="deviceProParamType">参数类型</param>
        /// <returns>返回自定义对象或抛出异常</returns>
        /// <exception cref="Exception"></exception>
        public T ReadCustomer<T>(string deviceChildCode, string deviceProParamType) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == deviceProParamType && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                throw new Exception("未找到协议信息");
            }
            else
            {
                return Communicator.ReadCustomer<T>(devicePro.DeviceProAddress);
            }
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号读取对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public object ReadValue<TEnum>(TEnum @enum, string deviceChildCode)
            where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        //public bool IsOccupied(string deviceChildCode)
        //{
        //    if (Communicator.IsConnected)
        //    {
        //    }
        //}
        /// <summary>
        ///
        /// </summary>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool IsOccupied(string deviceChildCode)
        {
            if (Communicator.IsConnected)
            {
                List<DeviceProDTO> devicePros = _deviceProDTOs.Where(x => x.DeviceChildCode == deviceChildCode && x.DeviceProParamName == "InteractiveSignal").ToList();
                if (devicePros.Count == 0)
                {
                    //todo åè®®ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                    throw new Exception();
                }
                for (int i = 0; i < devicePros.Count; i++)
                {
                    object readStatus = Communicator.ReadAsObj(devicePros[i].DeviceProAddress, devicePros[i].DeviceDataType);
                    //todo åè®®æ˜Žç»†ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                    DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePros[i].DeviceProParamName) ?? throw new Exception();
                    deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == "InteractiveSignal" && x.ProtocalDetailValue.Equals(readStatus.ToString()));
                    if (deviceProtocolDetail != null)
                    {
                        return true;
                    }
                    return false;
                }
            }
            //todo é€šè®¯æœªè¿žæŽ¥æ—¶æŠ›å‡ºå¼‚常
            return false;
        }
        public void Dispose()
        {
            _heartStatr = false;
            _communicator.Dispose();
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/CommonConveyorLine_BZ.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,342 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šä¸€èˆ¬è¾“送线实现类
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.ConveyorLine.Enum;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.StackerCrane.Enum;
namespace WIDESEAWCS_QuartzJob
{
    [Description("输送线")]
    public class CommonConveyorLine_BZ : IConveyorLine
    {
        #region Private Member
        /// <summary>
        /// å †åž›æœºé€šè®¯å¯¹è±¡
        /// </summary>
        private readonly BaseCommunicator _communicator;
        /// <summary>
        /// å †åž›æœºåè®®ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProDTO> _deviceProDTOs;
        /// <summary>
        /// å †åž›æœºåè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProtocolDetailDTO> _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public readonly string _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public readonly string _deviceName;
        private bool _heartStatr = true;
        private bool _isConnected = true;
        #endregion
        #region Public Member
        /// <summary>
        /// è¾“送线通讯对象
        /// </summary>
        public BaseCommunicator Communicator => _communicator;
        /// <summary>
        /// è¾“送线协议信息
        /// </summary>
        public List<DeviceProDTO> DeviceProDTOs => _deviceProDTOs;
        /// <summary>
        /// è¾“送线协议明细信息
        /// </summary>
        public List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public string DeviceCode => _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName => _deviceName;
        /// <summary>
        /// æ˜¯å¦æœ‰æ•…éšœ
        /// </summary>
        public bool IsFault => false;
        /// <summary>
        /// é€šè®¯æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        public bool IsConnected => Communicator.IsConnected && _isConnected;
        /// <summary>
        /// è®¾å¤‡çŠ¶æ€
        /// </summary>
        public DeviceStatus Status => DeviceStatus.Offline;
        #endregion
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
        /// <param name="communicator">堆垛机通讯对象</param>
        /// <param name="deviceProDTOs">堆垛机协议信息</param>
        /// <param name="deviceProtocolDetailDTOs">堆垛机协议明细信息</param>
        /// <param name="deviceCode">设备编号</param>
        /// <param name="deviceName">设备名称</param>
        public CommonConveyorLine_BZ(BaseCommunicator communicator, List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs, string deviceCode, string deviceName)
        {
            _communicator = communicator;
            _deviceProDTOs = deviceProDTOs;
            _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs;
            _deviceCode = deviceCode;
            _deviceName = deviceName;
            CheckConnect();
        }
        #endregion
        #region Private Method
        private void CheckConnect()
        {
            Task.Run(() =>
            {
                while (_heartStatr)
                {
                    try
                    {
                        DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault();
                        if (devicePro == null)
                            _isConnected = false;
                        else
                            Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                        _isConnected = true;
                    }
                    catch (Exception ex)
                    {
                        _isConnected = false;
                    }
                    Thread.Sleep(500);
                }
            });
        }
        #endregion
        #region Public Method
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TRsult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        public TRsult GetValue<TEnum, TRsult>(TEnum value, string deviceChildCode) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : (TRsult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// ä¸Žè®¾å¤‡çš„心跳
        /// </summary>
        public void Heartbeat()
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="command"></param>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool SendCommand<T>(T command, string deviceChildCode) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == nameof(DeviceCommand) && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                return false;
            }
            if (Communicator.WriteCustomer(devicePro.DeviceProAddress, command))
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// è¯»å–PLC数据,返回自定义对象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="deviceChildCode">子设备编号</param>
        /// <returns>返回自定义对象或抛出异常</returns>
        /// <exception cref="Exception"></exception>
        public T ReadCustomer<T>(string deviceChildCode) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == "DeviceCommand" && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                throw new Exception($"【{_deviceCode}】--未找到【{deviceChildCode}】协议信息");
            }
            else
            {
                return Communicator.ReadCustomer<T>(devicePro.DeviceProAddress);
            }
        }
        /// <summary>
        /// è¯»å–PLC数据,返回自定义对象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="deviceChildCode">子设备编号</param>
        /// <param name="deviceProParamType">参数类型</param>
        /// <returns>返回自定义对象或抛出异常</returns>
        /// <exception cref="Exception"></exception>
        public T ReadCustomer<T>(string deviceChildCode, string deviceProParamType) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == deviceProParamType && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                throw new Exception($"未找到【{deviceChildCode}】协议信息");
            }
            else
            {
                return Communicator.ReadCustomer<T>(devicePro.DeviceProAddress);
            }
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号读取对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public object ReadValue<TEnum>(TEnum @enum, string deviceChildCode)
            where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        //public bool IsOccupied(string deviceChildCode)
        //{
        //    if (Communicator.IsConnected)
        //    {
        //    }
        //}
        /// <summary>
        ///
        /// </summary>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool IsOccupied(string deviceChildCode)
        {
            if (Communicator.IsConnected)
            {
                List<DeviceProDTO> devicePros = _deviceProDTOs.Where(x => x.DeviceChildCode == deviceChildCode && x.DeviceProParamName == "InteractiveSignal").ToList();
                if (devicePros.Count == 0)
                {
                    //todo åè®®ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                    throw new Exception();
                }
                for (int i = 0; i < devicePros.Count; i++)
                {
                    object readStatus = Communicator.ReadAsObj(devicePros[i].DeviceProAddress, devicePros[i].DeviceDataType);
                    //todo åè®®æ˜Žç»†ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                    DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePros[i].DeviceProParamName) ?? throw new Exception();
                    deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == "InteractiveSignal" && x.ProtocalDetailValue.Equals(readStatus.ToString()));
                    if (deviceProtocolDetail != null)
                    {
                        return true;
                    }
                    return false;
                }
            }
            //todo é€šè®¯æœªè¿žæŽ¥æ—¶æŠ›å‡ºå¼‚常
            return false;
        }
        public void Dispose()
        {
            _heartStatr = false;
            _communicator.Dispose();
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/CommonConveyorLine_GW.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,342 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šä¸€èˆ¬è¾“送线实现类
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.ConveyorLine.Enum;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.StackerCrane.Enum;
namespace WIDESEAWCS_QuartzJob
{
    [Description("输送线")]
    public class CommonConveyorLine_GW : IConveyorLine
    {
        #region Private Member
        /// <summary>
        /// å †åž›æœºé€šè®¯å¯¹è±¡
        /// </summary>
        private readonly BaseCommunicator _communicator;
        /// <summary>
        /// å †åž›æœºåè®®ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProDTO> _deviceProDTOs;
        /// <summary>
        /// å †åž›æœºåè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        private readonly List<DeviceProtocolDetailDTO> _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public readonly string _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public readonly string _deviceName;
        private bool _heartStatr = true;
        private bool _isConnected = true;
        #endregion
        #region Public Member
        /// <summary>
        /// è¾“送线通讯对象
        /// </summary>
        public BaseCommunicator Communicator => _communicator;
        /// <summary>
        /// è¾“送线协议信息
        /// </summary>
        public List<DeviceProDTO> DeviceProDTOs => _deviceProDTOs;
        /// <summary>
        /// è¾“送线协议明细信息
        /// </summary>
        public List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs => _deviceProtocolDetailDTOs;
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        public string DeviceCode => _deviceCode;
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        public string DeviceName => _deviceName;
        /// <summary>
        /// æ˜¯å¦æœ‰æ•…éšœ
        /// </summary>
        public bool IsFault => false;
        /// <summary>
        /// é€šè®¯æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        public bool IsConnected => Communicator.IsConnected && _isConnected;
        /// <summary>
        /// è®¾å¤‡çŠ¶æ€
        /// </summary>
        public DeviceStatus Status => DeviceStatus.Offline;
        #endregion
        #region Constructor Function
        /// <summary>
        /// æž„造函数
        /// </summary>
        /// <param name="communicator">堆垛机通讯对象</param>
        /// <param name="deviceProDTOs">堆垛机协议信息</param>
        /// <param name="deviceProtocolDetailDTOs">堆垛机协议明细信息</param>
        /// <param name="deviceCode">设备编号</param>
        /// <param name="deviceName">设备名称</param>
        public CommonConveyorLine_GW(BaseCommunicator communicator, List<DeviceProDTO> deviceProDTOs, List<DeviceProtocolDetailDTO> deviceProtocolDetailDTOs, string deviceCode, string deviceName)
        {
            _communicator = communicator;
            _deviceProDTOs = deviceProDTOs;
            _deviceProtocolDetailDTOs = deviceProtocolDetailDTOs;
            _deviceCode = deviceCode;
            _deviceName = deviceName;
            CheckConnect();
        }
        #endregion
        #region Private Method
        private void CheckConnect()
        {
            Task.Run(() =>
            {
                while (_heartStatr)
                {
                    try
                    {
                        DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault();
                        if (devicePro == null)
                            _isConnected = false;
                        else
                            Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
                        _isConnected = true;
                    }
                    catch (Exception ex)
                    {
                        _isConnected = false;
                    }
                    Thread.Sleep(500);
                }
            });
        }
        #endregion
        #region Public Method
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TRsult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        public TRsult GetValue<TEnum, TRsult>(TEnum value, string deviceChildCode) where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == value.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : (TRsult)Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        /// <summary>
        /// ä¸Žè®¾å¤‡çš„心跳
        /// </summary>
        public void Heartbeat()
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="command"></param>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool SendCommand<T>(T command, string deviceChildCode) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == nameof(DeviceCommand) && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                return false;
            }
            if (Communicator.WriteCustomer(devicePro.DeviceProAddress, command))
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// è¯»å–PLC数据,返回自定义对象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="deviceChildCode">子设备编号</param>
        /// <returns>返回自定义对象或抛出异常</returns>
        /// <exception cref="Exception"></exception>
        public T ReadCustomer<T>(string deviceChildCode) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == "DeviceCommand" && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                throw new Exception($"【{_deviceCode}】--未找到【{deviceChildCode}】协议信息");
            }
            else
            {
                return Communicator.ReadCustomer<T>(devicePro.DeviceProAddress);
            }
        }
        /// <summary>
        /// è¯»å–PLC数据,返回自定义对象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="deviceChildCode">子设备编号</param>
        /// <param name="deviceProParamType">参数类型</param>
        /// <returns>返回自定义对象或抛出异常</returns>
        /// <exception cref="Exception"></exception>
        public T ReadCustomer<T>(string deviceChildCode, string deviceProParamType) where T : IDataTransfer, new()
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.Where(x => x.DeviceProParamType == deviceProParamType && x.DeviceChildCode == deviceChildCode).OrderBy(x => x.DeviceProOffset).FirstOrDefault();
            if (devicePro == null)
            {
                throw new Exception($"未找到【{deviceChildCode}】协议信息");
            }
            else
            {
                return Communicator.ReadCustomer<T>(devicePro.DeviceProAddress);
            }
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode)
            where TEnum : Enum
            where TValue : notnull
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : Communicator.WriteObj(devicePro.DeviceProAddress, devicePro.DeviceDataType, value);
        }
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号读取对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        public object ReadValue<TEnum>(TEnum @enum, string deviceChildCode)
            where TEnum : Enum
        {
            if (!IsConnected) throw new Exception($"通讯连接错误,请检查网络");
            DeviceProDTO? devicePro = _deviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == @enum.ToString() && x.DeviceChildCode == deviceChildCode);
            return devicePro == null ? throw new Exception() : Communicator.ReadAsObj(devicePro.DeviceProAddress, devicePro.DeviceDataType);
        }
        //public bool IsOccupied(string deviceChildCode)
        //{
        //    if (Communicator.IsConnected)
        //    {
        //    }
        //}
        /// <summary>
        ///
        /// </summary>
        /// <param name="deviceChildCode"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool IsOccupied(string deviceChildCode)
        {
            if (Communicator.IsConnected)
            {
                List<DeviceProDTO> devicePros = _deviceProDTOs.Where(x => x.DeviceChildCode == deviceChildCode && x.DeviceProParamName == "InteractiveSignal").ToList();
                if (devicePros.Count == 0)
                {
                    //todo åè®®ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                    throw new Exception();
                }
                for (int i = 0; i < devicePros.Count; i++)
                {
                    object readStatus = Communicator.ReadAsObj(devicePros[i].DeviceProAddress, devicePros[i].DeviceDataType);
                    //todo åè®®æ˜Žç»†ä¿¡æ¯æœªèŽ·å–åˆ°æ—¶æŠ›å‡ºå¼‚å¸¸
                    DeviceProtocolDetailDTO? deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == devicePros[i].DeviceProParamName) ?? throw new Exception();
                    deviceProtocolDetail = _deviceProtocolDetailDTOs.FirstOrDefault(x => x.DeviceProParamName == "InteractiveSignal" && x.ProtocalDetailValue.Equals(readStatus.ToString()));
                    if (deviceProtocolDetail != null)
                    {
                        return true;
                    }
                    return false;
                }
            }
            //todo é€šè®¯æœªè¿žæŽ¥æ—¶æŠ›å‡ºå¼‚常
            return false;
        }
        public void Dispose()
        {
            _heartStatr = false;
            _communicator.Dispose();
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/Enum/ConveyorLineStatus.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.ConveyorLine.Enum
{
    public enum ConveyorLineStatus
    {
        /// <summary>
        /// æœªçŸ¥
        /// </summary>
        [Description("未知")]
        Unknown,
        /// <summary>
        /// æ˜¯å¦è¢«å ç”¨
        /// </summary>
        [Description("是否被占用")]
        IsOccupied,
        InteractiveSignal,
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ConveyorLine/IConveyorLine.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,88 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè¾“送线接口层
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Communicator;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
namespace WIDESEAWCS_QuartzJob
{
    public interface IConveyorLine : IDevice
    {
        /// <summary>
        /// è¾“送线通讯对象
        /// </summary>
        BaseCommunicator Communicator { get; }
        /// <summary>
        /// è¾“送线协议信息
        /// </summary>
        List<DeviceProDTO> DeviceProDTOs { get; }
        /// <summary>
        /// è¾“送线协议明细信息
        /// </summary>
        List<DeviceProtocolDetailDTO> DeviceProtocolDetailDTOs { get; }
        /// <summary>
        /// ä¸Žè®¾å¤‡çš„心跳
        /// </summary>
        void Heartbeat();
        /// <summary>
        /// è¯»å–PLC协议地址的数据
        /// </summary>
        /// <typeparam name="TEnum">协议信息的枚举对象信息。</typeparam>
        /// <typeparam name="TRsult">读取数据的类型对象信息。</typeparam>
        /// <param name="value">枚举值</param>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns>读取到的数据</returns>
        TRsult GetValue<TEnum, TRsult>(TEnum value, string deviceChildCode) where TEnum : Enum;
        /// <summary>
        /// æ ¹æ®å‚数名称、设备子编号写入对应的数据。
        /// </summary>
        /// <typeparam name="TEnum">参数名称枚举类型。</typeparam>
        /// <typeparam name="TValue">要写入的数据类型。</typeparam>
        /// <param name="enum">参数名称。</param>
        /// <param name="value">要写入的数据。</param>
        /// <param name="deviceChildCode">设备子编号写</param>
        /// <returns>返回写入成功或失败</returns>
        bool SetValue<TEnum, TValue>(TEnum @enum, TValue value, string deviceChildCode) where TEnum : Enum where TValue : notnull;
        /// <summary>
        /// è¯»å–站台是否被占用
        /// </summary>
        /// <param name="deviceChildCode">设备子编号</param>
        /// <returns></returns>
        bool IsOccupied(string deviceChildCode);
        /// <summary>
        /// å‘送任务命令
        /// </summary>
        /// <typeparam name="T">任务命令对象的类型泛型</typeparam>
        /// <param name="command">任务命令</param>
        /// <returns></returns>
        bool SendCommand<T>(T command, string deviceChildCode) where T : IDataTransfer, new();
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/CustomException/QuartzJobException.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,184 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè‡ªå®šä¹‰è°ƒåº¦æœåŠ¡å¼‚å¸¸ç±»
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.CustomException
{
    /// <summary>
    /// å®šæ—¶å™¨é”™è¯¯ç±»
    /// </summary>
    [Serializable]
    public class QuartzJobException : Exception
    {
        /// <summary>
        /// é”™è¯¯ä»£ç 
        /// </summary>
        public int? ErrorCode { get; }
        /// <summary>
        /// é”™è¯¯ç±»åž‹
        /// </summary>
        public string ErrorType { get; }
        public Exception? BaseException { get; }
        public override string Message => _message;
        private string _message;
        /// <summary>
        /// åˆå§‹åŒ–一个新的 CommunicationException å®žä¾‹ã€‚
        /// </summary>
        /// <param name="message">错误的描述。</param>
        /// <param name="errorType">错误类型。</param>
        /// <param name="errorCode">错误代码(可选)。</param>
        /// <param name="innerException">导致当前异常的异常(可选)。</param>
        public QuartzJobException(string message, string errorType = "", int? errorCode = null, Exception? innerException = null)
        {
            ErrorCode = errorCode;
            ErrorType = errorType;
            BaseException = innerException;
            _message = message;
        }
        public override string ToString()
        {
            return base.ToString();
        }
    }
    public enum QuartzJobErrorType
    {
        /// <summary>
        ///
        /// </summary>
        Warning,
        /// <summary>
        ///
        /// </summary>
        Error,
        /// <summary>
        ///
        /// </summary>
        Exception,
        /// <summary>
        ///
        /// </summary>
        LogicError
    }
    /// <summary>
    /// è°ƒåº¦æœåС异叏
    /// </summary>
    public class QuartzJobExceptionMessage
    {
        public const string StartJobException = "调度服务开启异常,错误信息:{0}";
        public const string StopJobException = "调度服务停止异常,错误信息:{0}";
        public const string AddJobException = "调度计划添加异常:【{0}】,错误信息:{1}";
        public const string JobFactoryInstanceException = "从Factory中获取Scheduler实例异常,错误信息:{0}";
        public const string StopAJobException = "调度计划【{0}】停止异常,错误信息:{1}";
        public const string ResumeJobException = "调度计划【{0}】恢复异常,错误信息:{1}";
        public const string ExecuteJobException = "立即执行调度计划:【{0}】异常,错误信息:{1}";
    }
    /// <summary>
    /// è°ƒåº¦æœåŠ¡ä¿¡æ¯
    /// </summary>
    public class QuartzJobInfoMessage
    {
        /// <summary>
        ///
        /// </summary>
        public const string JobHasStart = "调度服务已经开启";
        /// <summary>
        ///
        /// </summary>
        public const string StartJobSuccess = "调度服务开启成功";
        /// <summary>
        ///
        /// </summary>
        public const string JobHasStop = "调度服务已经停止";
        /// <summary>
        ///
        /// </summary>
        public const string StopJobSuccess = "调度服务停止成功";
        /// <summary>
        ///
        /// </summary>
        public const string JobHasAdd = "该调度计划已经在执行:【{0}】,请勿重复启动!";
        /// <summary>
        ///
        /// </summary>
        public const string JobAddSuccess = "【{0}】调度计划添加到调度中心成功";
        /// <summary>
        ///
        /// </summary>
        public const string JobNotExist = "调度计划不存在:【{0}】";
        /// <summary>
        ///
        /// </summary>
        public const string StopAJobSuccess = "调度计划【{0}】停止成功";
        /// <summary>
        ///
        /// </summary>
        public const string ResumeJobSuccess = "调度计划【{0}】恢复成功";
        /// <summary>
        ///
        /// </summary>
        public const string ResumeJobNotExist = "未找到要恢复的调度计划:【{0}】";
        /// <summary>
        ///
        /// </summary>
        public const string PauseJobSuccess = "调度计划【{0}】暂停成功";
        /// <summary>
        ///
        /// </summary>
        public const string PauseJobNotExist = "未找到要暂停的调度计划:【{0}】";
        /// <summary>
        ///
        /// </summary>
        public const string ExecuteJobSuccess = "立即执行调度计划:【{0}】成功";
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DeviceInfoDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡ä¿¡æ¯DTO,继承设备信息实体,封装设备基础接口层属性
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.DTO
{
    public class DeviceInfoDTO : Dt_DeviceInfo
    {
        /// <summary>
        /// è®¾å¤‡åŸºç¡€æŽ¥å£å±‚
        /// </summary>
        public IDevice Device {  get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DeviceProDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡åè®®DTO
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.DTO
{
    public class DeviceProDTO
    {
        /// <summary>
        /// åè®®ä¸»é”®
        /// </summary>
        public int DeviceProId { get; set; }
        /// <summary>
        /// è®¾å¤‡ä¿¡æ¯ä¸»é”®
        /// </summary>
        public int DeviceId { get; set; }
        /// <summary>
        /// å­è®¾å¤‡ç¼–号
        /// </summary>
        public string DeviceChildCode { get; set; }
        /// <summary>
        /// åè®®æ•°æ®å—
        /// </summary>
        public string DeviceProDataBlock { get; set; }
        /// <summary>
        /// åç§»é‡
        /// </summary>
        public decimal DeviceProOffset { get; set; }
        /// <summary>
        /// åè®®åœ°å€
        /// </summary>
        public string DeviceProAddress
        {
            get
            {
                return DeviceProDataBlock + "." + DeviceProOffset;
            }
        }
        /// <summary>
        /// æ•°æ®ç±»åž‹
        /// </summary>
        public string DeviceDataType { get; set; }
        /// <summary>
        /// æ•°æ®é•¿åº¦
        /// </summary>
        public int DeviceProDataLength { get; set; }
        /// <summary>
        /// å‚数名称
        /// </summary>
        public string DeviceProParamName { get; set; }
        /// <summary>
        /// å‚数类型
        /// </summary>
        public string DeviceProParamType { get; set; }
        /// <summary>
        /// å‚数说明
        /// </summary>
        public string DeviceProParamDes { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DeviceProtocolDetailDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡åè®®æ˜Žç»†DTO
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.DTO
{
    public class DeviceProtocolDetailDTO
    {
        /// <summary>
        /// è®¾å¤‡ç±»åž‹
        /// </summary>
        public string DeviceType { get; set; }
        /// <summary>
        /// å‚数名称
        /// </summary>
        public string DeviceProParamName { get; set; }
        /// <summary>
        /// è®¾å¤‡åè®®æ˜Žç»†å–值
        /// </summary>
        public string ProtocalDetailValue { get; set; }
        /// <summary>
        /// è®¾å¤‡åè®®æ˜Žç»†ç±»åž‹
        /// </summary>
        public string ProtocolDetailType { get; set; }
        /// <summary>
        /// è®¾å¤‡åè®®æ˜Žç»†è¯´æ˜Ž
        /// </summary>
        public string ProtocolDetailDes { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DispatchInfoDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡é…ç½®DTO
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.DTO
{
    public class DispatchInfoDTO : Dt_DispatchInfo
    {
        /// <summary>
        /// å·²å¾ªçŽ¯æ¬¡æ•°
        /// </summary>
        public int CycleHasRunTimes { get; set; }
        /// <summary>
        /// æ‰§è¡Œä¼ å‚
        /// </summary>
        public object JobParams { get; set; }
        /// <summary>
        /// è®¾å¤‡ç±»åž‹
        /// </summary>
        public string DeviceType { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/DispatchStatusDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡çŠ¶æ€ä¿¡æ¯DTO
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.DTO
{
    internal class DispatchStatusDTO
    {
        /// <summary>
        /// ä»»åŠ¡ID
        /// </summary>
        public string JobId { get; set; }
        /// <summary>
        /// ä»»åŠ¡åç§°
        /// </summary>
        public string JobName { get; set; }
        /// <summary>
        /// ä»»åŠ¡åˆ†ç»„
        /// </summary>
        public string JobGroup { get; set; }
        /// <summary>
        /// è§¦å‘器ID
        /// </summary>
        public string TriggerId { get; set; }
        /// <summary>
        /// è§¦å‘器名称
        /// </summary>
        public string TriggerName { get; set; }
        /// <summary>
        /// è§¦å‘器分组
        /// </summary>
        public string TriggerGroup { get; set; }
        /// <summary>
        /// è§¦å‘器状态
        /// </summary>
        public string TriggerStatus { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DTO/RoutersAddDTO.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_DTO.BasicInfo
{
    public class RoutersAddDTO
    {
        /// <summary>
        /// ä½ç½®ç¼–号
        /// </summary>
        public string PositionCode { get; set; }
        /// <summary>
        /// å­ä½ç½®ç¼–号
        /// </summary>
        public string ChildPositionCode { get; set; }
        /// <summary>
        /// å †åž›æœºè¡Œ
        /// </summary>
        public string SCRow { get; set; }
        /// <summary>
        /// å †åž›æœºåˆ—
        /// </summary>
        public string SCColumn {  get; set; }
        /// <summary>
        /// å †åž›æœºå±‚
        /// </summary>
        public string SCLayer { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/CustomException/StackerCraneException.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.DeviceBase.CustomException
{
    internal class StackerCraneException
    {
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/DataLengthAttribute.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/DataLengthAttribute.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs ¸´ÖÆ
@@ -1,6 +1,6 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_ITaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob.DeviceBase
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
@@ -20,14 +20,17 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_ISystemRepository
namespace WIDESEAWCS_QuartzJob.DeviceBase
{
    public interface IAgvStationRepository : IRepository<AGVStation>
    [AttributeUsage(AttributeTargets.Property)]
    public class DataLengthAttribute : Attribute
    {
        public DataLengthAttribute(ushort dataLength)
        {
            DataLength = dataLength;
        }
        public ushort DataLength { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/DeviceCommand.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,247 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob.DeviceBase
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using HslCommunication.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.DeviceBase
{
    public class DeviceCommand : IDataTransfer
    {
        #region <Const>
        #endregion <Const>
        #region <Private Member>
        public ushort ReadCount { get; }
        private IByteTransform byteTransform = new ReverseBytesTransform();
        #endregion <Private Member>
        #region <Public Menber>
        #endregion <Public Menber>
        #region <Constructor function>
        public DeviceCommand()
        {
            ushort readCount = 0;
            PropertyInfo[] propertyInfos = GetType().GetProperties().Where(x => x.CanWrite).ToArray();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                object? obj = propertyInfo.GetValue(this);
                TypeCode typeCode = Type.GetTypeCode(propertyInfo.PropertyType);
                switch (typeCode)
                {
                    case TypeCode.Byte:
                    case TypeCode.SByte:
                    case TypeCode.Char:
                        readCount += sizeof(byte);
                        break;
                    case TypeCode.Int16:
                    case TypeCode.UInt16:
                        readCount += 2;
                        break;
                    case TypeCode.Single:
                    case TypeCode.Int32:
                    case TypeCode.UInt32:
                        readCount += 4;
                        break;
                    case TypeCode.String:
                        ushort dataLength = CheckStringAttribute(propertyInfo);
                        readCount += dataLength;
                        break;
                    default:
                        throw new NotSupportedException("Unsupported primitive type: " + propertyInfo.PropertyType);
                }
            }
            ReadCount = readCount;
        }
        #endregion <Constructor function>
        #region <Private Method>
        private ushort CheckStringAttribute(PropertyInfo propertyInfo)
        {
            Attribute? attribute = propertyInfo.GetCustomAttribute(typeof(DataLengthAttribute));
            if (attribute == null)
            {
                throw new Exception($"字符串需要配置【DataLength】特性");
            }
            ushort dataLength = ((DataLengthAttribute)attribute).DataLength;
            if (dataLength <= 0 || dataLength > 256)
            {
                throw new Exception($"【DataLength】特性请配置有效参数,参数范围【1-256】");
            }
            if (dataLength % 2 != 0)
            {
                dataLength += 1;
            }
            dataLength += 2;
            return dataLength;
        }
        #endregion <Private Method>
        #region <Public Method>
        public void ParseSource(byte[] Content)
        {
            PropertyInfo[] propertyInfos = GetType().GetProperties().Where(x => x.CanWrite).ToArray();
            int index = 0;
            for (int i = 0; i < propertyInfos.Length; i++)
            {
                PropertyInfo propertyInfo = propertyInfos[i];
                TypeCode typeCode = Type.GetTypeCode(propertyInfo.PropertyType);
                switch (typeCode)
                {
                    case TypeCode.Byte:
                    case TypeCode.SByte:
                        propertyInfo.SetValue(this, Content[index]);
                        index += sizeof(byte);
                        break;
                    case TypeCode.Char:
                        propertyInfo.SetValue(this, (char)Content[index]);
                        index += sizeof(char);
                        break;
                    case TypeCode.Int16:
                        propertyInfo.SetValue(this, byteTransform.TransInt16(Content, index));
                        index += sizeof(short);
                        break;
                    case TypeCode.UInt16:
                        propertyInfo.SetValue(this, byteTransform.TransUInt16(Content, index));
                        index += sizeof(ushort);
                        break;
                    case TypeCode.Single:
                        propertyInfo.SetValue(this, byteTransform.TransSingle(Content, index));
                        index += sizeof(float);
                        break;
                    case TypeCode.Int32:
                        propertyInfo.SetValue(this, byteTransform.TransInt32(Content, index));
                        index += sizeof(int);
                        break;
                    case TypeCode.UInt32:
                        propertyInfo.SetValue(this, byteTransform.TransUInt32(Content, index));
                        index += sizeof(uint);
                        break;
                    case TypeCode.String:
                        ushort dataLength = CheckStringAttribute(propertyInfo);
                        propertyInfo.SetValue(this, Encoding.Default.GetString(Content, index + 2, Content[index + 1]));
                        index += dataLength;
                        break;
                    default:
                        throw new NotSupportedException("Unsupported primitive type: " + propertyInfo.PropertyType);
                }
            }
        }
        public byte[] ToSource()
        {
            int propertyValueHasNull = -1;
            List<byte> bytes = new List<byte>();
            PropertyInfo[] propertyInfos = GetType().GetProperties().Where(x => x.CanWrite).ToArray();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                object? obj = propertyInfo.GetValue(this);
                if (obj == null && propertyValueHasNull != -1)
                {
                    throw new Exception($"{nameof(DeviceCommand)}错误");
                }
                else
                {
                    if (propertyValueHasNull == -1)
                        propertyValueHasNull = 2;
                }
                TypeCode typeCode = Type.GetTypeCode(propertyInfo.PropertyType);
                switch (typeCode)
                {
                    case TypeCode.Byte:
                    case TypeCode.SByte:
                    case TypeCode.Char:
                        if (obj != null)
                        {
                            bytes.Add((byte)obj);
                        }
                        else
                        { propertyValueHasNull = 1; }
                        break;
                    case TypeCode.Int16:
                    case TypeCode.UInt16:
                        if (obj != null)
                        {
                            byte[] bytesShort = BitConverter.GetBytes(Convert.ToUInt16(obj));
                            Array.Reverse(bytesShort);
                            bytes.AddRange(bytesShort);
                        }
                        else
                        { propertyValueHasNull = 1; }
                        break;
                    case TypeCode.Single:
                        if (obj != null)
                        {
                            byte[] bytesSingle = BitConverter.GetBytes(Convert.ToSingle(obj));
                            Array.Reverse(bytesSingle);
                            bytes.AddRange(bytesSingle);
                        }
                        else
                        { propertyValueHasNull = 1; }
                        break;
                    case TypeCode.Int32:
                    case TypeCode.UInt32:
                        if (obj != null)
                        {
                            byte[] bytesInt = BitConverter.GetBytes(Convert.ToUInt32(obj));
                            Array.Reverse(bytesInt);
                            bytes.AddRange(bytesInt);
                        }
                        else
                        { propertyValueHasNull = 1; }
                        break;
                    case TypeCode.String:
                        if (obj != null)
                        {
                            ushort dataLength = CheckStringAttribute(propertyInfo);
                            byte[] bytesString = Encoding.Default.GetBytes(obj.ToString());
                            bytes.Add(Convert.ToByte(dataLength));
                            bytes.Add(Convert.ToByte(obj.ToString().Length));
                            bytes.AddRange(bytesString);
                            for (int i = 0; i < dataLength - obj.ToString().Length - 2; i++)
                            {
                                bytes.Add(0);
                            }
                        }
                        else
                        { propertyValueHasNull = 1; }
                        break;
                    default:
                        throw new NotSupportedException("Unsupported primitive type: " + propertyInfo.PropertyType);
                }
            }
            return bytes.ToArray();
        }
        #endregion <Public Method>
        #region <Event>
        #endregion <Event>
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/DeviceStatus.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,53 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡çŠ¶æ€æžšä¸¾
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.DeviceBase
{
    public enum DeviceStatus
    {
        /// <summary>
        /// ç©ºé—²
        /// </summary>
        Idle,
        /// <summary>
        /// å·¥ä½œä¸­
        /// </summary>
        Working,
        /// <summary>
        /// æ•…éšœ
        /// </summary>
        Fault,
        /// <summary>
        /// æœªçŸ¥
        /// </summary>
        Unkonw,
        /// <summary>
        /// ç¦»çº¿
        /// </summary>
        Offline
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceBase/IDevice.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡æŽ¥å£å±‚,所有设备继承的底层接口
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using HslCommunication;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.DeviceBase
{
    /// <summary>
    /// è®¾å¤‡æŽ¥å£å±‚
    /// </summary>
    public interface IDevice : IDisposable
    {
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        string DeviceCode { get; }
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        string DeviceName { get; }
        /// <summary>
        /// è®¾å¤‡æ˜¯å¦æœ‰æ•…éšœ
        /// </summary>
        bool IsFault { get; }
        /// <summary>
        /// è®¾å¤‡æ˜¯å¦å·²è¿žæŽ¥
        /// </summary>
        bool IsConnected { get; }
        /// <summary>
        /// è®¾å¤‡çŠ¶æ€(空闲/运行中...)
        /// </summary>
        DeviceStatus Status { get; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/DeviceEnum/DeviceStatus.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡å¯ç”¨ç¦ç”¨çŠ¶æ€æžšä¸¾
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.DeviceEnum
{
    public enum DeviceStatusEnum
    {
        /// <summary>
        /// ç¦ç”¨
        /// </summary>
        [Description("禁用")]
        Disable,
        /// <summary>
        /// å¯ç”¨
        /// </summary>
        [Description("启用")]
        Enable
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/JobBase.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
using HslCommunication;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.LogHelper;
namespace WIDESEAWCS_QuartzJob
{
    public class JobBase
    {
        /// <summary>
        /// æ‰§è¡ŒæŒ‡å®šä»»åŠ¡
        /// </summary>
        /// <param name="context"></param>
        /// <param name="action"></param>
        public async void ExecuteJob(IJobExecutionContext context, Func<Task> func)
        {
            StringBuilder stringBuilder = new StringBuilder();
            //JOBID
            int jobid = context.JobDetail.Key.Name.ObjToInt();
            //JOB组名
            string groupName = context.JobDetail.Key.Group;
            //日志
            stringBuilder.AppendLine($"【{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}】【执行开始】【Id:{jobid},组别:{groupName}】");
            try
            {
                await func();//执行任务
                stringBuilder.AppendLine($"【{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}】【执行成功】");
                JobDataMap jobPars = context.JobDetail.JobDataMap;
                stringBuilder.AppendLine(jobPars.GetString("JobParams"));
            }
            catch (Exception ex)
            {
                JobExecutionException e2 = new JobExecutionException(ex);
                //true  æ˜¯ç«‹å³é‡æ–°æ‰§è¡Œä»»åŠ¡
                e2.RefireImmediately = true;
                stringBuilder.AppendLine($"【{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}】【执行失败:{ex.Message}】");
                stringBuilder.AppendLine($"【堆栈信息:{ex.StackTrace}】");
            }
            finally
            {
                //QuartzLogger.WriteLogToFile($"Debug_{fileName}", msg);
            }
        }
        public void WriteDebug(string fileName, string msg)
        {
            if( AppSettings.app(new string[] { "LogDeubgEnable" }).ObjToBool())
            {
                StringBuilder builder = new StringBuilder(msg);
                builder.Append(Environment.NewLine);
                builder.Append(Environment.NewLine);
                QuartzLogger.WriteLogToFile($"Debug_{fileName}", builder.ToString());
            }
        }
        public void WriteInfo(string fileName, string msg)
        {
            StringBuilder builder = new StringBuilder(msg);
            builder.Append(Environment.NewLine);
            builder.Append(Environment.NewLine);
            QuartzLogger.WriteLogToFile($"Info_{fileName}", builder.ToString());
        }
        public void WriteError(string fileName, string msg, Exception ex)
        {
            StringBuilder builder = new StringBuilder(msg);
            builder.Append(Environment.NewLine);
            builder.Append(StringResources.Language.ExceptionMessage);
            builder.Append(ex.Message);
            builder.Append(Environment.NewLine);
            builder.Append(StringResources.Language.ExceptionSource);
            builder.Append(ex.Source);
            builder.Append(Environment.NewLine);
            builder.Append(StringResources.Language.ExceptionStackTrace);
            builder.Append(ex.StackTrace);
            builder.Append(Environment.NewLine);
            builder.Append(StringResources.Language.ExceptionType);
            builder.Append(ex.GetType().ToString());
            builder.Append(Environment.NewLine);
            builder.Append(StringResources.Language.ExceptionTargetSite);
            builder.Append(ex.TargetSite?.ToString());
            builder.Append(Environment.NewLine);
            builder.Append(Environment.NewLine);
            QuartzLogger.WriteLogToFile($"Error_{fileName}", builder.ToString());
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DeviceInfo.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,115 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡ä¿¡æ¯å®žä½“
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Magicodes.ExporterAndImporter.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
namespace WIDESEAWCS_QuartzJob.Models
{
    /// <summary>
    /// è®¾å¤‡ä¿¡æ¯
    /// </summary>
    [SugarTable(nameof(Dt_DeviceInfo), "设备信息")]
    public class Dt_DeviceInfo : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [ImporterHeader(IsIgnore = true)]
        [ExporterHeader(DisplayName = "主键")]
        [SugarColumn(IsIdentity = true, IsNullable = true, IsPrimaryKey = true, ColumnDescription = "主键")]
        public int Id { get; set; }
        /// <summary>
        /// è®¾å¤‡ç¼–号
        /// </summary>
        [ImporterHeader(Name = "设备编号")]
        [ExporterHeader(DisplayName = "设备编号")]
        [SugarColumn(IsNullable = true, Length = 20, ColumnDescription = "设备编号")]
        public string DeviceCode { get; set; }
        /// <summary>
        /// è®¾å¤‡åç§°
        /// </summary>
        [ImporterHeader(Name = "设备名称")]
        [ExporterHeader(DisplayName = "设备名称")]
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "设备名称")]
        public string DeviceName { get; set; }
        /// <summary>
        /// è®¾å¤‡ç±»åž‹
        /// </summary>
        [ImporterHeader(Name = "设备类型")]
        [ExporterHeader(DisplayName = "设备类型")]
        [SugarColumn(IsNullable = true, Length = 20, ColumnDescription = "设备类型")]
        public string DeviceType { get; set; }
        /// <summary>
        /// è®¾å¤‡çŠ¶æ€
        /// </summary>
        [ImporterHeader(Name = "设备状态")]
        [ExporterHeader(DisplayName = "设备状态")]
        [SugarColumn(IsNullable = true, Length = 20, ColumnDescription = "设备状态")]
        public string DeviceStatus { get; set; }
        /// <summary>
        /// è®¾å¤‡IP
        /// </summary>
        [ImporterHeader(Name = "设备IP")]
        [ExporterHeader(DisplayName = "设备IP")]
        [SugarColumn(IsNullable = true, Length = 20, ColumnDescription = "设备IP")]
        public string DeviceIp { get; set; }
        /// <summary>
        /// è®¾å¤‡ç«¯å£
        /// </summary>
        [ImporterHeader(Name = "设备端口")]
        [ExporterHeader(DisplayName = "设备端口")]
        [SugarColumn(IsNullable = true, ColumnDescription = "设备端口")]
        public int DevicePort { get; set; }
        /// <summary>
        /// PLC类型
        /// </summary>
        [ImporterHeader(Name = "PLC类型")]
        [ExporterHeader(DisplayName = "PLC类型")]
        [SugarColumn(IsNullable = true, Length = 20, ColumnDescription = "PLC类型")]
        public string DevicePlcType { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [ImporterHeader(Name = "备注")]
        [ExporterHeader(DisplayName = "备注")]
        [SugarColumn(Length = 200, IsNullable = true, ColumnDescription = "备注")]
        public string DeviceRemark { get; set; }
        /// <summary>
        /// è®¾å¤‡åè®®é›†åˆ
        /// </summary>
        [ImporterHeader(IsIgnore =true)]
        [ExporterHeader(IsIgnore = true)]
        [Navigate(NavigateType.OneToMany, nameof(Dt_DeviceProtocol.DeviceId), nameof(Id)), SugarColumn(IsIgnore = true, IsNullable = true)]
        public List<Dt_DeviceProtocol> ProtocolList { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DeviceProtocol.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡åè®®å®žä½“
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Magicodes.ExporterAndImporter.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
namespace WIDESEAWCS_QuartzJob.Models
{
    /// <summary>
    /// è®¾å¤‡åè®®
    /// </summary>
    [SugarTable(nameof(Dt_DeviceProtocol), "设备协议")]
    public class Dt_DeviceProtocol : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [ImporterHeader(IsIgnore = true)]
        [ExporterHeader(IsIgnore = true)]
        [SugarColumn(IsIdentity = true, IsNullable = true, IsPrimaryKey = true, ColumnDescription = "主键")]
        public int Id { get; set; }
        /// <summary>
        /// è®¾å¤‡ä¸»é”®
        /// </summary>
        [ImporterHeader(IsIgnore = true)]
        [ExporterHeader(IsIgnore = true)]
        [SugarColumn(IsNullable = false, ColumnDescription = "设备主键")]
        public int DeviceId { get; set; }
        /// <summary>
        /// è®¾å¤‡å­ç¼–号
        /// </summary>
        [ImporterHeader(Name = "设备子编号")]
        [ExporterHeader(DisplayName = "设备子编号")]
        [SugarColumn(IsNullable = true, Length = 20, ColumnDescription = "设备子编号")]
        public string DeviceChildCode { get; set; }
        /// <summary>
        /// åè®®æ•°æ®å—
        /// </summary>
        [ImporterHeader(Name = "协议数据块")]
        [ExporterHeader(DisplayName = "协议数据块")]
        [SugarColumn(IsNullable = true, Length = 10, ColumnDescription = "协议数据块")]
        public string DeviceProDataBlock { get; set; }
        /// <summary>
        /// åç§»é‡
        /// </summary>
        [ImporterHeader(Name = "偏移量")]
        [ExporterHeader(DisplayName = "偏移量")]
        [SugarColumn(IsNullable = true, DecimalDigits = 1, ColumnDescription = "偏移量")]
        public decimal DeviceProOffset { get; set; }
        /// <summary>
        /// æ•°æ®ç±»åž‹
        /// </summary>
        [ImporterHeader(Name = "数据类型")]
        [ExporterHeader(DisplayName = "数据类型")]
        [SugarColumn(IsNullable = true, Length = 10, ColumnDescription = "数据类型")]
        public string DeviceProDataType { get; set; }
        /// <summary>
        /// æ•°æ®é•¿åº¦
        /// </summary>
        [ImporterHeader(Name = "数据长度")]
        [ExporterHeader(DisplayName = "数据长度")]
        [SugarColumn(IsNullable = false, ColumnDescription = "数据长度", DefaultValue = "1")]
        public int DeviceProDataLength { get; set; }
        /// <summary>
        /// å‚数名称
        /// </summary>
        [ImporterHeader(Name = "参数名称")]
        [ExporterHeader(DisplayName = "参数名称")]
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "参数名称")]
        public string DeviceProParamName { get; set; }
        /// <summary>
        /// å‚数类型
        /// </summary>
        [ImporterHeader(Name = "参数类型")]
        [ExporterHeader(DisplayName = "参数类型")]
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "参数类型")]
        public string DeviceProParamType { get; set; }
        /// <summary>
        /// å‚数说明
        /// </summary>
        [ImporterHeader(Name = "参数说明")]
        [ExporterHeader(DisplayName = "参数说明")]
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "参数说明")]
        public string DeviceProParamDes { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [ImporterHeader(Name = "备注")]
        [ExporterHeader(DisplayName = "备注")]
        [SugarColumn(IsNullable = true, Length = 200, ColumnDescription = "备注")]
        public string DeviceProRemark { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DeviceProtocolDetail.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,91 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡åè®®æ˜Žç»†å®žä½“
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Magicodes.ExporterAndImporter.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
namespace WIDESEAWCS_QuartzJob.Models
{
    /// <summary>
    /// è®¾å¤‡åè®®æ˜Žç»†
    /// </summary>
    [SugarTable(nameof(Dt_DeviceProtocolDetail), "设备协议明细")]
    public class Dt_DeviceProtocolDetail : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [ImporterHeader(Name = "主键")]
        [ExporterHeader(DisplayName = "主键")]
        [SugarColumn(IsIdentity = true, IsNullable = true, IsPrimaryKey = true, ColumnDescription = "主键")]
        public int Id { get; set; }
        /// <summary>
        /// è®¾å¤‡ç±»åž‹
        /// </summary>
        [ImporterHeader(Name = "设备类型")]
        [ExporterHeader(DisplayName = "设备类型")]
        [SugarColumn(IsNullable = false, Length = 20, ColumnDescription = "设备类型")]
        public string DeviceType { get; set; }
        /// <summary>
        /// è®¾å¤‡åè®®å‚数名称
        /// </summary>
        [ImporterHeader(Name = "设备协议参数名称")]
        [ExporterHeader(DisplayName = "设备协议参数名称")]
        [SugarColumn(IsNullable = false, ColumnDescription = "设备协议参数名称")]
        public string DeviceProParamName { get; set; }
        /// <summary>
        /// è®¾å¤‡åè®®æ˜Žç»†ç±»åž‹
        /// </summary>
        [ImporterHeader(Name = "设备协议明细类型")]
        [ExporterHeader(DisplayName = "设备协议明细类型")]
        [SugarColumn(Length = 50, ColumnDescription = "设备协议明细类型")]
        public string ProtocolDetailType { get; set; }
        /// <summary>
        /// è®¾å¤‡åè®®æ˜Žç»†å–值
        /// </summary>
        [ImporterHeader(Name = "设备协议明细取值")]
        [ExporterHeader(DisplayName = "设备协议明细取值")]
        [SugarColumn(Length = 50, IsNullable = false, ColumnDescription = "设备协议明细取值")]
        public string ProtocalDetailValue { get; set; }
        /// <summary>
        /// è®¾å¤‡åè®®æ˜Žç»†è¯´æ˜Ž
        /// </summary>
        [ImporterHeader(Name = "设备协议明细说明")]
        [ExporterHeader(DisplayName = "设备协议明细说明")]
        [SugarColumn(IsNullable = true, Length = 500, ColumnDescription = "设备协议明细说明")]
        public string ProtocolDetailDes { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [ImporterHeader(Name = "备注")]
        [ExporterHeader(DisplayName = "备注")]
        [SugarColumn(IsNullable = true, Length = 200, ColumnDescription = "备注")]
        public string Remark { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_DispatchInfo.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,107 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡é…ç½®å®žä½“
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Magicodes.ExporterAndImporter.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
using WIDESEAWCS_Core.Tenants;
namespace WIDESEAWCS_QuartzJob.Models
{
    /// <summary>
    /// è°ƒåº¦æœåŠ¡é…ç½®
    /// </summary>
    [SugarTable(nameof(Dt_DispatchInfo), "调度服务配置")]
    public class Dt_DispatchInfo : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [ImporterHeader(Name = "主键")]
        [ExporterHeader(DisplayName = "主键")]
        [SugarColumn(IsIdentity = true, IsNullable = true, IsPrimaryKey = true, ColumnDescription = "主键")]
        public int Id { get; set; }
        /// <summary>
        /// ä»»åŠ¡åç§°
        /// </summary>
        [ImporterHeader(Name = "任务名称")]
        [ExporterHeader(DisplayName = "任务名称")]
        [SugarColumn(Length = 50, IsNullable = false, ColumnDescription = "任务名称")]
        public string Name { get; set; }
        /// <summary>
        /// ä»»åŠ¡åˆ†ç»„
        /// </summary>
        [ImporterHeader(Name = "任务分组")]
        [ExporterHeader(DisplayName = "任务分组")]
        [SugarColumn(Length = 50, IsNullable = false, ColumnDescription = "任务分组")]
        public string JobGroup { get; set; }
        /// <summary>
        /// ä»»åŠ¡æ‰€åœ¨DLL对应的程序集名称
        /// </summary>
        [ImporterHeader(Name = "程序集名称")]
        [ExporterHeader(DisplayName = "程序集名称")]
        [SugarColumn(Length = 50, IsNullable = false, ColumnDescription = "任务所在DLL对应的程序集名称")]
        public string AssemblyName { get; set; }
        /// <summary>
        /// ä»»åŠ¡æ‰€åœ¨ç±»
        /// </summary>
        [ImporterHeader(Name = "任务所在类")]
        [ExporterHeader(DisplayName = "任务所在类")]
        [SugarColumn(Length = 50, IsNullable = false, ColumnDescription = "任务所在类")]
        public string ClassName { get; set; }
        /// <summary>
        /// æ‰§è¡Œé—´é𔿗¶é—´, ç§’为单位
        /// </summary>
        [ImporterHeader(Name = "执行间隔时间")]
        [ExporterHeader(DisplayName = "执行间隔时间")]
        [SugarColumn(IsNullable = false, ColumnDescription = "执行间隔时间")]
        public int IntervalSecond { get; set; }
        /// <summary>
        /// å¼€å§‹æ—¶é—´
        /// </summary>
        [ImporterHeader(Name = "开始时间")]
        [ExporterHeader(DisplayName = "开始时间")]
        [SugarColumn(IsNullable = true, ColumnDescription = "开始时间")]
        public DateTime? BeginTime { get; set; }
        /// <summary>
        /// ç»“束时间
        /// </summary>
        [ImporterHeader(Name = "结束时间")]
        [ExporterHeader(DisplayName = "结束时间")]
        [SugarColumn(IsNullable = true, ColumnDescription = "结束时间")]
        public DateTime? EndTime { get; set; }
        /// <summary>
        /// ä»»åŠ¡æè¿°
        /// </summary>
        [ImporterHeader(Name = "任务描述")]
        [ExporterHeader(DisplayName = "任务描述")]
        [SugarColumn(Length = 1000, IsNullable = true, ColumnDescription = "任务描述")]
        public string Remark { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Models/Dt_Router.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,112 @@
using Magicodes.ExporterAndImporter.Core;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB.Models;
using WIDESEAWCS_Core.Enums;
namespace WIDESEAWCS_QuartzJob.Models
{
    [SugarTable(nameof(Dt_Router), "设备路由配置")]
    public class Dt_Router : BaseEntity
    {
        /// <summary>
        /// ä¸»é”®
        /// </summary>
        [ImporterHeader(Name = "主键")]
        [ExporterHeader(DisplayName = "主键")]
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnDescription = "主键")]
        public int Id { get; set; }
        /// <summary>
        /// èµ·ç‚¹ä½ç½®
        /// </summary>
        [ImporterHeader(Name = "起点位置")]
        [ExporterHeader(DisplayName = "起点位置")]
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "起点位置")]
        public string StartPosi { get; set; }
        /// <summary>
        /// ç»ˆç‚¹ä½ç½®
        /// </summary>
        [ImporterHeader(Name = "终点位置")]
        [ExporterHeader(DisplayName = "终点位置")]
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "终点位置")]
        public string NextPosi { get; set; }
        /// <summary>
        /// è·¯ç”±ç±»åž‹
        /// </summary>
        [ImporterHeader(Name = "路由类型")]
        [ExporterHeader(DisplayName = "路由类型")]
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "路由类型")]
        public RouterInOutType InOutType { get; set; }
        /// <summary>
        /// å­ä½ç½®
        /// </summary>
        [ImporterHeader(Name = "子位置")]
        [ExporterHeader(DisplayName = "子位置")]
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "子位置")]
        public string ChildPosi { get; set; }
        /// <summary>
        /// å­ä½ç½®æ‰€å±žè®¾å¤‡
        /// </summary>
        [ImporterHeader(Name = "子位置所属设备")]
        [ExporterHeader(DisplayName = "子位置所属设备")]
        [SugarColumn(IsNullable = false, Length = 50, ColumnDescription = "子位置所属设备")]
        public string ChildPosiDeviceCode { get; set; }
        /// <summary>
        /// å †åž›æœºå–è´§/放货行
        /// </summary>
        [ImporterHeader(Name = "堆垛机取货/放货行")]
        [ExporterHeader(DisplayName = "堆垛机取货/放货行")]
        [SugarColumn(IsNullable = true, ColumnDescription = "堆垛机取货/放货行")]
        public int? SrmRow { get; set; }
        /// <summary>
        /// å †åž›æœºå–è´§/放货列
        /// </summary>
        [ImporterHeader(Name = "堆垛机取货/放货列")]
        [ExporterHeader(DisplayName = "堆垛机取货/放货列")]
        [SugarColumn(IsNullable = true, ColumnDescription = "堆垛机取货/放货列")]
        public int? SrmColumn { get; set; }
        /// <summary>
        /// å †åž›æœºå–è´§/放货层
        /// </summary>
        [ImporterHeader(Name = "堆垛机取货/放货层")]
        [ExporterHeader(DisplayName = "堆垛机取货/放货层")]
        [SugarColumn(IsNullable = true, ColumnDescription = "堆垛机取货/放货层")]
        public int? SrmLayer { get; set; }
        /// <summary>
        /// æ·±åº¦
        /// </summary>
        [ImporterHeader(Name = "深度")]
        [ExporterHeader(DisplayName = "深度")]
        [SugarColumn(IsNullable = true, ColumnDescription = "深度")]
        public int? Depth { get; set; }
        /// <summary>
        /// æ˜¯å¦æ˜¯æœ€ç»ˆç‚¹
        /// </summary>
        [ImporterHeader(Name = "是否是最终点")]
        [ExporterHeader(DisplayName = "是否是最终点")]
        [SugarColumn(IsNullable = false, ColumnDescription = "是否是最终点")]
        public bool IsEnd { get; set; }
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [ImporterHeader(Name = "备注")]
        [ExporterHeader(DisplayName = "备注")]
        [SugarColumn(IsNullable = true, ColumnDescription = "备注")]
        public string Remark { get; set; }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzExtensions/JobSetup.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡æ³¨å…¥
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Microsoft.Extensions.DependencyInjection;
using Quartz.Spi;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob.QuartzExtensions
{
    /// <summary>
    /// è°ƒåº¦æœåŠ¡æ³¨å…¥
    /// </summary>
    public static class JobSetup
    {
        public static void AddJobSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            services.AddSingleton<IJobFactory, JobFactory>();
            services.AddSingleton<ISchedulerCenter, SchedulerCenterServer>();
            //任务注入
            var baseType = typeof(IJob);
            var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
            var referencedAssemblies = System.IO.Directory.GetFiles(path, "WIDESEAWCS_Tasks.dll").Select(Assembly.LoadFrom).ToArray();
            var types = referencedAssemblies
                .SelectMany(a => a.DefinedTypes)
                .Select(type => type.AsType())
                .Where(x => x != baseType && baseType.IsAssignableFrom(x)).ToArray();
            var implementTypes = types.Where(x => x.IsClass).ToArray();
            foreach (var implementType in implementTypes)
            {
                services.AddTransient(implementType);
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzExtensions/QuartzJobAutofacModuleRegister.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,64 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡ä»“å‚¨ä¸šåŠ¡å±‚æ³¨å…¥
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Autofac;
using Autofac.Extras.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.AOP;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_QuartzJob.Repository;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_QuartzJob.QuartzExtensions
{
    public class QuartzJobAutofacModuleRegister : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            var basePath = AppContext.BaseDirectory;
            #region å¸¦æœ‰æŽ¥å£å±‚的服务注入
            var dllFile = Path.Combine(basePath, "WIDESEAWCS_QuartzJob.dll");
            if (!File.Exists(dllFile))
            {
                var msg = "WIDESEAWCS_QuartzJob.dll ä¸¢å¤±ï¼Œå› ä¸ºé¡¹ç›®è§£è€¦äº†ï¼Œæ‰€ä»¥éœ€è¦å…ˆF6编译,再F5运行,请检查 bin æ–‡ä»¶å¤¹ï¼Œå¹¶æ‹·è´ã€‚";
                //log.Error(msg);
                throw new Exception(msg);
            }
            Type baseType = typeof(IDependency);
            //builder.RegisterGeneric(typeof(RepositoryBase<>)).As(typeof(IRepository<>)).InstancePerDependency();//注册仓储
            //builder.RegisterGeneric(typeof(ServiceBase<,>)).As(typeof(IService<>)).InstancePerDependency();//注册服务
            // èŽ·å– Service.dll ç¨‹åºé›†æœåŠ¡ï¼Œå¹¶æ³¨å†Œ
            Assembly assemblysServices = Assembly.LoadFrom(dllFile);
            builder.RegisterAssemblyTypes(assemblysServices).Where(type => (baseType.IsAssignableFrom(type)) && !type.IsAbstract)
            .AsSelf().AsImplementedInterfaces()
            .InstancePerLifetimeScope();  //引用Autofac.Extras.DynamicProxy;
            #endregion
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzExtensions/QuartzJobDataTableHostedService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,79 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡å±‚å®žä½“æ˜ å°„
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.Seed;
using WIDESEAWCS_Core;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using WIDESEAWCS_QuartzJob.Seed;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_QuartzJob.QuartzExtensions
{
    public sealed class QuartzJobDataTableHostedService : IHostedService
    {
        private readonly DBContext _dbContext;
        private readonly ILogger<QuartzJobDataTableHostedService> _logger;
        private readonly string _webRootPath;
        private readonly IServiceProvider _serviceProvider;
        public QuartzJobDataTableHostedService(
            IServiceProvider serviceProvider,
            IWebHostEnvironment webHostEnvironment,
            ILogger<QuartzJobDataTableHostedService> logger)
        {
            _serviceProvider = serviceProvider;
            _logger = logger;
            _webRootPath = webHostEnvironment.WebRootPath;
            using var scope = _serviceProvider.CreateScope();
            DBContext dbContext = scope.ServiceProvider.GetService<DBContext>();
            _dbContext = dbContext;
        }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("开始创建定时器调度数据表");
            await DoWork();
        }
        private async Task DoWork()
        {
            try
            {
                await QuartzJobCreateDataTabel.SeedAsync(_dbContext, _webRootPath);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "定时器调度数据表创建错误");
                throw;
            }
        }
        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("定时器调度数据表结束");
            return Task.CompletedTask;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzExtensions/QuartzJobHostedService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,129 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡è‡ªåŠ¨å¼€å¯
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_QuartzJob.DeviceBase;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_QuartzJob.QuartzExtensions
{
    public class QuartzJobHostedService : IHostedService
    {
        private readonly ISchedulerCenter _schedulerCenter;
        private readonly ILogger<QuartzJobHostedService> _logger;
        private readonly IDeviceInfoService _deviceInfoService;
        private readonly IDispatchInfoService _dispatchInfoService;
        private readonly IDeviceProtocolDetailService _deviceProtocolDetailService;
        public QuartzJobHostedService(ILogger<QuartzJobHostedService> logger, IDeviceInfoService deviceInfoService, IDispatchInfoService dispatchInfoService, ISchedulerCenter schedulerCenter, IDeviceProtocolDetailService deviceProtocolDetailService)
        {
            _logger = logger;
            _deviceInfoService = deviceInfoService;
            _dispatchInfoService = dispatchInfoService;
            _schedulerCenter = schedulerCenter;
            _deviceProtocolDetailService = deviceProtocolDetailService;
        }
        /// <summary>
        /// å¯åŠ¨ç¨‹åºè‡ªåŠ¨å¼€å¯è°ƒåº¦æœåŠ¡
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            try
            {
                List<DispatchInfoDTO> dispatches = _dispatchInfoService.QueryDispatchInfos();
                List<DeviceInfoDTO> deviceInfos = await _deviceInfoService.QueryDeviceProInfos();
                deviceInfos.ForEach(x =>
                {
                    if (dispatches.Exists(d => d.JobGroup == x.DeviceType))
                    {
                        #region è¿žæŽ¥PLC
                        Assembly assembly = Assembly.Load($"WIDESEAWCS_Communicator");
                        Type? type = assembly.GetType($"WIDESEAWCS_Communicator.{x.DevicePlcType}");
                        object? obj = Activator.CreateInstance(type, new object[] { x.DeviceIp, x.DevicePort, x.DeviceName });
                        bool? connectResult = (bool)type.InvokeMember("Connect", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, new object[] { });
                        if (connectResult ?? false) ConsoleHelper.WriteSuccessLine(x.DeviceCode + "连接成功"); else ConsoleHelper.WriteErrorLine(x.DeviceCode + "连接失败");
                        #endregion
                        #region å®žä¾‹åŒ–设备对象
                        List<DeviceProDTO> devicePros = x.ProtocolList.Select(d => new DeviceProDTO
                        {
                            DeviceChildCode = d.DeviceChildCode,
                            DeviceDataType = d.DeviceProDataType,
                            DeviceId = d.DeviceId,
                            DeviceProId = d.Id,
                            DeviceProDataBlock = d.DeviceProDataBlock,
                            DeviceProDataLength = d.DeviceProDataLength,
                            DeviceProOffset = d.DeviceProOffset,
                            DeviceProParamDes = d.DeviceProParamDes,
                            DeviceProParamName = d.DeviceProParamName,
                            DeviceProParamType = d.DeviceProParamType,
                        }).ToList();
                        List<DeviceProtocolDetailDTO> deviceProtocolDetails = _deviceProtocolDetailService.GetDeviceProtocolDetailsByDeviceType(x.DeviceType);
                        Assembly assemblyDevice = Assembly.Load($"WIDESEAWCS_QuartzJob");
                        Type typeDevice = assemblyDevice.GetType($"WIDESEAWCS_QuartzJob.{x.DeviceType}");
                        object deviceInstance = Activator.CreateInstance(typeDevice, new object[] { obj, devicePros, deviceProtocolDetails, x.DeviceCode, x.DeviceName });
                        #endregion
                        x.Device = (IDevice)deviceInstance;
                        Storage.Devices.Add((IDevice)deviceInstance);
                    }
                });
                for (int i = 0; i < dispatches.Count; i++)
                {
                    DeviceInfoDTO? deviceProInfo = deviceInfos.FirstOrDefault(x => x.Id == dispatches[i].Id);
                    dispatches[i].JobParams = deviceProInfo?.Device;
                    WebResponseContent responseContent = await _schedulerCenter.AddScheduleJobAsync(dispatches[i]);
                    if (responseContent.Status) ConsoleHelper.WriteSuccessLine(dispatches[i].JobGroup + "调度服务添加成功"); else ConsoleHelper.WriteErrorLine(dispatches[i].JobGroup + "调度服务添加失败");
                }
                await _schedulerCenter.StartScheduleAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "调度服务开启异常");
                Console.WriteLine("调度服务开启异常" + ex.ToString());
                throw;
            }
        }
        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Stop QuartzJob Service!");
            return Task.CompletedTask;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/ISchedulerCenter.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡æŽ¥å£å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_QuartzJob.DTO;
namespace WIDESEAWCS_QuartzJob
{
    /// <summary>
    /// è°ƒåº¦æœåŠ¡æŽ¥å£
    /// </summary>
    public interface ISchedulerCenter
    {
        /// <summary>
        /// å¼€å¯ä»»åŠ¡è°ƒåº¦
        /// </summary>
        /// <returns></returns>
        Task<WebResponseContent> StartScheduleAsync();
        /// <summary>
        /// åœæ­¢ä»»åŠ¡è°ƒåº¦
        /// </summary>
        /// <returns></returns>
        Task<WebResponseContent> StopScheduleAsync();
        /// <summary>
        ///
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        Task<WebResponseContent> AddScheduleJobAsync(DispatchInfoDTO sysSchedule);
        /// <summary>
        /// åœæ­¢ä¸€ä¸ªä»»åŠ¡
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        Task<WebResponseContent> StopScheduleJobAsync(DispatchInfoDTO sysSchedule);
        /// <summary>
        /// æ£€æµ‹ä»»åŠ¡æ˜¯å¦å­˜åœ¨
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        Task<bool> IsExistScheduleJobAsync(DispatchInfoDTO sysSchedule);
        /// <summary>
        /// æš‚停指定的计划任务
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        Task<WebResponseContent> PauseJob(DispatchInfoDTO sysSchedule);
        /// <summary>
        /// æ¢å¤ä¸€ä¸ªä»»åŠ¡
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        Task<WebResponseContent> ResumeJob(DispatchInfoDTO sysSchedule);
        /// <summary>
        /// èŽ·å–ä»»åŠ¡è§¦å‘å™¨çŠ¶æ€
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        //Task<List<DispatchInfoDTO>> GetTaskStaus(DispatchInfoDTO sysSchedule);
        /// <summary>
        /// èŽ·å–è§¦å‘å™¨æ ‡è¯†
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        string GetTriggerState(string key);
        /// <summary>
        /// ç«‹å³æ‰§è¡Œ ä¸€ä¸ªä»»åŠ¡
        /// </summary>
        /// <param name="tasksQz"></param>
        /// <returns></returns>
        Task<WebResponseContent> ExecuteJobAsync(DispatchInfoDTO tasksQz);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/JobFactory.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šJob工厂类
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Microsoft.Extensions.DependencyInjection;
using Quartz.Spi;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEAWCS_QuartzJob
{
    public class JobFactory : IJobFactory
    {
        /// <summary>
        /// æ³¨å…¥åå°„获取依赖对象
        /// </summary>
        private readonly IServiceProvider _serviceProvider;
        public JobFactory(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        /// <summary>
        /// å®žçŽ°æŽ¥å£Job
        /// </summary>
        /// <param name="bundle"></param>
        /// <param name="scheduler"></param>
        /// <returns></returns>
        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            try
            {
                IServiceScope serviceScope = _serviceProvider.CreateScope();
                IJob? job = serviceScope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob;
                return job;
            }
            catch (Exception)
            {
                throw;
            }
        }
        public void ReturnJob(IJob job)
        {
            IDisposable? disposable = job as IDisposable;
            disposable?.Dispose();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/QuartzNet/SchedulerCenterServer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,458 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡å®žçŽ°ç±»
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Quartz.Impl.Triggers;
using Quartz.Impl;
using Quartz.Spi;
using Quartz;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.CustomException;
namespace WIDESEAWCS_QuartzJob
{
    public class SchedulerCenterServer : ISchedulerCenter
    {
        private Task<IScheduler> _scheduler;
        private readonly IJobFactory _iocjobFactory;
        public SchedulerCenterServer(IJobFactory jobFactory)
        {
            _iocjobFactory = jobFactory;
            _scheduler = GetSchedulerAsync();
        }
        private Task<IScheduler> GetSchedulerAsync()
        {
            if (_scheduler != null)
                return this._scheduler;
            else
            {
                try
                {
                    // ä»ŽFactory中获取Scheduler实例
                    NameValueCollection collection = new NameValueCollection
                    {
                        { "quartz.serializer.type", "binary" },
                    };
                    StdSchedulerFactory factory = new StdSchedulerFactory(collection);
                    return _scheduler = factory.GetScheduler();
                }
                catch (Exception ex)
                {
                    throw new QuartzJobException(string.Format(QuartzJobExceptionMessage.JobFactoryInstanceException, ex.Message), innerException: ex);
                }
            }
        }
        /// <summary>
        /// å¼€å¯ä»»åŠ¡è°ƒåº¦
        /// </summary>
        /// <returns></returns>
        public async Task<WebResponseContent> StartScheduleAsync()
        {
            WebResponseContent result = new WebResponseContent();
            try
            {
                this._scheduler.Result.JobFactory = this._iocjobFactory;
                if (!this._scheduler.Result.IsStarted)
                {
                    //等待任务运行完成
                    await this._scheduler.Result.Start();
                    await Console.Out.WriteLineAsync(QuartzJobInfoMessage.StartJobSuccess);
                    result = WebResponseContent.Instance.OK(QuartzJobInfoMessage.StartJobSuccess);
                    return result;
                }
                else
                {
                    result = WebResponseContent.Instance.Error(QuartzJobInfoMessage.JobHasStart);
                    return result;
                }
            }
            catch (Exception ex)
            {
                throw new QuartzJobException(string.Format(QuartzJobExceptionMessage.StartJobException, ex.Message), innerException: ex);
            }
        }
        /// <summary>
        /// åœæ­¢ä»»åŠ¡è°ƒåº¦
        /// </summary>
        /// <returns></returns>
        public async Task<WebResponseContent> StopScheduleAsync()
        {
            WebResponseContent result = new WebResponseContent();
            try
            {
                if (!this._scheduler.Result.IsShutdown)
                {
                    //等待任务运行完成
                    await this._scheduler.Result.Shutdown();
                    await Console.Out.WriteLineAsync(QuartzJobInfoMessage.StopJobSuccess);
                    result = WebResponseContent.Instance.OK(QuartzJobInfoMessage.StopJobSuccess);
                    return result;
                }
                else
                {
                    result = WebResponseContent.Instance.Error(QuartzJobInfoMessage.JobHasStop);
                    return result;
                }
            }
            catch (Exception ex)
            {
                throw new QuartzJobException(string.Format(QuartzJobExceptionMessage.StopJobException, ex.Message), innerException: ex);
            }
        }
        /// <summary>
        /// æ·»åŠ ä¸€ä¸ªè®¡åˆ’ä»»åŠ¡ï¼ˆæ˜ å°„ç¨‹åºé›†æŒ‡å®šIJob实现类)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tasksQz"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> AddScheduleJobAsync(DispatchInfoDTO tasksQz)
        {
            WebResponseContent result = new WebResponseContent();
            if (tasksQz != null)
            {
                try
                {
                    JobKey jobKey = new JobKey(tasksQz.Id.ToString(), tasksQz.JobGroup);
                    if (await _scheduler.Result.CheckExists(jobKey))
                    {
                        result = WebResponseContent.Instance.Error(string.Format(QuartzJobInfoMessage.JobHasAdd, tasksQz.Name));
                        return result;
                    }
                    #region è®¾ç½®å¼€å§‹æ—¶é—´å’Œç»“束时间
                    if (tasksQz.BeginTime == null)
                    {
                        tasksQz.BeginTime = DateTime.Now;
                    }
                    DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(tasksQz.BeginTime, 1);//设置开始时间
                    if (tasksQz.EndTime == null)
                    {
                        tasksQz.EndTime = DateTime.MaxValue.AddDays(-1);
                    }
                    DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(tasksQz.EndTime, 1);//设置暂停时间
                    #endregion
                    #region é€šè¿‡åå°„获取程序集类型和类
                    var basePath = AppContext.BaseDirectory;
                    var dllFile = Path.Combine(basePath, $"{tasksQz.AssemblyName}.dll");
                    if (!File.Exists(dllFile))
                    {
                        var msg = $"{tasksQz.AssemblyName}.dll未找到,请检查数据或文件";
                        //log.Error(msg);
                        throw new Exception(msg);
                    }
                    Assembly assembly = Assembly.Load(new AssemblyName(tasksQz.AssemblyName));
                    Type jobType = assembly.GetType(tasksQz.AssemblyName + "." + tasksQz.ClassName);
                    #endregion
                    //传入反射出来的执行程序集
                    //IJobDetail jobDetail = JobBuilder.Create(jobType)
                    //   .WithIdentity(tasksQz.Id.ToString(), tasksQz.JobGroup)
                    //   .Build();
                    //jobDetail.JobDataMap.Add("JobParams", tasksQz.JobParams);
                    IJobDetail job = new JobDetailImpl(tasksQz.Id.ToString(), tasksQz.JobGroup, jobType);
                    job.JobDataMap.Add("JobParams", tasksQz.JobParams);
                    ITrigger trigger = CreateSimpleTrigger(tasksQz);
                    // å‘Šè¯‰Quartz使用我们的触发器来安排作业
                    await _scheduler.Result.ScheduleJob(job, trigger);
                    //await _scheduler.Result.ScheduleJob(jobDetail, trigger);
                    result = WebResponseContent.Instance.OK(string.Format(QuartzJobInfoMessage.JobAddSuccess, tasksQz.Name));
                    return result;
                }
                catch (Exception ex)
                {
                    throw new QuartzJobException(string.Format(QuartzJobExceptionMessage.AddJobException, tasksQz.Name, ex.Message), innerException: ex);
                }
            }
            else
            {
                result = WebResponseContent.Instance.Error(string.Format(QuartzJobInfoMessage.JobNotExist, tasksQz?.Name));
                return result;
            }
        }
        /// <summary>
        /// ä»»åŠ¡æ˜¯å¦å­˜åœ¨?
        /// </summary>
        /// <returns></returns>
        public async Task<bool> IsExistScheduleJobAsync(DispatchInfoDTO sysSchedule)
        {
            JobKey jobKey = new JobKey(sysSchedule.Id.ToString(), sysSchedule.JobGroup);
            if (await _scheduler.Result.CheckExists(jobKey))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// åœæ­¢ä¸€ä¸ªæŒ‡å®šçš„计划任务
        /// </summary>
        /// <returns></returns>
        public async Task<WebResponseContent> StopScheduleJobAsync(DispatchInfoDTO sysSchedule)
        {
            WebResponseContent result = new WebResponseContent();
            try
            {
                JobKey jobKey = new JobKey(sysSchedule.Id.ToString(), sysSchedule.JobGroup);
                if (!await _scheduler.Result.CheckExists(jobKey))
                {
                    result = WebResponseContent.Instance.Error(string.Format(QuartzJobInfoMessage.JobNotExist, sysSchedule.Name));
                    return result;
                }
                else
                {
                    await this._scheduler.Result.DeleteJob(jobKey);
                    result = WebResponseContent.Instance.OK(string.Format(QuartzJobInfoMessage.StopAJobSuccess, sysSchedule.Name));
                    return result;
                }
            }
            catch (Exception ex)
            {
                throw new QuartzJobException(string.Format(QuartzJobExceptionMessage.StopAJobException, sysSchedule.Name, ex.Message), innerException: ex);
            }
        }
        /// <summary>
        /// æ¢å¤æŒ‡å®šçš„计划任务
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> ResumeJob(DispatchInfoDTO sysSchedule)
        {
            WebResponseContent result = new WebResponseContent();
            try
            {
                JobKey jobKey = new JobKey(sysSchedule.Id.ToString(), sysSchedule.JobGroup);
                if (!await _scheduler.Result.CheckExists(jobKey))
                {
                    result = WebResponseContent.Instance.Error(string.Format(QuartzJobInfoMessage.ResumeJobNotExist, sysSchedule.Name));
                    return result;
                }
                await this._scheduler.Result.ResumeJob(jobKey);
                result = WebResponseContent.Instance.OK(string.Format(QuartzJobInfoMessage.ResumeJobSuccess, sysSchedule.Name));
                return result;
            }
            catch (Exception ex)
            {
                throw new QuartzJobException(string.Format(QuartzJobExceptionMessage.ResumeJobException, sysSchedule.Name, ex.Message), innerException: ex);
            }
        }
        /// <summary>
        /// æš‚停指定的计划任务
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> PauseJob(DispatchInfoDTO sysSchedule)
        {
            WebResponseContent result = new WebResponseContent();
            try
            {
                JobKey jobKey = new JobKey(sysSchedule.Id.ToString(), sysSchedule.JobGroup);
                if (!await _scheduler.Result.CheckExists(jobKey))
                {
                    result = WebResponseContent.Instance.Error(string.Format(QuartzJobInfoMessage.PauseJobNotExist, sysSchedule.Name));
                    return result;
                }
                await this._scheduler.Result.PauseJob(jobKey);
                result = WebResponseContent.Instance.OK(string.Format(QuartzJobInfoMessage.PauseJobSuccess, sysSchedule.Name));
                return result;
            }
            catch (Exception)
            {
                throw;
            }
        }
        #region çŠ¶æ€çŠ¶æ€å¸®åŠ©æ–¹æ³•
        //public async Task<List<DispatchInfoDTO>> GetTaskStaus(DispatchInfoDTO sysSchedule)
        //{
        //    var ls = new List<TaskInfoDto>();
        //    var noTask = new List<TaskInfoDto>{ new TaskInfoDto {
        //        jobId = sysSchedule.Id.ObjToString(),
        //        jobGroup = sysSchedule.JobGroup,
        //        triggerId = "",
        //        triggerGroup = "",
        //        triggerStatus = "不存在"
        //    } };
        //    JobKey jobKey = new JobKey(sysSchedule.Id.ToString(), sysSchedule.JobGroup);
        //    IJobDetail job = await this._scheduler.Result.GetJobDetail(jobKey);
        //    if (job == null)
        //    {
        //        return noTask;
        //    }
        //    //info.Append(string.Format("任务ID:{0}\r\n任务名称:{1}\r\n", job.Key.Name, job.Description));
        //    var triggers = await this._scheduler.Result.GetTriggersOfJob(jobKey);
        //    if (triggers == null || triggers.Count == 0)
        //    {
        //        return noTask;
        //    }
        //    foreach (var trigger in triggers)
        //    {
        //        var triggerStaus = await this._scheduler.Result.GetTriggerState(trigger.Key);
        //        string state = GetTriggerState(triggerStaus.ObjToString());
        //        ls.Add(new TaskInfoDto
        //        {
        //            jobId = job.Key.Name,
        //            jobGroup = job.Key.Group,
        //            triggerId = trigger.Key.Name,
        //            triggerGroup = trigger.Key.Group,
        //            triggerStatus = state
        //        });
        //        //info.Append(string.Format("触发器ID:{0}\r\n触发器名称:{1}\r\n状态:{2}\r\n", item.Key.Name, item.Description, state));
        //    }
        //    return ls;
        //}
        public string GetTriggerState(string key)
        {
            string state = null;
            if (key != null)
                key = key.ToUpper();
            switch (key)
            {
                case "1":
                    state = "暂停";
                    break;
                case "2":
                    state = "完成";
                    break;
                case "3":
                    state = "出错";
                    break;
                case "4":
                    state = "阻塞";
                    break;
                case "0":
                    state = "正常";
                    break;
                case "-1":
                    state = "不存在";
                    break;
                case "BLOCKED":
                    state = "阻塞";
                    break;
                case "COMPLETE":
                    state = "完成";
                    break;
                case "ERROR":
                    state = "出错";
                    break;
                case "NONE":
                    state = "不存在";
                    break;
                case "NORMAL":
                    state = "正常";
                    break;
                case "PAUSED":
                    state = "暂停";
                    break;
            }
            return state;
        }
        #endregion
        #region åˆ›å»ºè§¦å‘器帮助方法
        /// <summary>
        /// åˆ›å»ºSimpleTrigger触发器(简单触发器)
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <returns></returns>
        private ITrigger CreateSimpleTrigger(DispatchInfoDTO sysSchedule)
        {
            ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
            .StartAt(sysSchedule.BeginTime.GetValueOrDefault())
            .WithSimpleSchedule(x => x
                .WithIntervalInSeconds(sysSchedule.IntervalSecond)
                .RepeatForever()
            )
            .EndAt(sysSchedule.EndTime.GetValueOrDefault())
            .Build();
            return trigger;
        }
        #endregion
        /// <summary>
        /// ç«‹å³æ‰§è¡Œ ä¸€ä¸ªä»»åŠ¡ æ‰§è¡Œä¸€æ¬¡
        /// </summary>
        /// <param name="tasksQz"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> ExecuteJobAsync(DispatchInfoDTO tasksQz)
        {
            var result = new WebResponseContent();
            try
            {
                JobKey jobKey = new JobKey(tasksQz.Id.ToString(), tasksQz.JobGroup);
                //判断任务是否存在,存在则 è§¦å‘一次,不存在则先添加一个任务,触发以后再 åœæ­¢ä»»åŠ¡
                if (!await _scheduler.Result.CheckExists(jobKey))
                {
                    //不存在 åˆ™ æ·»åŠ ä¸€ä¸ªè®¡åˆ’ä»»åŠ¡
                    await AddScheduleJobAsync(tasksQz);
                    //触发执行一次
                    await _scheduler.Result.TriggerJob(jobKey);
                    //停止任务
                    await StopScheduleJobAsync(tasksQz);
                    result = WebResponseContent.Instance.OK(string.Format(QuartzJobInfoMessage.ExecuteJobSuccess, tasksQz.Name));
                }
                else
                {
                    await _scheduler.Result.TriggerJob(jobKey);
                    result = WebResponseContent.Instance.OK(string.Format(QuartzJobInfoMessage.ExecuteJobSuccess, tasksQz.Name));
                }
            }
            catch (Exception ex)
            {
                throw new QuartzJobException(string.Format(QuartzJobExceptionMessage.ResumeJobException, tasksQz.Name, ex.Message), innerException: ex);
            }
            return result;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceInfoRepository.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemRepository/AgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceInfoRepository.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemRepository/AgvStationRepository.cs ¸´ÖÆ
@@ -1,10 +1,10 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_TaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 * æè¿°ï¼šè®¾å¤‡ä¿¡æ¯ä»“储实现层
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
@@ -21,15 +21,14 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_ISystemRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_SystemRepository
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public class AgvStationRepository : RepositoryBase<AGVStation>, IAgvStationRepository
    public class DeviceInfoRepository : RepositoryBase<Dt_DeviceInfo>, IDeviceInfoRepository
    {
        public AgvStationRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        public DeviceInfoRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        {
        }
    }
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceProtocolDetailRepository.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemRepository/AgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceProtocolDetailRepository.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemRepository/AgvStationRepository.cs ¸´ÖÆ
@@ -1,10 +1,10 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_TaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 * æè¿°ï¼šè®¾å¤‡åè®®æ˜Žç»†ä¿¡æ¯ä»“储实现层
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
@@ -21,15 +21,14 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_ISystemRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_SystemRepository
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public class AgvStationRepository : RepositoryBase<AGVStation>, IAgvStationRepository
    public class DeviceProtocolDetailRepository : RepositoryBase<Dt_DeviceProtocolDetail>, IDeviceProtocolDetailRepository
    {
        public AgvStationRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        public DeviceProtocolDetailRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        {
        }
    }
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceProtocolRepository.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DeviceProtocolRepository.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs ¸´ÖÆ
@@ -1,10 +1,10 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_ITaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 * æè¿°ï¼šè®¾å¤‡åè®®ä»“储实现层
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
@@ -21,13 +21,15 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_ISystemRepository
{
    public interface IAgvStationRepository : IRepository<AGVStation>
    {
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public class DeviceProtocolRepository : RepositoryBase<Dt_DeviceProtocol>, IDeviceProtocolRepository
    {
        public DeviceProtocolRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        {
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DispatchInfoRepository.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/DispatchInfoRepository.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs ¸´ÖÆ
@@ -1,10 +1,10 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_ITaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡é…ç½®ä»“å‚¨å®žçŽ°å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
@@ -21,13 +21,15 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_ISystemRepository
{
    public interface IAgvStationRepository : IRepository<AGVStation>
    {
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public class DispatchInfoRepository : RepositoryBase<Dt_DispatchInfo>, IDispatchInfoRepository
    {
        public DispatchInfoRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        {
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceInfoRepository.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceInfoRepository.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs ¸´ÖÆ
@@ -1,10 +1,10 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_ITaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 * æè¿°ï¼šè®¾å¤‡ä¿¡æ¯ä»“储接口层
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
@@ -21,13 +21,12 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_ISystemRepository
{
    public interface IAgvStationRepository : IRepository<AGVStation>
    {
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public interface IDeviceInfoRepository : IRepository<Dt_DeviceInfo>
    {
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceProtocolDetailRepository.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceProtocolDetailRepository.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs ¸´ÖÆ
@@ -1,10 +1,10 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_ITaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 * æè¿°ï¼šè®¾å¤‡åè®®æ˜Žç»†ä»“储接口层
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
@@ -21,13 +21,12 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_ISystemRepository
{
    public interface IAgvStationRepository : IRepository<AGVStation>
    {
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public interface IDeviceProtocolDetailRepository : IRepository<Dt_DeviceProtocolDetail>
    {
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceProtocolRepository.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDeviceProtocolRepository.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs ¸´ÖÆ
@@ -1,10 +1,10 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_ITaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 * æè¿°ï¼šè®¾å¤‡åè®®ä»“储接口层
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
@@ -21,13 +21,12 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_ISystemRepository
{
    public interface IAgvStationRepository : IRepository<AGVStation>
    {
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public interface IDeviceProtocolRepository : IRepository<Dt_DeviceProtocol>
    {
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDispatchInfoRepository.cs
copy from "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs" copy to "\351\241\271\347\233\256\344\273\243\347\240\201/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IDispatchInfoRepository.cs"
Îļþ´Ó ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_ISystemRepository/IAgvStationRepository.cs ¸´ÖÆ
@@ -1,10 +1,10 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_ITaskInfoRepository
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼š
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡é…ç½®ä»“å‚¨æŽ¥å£å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
@@ -21,13 +21,12 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_Model.Models.System;
namespace WIDESEAWCS_ISystemRepository
{
    public interface IAgvStationRepository : IRepository<AGVStation>
    {
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public interface IDispatchInfoRepository : IRepository<Dt_DispatchInfo>
    {
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/IRouterRepository.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public interface IRouterRepository : IRepository<Dt_Router>
    {
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Repository/RouterRepository.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Repository
{
    public class RouterRepository : RepositoryBase<Dt_Router>, IRouterRepository
    {
        public RouterRepository(IUnitOfWorkManage unitOfWorkManage) : base(unitOfWorkManage)
        {
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Seed/QuartzJobCreateDataTabel.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,138 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šæ˜ å°„QuartzJob数据库表
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.DB;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Seed;
namespace WIDESEAWCS_QuartzJob.Seed
{
    public class QuartzJobCreateDataTabel
    {
        private static string SeedDataFolder = "WIDESEAWCS_DB.DBSeed.Json/{0}.tsv";
        /// <summary>
        /// æ˜ å°„QuartzJob数据库表
        /// </summary>
        /// <param name="dbContext"></param>
        /// <returns></returns>
        public static async Task SeedAsync(DBContext dbContext, string WebRootPath)
        {
            try
            {
                Console.WriteLine("Create QuartzJob Tables...");
                var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
                var referencedAssemblies = System.IO.Directory.GetFiles(path, "WIDESEAWCS_QuartzJob.dll").Select(Assembly.LoadFrom).ToArray();
                var modelTypes = referencedAssemblies
                    .SelectMany(a => a.DefinedTypes)
                    .Select(type => type.AsType())
                    .Where(x => x.IsClass && x.Namespace is "WIDESEAWCS_QuartzJob.Models" && x.GetCustomAttribute<SugarTable>() != null)
                    .ToList();
                SeedDataFolder = Path.Combine(WebRootPath, SeedDataFolder);
                modelTypes.ForEach(t =>
                {
                    //var diffString = dbContext.Db.CodeFirst.GetDifferenceTables(t).ToDiffString();
                    // è¿™é‡Œåªæ”¯æŒæ·»åŠ è¡¨ï¼Œä¸æ”¯æŒåˆ é™¤
                    // å¦‚果想要删除,数据库直接右键删除,或者联系SqlSugar作者;
                    IDbMaintenance dbMaintenance = dbContext.Db.DbMaintenance;
                    if (!dbMaintenance.IsAnyTable(t.Name, false))
                    {
                        Console.WriteLine(t.Name);
                        dbContext.Db.CodeFirst.InitTables(t);
                        string seedData = FileHelper.ReadFile(string.Format(SeedDataFolder, t.Name), Encoding.UTF8);
                        #region AddSeedData
                        if (seedData != "不存在相应的目录")
                        {
                            List<Dictionary<string, object>> dicFile = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(seedData);
                            if (dicFile.Count > 0)
                            {
                                List<Dictionary<string, object>> dic = new List<Dictionary<string, object>>();
                                List<string> columnNames = dbContext.Db.DbMaintenance.GetColumnInfosByTableName(t.Name, false).Select(x => x.DbColumnName).ToList();
                                var a = t.GetProperties().FirstOrDefault(x => !columnNames.Contains(x.Name));
                                List<PropertyInfo> propertyInfos = t.GetProperties().Where(x => columnNames.Contains(x.Name)).ToList();
                                for (int j = 0; j < dicFile.Count; j++)
                                {
                                    Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
                                    for (int i = 0; i < propertyInfos.Count; i++)
                                    {
                                        PropertyInfo propertyInfo = propertyInfos[i];
                                        SugarColumn sugarColumn = propertyInfo.GetCustomAttribute<SugarColumn>();
                                        if (sugarColumn != null)
                                        {
                                            if (!sugarColumn.IsIgnore)
                                            {
                                                keyValuePairs.Add(propertyInfo.Name, dicFile[j][propertyInfo.Name]);
                                            }
                                        }
                                    }
                                    dic.Add(keyValuePairs);
                                }
                                if (dic.Count > 0)
                                {
                                    for (int i = 0; i < dic.Count; i++)
                                    {
                                        if (dic[i].ContainsKey("CreateDate"))
                                            dic[i]["CreateDate"] = DateTime.Now;
                                        else
                                            dic[i].Add("CreateDate", DateTime.Now);
                                    }
                                    string str = $"SET IDENTITY_INSERT {t.Name} ON;";
                                    str += dbContext.Db.Insertable(dic).AS(t.Name).ToSqlString();
                                    str += ($"SET IDENTITY_INSERT {t.Name} OFF;");
                                    dbContext.Db.Ado.ExecuteCommand(str);
                                    ConsoleHelper.WriteSuccessLine($"Table [{t.Name}] SeedData Added Successfully");
                                }
                            }
                        }
                        #endregion
                    }
                });
                ConsoleHelper.WriteSuccessLine($"QuartzJob Tables Created Successfully!");
                Console.WriteLine();
            }
            catch (Exception ex)
            {
                // 1、若是Mysql,查看常见问题:https://github.com/anjoy8/Blog.Core/issues/148#issue-776281770
                //2、若是Oracle,查看常见问题:https://github.com/anjoy8/Blog.Core/issues/148#issuecomment-752340231
                throw new Exception("错误:" + ex.Message);
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DeviceInfoService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡ä¿¡æ¯ä¸šåŠ¡å®žçŽ°å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using AutoMapper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_QuartzJob.DeviceEnum;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Repository;
namespace WIDESEAWCS_QuartzJob.Service
{
    public class DeviceInfoService : ServiceBase<Dt_DeviceInfo, IDeviceInfoRepository>, IDeviceInfoService
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly IMapper _mapper;
        public DeviceInfoService(IDeviceInfoRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IMapper mapper) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _mapper = mapper;
        }
        public override WebResponseContent AddData(SaveModel saveModel)
        {
            return base.AddData(saveModel);
        }
        /// <summary>
        /// æŸ¥è¯¢è®¾å¤‡ä»¥åŠå¯¹åº”的协议信息。
        /// </summary>
        /// <returns>返回设备信息以及对应协议信息的集合。</returns>
        public async Task<List<DeviceInfoDTO>> QueryDeviceProInfos()
        {
            List<Dt_DeviceInfo> deviceInfos = await Db.Queryable<Dt_DeviceInfo>().Where(x => x.DeviceStatus == ((int)DeviceStatusEnum.Enable).ToString()).Includes(x => x.ProtocolList).ToListAsync();
            return _mapper.Map<List<DeviceInfoDTO>>(deviceInfos);
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DeviceProtocolDetailService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡åè®®æ˜Žç»†ä¸šåŠ¡å®žçŽ°å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using AutoMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_QuartzJob.DeviceEnum;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Repository;
namespace WIDESEAWCS_QuartzJob.Service
{
    public class DeviceProtocolDetailService : ServiceBase<Dt_DeviceProtocolDetail, IDeviceProtocolDetailRepository>, IDeviceProtocolDetailService
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly IMapper _mapper;
        public DeviceProtocolDetailService(IDeviceProtocolDetailRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IMapper mapper) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _mapper = mapper;
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç±»åž‹èŽ·å–åè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        /// <param name="deviceType">设备类型</param>
        /// <returns>返回设备协议明细DTO集合</returns>
        public List<DeviceProtocolDetailDTO> GetDeviceProtocolDetailsByDeviceType(string deviceType)
        {
            return BaseDal.QueryData(x => x.DeviceType == deviceType).Select(x => new DeviceProtocolDetailDTO { DeviceType = x.DeviceType, DeviceProParamName = x.DeviceProParamName, ProtocalDetailValue = x.ProtocalDetailValue, ProtocolDetailDes = x.ProtocolDetailDes, ProtocolDetailType = x.ProtocolDetailType }).ToList();
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DeviceProtocolService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,210 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡åè®®ä¸šåŠ¡å®žçŽ°å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Magicodes.ExporterAndImporter.Core.Models;
using Magicodes.ExporterAndImporter.Excel;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Repository;
namespace WIDESEAWCS_QuartzJob.Service
{
    public class DeviceProtocolService : ServiceBase<Dt_DeviceProtocol, IDeviceProtocolRepository>, IDeviceProtocolService
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        public DeviceProtocolService(IDeviceProtocolRepository BaseDal, IUnitOfWorkManage unitOfWorkManage) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
        }
        /// <summary>
        /// è¯»å–导入文件的数据返回到前端
        /// </summary>
        /// <param name="fileInput">文件</param>
        /// <returns>返回读取结果,成功返回数据,失败返回错误信息</returns>
        public WebResponseContent GetImportData(List<IFormFile> fileInput)
        {
            try
            {
                if (fileInput == null || fileInput.Count == 0)
                    return new WebResponseContent { Status = true, Message = "请选择上传的文件" };
                Microsoft.AspNetCore.Http.IFormFile formFile = fileInput[0];
                string dicPath = AppDomain.CurrentDomain.BaseDirectory + $"ExcelImprot/{DateTime.Now.ToString("yyyMMdd")}/{typeof(Dt_DeviceProtocol).Name}/";
                if (!Directory.Exists(dicPath)) Directory.CreateDirectory(dicPath);
                string fileName = $"{Guid.NewGuid()}_{formFile.FileName}";
                dicPath = $"{dicPath}{fileName}";
                using (FileStream stream = new FileStream(dicPath, FileMode.Create))
                {
                    formFile.CopyTo(stream);
                }
                ExcelImporter importer = new ExcelImporter();
                ImportResult<Dt_DeviceProtocol> importResult = importer.Import<Dt_DeviceProtocol>(dicPath, "").Result;
                if (importResult.HasError)
                {
                    return WebResponseContent.Instance.Error(importResult.TemplateErrors.Serialize());
                }
                return WebResponseContent.Instance.OK(data: importResult.Data);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        public override WebResponseContent AddData(SaveModel saveModel)
        {
            //saveModel.MainData[""]
            return base.AddData(saveModel);
        }
        //public WebResponseContent InsertProtocol_Line(int PLCid, string ChildCode,decimal ProOffsetStart)
        //{
        //    Type type = typeof();
        //}
        // å°è£…检查逻辑
        private bool DeviceProtocolExists(int DeviceID, string DeviceChildCode, decimal DeviceProOffset)
        {
            return BaseDal.QueryFirst(x => x.DeviceId == DeviceID && x.DeviceChildCode == DeviceChildCode && x.DeviceProOffset == DeviceProOffset) != null;
        }
        // å°è£…对象创建逻辑
        private Dt_DeviceProtocol CreateDeviceProtocol(int DeviceID, string DeviceChildCode, decimal DeviceProOffset, int additionalOffset, string dataType, int dataLength, string paramName, string DeviceProDataBlock, string DeviceProParamType)
        {
            decimal DeviceProOffsets = DeviceProOffset + additionalOffset;
            return new Dt_DeviceProtocol
            {
                DeviceId = DeviceID,
                DeviceChildCode = DeviceChildCode,
                DeviceProDataBlock = DeviceProDataBlock,
                DeviceProOffset = DeviceProOffsets,
                DeviceProDataLength = dataLength,
                DeviceProDataType = dataType,
                DeviceProParamName = paramName,
                DeviceProParamType = DeviceProParamType,
                DeviceProParamDes = "1",
                DeviceProRemark = "",
                Creater = "admin",
                CreateDate = DateTime.Now,
            };
        }
        public WebResponseContent AddAfterDeviceProtocol(int DeviceID, string DeviceChildCode, decimal DeviceProOffset)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                if (DeviceProtocolExists(DeviceID, DeviceChildCode, DeviceProOffset))
                {
                    throw new InvalidOperationException("已存在该节点明细");
                }
                var protocols = new List<Dt_DeviceProtocol>
                {
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 0, "int", 1, "ConveyorLineTargetAddress","DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 2, "int", 1, "ConveyorLineTaskNum", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 6, "string", 25, "ConveyorLineBarcode", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 34, "int", 1, "Reserve1", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 36, "int", 1, "Reserve2", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 38, "int", 1, "Reserve3", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 40, "byte", 1, "InteractiveSignal", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 42, "int", 1, "HasPallet", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 44, "int", 1, "ConveyorLineAlarm", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 46, "int", 1, "ResponState", "DB1000", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffset, 48, "int", 1, "Reserve5", "DB1000", "DeviceCommand")
                };
                var result = BaseDal.AddData(protocols);
                return content.OK(data: result);
            }
            catch (Exception ex)
            {
                return content.Error(ex.Message);
            }
        }
        public WebResponseContent AddBeforeDeviceProtocol(int DeviceID, string DeviceChildCode, decimal DeviceProOffsetRead, decimal DeviceProOffsetWrite)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                if (DeviceProtocolExists(DeviceID, DeviceChildCode, DeviceProOffsetRead))
                {
                    throw new InvalidOperationException("已存在该节点明细");
                }
                var protocols = new List<Dt_DeviceProtocol>
                {
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 0, "int", 1, "InteractiveSignal","DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 2, "string", 25, "ConveyorLineBarcode", "DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 30, "dint", 1, "ConveyorLineTargetAddress", "DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 34, "dint", 1, "ConveyorLineTaskNum", "DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 38, "dint", 1, "ConveyorLineAlarm", "DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetWrite, 0, "w", 1, "WriteInteractiveSignal", "DB901", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetWrite, 2, "string", 25, "WriteConveyorLineBarcode", "DB901", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetWrite, 30, "dint", 1, "WriteConveyorLineTargetAddress", "DB901", "DeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetWrite, 34, "dint", 1, "WriteConveyorLineTaskNum", "DB901", "DeviceCommand"),
                };
                var result = BaseDal.AddData(protocols);
                return content.OK(data: result);
            }
            catch (Exception ex)
            {
                return content.Error(ex.Message);
            }
        }
        public WebResponseContent AddBeforReadDeviceProtocol(int DeviceID, string DeviceChildCode, decimal DeviceProOffsetRead)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                if (DeviceProtocolExists(DeviceID, DeviceChildCode, DeviceProOffsetRead))
                {
                    throw new InvalidOperationException("已存在该节点明细");
                }
                var protocols = new List<Dt_DeviceProtocol>
                {
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 0, "int", 1, "InteractiveSignal","DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 2, "string", 25, "ConveyorLineBarcode", "DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 30, "dint", 1, "ConveyorLineTargetAddress", "DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 34, "dint", 1, "ConveyorLineTaskNum", "DB900", "ReadDeviceCommand"),
                    CreateDeviceProtocol(DeviceID, DeviceChildCode, DeviceProOffsetRead, 38, "dint", 1, "ConveyorLineAlarm", "DB900", "ReadDeviceCommand"),
                };
                var result = BaseDal.AddData(protocols);
                return content.OK(data: result);
            }
            catch (Exception ex)
            {
                return content.Error(ex.Message);
            }
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/DispatchInfoService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,128 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè°ƒåº¦æœåŠ¡é…ç½®ä¸šåŠ¡å®žçŽ°å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using Quartz.Impl.Matchers;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_QuartzJob.DeviceEnum;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Repository;
using Quartz.Impl;
using System.Collections.Specialized;
namespace WIDESEAWCS_QuartzJob.Service
{
    public class DispatchInfoService : ServiceBase<Dt_DispatchInfo, IDispatchInfoRepository>, IDispatchInfoService
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly IDeviceInfoRepository _deviceInfoRepository;
        private readonly ISchedulerCenter _schedulerCenter;
        public DispatchInfoService(IDispatchInfoRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IDeviceInfoRepository deviceInfoRepository, ISchedulerCenter schedulerCenter) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _deviceInfoRepository = deviceInfoRepository;
            _schedulerCenter = schedulerCenter;
        }
        /// <summary>
        /// æŸ¥è¯¢è°ƒåº¦æœåŠ¡Job与对应的设备信息。
        /// </summary>
        /// <returns>返回调度服务JobDTO集合。</returns>
        public List<DispatchInfoDTO> QueryDispatchInfos()
        {
            return Db.Queryable<Dt_DispatchInfo, Dt_DeviceInfo>((a, b) => a.JobGroup == b.DeviceType && b.DeviceStatus == ((int)DeviceStatusEnum.Enable).ToString()).Select((a, b) => new DispatchInfoDTO
            {
                JobGroup = a.JobGroup,
                AssemblyName = a.AssemblyName,
                BeginTime = a.BeginTime,
                ClassName = a.ClassName,
                CreateDate = a.CreateDate,
                Creater = a.Creater,
                CycleHasRunTimes = 0,
                EndTime = a.EndTime,
                Id = b.Id,
                IntervalSecond = a.IntervalSecond,
                Modifier = a.Modifier,
                ModifyDate = a.ModifyDate,
                Name = a.Name,
                Remark = a.Remark,
                DeviceType = b.DeviceType
            }).ToList();
        }
        public async Task<WebResponseContent> GetDispatchInfosAsync()
        {
            WebResponseContent content = new WebResponseContent();
            NameValueCollection collection = new NameValueCollection
            {
                { "quartz.serializer.type", "binary" },
            };
            StdSchedulerFactory factory = new StdSchedulerFactory(collection);
            IScheduler scheduler = await factory.GetScheduler();
            var jobKeys = await scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup());
            foreach (var jobKey in jobKeys)
            {
                // åœ¨è¿™é‡Œå¤„理每个JobKey
                IJobDetail jobDetail = await scheduler.GetJobDetail(jobKey);
                if (jobDetail != null)
                {
                    // å¯ä»¥èŽ·å–Job的描述信息
                    string jobDescription = jobDetail.Description;
                    // ä»¥åŠJob的数据映射(JobDataMap)
                    JobDataMap jobDataMap = jobDetail.JobDataMap;
                }
            }
            var triggerKeys = await scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup());
            foreach (var triggerKey in triggerKeys)
            {
                // åœ¨è¿™é‡Œå¤„理每个TriggerKey
                ITrigger trigger = await scheduler.GetTrigger(triggerKey);
                if (trigger != null)
                {
                    // èŽ·å–ä¸‹ä¸€æ¬¡è§¦å‘æ—¶é—´ï¼ˆå¦‚æžœæœ‰ï¼‰
                    DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc();
                    // èŽ·å–ä¸Šæ¬¡è§¦å‘æ—¶é—´ï¼ˆå¦‚æžœæœ‰ï¼‰
                    DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc();
                    // èŽ·å–è§¦å‘ç±»åž‹ï¼ˆå¦‚SimpleTrigger、CronTrigger)
                    string triggerType = trigger.GetType().Name;
                    // å¯¹äºŽCronTrigger,还可以获取Cron表达式(如果是)
                    //if (trigger is CronTrigger cronTrigger)
                    //{
                    //    string cronExpression = cronTrigger.CronExpressionString;
                    //}
                    if (!previousFireTime.HasValue && nextFireTime.HasValue)
                    {
                        Console.WriteLine($"Job处于等待触发状态,Trigger名称: {triggerKey.Name}");
                    }
                }
            }
            return content;
        }
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDeviceInfoService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡ä¿¡æ¯ä¸šåŠ¡æŽ¥å£å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Service
{
    public interface IDeviceInfoService : IService<Dt_DeviceInfo>
    {
        /// <summary>
        /// æŸ¥è¯¢è®¾å¤‡ä»¥åŠå¯¹åº”的协议信息。
        /// </summary>
        /// <returns>返回设备信息以及对应协议信息的集合。</returns>
        Task<List<DeviceInfoDTO>> QueryDeviceProInfos();
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDeviceProtocolDetailService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡åè®®æ˜Žç»†ä¸šåŠ¡æŽ¥å£å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Service
{
    public interface IDeviceProtocolDetailService : IService<Dt_DeviceProtocolDetail>
    {
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç±»åž‹èŽ·å–åè®®æ˜Žç»†ä¿¡æ¯
        /// </summary>
        /// <param name="deviceType">设备类型</param>
        /// <returns>返回设备协议明细DTO集合</returns>
        List<DeviceProtocolDetailDTO> GetDeviceProtocolDetailsByDeviceType(string deviceType);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDeviceProtocolService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šè®¾å¤‡åè®®ä¸šåŠ¡æŽ¥å£å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Service
{
    public interface IDeviceProtocolService : IService<Dt_DeviceProtocol>
    {
        /// <summary>
        /// è¯»å–导入文件的数据返回到前端
        /// </summary>
        /// <param name="fileInput">文件</param>
        /// <returns>返回读取结果,成功返回数据,失败返回错误信息</returns>
        WebResponseContent GetImportData(List<IFormFile> fileInput);
        WebResponseContent AddAfterDeviceProtocol(int DeviceID, string DeviceChildCode, decimal DeviceProOffset);
        WebResponseContent AddBeforeDeviceProtocol(int DeviceID, string DeviceChildCode, decimal DeviceProOffsetRead, decimal DeviceProOffsetWrite);
        WebResponseContent AddBeforReadDeviceProtocol(int DeviceID, string DeviceChildCode, decimal DeviceProOffsetRead);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IDispatchInfoService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
#region << ç‰ˆ æœ¬ æ³¨ é‡Š >>
/*----------------------------------------------------------------
 * å‘½åç©ºé—´ï¼šWIDESEAWCS_QuartzJob
 * åˆ›å»ºè€…:胡童庆
 * åˆ›å»ºæ—¶é—´ï¼š2024/8/2 16:13:36
 * ç‰ˆæœ¬ï¼šV1.0.0
 * æè¿°ï¼šä»»åŠ¡è°ƒåº¦é…ç½®ä¸šåŠ¡æŽ¥å£å±‚
 *
 * ----------------------------------------------------------------
 * ä¿®æ”¹äººï¼š
 * ä¿®æ”¹æ—¶é—´ï¼š
 * ç‰ˆæœ¬ï¼šV1.0.1
 * ä¿®æ”¹è¯´æ˜Žï¼š
 *
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_QuartzJob.DTO;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Service
{
    public interface IDispatchInfoService : IService<Dt_DispatchInfo>
    {
        /// <summary>
        /// æŸ¥è¯¢å®šæ—¶å™¨Job与对应的设备信息。
        /// </summary>
        /// <returns>返回定时器Job与对应的设备信息DTO集合。</returns>
        List<DispatchInfoDTO> QueryDispatchInfos();
        Task<WebResponseContent> GetDispatchInfosAsync();
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/IRouterService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_QuartzJob.Service
{
    public interface IRouterService : IService<Dt_Router>
    {
        /// <summary>
        /// æ ¹æ®èµ·ç‚¹/当前位置、终点获取下一个子节点。
        /// </summary>
        /// <param name="startPosi">起点/当前位置。</param>
        /// <param name="endPosi">终点。</param>
        /// <returns>返回路由实体集合。</returns>
        List<Dt_Router> QueryNextRoutes(string startPosi, string endPosi);
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号获取对应的路由点位编号(输送线站台编号)信息
        /// </summary>
        /// <param name="deviceCode">设备编号</param>
        /// <returns>返回路由点位编号(输送线站台编号)集合</returns>
        List<string> QueryAllPositions(string deviceCode);
        /// <summary>
        /// èŽ·å–è·¯ç”±è¡¨ä¸­æ‰€æœ‰å®Œæ•´çš„è·¯ç”±ä¿¡æ¯(前端展示)
        /// </summary>
        /// <returns>匿名对象集合</returns>
        List<object> GetAllWholeRouters();
        WebResponseContent AddRouters(List<RoutersAddDTO> routersAddDTOs, int routerType);
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号获取对应的出站路由点位编号(输送线站台编号)信息
        /// </summary>
        /// <param name="deviceCode">设备编号</param>
        /// <returns>返回路由点位编号(输送线站台编号)集合</returns>
        List<string> QueryOutDeviceCodes(string deviceCode);
    }
}
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Service/RouterService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,332 @@
using Masuit.Tools;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Repository;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_BasicInfoService
{
    public class RouterService : ServiceBase<Dt_Router, IRouterRepository>, IRouterService
    {
        private readonly IDeviceProtocolRepository _deviceProtocolRepository;
        private readonly IDeviceInfoRepository _deviceInfoRepository;
        public RouterService(IRouterRepository BaseDal, IDeviceProtocolRepository deviceProtocolRepository, IDeviceInfoRepository deviceInfoRepository) : base(BaseDal)
        {
            _deviceProtocolRepository = deviceProtocolRepository;
            _deviceInfoRepository = deviceInfoRepository;
        }
        /// <summary>
        /// æ ¹æ®èµ·ç‚¹/当前位置、终点获取下一个子节点。
        /// </summary>
        /// <param name="startPosi">起点/当前位置。</param>
        /// <param name="endPosi">终点。</param>
        /// <returns>返回路由实体集合。</returns>
        //public List<Dt_Router> QueryNextRoutes(string startPosi, string endPosi)
        //{
        //    //todo æ–¹æ³•需优化
        //    List<Dt_Router> routers = new List<Dt_Router>();
        //    try
        //    {
        //        List<Dt_Router> dt_Routers = BaseDal.QueryData(x => x.NextPosi == endPosi || x.ChildPosi == endPosi, new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
        //        if (dt_Routers.Count > 0)
        //        {
        //            foreach (var item in dt_Routers)
        //            {
        //                if (item.StartPosi == startPosi && !routers.Any(x => x.Id == item.Id))
        //                {
        //                    routers.Add(item);
        //                }
        //                else
        //                {
        //                    List<Dt_Router> tempRouters = QueryNextRoutes(startPosi, item.StartPosi);
        //                    foreach (var router in tempRouters)
        //                    {
        //                        if (router.StartPosi == startPosi && !routers.Any(x => x.Id == router.Id))
        //                        {
        //                            routers.Add(router);
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //        else
        //        {
        //            throw new Exception($"该路径未配置或配置错误,请检查设备路由信息,起点:【{startPosi}】,终点:【{endPosi}】");
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        //throw new Exception(ex.Message);
        //        //记录错误信息
        //    }
        //    return routers;
        //}
        /// <summary>
        /// æ ¹æ®èµ·ç‚¹/当前位置、终点获取下一个子节点。
        /// </summary>
        /// <param name="startPosi">起点/当前位置。</param>
        /// <param name="endPosi">终点。</param>
        /// <returns>返回路由实体集合。</returns>
        public List<Dt_Router> QueryNextRoutes(string startPosi, string endPosi)
        {
            // ç”¨äºŽè®°å½•已经访问过的起点和终点组合,避免重复访问进入死循环
            HashSet<string> visitedRoutes = new HashSet<string>();
            return QueryNextRoutesInternal(startPosi, endPosi, visitedRoutes);
        }
        private List<Dt_Router> QueryNextRoutesInternal(string startPosi, string endPosi, HashSet<string> visitedRoutes)
        {
            List<Dt_Router> routers = new List<Dt_Router>();
            try
            {
                // æž„建一个唯一标识当前起点和终点组合的字符串
                string routeKey = $"{startPosi}_{endPosi}";
                if (visitedRoutes.Contains(routeKey))
                {
                    // å¦‚果已经访问过,直接返回空列表,避免重复进入相同的递归分支
                    return routers;
                }
                visitedRoutes.Add(routeKey);
                List<Dt_Router> dt_Routers = BaseDal.QueryData(x => (x.NextPosi == endPosi || x.ChildPosi == endPosi) && x.StartPosi == startPosi, new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
                if (dt_Routers.IsNullOrEmpty())
                {
                    dt_Routers = BaseDal.QueryData(x => x.NextPosi == endPosi || x.ChildPosi == endPosi, new Dictionary<string, OrderByType> { { nameof(Dt_Router.IsEnd), OrderByType.Desc } });
                }
                if (dt_Routers.Count > 0)
                {
                    foreach (var item in dt_Routers)
                    {
                        if (item.StartPosi == startPosi && !routers.Any(x => x.Id == item.Id))
                        {
                            routers.Add(item);
                        }
                        else
                        {
                            List<Dt_Router> tempRouters = QueryNextRoutesInternal(startPosi, item.StartPosi, visitedRoutes);
                            foreach (var router in tempRouters)
                            {
                                if (router.StartPosi == startPosi && !routers.Any(x => x.Id == router.Id))
                                {
                                    routers.Add(router);
                                }
                            }
                        }
                    }
                }
                else
                {
                    throw new Exception($"该路径未配置或配置错误,请检查设备路由信息,起点:【{startPosi}】,终点:【{endPosi}】");
                }
            }
            catch (Exception ex)
            {
                // è¿™é‡Œå¯ä»¥æ ¹æ®å®žé™…需求更好地处理异常,比如记录日志等,目前只是注释掉了直接抛出异常
                //throw new Exception(ex.Message);
                //记录错误信息
            }
            return routers;
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号获取对应的路由点位编号(输送线站台编号)信息
        /// </summary>
        /// <param name="deviceCode">设备编号</param>
        /// <returns>返回路由点位编号(输送线站台编号)集合</returns>
        public List<string> QueryAllPositions(string deviceCode)
        {
            List<string> positions = new List<string>();
            try
            {
                List<string> inRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.In).GroupBy(x => x.StartPosi).Select(x => x.Key).ToList();
                List<string> outRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.Out).GroupBy(x => x.ChildPosi).Select(x => x.Key).ToList();
                positions.AddRange(inRouterPositions);
                positions.AddRange(outRouterPositions);
                return positions.GroupBy(x => x).Select(x => x.Key).ToList();
            }
            catch
            {
            }
            return positions;
        }
        /// <summary>
        /// èŽ·å–è·¯ç”±è¡¨ä¸­æ‰€æœ‰å®Œæ•´çš„è·¯ç”±ä¿¡æ¯(前端调用展示数据)。
        /// </summary>
        /// <returns>匿名对象集合。</returns>
        public List<object> GetAllWholeRouters()
        {
            List<object> data = new List<object>();
            List<Dt_Router> allRouters = BaseDal.QueryData(x => true);
            List<Dt_Router> dt_Routers = allRouters.Where(x => x.IsEnd).OrderBy(x => x.Id).ToList();
            foreach (var item in dt_Routers)
            {
                string routes = $"{item.ChildPosi},";
                string str = GetPreviousRoutes(item.StartPosi, allRouters, item.InOutType);
                if (!string.IsNullOrEmpty(str))
                {
                    if (str.EndsWith(","))
                        str = str.Substring(0, str.Length - 1);
                    routes += str;
                }
                if (item.InOutType == RouterInOutType.In)
                {
                    List<string> itemRouters = routes.Split(",").Reverse().ToList();
                    object obj = new { type = RouterInOutType.In, routes = itemRouters };
                    data.Add(obj);
                }
                else
                {
                    List<string> itemRouters = routes.Split(",").Reverse().ToList();
                    object obj = new { type = RouterInOutType.Out, routes = itemRouters };
                    data.Add(obj);
                }
            }
            return data;
        }
        private string GetPreviousRoutes(string startPosi, List<Dt_Router> allRouters, RouterInOutType routerType)
        {
            string routers = string.Empty;
            if (!string.IsNullOrEmpty(startPosi))
            {
                if (!routers.EndsWith(","))
                    routers += $"{startPosi},";
                else
                    routers += $"{startPosi}";
            }
            List<Dt_Router> preRouters = allRouters.Where(x => x.NextPosi == startPosi && x.InOutType == routerType).ToList();
            foreach (var item in preRouters)
            {
                string str = GetPreviousRoutes(item.StartPosi, allRouters, routerType);
                if (!string.IsNullOrEmpty(str))
                {
                    if (routers.EndsWith(","))
                        routers += $"{str}";
                    else
                        routers += $"{str},";
                }
            }
            return routers;
        }
        /// <summary>
        /// æ·»åŠ å®Œæ•´è·¯ç”±ä¿¡æ¯(前端调用配置路由信息)。
        /// </summary>
        /// <param name="routersAddDTOs">设备路由配置添加DTO</param>
        /// <param name="routerType">路由类型</param>
        /// <returns>返回处理结果</returns>
        public WebResponseContent AddRouters(List<RoutersAddDTO> routersAddDTOs, int routerType)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                if (routersAddDTOs.GroupBy(x => x.ChildPositionCode).Where(x => !string.IsNullOrEmpty(x.Key)).Select(x => x.Count()).Any(x => x > 1))
                {
                    return content = WebResponseContent.Instance.Error("子位置编号重复");
                }
                if (routersAddDTOs.GroupBy(x => x.PositionCode).Select(x => x.Count()).Any(x => x > 1))
                {
                    return content = WebResponseContent.Instance.Error("根位置编号重复");
                }
                List<dynamic> deviceCode = _deviceInfoRepository.QueryTabs<Dt_DeviceInfo, Dt_DeviceProtocol, dynamic>((a, b) => new object[] { JoinType.Inner, a.Id == b.DeviceId }, (a, b) => new { b.DeviceChildCode, a.DeviceCode }, (a, b) => true, x => true).Distinct().ToList();
                List<Dt_Router> routers = new List<Dt_Router>();
                for (int i = 0; i < routersAddDTOs.Count - 1; i++)
                {
                    dynamic obj = deviceCode.FirstOrDefault(x => x.DeviceChildCode == routersAddDTOs[i + 1].PositionCode || x.DeviceChildCode == routersAddDTOs[i + 1].ChildPositionCode);
                    Dt_Router router = new Dt_Router()
                    {
                        ChildPosi = routersAddDTOs[i + 1].PositionCode,
                        ChildPosiDeviceCode = obj.DeviceCode,
                        Depth = 1,
                        InOutType = (RouterInOutType)routerType,
                        NextPosi = routersAddDTOs[i + 1].PositionCode,
                        SrmColumn = string.IsNullOrEmpty(routersAddDTOs[i].SCColumn) ? int.TryParse(routersAddDTOs[i + 1].SCColumn, out int col) ? col : null : int.TryParse(routersAddDTOs[i].SCColumn, out int col2) ? col2 : null,
                        SrmLayer = string.IsNullOrEmpty(routersAddDTOs[i].SCLayer) ? int.TryParse(routersAddDTOs[i + 1].SCLayer, out int lay) ? lay : null : int.TryParse(routersAddDTOs[i].SCLayer, out int lay2) ? lay2 : null,
                        SrmRow = string.IsNullOrEmpty(routersAddDTOs[i].SCRow) ? int.TryParse(routersAddDTOs[i + 1].SCRow, out int row) ? row : null : int.TryParse(routersAddDTOs[i].SCRow, out int row2) ? row2 : null,
                        StartPosi = routersAddDTOs[i].PositionCode,
                        IsEnd = false
                    };
                    if (i == routersAddDTOs.Count - 2)
                    {
                        if (routerType == (int)RouterInOutType.Out)
                            router.ChildPosi = routersAddDTOs[i + 1].ChildPositionCode;
                        router.IsEnd = true;
                    }
                    routers.Add(router);
                }
                if (routers.Any(x => x.StartPosi == x.ChildPosi))
                {
                    return content = WebResponseContent.Instance.Error("输入数据起点位置编号与子位置编号相同");
                }
                if (routers.Any(x => x.StartPosi == x.NextPosi))
                {
                    return content = WebResponseContent.Instance.Error("输入数据起点位置编号与终点位置编号相同");
                }
                List<Dt_Router> dt_Routers = BaseDal.QueryData(x => x.InOutType == (RouterInOutType)routerType);
                dt_Routers.ForEach(x =>
                {
                    var t = routers.FirstOrDefault(v => v.StartPosi == x.StartPosi && v.NextPosi == x.NextPosi);
                    if (t != null)
                    {
                        routers.Remove(t);
                    }
                    var r = routers.FirstOrDefault(v => v.StartPosi == x.StartPosi && v.ChildPosi == x.ChildPosi);
                    if (r != null)
                    {
                        routers.Remove(r);
                    }
                });
                BaseDal.AddData(routers);
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号获取出库路由点位
        /// </summary>
        /// <param name="deviceCode"></param>
        /// <returns></returns>
        public List<string> QueryOutDeviceCodes(string deviceCode)
        {
            List<string> positions = new List<string>();
            try
            {
                List<string> outRouterPositions = BaseDal.QueryData(x => x.ChildPosiDeviceCode == deviceCode && x.InOutType == RouterInOutType.Out).GroupBy(x => x.ChildPosi).Select(x => x.Key).ToList();
                positions.AddRange(outRouterPositions);
                return positions.GroupBy(x => x).Select(x => x.Key).ToList();
            }
            catch
            {
            }
            return positions;
        }
    }
}
在上述文件截断后对比
项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ShuttleCar/IShuttleCar.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/ShuttleCar/ShuttleCar.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/CommonStackerCrane.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Common/CommonStackerStationCrane.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Enum/StackerCraneStatus.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/IStackerCrane.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/Spec/SpeStackerCrane.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/StackerCrane/StackerCraneTaskCompletedEventArgs.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/Storage.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_QuartzJob/WIDESEAWCS_QuartzJob.csproj 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/.config/dotnet-tools.json 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/BasicInfo/Dt_StationManagerController.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/QuartzJob/DeviceProtocolController.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/QuartzJob/SchedulerController.cs (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/System/AgvStationController.cs (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/System/Sys_DictionaryController.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/System/Sys_LogController.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/CustomProfile.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-23/B202站台241223.txt (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-23/LineJob站台241223.txt (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-23/LineJob错误信息站台241223.txt (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-29/LineJob站台241229.txt (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-29/LineJob错误信息站台241229.txt (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-30/B202站台241230.txt (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-30/LineJob站台241230.txt (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Log/站台读取信息记录/2024-12-30/LineJob错误信息站台241230.txt (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Program.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Properties/PublishProfiles/FolderProfile.pubxml 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Properties/PublishProfiles/FolderProfile1.pubxml 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/appsettings.json 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/GlobalUsing.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Hub/ISimpleHub.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Hub/SimpleHub.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Provider/UserIdProvider.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Service/INoticeService.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/Service/SignalrNoticeService.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SignalR/WIDESEAWCS_SignalR.csproj 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemRepository/WIDESEAWCS_SystemRepository.csproj 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemServices/AgvStationService.cs (已删除) 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_SystemServices/WIDESEAWCS_SystemServices.csproj 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/TaskRepository.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoRepository/WIDESEAWCS_TaskInfoRepository.csproj 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskExecuteDetailService.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Task_HtyService.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/WIDESEAWCS_TaskInfoService.csproj 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/CommonConveyorLineJob.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineJob/ConveyorLineTaskCommand.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/CommonStackerCraneJob.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/StackerCraneJob/StackerCraneDBName.cs 项目代码/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/WIDESEAWCS_Tasks.csproj 项目代码/大屏/package-lock.json 项目代码/大屏/src/views/centerRight1.vue 项目资料/AGV交互协议/AGV RCS --WCS 交互协议表V1.0.docx (已删除) 项目资料/AGV交互协议/PC交互(1).xls 项目资料/AGV交互协议/江西AGV与WCS和输送通信协议 2025.6.10(1).xlsx