From c4ed4ffe5e2739ce7cd6d8d638e2bcc3a2de3274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=A6=20=E8=B5=B5?= <89237069@qq.com> Date: Wed, 28 May 2025 09:06:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 31 + API/CherryTaskManager/CherryTaskManager.http | 6 + .../DataBaseMigration.csproj | 42 + .../20250526065431_Init.Designer.cs | 2197 +++++++ .../Migrations/20250526065431_Init.cs | 1039 +++ .../Migrations/JobDbContextModelSnapshot.cs | 2194 +++++++ API/CherryTaskManager/Program.cs | 118 + .../Properties/launchSettings.json | 31 + API/CherryTaskManager/WeatherForecast.cs | 13 + .../appsettings.Development.json | 8 + API/CherryTaskManager/appsettings.json | 55 + API/TaskManager.Contracts/Dtos/Dtos.cs | 1020 +++ .../TaskManager.Contracts.csproj | 13 + API/TaskManager.Entity/Entity.cs | 767 +++ .../TaskManager.Entity.csproj | 13 + .../JobDbContext.cs | 265 + .../TaskManager.EntityFramework.csproj | 19 + .../Controllers/LogController.cs | 68 + .../Controllers/RecurringJobBaseController.cs | 175 + .../RecurringJobInputPageController.cs | 6 + .../RecurringJobOutPageController.cs | 278 + .../Controllers/SUPPLIER_BOM_CONTROLLER.cs | 6 + .../SUPPLIER_CON_DATE_CONTROLLER.cs | 6 + .../SUPPLIER_CON_MMRP_CONTROLLER.cs | 6 + .../Controllers/SUPPLIER_CON_PO_CONTROLLER.cs | 6 + .../SUPPLIER_DEL_STATE_CONTROLLER.cs | 15 + .../SUPPLIER_EMPLOYEE_CONTROLLER.cs | 6 + .../Controllers/SUPPLIER_INFO_CONTROLLER.cs | 6 + .../SUPPLIER_INV_DATA_CONTROLLER.cs | 15 + .../SUPPLIER_MRP_DATE_CONTROLLER.cs | 15 + .../SUPPLIER_MRP_MONTH_CONTROLLER.cs | 14 + .../SUPPLIER_MRP_STATE_CONTROLLER.cs | 15 + .../SUPPLIER_MRP_WARNING_CONTROLLER.cs | 15 + .../Controllers/SUPPLIER_PO_CONTROLLER.cs | 14 + ...SUPPLIER_PRO_ATTACHMENT_DATA_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_CPS_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_CSCHEDUL_CONTROLLER.cs | 14 + .../SUPPLIER_PRO_DATA_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_ENVIRONMENT_CONTROLLER.cs | 5 + ...SUPPLIER_PRO_FIRST_PASSYIELD_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_FLAW_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_HSCHEDUL_CONTROLLER.cs | 15 + .../SUPPLIER_PRO_MATERIAL_DATA_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_MATERIAL_STOCK_CONTROLLER.cs | 6 + ...IER_PRO_OEE_ACHIEVEMENT_RATE_CONTROLLER.cs | 6 + ...UPPLIER_PRO_OEE_TIME_DETAILS_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_PLANING_CONTROLLER.cs | 15 + .../SUPPLIER_PRO_PROCESS_CONTROLLER.cs | 6 + ...PPLIER_PRO_PROCESS_EQUIPMENT_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_SCHEDULING_CONTROLLER.cs | 6 + ..._PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_TSCHEDUL_CONTROLLER.cs | 15 + .../Controllers/SUPPLIER_RETURN_CONTROLLER.cs | 15 + .../SUPPLIER_SA_WEEK_CONTROLLER.cs | 17 + .../SUPPLIER_SINV_DATA_CONTROLLER.cs | 14 + .../Controllers/TOKEN_CONTROLLER.cs | 185 + .../Controllers/TaskConifgureController.cs | 578 ++ .../Controllers/WeatherForecastController.cs | 33 + API/TaskManager.Job/TaskManager.Job.csproj | 24 + API/Wood.Admin.WebApi/DataSeed.sql | 194 + .../Filter/ApiAuthorizeAttribute.cs | 63 + .../Filter/ApiExceptionFilter.cs | 34 + .../Filter/ApiPerformanceLoggingFilter.cs | 135 + .../Filter/ApiResponseWrapperFilter.cs | 117 + .../Middleware/FileServerMiddleware.cs | 33 + .../Middleware/GlobalExceptionMiddleware.cs | 81 + .../ModelBindingMetadataProvider.cs | 25 + .../Other/AutoRouteConvention.cs | 127 + .../Other/ServiceCollectionExtensions.cs | 214 + API/Wood.Admin.WebApi/Program.cs | 61 + .../Properties/launchSettings.json | 22 + API/Wood.Admin.WebApi/Startup.cs | 346 + .../Wood.Admin.WebApi.csproj | 61 + .../appsettings.Development.json | 9 + API/Wood.Admin.WebApi/appsettings.json | 32 + .../template/用户信息导入模板.xlsx | Bin 0 -> 10849 bytes API/Wood.AutoJob/Attributes/CronAttribute.cs | 74 + .../Attributes/DailyAtAttribute.cs | 75 + .../Attributes/JobDetailAttribute.cs | 31 + .../Attributes/PeriodMinutesAttribute.cs | 72 + .../Attributes/PeriodSecondsAttribute.cs | 73 + API/Wood.AutoJob/AutoJobCenter.cs | 279 + API/Wood.AutoJob/AutoJobTask.cs | 157 + API/Wood.AutoJob/Job/DBLogClearJob.cs | 37 + API/Wood.AutoJob/Wood.AutoJob.csproj | 21 + API/Wood.Cache/Wood.Cache.Interface/ICache.cs | 27 + .../Wood.Cache.Interface.csproj | 14 + .../Wood.MemoryCache/MemoryCacheImp.cs | 126 + .../Wood.MemoryCache/Wood.MemoryCache.csproj | 20 + .../Wood.RedisCache/RedisCacheImp.cs | 188 + .../Wood.RedisCache/Wood.RedisCache.csproj | 20 + .../DataSeed/UserDataSeed.cs | 31 + .../DbContext/SqlSugarDbContext.cs | 234 + .../Extension/DatabaseExtension.cs | 277 + .../Extension/DatabasePageExtension.cs | 110 + .../Extension/RepositoryExtension.cs | 169 + .../Extension/SqlSugarPagedExtensions.cs | 146 + API/Wood.Data.Repository/Repository.cs | 92 + .../UnitOfWork/IUnitOfWork.cs | 35 + .../UnitOfWork/SqlSugarUnitOfWork.cs | 79 + .../UnitOfWork/UnitOfWorkAttribute.cs | 123 + .../Wood.Data.Repository.csproj | 22 + API/Wood.Entity/BaseIdParam.cs | 28 + API/Wood.Entity/ElDto.cs | 74 + API/Wood.Entity/EntityBase.cs | 143 + API/Wood.Entity/Enum/SysManageEnum.cs | 256 + API/Wood.Entity/IEntityFilter.cs | 59 + API/Wood.Entity/Interface/IDiff.cs | 9 + API/Wood.Entity/Interface/ILifeTimeService.cs | 15 + API/Wood.Entity/Interface/IScoped.cs | 10 + API/Wood.Entity/Interface/ISingleton.cs | 10 + API/Wood.Entity/Interface/ITransient.cs | 10 + API/Wood.Entity/Pagination.cs | 50 + .../SystemManage/DataDictDetailEntity.cs | 48 + .../SystemManage/DataDictEntity.cs | 43 + API/Wood.Entity/SystemManage/FileEntity.cs | 68 + .../SystemManage/JobDetailEntity.cs | 40 + .../SystemManage/JobTriggerEntity.cs | 114 + API/Wood.Entity/SystemManage/LogDiffEntity.cs | 57 + .../SystemManage/LogEventEntity.cs | 64 + .../SystemManage/LogExceptionEntity.cs | 36 + API/Wood.Entity/SystemManage/LogJobEntity.cs | 55 + .../SystemManage/LogLoginEntity.cs | 42 + .../SystemManage/LogOperationEntity.cs | 97 + .../SystemManage/MenuAuthorizeEntity.cs | 23 + API/Wood.Entity/SystemManage/MenuEntity.cs | 96 + API/Wood.Entity/SystemManage/MessageEntity.cs | 71 + API/Wood.Entity/SystemManage/OrgEntity.cs | 58 + .../SystemManage/PositionEntity.cs | 38 + .../SystemManage/RoleDataScopeEntity.cs | 27 + API/Wood.Entity/SystemManage/RoleEntity.cs | 52 + API/Wood.Entity/SystemManage/TenantEntity.cs | 32 + .../SystemManage/UserBelongRoleEntity.cs | 30 + API/Wood.Entity/SystemManage/UserEntity.cs | 140 + .../SystemManage/UserMessageEntity.cs | 47 + .../SystemManage/UserRefreshTokenEntity.cs | 46 + API/Wood.Entity/TData.cs | 190 + API/Wood.Entity/UserCache.cs | 82 + API/Wood.Entity/Wood.Entity.csproj | 18 + API/Wood.EventBus/Events/LogExceptionEvent.cs | 49 + API/Wood.EventBus/Events/LogOperationEvent.cs | 6 + API/Wood.EventBus/IEventBus.cs | 10 + API/Wood.EventBus/IEventLog.cs | 16 + API/Wood.EventBus/IIntegrationEventHandler.cs | 98 + API/Wood.EventBus/InMemoryEventBus.cs | 65 + API/Wood.EventBus/IntegrationEvent.cs | 36 + API/Wood.EventBus/Wood.EventBus.csproj | 19 + .../BaseService/ApiCRUDService.cs | 63 + API/Wood.Service/BaseService/ApiManager.cs | 36 + API/Wood.Service/BaseService/ApiService.cs | 47 + API/Wood.Service/Controllers/LogController.cs | 67 + .../Controllers/RecurringJobBaseController.cs | 175 + .../RecurringJobInputPageController.cs | 6 + .../RecurringJobOutPageController.cs | 278 + .../Controllers/SUPPLIER_BOM_CONTROLLER.cs | 6 + .../SUPPLIER_CON_DATE_CONTROLLER.cs | 6 + .../SUPPLIER_CON_MMRP_CONTROLLER.cs | 6 + .../Controllers/SUPPLIER_CON_PO_CONTROLLER.cs | 6 + .../Controllers/SUPPLIER_DEL_STATE_Service.cs | 15 + .../Controllers/SUPPLIER_EMPLOYEE_Service.cs | 6 + .../Controllers/SUPPLIER_INFO_Service.cs | 6 + .../Controllers/SUPPLIER_INV_DATA_Service.cs | 15 + .../Controllers/SUPPLIER_MRP_DATE_Service.cs | 15 + .../Controllers/SUPPLIER_MRP_MONTH_Service.cs | 14 + .../Controllers/SUPPLIER_MRP_Service.cs | 15 + .../SUPPLIER_MRP_WARNING_Service.cs | 15 + .../Controllers/SUPPLIER_PO_Service.cs | 14 + .../SUPPLIER_PRO_ATTACHMENT_DATA_Service.cs | 6 + .../Controllers/SUPPLIER_PRO_CPS_Service.cs | 6 + .../SUPPLIER_PRO_CSCHEDUL_Service.cs | 14 + .../Controllers/SUPPLIER_PRO_DATA_Service.cs | 6 + .../SUPPLIER_PRO_ENVIRONMENT_Service.cs | 5 + .../SUPPLIER_PRO_FIRST_PASSYIELD_Service.cs | 6 + .../Controllers/SUPPLIER_PRO_FLAW_Service.cs | 6 + .../SUPPLIER_PRO_HSCHEDUL_Service.cs | 15 + .../SUPPLIER_PRO_MATERIAL_DATA_Service.cs | 6 + .../SUPPLIER_PRO_MATERIAL_STOCK_Service.cs | 6 + ...PPLIER_PRO_OEE_ACHIEVEMENT_RATE_Service.cs | 6 + .../SUPPLIER_PRO_OEE_TIME_DETAILS_Service.cs | 6 + .../SUPPLIER_PRO_PLANING_Service.cs | 18 + .../SUPPLIER_PRO_PROCESS_EQUIPMENT_Service.cs | 6 + .../SUPPLIER_PRO_PROCESS_Service.cs | 6 + .../SUPPLIER_PRO_SCHEDULING_Service.cs | 6 + ..._PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs | 6 + .../SUPPLIER_PRO_TSCHEDUL_Service.cs | 15 + .../Controllers/SUPPLIER_RETURN_Service.cs | 15 + .../Controllers/SUPPLIER_SA_WEEK_Service.cs | 17 + .../Controllers/SUPPLIER_SINV_DATA_Service.cs | 14 + .../Controllers/TOKEN_CONTROLLER.cs | 185 + .../Controllers/TaskConifgureController.cs | 578 ++ .../Controllers/WeatherForecastController.cs | 33 + .../Events/LogExceptionEventHandler.cs | 29 + .../Events/LogOperationEventHandler.cs | 26 + .../SystemManage/AutoJobService.cs | 115 + .../SystemManage/DataDictDetailService.cs | 48 + .../SystemManage/DataDictService.cs | 45 + .../SystemManage/Dto/AutoJobDto.cs | 39 + API/Wood.Service/SystemManage/Dto/FileDto.cs | 65 + API/Wood.Service/SystemManage/Dto/LogDto.cs | 21 + API/Wood.Service/SystemManage/Dto/MenuDto.cs | 20 + .../SystemManage/Dto/MessageDto.cs | 65 + API/Wood.Service/SystemManage/Dto/OrgDto.cs | 14 + API/Wood.Service/SystemManage/Dto/RoleDto.cs | 41 + .../SystemManage/Dto/TenantDto.cs | 25 + API/Wood.Service/SystemManage/Dto/UserDto.cs | 146 + API/Wood.Service/SystemManage/FileService.cs | 95 + API/Wood.Service/SystemManage/LogService.cs | 118 + .../SystemManage/Manager/FileManager.cs | 178 + .../SystemManage/Manager/OrgManager.cs | 52 + .../SystemManage/Manager/UserManager.cs | 129 + API/Wood.Service/SystemManage/MenuService.cs | 211 + .../SystemManage/MessageService.cs | 198 + API/Wood.Service/SystemManage/OrgService.cs | 108 + .../SystemManage/Param/AutoJobParam.cs | 23 + .../SystemManage/Param/DataDictDetailParam.cs | 29 + .../SystemManage/Param/DataDictParam.cs | 21 + .../SystemManage/Param/LogParam.cs | 64 + .../SystemManage/Param/MenuParam.cs | 38 + .../SystemManage/Param/MessageParam.cs | 43 + .../SystemManage/Param/OrgParam.cs | 27 + .../SystemManage/Param/PositionParam.cs | 28 + .../SystemManage/Param/RoleParam.cs | 42 + .../SystemManage/Param/TenantParam.cs | 42 + .../SystemManage/Param/UserParam.cs | 204 + .../SystemManage/PositionService.cs | 58 + API/Wood.Service/SystemManage/RoleService.cs | 141 + .../SystemManage/SystemService.cs | 33 + .../SystemManage/TenantService.cs | 205 + API/Wood.Service/SystemManage/UserService.cs | 611 ++ API/Wood.Service/Wood.Service.csproj | 44 + API/Wood.Test.Service/TestService.cs | 105 + .../Wood.Test.Service.csproj | 18 + API/Wood.Util/Browser/Browser.cs | 72 + API/Wood.Util/Browser/Chrome.cs | 25 + API/Wood.Util/Browser/Edge.cs | 24 + API/Wood.Util/Browser/Firefox.cs | 24 + API/Wood.Util/Browser/InternetExplorer.cs | 44 + API/Wood.Util/Browser/Opera.cs | 33 + API/Wood.Util/Browser/Safari.cs | 24 + API/Wood.Util/CaptchaHelper.cs | 150 + API/Wood.Util/ComputerHelper.cs | 160 + API/Wood.Util/ConcurrentList.cs | 140 + API/Wood.Util/Config/JwtConfig.cs | 26 + API/Wood.Util/Config/SystemConfig.cs | 67 + API/Wood.Util/CryptogramHelper.cs | 404 ++ API/Wood.Util/DataTableHelper.cs | 49 + API/Wood.Util/DateTimeHelper.cs | 88 + API/Wood.Util/EncodingHelper.cs | 60 + API/Wood.Util/ExcelHelper.cs | 20 + API/Wood.Util/ExceptionHelper.cs | 58 + API/Wood.Util/Extension/Extension.Convert.cs | 108 + API/Wood.Util/Extension/Extension.Enum.cs | 77 + .../Extension/Extension.Exception.cs | 50 + API/Wood.Util/Extension/Extension.Type.cs | 149 + API/Wood.Util/Extension/Extension.Validate.cs | 46 + API/Wood.Util/FileHelper.cs | 307 + API/Wood.Util/GM/GmCrypto.cs | 242 + API/Wood.Util/GlobalConstant.cs | 12 + API/Wood.Util/GlobalContext.cs | 84 + API/Wood.Util/HttpHelper.cs | 181 + API/Wood.Util/IdGeneratorHelper.cs | 68 + .../JsonConvert/DateOnlyConverter.cs | 40 + .../JsonConvert/LongToStringJsonConverter.cs | 39 + .../JsonConvert/NullableIntConverter.cs | 25 + .../NullableLongToStringJsonConverter.cs | 44 + API/Wood.Util/JsonHelper.cs | 32 + .../JwtAuthorization/HttpContextExtension.cs | 54 + API/Wood.Util/JwtAuthorization/JwtHelper.cs | 80 + API/Wood.Util/JwtAuthorization/JwtToken.cs | 34 + API/Wood.Util/JwtAuthorization/JwtUserInfo.cs | 91 + API/Wood.Util/NetHelper.cs | 264 + API/Wood.Util/ReflectionHelper.cs | 57 + API/Wood.Util/ShellHelper.cs | 47 + API/Wood.Util/Snowflake.cs | 112 + API/Wood.Util/TextHelper.cs | 63 + .../Validations/ChineseOnlyAttribute.cs | 25 + .../Validations/UniqueValueAttribute.cs | 127 + API/Wood.Util/Validations/ValidatorHelper.cs | 350 + API/Wood.Util/Wood.Util.csproj | 21 + API/WoodAdmin.sln | 263 + Doc/autojob.md | 81 + Doc/eventbus.md | 33 + Doc/home.md | 106 + Doc/service.md | 74 + LICENSE | 21 + README.md | 19 + Web/.env | 1 + Web/.env.development | 5 + Web/.env.production | 6 + Web/.eslintrc.cjs | 14 + Web/.prettierrc.json | 9 + Web/index.html | 13 + Web/jsconfig.json | 8 + Web/package-lock.json | 5680 +++++++++++++++++ Web/package.json | 42 + Web/public/favicon.ico | Bin 0 -> 4286 bytes Web/src/App.vue | 4 + Web/src/api/system/autoJobApi.js | 50 + Web/src/api/system/dataDictApi.js | 68 + Web/src/api/system/dataDictDetailApi.js | 80 + Web/src/api/system/fileApi.js | 38 + Web/src/api/system/logApi.js | 111 + Web/src/api/system/menuApi.js | 83 + Web/src/api/system/messageApi.js | 135 + Web/src/api/system/orgApi.js | 79 + Web/src/api/system/positionApi.js | 77 + Web/src/api/system/roleApi.js | 90 + Web/src/api/system/sysApi.js | 13 + Web/src/api/system/tenantApi.js | 78 + Web/src/api/system/userApi.js | 172 + Web/src/assets/401_images/401.gif | Bin 0 -> 164227 bytes Web/src/assets/404.png | Bin 0 -> 98071 bytes Web/src/assets/404_cloud.png | Bin 0 -> 4766 bytes Web/src/assets/404_images/404.png | Bin 0 -> 98071 bytes Web/src/assets/404_images/404_cloud.png | Bin 0 -> 4766 bytes Web/src/components/Breadcrumb/index.vue | 84 + Web/src/components/Hamburger/index.vue | 45 + Web/src/components/RightPanel/index.vue | 148 + Web/src/components/Screenfull/index.vue | 55 + Web/src/components/SizeSelect/index.vue | 71 + Web/src/components/SvgIcon/elIcon.vue | 9 + Web/src/components/SvgIcon/icon.vue | 38 + Web/src/components/SwitchDark/index.vue | 23 + .../components/Uploads/importErrorDialog.vue | 88 + .../components/Uploads/multipleImgUpload.vue | 115 + .../components/Uploads/singleImgUpload.vue | 102 + Web/src/components/Uploads/uploadButton.vue | 123 + Web/src/directive/authDirective.js | 60 + Web/src/directive/index.js | 10 + Web/src/layout/components/AppMain.vue | 73 + Web/src/layout/components/Footer/index.vue | 17 + Web/src/layout/components/Navbar.vue | 187 + Web/src/layout/components/Settings/index.vue | 198 + .../layout/components/Sidebar/FixiOSBug.js | 18 + Web/src/layout/components/Sidebar/Logo.vue | 91 + .../layout/components/Sidebar/SidebarItem.vue | 99 + Web/src/layout/components/Sidebar/index.vue | 122 + .../layout/components/SidebarColumn/index.vue | 143 + .../layout/components/TagsView/ScrollPane.vue | 94 + Web/src/layout/components/TagsView/index.vue | 338 + Web/src/layout/components/index.js | 6 + Web/src/layout/index.vue | 119 + Web/src/main.js | 47 + Web/src/permission.js | 110 + Web/src/router/index.js | 159 + Web/src/settings.js | 39 + Web/src/stores/index.js | 15 + Web/src/stores/modules/app.js | 34 + Web/src/stores/modules/permission.js | 66 + Web/src/stores/modules/settings.js | 67 + Web/src/stores/modules/tagsView.js | 158 + Web/src/stores/modules/user.js | 152 + Web/src/styles/element-ui.scss | 100 + Web/src/styles/font-awesome/font-awesome.scss | 2332 +++++++ .../font-awesome/fontawesome-webfont.eot | Bin 0 -> 165742 bytes .../font-awesome/fontawesome-webfont.svg | 2671 ++++++++ .../font-awesome/fontawesome-webfont.ttf | Bin 0 -> 165548 bytes .../font-awesome/fontawesome-webfont.woff | Bin 0 -> 98024 bytes .../font-awesome/fontawesome-webfont.woff2 | Bin 0 -> 77160 bytes Web/src/styles/index.scss | 169 + Web/src/styles/mixin.scss | 28 + Web/src/styles/transition.scss | 48 + Web/src/styles/variables.module.scss | 37 + Web/src/utils/auth.js | 33 + Web/src/utils/base64Conver.js | 84 + Web/src/utils/download.js | 113 + Web/src/utils/formatTime.js | 260 + Web/src/utils/get-page-title.js | 10 + Web/src/utils/index.js | 73 + Web/src/utils/request.js | 120 + Web/src/utils/validate.js | 382 ++ Web/src/utils/waitUtils/countWait.js | 69 + Web/src/utils/waitUtils/simpleWait.js | 63 + Web/src/utils/waitUtils/waitable.js | 46 + Web/src/views/404.vue | 226 + Web/src/views/500.vue | 716 +++ Web/src/views/dashboard/index.vue | 28 + .../autoJob/components/deferredJobDialog.vue | 74 + Web/src/views/system/autoJob/index.vue | 137 + .../views/system/components/dictSelect.vue | 29 + .../views/system/components/enumSelect.vue | 29 + .../views/system/components/orgCascader.vue | 89 + Web/src/views/system/components/orgTree.vue | 68 + .../system/components/positionSelect.vue | 26 + .../views/system/components/userSelect.vue | 65 + .../system/components/userSelectDialog.vue | 129 + .../dataDict/components/dictDetailDialog.vue | 135 + .../system/dataDict/components/editDialog.vue | 141 + .../components/editDictDetailDialog.vue | 151 + Web/src/views/system/dataDict/index.vue | 132 + Web/src/views/system/log/logDiffIndex.vue | 88 + Web/src/views/system/log/logEventIndex.vue | 89 + .../views/system/log/logExceptionIndex.vue | 106 + Web/src/views/system/log/logJobIndex.vue | 89 + Web/src/views/system/log/logLoginIndex.vue | 89 + Web/src/views/system/log/logOperateIndex.vue | 103 + .../system/login/components/tenantDialog.vue | 93 + Web/src/views/system/login/index.vue | 308 + .../system/menu/components/editDialog.vue | 350 + .../system/menu/components/elIconList.vue | 40 + .../system/menu/components/faIconList.vue | 825 +++ Web/src/views/system/menu/index.vue | 107 + .../system/message/components/editDialog.vue | 240 + .../message/components/publishDialog.vue | 196 + .../system/message/components/viewDialog.vue | 82 + Web/src/views/system/message/publishIndex.vue | 180 + Web/src/views/system/message/receiveIndex.vue | 114 + .../system/org/components/editDialog.vue | 193 + Web/src/views/system/org/index.vue | 92 + Web/src/views/system/personalCenter/index.vue | 263 + .../system/position/components/editDialog.vue | 141 + Web/src/views/system/position/index.vue | 117 + Web/src/views/system/redirect/index.vue | 14 + .../role/components/editDataTypeDialog.vue | 113 + .../system/role/components/editDialog.vue | 207 + Web/src/views/system/role/index.vue | 134 + .../system/tenant/components/editDialog.vue | 140 + Web/src/views/system/tenant/index.vue | 166 + .../system/user/components/editDialog.vue | 232 + Web/src/views/system/user/index.vue | 218 + Web/vite.config.js | 49 + 421 files changed, 50594 insertions(+) create mode 100644 .gitignore create mode 100644 API/CherryTaskManager/CherryTaskManager.http create mode 100644 API/CherryTaskManager/DataBaseMigration.csproj create mode 100644 API/CherryTaskManager/Migrations/20250526065431_Init.Designer.cs create mode 100644 API/CherryTaskManager/Migrations/20250526065431_Init.cs create mode 100644 API/CherryTaskManager/Migrations/JobDbContextModelSnapshot.cs create mode 100644 API/CherryTaskManager/Program.cs create mode 100644 API/CherryTaskManager/Properties/launchSettings.json create mode 100644 API/CherryTaskManager/WeatherForecast.cs create mode 100644 API/CherryTaskManager/appsettings.Development.json create mode 100644 API/CherryTaskManager/appsettings.json create mode 100644 API/TaskManager.Contracts/Dtos/Dtos.cs create mode 100644 API/TaskManager.Contracts/TaskManager.Contracts.csproj create mode 100644 API/TaskManager.Entity/Entity.cs create mode 100644 API/TaskManager.Entity/TaskManager.Entity.csproj create mode 100644 API/TaskManager.EntityFramework/JobDbContext.cs create mode 100644 API/TaskManager.EntityFramework/TaskManager.EntityFramework.csproj create mode 100644 API/TaskManager.Job/Controllers/LogController.cs create mode 100644 API/TaskManager.Job/Controllers/RecurringJobBaseController.cs create mode 100644 API/TaskManager.Job/Controllers/RecurringJobInputPageController.cs create mode 100644 API/TaskManager.Job/Controllers/RecurringJobOutPageController.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_BOM_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_CON_DATE_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_CON_MMRP_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_CON_PO_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_DEL_STATE_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_EMPLOYEE_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_INFO_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_INV_DATA_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_MRP_DATE_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_MRP_MONTH_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_MRP_STATE_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_MRP_WARNING_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PO_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_ATTACHMENT_DATA_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_CPS_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_CSCHEDUL_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_DATA_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_ENVIRONMENT_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_FIRST_PASSYIELD_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_FLAW_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_HSCHEDUL_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_MATERIAL_DATA_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_MATERIAL_STOCK_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_OEE_TIME_DETAILS_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_PLANING_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_PROCESS_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_PROCESS_EQUIPMENT_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_SCHEDULING_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_PRO_TSCHEDUL_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_RETURN_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_SA_WEEK_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/SUPPLIER_SINV_DATA_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/TOKEN_CONTROLLER.cs create mode 100644 API/TaskManager.Job/Controllers/TaskConifgureController.cs create mode 100644 API/TaskManager.Job/Controllers/WeatherForecastController.cs create mode 100644 API/TaskManager.Job/TaskManager.Job.csproj create mode 100644 API/Wood.Admin.WebApi/DataSeed.sql create mode 100644 API/Wood.Admin.WebApi/Filter/ApiAuthorizeAttribute.cs create mode 100644 API/Wood.Admin.WebApi/Filter/ApiExceptionFilter.cs create mode 100644 API/Wood.Admin.WebApi/Filter/ApiPerformanceLoggingFilter.cs create mode 100644 API/Wood.Admin.WebApi/Filter/ApiResponseWrapperFilter.cs create mode 100644 API/Wood.Admin.WebApi/Middleware/FileServerMiddleware.cs create mode 100644 API/Wood.Admin.WebApi/Middleware/GlobalExceptionMiddleware.cs create mode 100644 API/Wood.Admin.WebApi/Middleware/ModelBindingMetadataProvider.cs create mode 100644 API/Wood.Admin.WebApi/Other/AutoRouteConvention.cs create mode 100644 API/Wood.Admin.WebApi/Other/ServiceCollectionExtensions.cs create mode 100644 API/Wood.Admin.WebApi/Program.cs create mode 100644 API/Wood.Admin.WebApi/Properties/launchSettings.json create mode 100644 API/Wood.Admin.WebApi/Startup.cs create mode 100644 API/Wood.Admin.WebApi/Wood.Admin.WebApi.csproj create mode 100644 API/Wood.Admin.WebApi/appsettings.Development.json create mode 100644 API/Wood.Admin.WebApi/appsettings.json create mode 100644 API/Wood.Admin.WebApi/wwwroot/template/用户信息导入模板.xlsx create mode 100644 API/Wood.AutoJob/Attributes/CronAttribute.cs create mode 100644 API/Wood.AutoJob/Attributes/DailyAtAttribute.cs create mode 100644 API/Wood.AutoJob/Attributes/JobDetailAttribute.cs create mode 100644 API/Wood.AutoJob/Attributes/PeriodMinutesAttribute.cs create mode 100644 API/Wood.AutoJob/Attributes/PeriodSecondsAttribute.cs create mode 100644 API/Wood.AutoJob/AutoJobCenter.cs create mode 100644 API/Wood.AutoJob/AutoJobTask.cs create mode 100644 API/Wood.AutoJob/Job/DBLogClearJob.cs create mode 100644 API/Wood.AutoJob/Wood.AutoJob.csproj create mode 100644 API/Wood.Cache/Wood.Cache.Interface/ICache.cs create mode 100644 API/Wood.Cache/Wood.Cache.Interface/Wood.Cache.Interface.csproj create mode 100644 API/Wood.Cache/Wood.MemoryCache/MemoryCacheImp.cs create mode 100644 API/Wood.Cache/Wood.MemoryCache/Wood.MemoryCache.csproj create mode 100644 API/Wood.Cache/Wood.RedisCache/RedisCacheImp.cs create mode 100644 API/Wood.Cache/Wood.RedisCache/Wood.RedisCache.csproj create mode 100644 API/Wood.Data.Repository/DataSeed/UserDataSeed.cs create mode 100644 API/Wood.Data.Repository/DbContext/SqlSugarDbContext.cs create mode 100644 API/Wood.Data.Repository/Extension/DatabaseExtension.cs create mode 100644 API/Wood.Data.Repository/Extension/DatabasePageExtension.cs create mode 100644 API/Wood.Data.Repository/Extension/RepositoryExtension.cs create mode 100644 API/Wood.Data.Repository/Extension/SqlSugarPagedExtensions.cs create mode 100644 API/Wood.Data.Repository/Repository.cs create mode 100644 API/Wood.Data.Repository/UnitOfWork/IUnitOfWork.cs create mode 100644 API/Wood.Data.Repository/UnitOfWork/SqlSugarUnitOfWork.cs create mode 100644 API/Wood.Data.Repository/UnitOfWork/UnitOfWorkAttribute.cs create mode 100644 API/Wood.Data.Repository/Wood.Data.Repository.csproj create mode 100644 API/Wood.Entity/BaseIdParam.cs create mode 100644 API/Wood.Entity/ElDto.cs create mode 100644 API/Wood.Entity/EntityBase.cs create mode 100644 API/Wood.Entity/Enum/SysManageEnum.cs create mode 100644 API/Wood.Entity/IEntityFilter.cs create mode 100644 API/Wood.Entity/Interface/IDiff.cs create mode 100644 API/Wood.Entity/Interface/ILifeTimeService.cs create mode 100644 API/Wood.Entity/Interface/IScoped.cs create mode 100644 API/Wood.Entity/Interface/ISingleton.cs create mode 100644 API/Wood.Entity/Interface/ITransient.cs create mode 100644 API/Wood.Entity/Pagination.cs create mode 100644 API/Wood.Entity/SystemManage/DataDictDetailEntity.cs create mode 100644 API/Wood.Entity/SystemManage/DataDictEntity.cs create mode 100644 API/Wood.Entity/SystemManage/FileEntity.cs create mode 100644 API/Wood.Entity/SystemManage/JobDetailEntity.cs create mode 100644 API/Wood.Entity/SystemManage/JobTriggerEntity.cs create mode 100644 API/Wood.Entity/SystemManage/LogDiffEntity.cs create mode 100644 API/Wood.Entity/SystemManage/LogEventEntity.cs create mode 100644 API/Wood.Entity/SystemManage/LogExceptionEntity.cs create mode 100644 API/Wood.Entity/SystemManage/LogJobEntity.cs create mode 100644 API/Wood.Entity/SystemManage/LogLoginEntity.cs create mode 100644 API/Wood.Entity/SystemManage/LogOperationEntity.cs create mode 100644 API/Wood.Entity/SystemManage/MenuAuthorizeEntity.cs create mode 100644 API/Wood.Entity/SystemManage/MenuEntity.cs create mode 100644 API/Wood.Entity/SystemManage/MessageEntity.cs create mode 100644 API/Wood.Entity/SystemManage/OrgEntity.cs create mode 100644 API/Wood.Entity/SystemManage/PositionEntity.cs create mode 100644 API/Wood.Entity/SystemManage/RoleDataScopeEntity.cs create mode 100644 API/Wood.Entity/SystemManage/RoleEntity.cs create mode 100644 API/Wood.Entity/SystemManage/TenantEntity.cs create mode 100644 API/Wood.Entity/SystemManage/UserBelongRoleEntity.cs create mode 100644 API/Wood.Entity/SystemManage/UserEntity.cs create mode 100644 API/Wood.Entity/SystemManage/UserMessageEntity.cs create mode 100644 API/Wood.Entity/SystemManage/UserRefreshTokenEntity.cs create mode 100644 API/Wood.Entity/TData.cs create mode 100644 API/Wood.Entity/UserCache.cs create mode 100644 API/Wood.Entity/Wood.Entity.csproj create mode 100644 API/Wood.EventBus/Events/LogExceptionEvent.cs create mode 100644 API/Wood.EventBus/Events/LogOperationEvent.cs create mode 100644 API/Wood.EventBus/IEventBus.cs create mode 100644 API/Wood.EventBus/IEventLog.cs create mode 100644 API/Wood.EventBus/IIntegrationEventHandler.cs create mode 100644 API/Wood.EventBus/InMemoryEventBus.cs create mode 100644 API/Wood.EventBus/IntegrationEvent.cs create mode 100644 API/Wood.EventBus/Wood.EventBus.csproj create mode 100644 API/Wood.Service/BaseService/ApiCRUDService.cs create mode 100644 API/Wood.Service/BaseService/ApiManager.cs create mode 100644 API/Wood.Service/BaseService/ApiService.cs create mode 100644 API/Wood.Service/Controllers/LogController.cs create mode 100644 API/Wood.Service/Controllers/RecurringJobBaseController.cs create mode 100644 API/Wood.Service/Controllers/RecurringJobInputPageController.cs create mode 100644 API/Wood.Service/Controllers/RecurringJobOutPageController.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_BOM_CONTROLLER.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_CON_DATE_CONTROLLER.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_CON_MMRP_CONTROLLER.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_CON_PO_CONTROLLER.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_DEL_STATE_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_EMPLOYEE_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_INFO_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_INV_DATA_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_MRP_DATE_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_MRP_MONTH_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_MRP_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_MRP_WARNING_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PO_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_ATTACHMENT_DATA_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_CPS_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_CSCHEDUL_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_DATA_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_ENVIRONMENT_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_FIRST_PASSYIELD_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_FLAW_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_HSCHEDUL_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_MATERIAL_DATA_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_MATERIAL_STOCK_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_OEE_TIME_DETAILS_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_PLANING_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_PROCESS_EQUIPMENT_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_PROCESS_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_SCHEDULING_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_PRO_TSCHEDUL_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_RETURN_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_SA_WEEK_Service.cs create mode 100644 API/Wood.Service/Controllers/SUPPLIER_SINV_DATA_Service.cs create mode 100644 API/Wood.Service/Controllers/TOKEN_CONTROLLER.cs create mode 100644 API/Wood.Service/Controllers/TaskConifgureController.cs create mode 100644 API/Wood.Service/Controllers/WeatherForecastController.cs create mode 100644 API/Wood.Service/Events/LogExceptionEventHandler.cs create mode 100644 API/Wood.Service/Events/LogOperationEventHandler.cs create mode 100644 API/Wood.Service/SystemManage/AutoJobService.cs create mode 100644 API/Wood.Service/SystemManage/DataDictDetailService.cs create mode 100644 API/Wood.Service/SystemManage/DataDictService.cs create mode 100644 API/Wood.Service/SystemManage/Dto/AutoJobDto.cs create mode 100644 API/Wood.Service/SystemManage/Dto/FileDto.cs create mode 100644 API/Wood.Service/SystemManage/Dto/LogDto.cs create mode 100644 API/Wood.Service/SystemManage/Dto/MenuDto.cs create mode 100644 API/Wood.Service/SystemManage/Dto/MessageDto.cs create mode 100644 API/Wood.Service/SystemManage/Dto/OrgDto.cs create mode 100644 API/Wood.Service/SystemManage/Dto/RoleDto.cs create mode 100644 API/Wood.Service/SystemManage/Dto/TenantDto.cs create mode 100644 API/Wood.Service/SystemManage/Dto/UserDto.cs create mode 100644 API/Wood.Service/SystemManage/FileService.cs create mode 100644 API/Wood.Service/SystemManage/LogService.cs create mode 100644 API/Wood.Service/SystemManage/Manager/FileManager.cs create mode 100644 API/Wood.Service/SystemManage/Manager/OrgManager.cs create mode 100644 API/Wood.Service/SystemManage/Manager/UserManager.cs create mode 100644 API/Wood.Service/SystemManage/MenuService.cs create mode 100644 API/Wood.Service/SystemManage/MessageService.cs create mode 100644 API/Wood.Service/SystemManage/OrgService.cs create mode 100644 API/Wood.Service/SystemManage/Param/AutoJobParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/DataDictDetailParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/DataDictParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/LogParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/MenuParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/MessageParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/OrgParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/PositionParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/RoleParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/TenantParam.cs create mode 100644 API/Wood.Service/SystemManage/Param/UserParam.cs create mode 100644 API/Wood.Service/SystemManage/PositionService.cs create mode 100644 API/Wood.Service/SystemManage/RoleService.cs create mode 100644 API/Wood.Service/SystemManage/SystemService.cs create mode 100644 API/Wood.Service/SystemManage/TenantService.cs create mode 100644 API/Wood.Service/SystemManage/UserService.cs create mode 100644 API/Wood.Service/Wood.Service.csproj create mode 100644 API/Wood.Test.Service/TestService.cs create mode 100644 API/Wood.Test.Service/Wood.Test.Service.csproj create mode 100644 API/Wood.Util/Browser/Browser.cs create mode 100644 API/Wood.Util/Browser/Chrome.cs create mode 100644 API/Wood.Util/Browser/Edge.cs create mode 100644 API/Wood.Util/Browser/Firefox.cs create mode 100644 API/Wood.Util/Browser/InternetExplorer.cs create mode 100644 API/Wood.Util/Browser/Opera.cs create mode 100644 API/Wood.Util/Browser/Safari.cs create mode 100644 API/Wood.Util/CaptchaHelper.cs create mode 100644 API/Wood.Util/ComputerHelper.cs create mode 100644 API/Wood.Util/ConcurrentList.cs create mode 100644 API/Wood.Util/Config/JwtConfig.cs create mode 100644 API/Wood.Util/Config/SystemConfig.cs create mode 100644 API/Wood.Util/CryptogramHelper.cs create mode 100644 API/Wood.Util/DataTableHelper.cs create mode 100644 API/Wood.Util/DateTimeHelper.cs create mode 100644 API/Wood.Util/EncodingHelper.cs create mode 100644 API/Wood.Util/ExcelHelper.cs create mode 100644 API/Wood.Util/ExceptionHelper.cs create mode 100644 API/Wood.Util/Extension/Extension.Convert.cs create mode 100644 API/Wood.Util/Extension/Extension.Enum.cs create mode 100644 API/Wood.Util/Extension/Extension.Exception.cs create mode 100644 API/Wood.Util/Extension/Extension.Type.cs create mode 100644 API/Wood.Util/Extension/Extension.Validate.cs create mode 100644 API/Wood.Util/FileHelper.cs create mode 100644 API/Wood.Util/GM/GmCrypto.cs create mode 100644 API/Wood.Util/GlobalConstant.cs create mode 100644 API/Wood.Util/GlobalContext.cs create mode 100644 API/Wood.Util/HttpHelper.cs create mode 100644 API/Wood.Util/IdGeneratorHelper.cs create mode 100644 API/Wood.Util/JsonConvert/DateOnlyConverter.cs create mode 100644 API/Wood.Util/JsonConvert/LongToStringJsonConverter.cs create mode 100644 API/Wood.Util/JsonConvert/NullableIntConverter.cs create mode 100644 API/Wood.Util/JsonConvert/NullableLongToStringJsonConverter.cs create mode 100644 API/Wood.Util/JsonHelper.cs create mode 100644 API/Wood.Util/JwtAuthorization/HttpContextExtension.cs create mode 100644 API/Wood.Util/JwtAuthorization/JwtHelper.cs create mode 100644 API/Wood.Util/JwtAuthorization/JwtToken.cs create mode 100644 API/Wood.Util/JwtAuthorization/JwtUserInfo.cs create mode 100644 API/Wood.Util/NetHelper.cs create mode 100644 API/Wood.Util/ReflectionHelper.cs create mode 100644 API/Wood.Util/ShellHelper.cs create mode 100644 API/Wood.Util/Snowflake.cs create mode 100644 API/Wood.Util/TextHelper.cs create mode 100644 API/Wood.Util/Validations/ChineseOnlyAttribute.cs create mode 100644 API/Wood.Util/Validations/UniqueValueAttribute.cs create mode 100644 API/Wood.Util/Validations/ValidatorHelper.cs create mode 100644 API/Wood.Util/Wood.Util.csproj create mode 100644 API/WoodAdmin.sln create mode 100644 Doc/autojob.md create mode 100644 Doc/eventbus.md create mode 100644 Doc/home.md create mode 100644 Doc/service.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Web/.env create mode 100644 Web/.env.development create mode 100644 Web/.env.production create mode 100644 Web/.eslintrc.cjs create mode 100644 Web/.prettierrc.json create mode 100644 Web/index.html create mode 100644 Web/jsconfig.json create mode 100644 Web/package-lock.json create mode 100644 Web/package.json create mode 100644 Web/public/favicon.ico create mode 100644 Web/src/App.vue create mode 100644 Web/src/api/system/autoJobApi.js create mode 100644 Web/src/api/system/dataDictApi.js create mode 100644 Web/src/api/system/dataDictDetailApi.js create mode 100644 Web/src/api/system/fileApi.js create mode 100644 Web/src/api/system/logApi.js create mode 100644 Web/src/api/system/menuApi.js create mode 100644 Web/src/api/system/messageApi.js create mode 100644 Web/src/api/system/orgApi.js create mode 100644 Web/src/api/system/positionApi.js create mode 100644 Web/src/api/system/roleApi.js create mode 100644 Web/src/api/system/sysApi.js create mode 100644 Web/src/api/system/tenantApi.js create mode 100644 Web/src/api/system/userApi.js create mode 100644 Web/src/assets/401_images/401.gif create mode 100644 Web/src/assets/404.png create mode 100644 Web/src/assets/404_cloud.png create mode 100644 Web/src/assets/404_images/404.png create mode 100644 Web/src/assets/404_images/404_cloud.png create mode 100644 Web/src/components/Breadcrumb/index.vue create mode 100644 Web/src/components/Hamburger/index.vue create mode 100644 Web/src/components/RightPanel/index.vue create mode 100644 Web/src/components/Screenfull/index.vue create mode 100644 Web/src/components/SizeSelect/index.vue create mode 100644 Web/src/components/SvgIcon/elIcon.vue create mode 100644 Web/src/components/SvgIcon/icon.vue create mode 100644 Web/src/components/SwitchDark/index.vue create mode 100644 Web/src/components/Uploads/importErrorDialog.vue create mode 100644 Web/src/components/Uploads/multipleImgUpload.vue create mode 100644 Web/src/components/Uploads/singleImgUpload.vue create mode 100644 Web/src/components/Uploads/uploadButton.vue create mode 100644 Web/src/directive/authDirective.js create mode 100644 Web/src/directive/index.js create mode 100644 Web/src/layout/components/AppMain.vue create mode 100644 Web/src/layout/components/Footer/index.vue create mode 100644 Web/src/layout/components/Navbar.vue create mode 100644 Web/src/layout/components/Settings/index.vue create mode 100644 Web/src/layout/components/Sidebar/FixiOSBug.js create mode 100644 Web/src/layout/components/Sidebar/Logo.vue create mode 100644 Web/src/layout/components/Sidebar/SidebarItem.vue create mode 100644 Web/src/layout/components/Sidebar/index.vue create mode 100644 Web/src/layout/components/SidebarColumn/index.vue create mode 100644 Web/src/layout/components/TagsView/ScrollPane.vue create mode 100644 Web/src/layout/components/TagsView/index.vue create mode 100644 Web/src/layout/components/index.js create mode 100644 Web/src/layout/index.vue create mode 100644 Web/src/main.js create mode 100644 Web/src/permission.js create mode 100644 Web/src/router/index.js create mode 100644 Web/src/settings.js create mode 100644 Web/src/stores/index.js create mode 100644 Web/src/stores/modules/app.js create mode 100644 Web/src/stores/modules/permission.js create mode 100644 Web/src/stores/modules/settings.js create mode 100644 Web/src/stores/modules/tagsView.js create mode 100644 Web/src/stores/modules/user.js create mode 100644 Web/src/styles/element-ui.scss create mode 100644 Web/src/styles/font-awesome/font-awesome.scss create mode 100644 Web/src/styles/font-awesome/fontawesome-webfont.eot create mode 100644 Web/src/styles/font-awesome/fontawesome-webfont.svg create mode 100644 Web/src/styles/font-awesome/fontawesome-webfont.ttf create mode 100644 Web/src/styles/font-awesome/fontawesome-webfont.woff create mode 100644 Web/src/styles/font-awesome/fontawesome-webfont.woff2 create mode 100644 Web/src/styles/index.scss create mode 100644 Web/src/styles/mixin.scss create mode 100644 Web/src/styles/transition.scss create mode 100644 Web/src/styles/variables.module.scss create mode 100644 Web/src/utils/auth.js create mode 100644 Web/src/utils/base64Conver.js create mode 100644 Web/src/utils/download.js create mode 100644 Web/src/utils/formatTime.js create mode 100644 Web/src/utils/get-page-title.js create mode 100644 Web/src/utils/index.js create mode 100644 Web/src/utils/request.js create mode 100644 Web/src/utils/validate.js create mode 100644 Web/src/utils/waitUtils/countWait.js create mode 100644 Web/src/utils/waitUtils/simpleWait.js create mode 100644 Web/src/utils/waitUtils/waitable.js create mode 100644 Web/src/views/404.vue create mode 100644 Web/src/views/500.vue create mode 100644 Web/src/views/dashboard/index.vue create mode 100644 Web/src/views/system/autoJob/components/deferredJobDialog.vue create mode 100644 Web/src/views/system/autoJob/index.vue create mode 100644 Web/src/views/system/components/dictSelect.vue create mode 100644 Web/src/views/system/components/enumSelect.vue create mode 100644 Web/src/views/system/components/orgCascader.vue create mode 100644 Web/src/views/system/components/orgTree.vue create mode 100644 Web/src/views/system/components/positionSelect.vue create mode 100644 Web/src/views/system/components/userSelect.vue create mode 100644 Web/src/views/system/components/userSelectDialog.vue create mode 100644 Web/src/views/system/dataDict/components/dictDetailDialog.vue create mode 100644 Web/src/views/system/dataDict/components/editDialog.vue create mode 100644 Web/src/views/system/dataDict/components/editDictDetailDialog.vue create mode 100644 Web/src/views/system/dataDict/index.vue create mode 100644 Web/src/views/system/log/logDiffIndex.vue create mode 100644 Web/src/views/system/log/logEventIndex.vue create mode 100644 Web/src/views/system/log/logExceptionIndex.vue create mode 100644 Web/src/views/system/log/logJobIndex.vue create mode 100644 Web/src/views/system/log/logLoginIndex.vue create mode 100644 Web/src/views/system/log/logOperateIndex.vue create mode 100644 Web/src/views/system/login/components/tenantDialog.vue create mode 100644 Web/src/views/system/login/index.vue create mode 100644 Web/src/views/system/menu/components/editDialog.vue create mode 100644 Web/src/views/system/menu/components/elIconList.vue create mode 100644 Web/src/views/system/menu/components/faIconList.vue create mode 100644 Web/src/views/system/menu/index.vue create mode 100644 Web/src/views/system/message/components/editDialog.vue create mode 100644 Web/src/views/system/message/components/publishDialog.vue create mode 100644 Web/src/views/system/message/components/viewDialog.vue create mode 100644 Web/src/views/system/message/publishIndex.vue create mode 100644 Web/src/views/system/message/receiveIndex.vue create mode 100644 Web/src/views/system/org/components/editDialog.vue create mode 100644 Web/src/views/system/org/index.vue create mode 100644 Web/src/views/system/personalCenter/index.vue create mode 100644 Web/src/views/system/position/components/editDialog.vue create mode 100644 Web/src/views/system/position/index.vue create mode 100644 Web/src/views/system/redirect/index.vue create mode 100644 Web/src/views/system/role/components/editDataTypeDialog.vue create mode 100644 Web/src/views/system/role/components/editDialog.vue create mode 100644 Web/src/views/system/role/index.vue create mode 100644 Web/src/views/system/tenant/components/editDialog.vue create mode 100644 Web/src/views/system/tenant/index.vue create mode 100644 Web/src/views/system/user/components/editDialog.vue create mode 100644 Web/src/views/system/user/index.vue create mode 100644 Web/vite.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36e9ce1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# Build and Release Folders +bin-debug/ +bin-release/ +[Oo]bj/ +[Bb]in/ + +# Other files and folders +.settings/ + +# Executables +*.swf +*.air +*.ipa +*.apk + +# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` +# should NOT be excluded as they contain compiler settings and other important +# information for Eclipse / Flash Builder. + +/Web/node_modules/ +/Web/dist/ +/Web/.vscode/ +/Web/.vscode/ +/Web/vite.config.js.timestamp* + +/API/.vs/ +/API/WoodAdmin.db +/API/Wood.Admin.WebApi/logs +/API/Wood.Admin.WebApi/wwwroot/uploads +bin/ +obj/ diff --git a/API/CherryTaskManager/CherryTaskManager.http b/API/CherryTaskManager/CherryTaskManager.http new file mode 100644 index 0000000..f4d6fc7 --- /dev/null +++ b/API/CherryTaskManager/CherryTaskManager.http @@ -0,0 +1,6 @@ +@CherryTaskManager_HostAddress = http://localhost:5014 + +GET {{CherryTaskManager_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/API/CherryTaskManager/DataBaseMigration.csproj b/API/CherryTaskManager/DataBaseMigration.csproj new file mode 100644 index 0000000..e043cf4 --- /dev/null +++ b/API/CherryTaskManager/DataBaseMigration.csproj @@ -0,0 +1,42 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + diff --git a/API/CherryTaskManager/Migrations/20250526065431_Init.Designer.cs b/API/CherryTaskManager/Migrations/20250526065431_Init.Designer.cs new file mode 100644 index 0000000..2f10a63 --- /dev/null +++ b/API/CherryTaskManager/Migrations/20250526065431_Init.Designer.cs @@ -0,0 +1,2197 @@ +// +using System; +using CherryTaskManager; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CherryTaskManager.Migrations +{ + [DbContext(typeof(JobDbContext))] + [Migration("20250526065431_Init")] + partial class Init + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_BOM", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_BOM"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_CON_DATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("FeedbackResults") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Measures") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityMeet1") + .HasColumnType("int"); + + b.Property("QuantityMeet10") + .HasColumnType("int"); + + b.Property("QuantityMeet11") + .HasColumnType("int"); + + b.Property("QuantityMeet12") + .HasColumnType("int"); + + b.Property("QuantityMeet13") + .HasColumnType("int"); + + b.Property("QuantityMeet14") + .HasColumnType("int"); + + b.Property("QuantityMeet15") + .HasColumnType("int"); + + b.Property("QuantityMeet16") + .HasColumnType("int"); + + b.Property("QuantityMeet17") + .HasColumnType("int"); + + b.Property("QuantityMeet18") + .HasColumnType("int"); + + b.Property("QuantityMeet19") + .HasColumnType("int"); + + b.Property("QuantityMeet2") + .HasColumnType("int"); + + b.Property("QuantityMeet20") + .HasColumnType("int"); + + b.Property("QuantityMeet21") + .HasColumnType("int"); + + b.Property("QuantityMeet22") + .HasColumnType("int"); + + b.Property("QuantityMeet23") + .HasColumnType("int"); + + b.Property("QuantityMeet24") + .HasColumnType("int"); + + b.Property("QuantityMeet25") + .HasColumnType("int"); + + b.Property("QuantityMeet26") + .HasColumnType("int"); + + b.Property("QuantityMeet27") + .HasColumnType("int"); + + b.Property("QuantityMeet28") + .HasColumnType("int"); + + b.Property("QuantityMeet29") + .HasColumnType("int"); + + b.Property("QuantityMeet3") + .HasColumnType("int"); + + b.Property("QuantityMeet30") + .HasColumnType("int"); + + b.Property("QuantityMeet31") + .HasColumnType("int"); + + b.Property("QuantityMeet4") + .HasColumnType("int"); + + b.Property("QuantityMeet5") + .HasColumnType("int"); + + b.Property("QuantityMeet6") + .HasColumnType("int"); + + b.Property("QuantityMeet7") + .HasColumnType("int"); + + b.Property("QuantityMeet8") + .HasColumnType("int"); + + b.Property("QuantityMeet9") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureSpecific") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_CON_DATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_CON_MMRP", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("FeedbackResults") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Measures") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityMeet1") + .HasColumnType("int"); + + b.Property("QuantityMeet10") + .HasColumnType("int"); + + b.Property("QuantityMeet11") + .HasColumnType("int"); + + b.Property("QuantityMeet12") + .HasColumnType("int"); + + b.Property("QuantityMeet2") + .HasColumnType("int"); + + b.Property("QuantityMeet3") + .HasColumnType("int"); + + b.Property("QuantityMeet4") + .HasColumnType("int"); + + b.Property("QuantityMeet5") + .HasColumnType("int"); + + b.Property("QuantityMeet6") + .HasColumnType("int"); + + b.Property("QuantityMeet7") + .HasColumnType("int"); + + b.Property("QuantityMeet8") + .HasColumnType("int"); + + b.Property("QuantityMeet9") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartMonth") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureSpecific") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_CON_MMRP"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_CON_PO", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("FeedbackResults") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Measures") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PurchaseOrder") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityMeet") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureSpecific") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_CON_PO"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_DEL_STATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DataCreateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DeliveryNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDelivery") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReceivingCrossings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RoadReceiveTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RoadShippedTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialSrate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierReceiveTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_DEL_STATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_EMPLOYEE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_EMPLOYEE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_INFO", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_INFO"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_INV_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DataUpdateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityCurrent") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StockState") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_INV_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_MRP_DATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("IsUpdate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDemand1") + .HasColumnType("int"); + + b.Property("QuantityDemand10") + .HasColumnType("int"); + + b.Property("QuantityDemand11") + .HasColumnType("int"); + + b.Property("QuantityDemand12") + .HasColumnType("int"); + + b.Property("QuantityDemand13") + .HasColumnType("int"); + + b.Property("QuantityDemand14") + .HasColumnType("int"); + + b.Property("QuantityDemand15") + .HasColumnType("int"); + + b.Property("QuantityDemand16") + .HasColumnType("int"); + + b.Property("QuantityDemand17") + .HasColumnType("int"); + + b.Property("QuantityDemand18") + .HasColumnType("int"); + + b.Property("QuantityDemand19") + .HasColumnType("int"); + + b.Property("QuantityDemand2") + .HasColumnType("int"); + + b.Property("QuantityDemand20") + .HasColumnType("int"); + + b.Property("QuantityDemand21") + .HasColumnType("int"); + + b.Property("QuantityDemand22") + .HasColumnType("int"); + + b.Property("QuantityDemand23") + .HasColumnType("int"); + + b.Property("QuantityDemand24") + .HasColumnType("int"); + + b.Property("QuantityDemand25") + .HasColumnType("int"); + + b.Property("QuantityDemand26") + .HasColumnType("int"); + + b.Property("QuantityDemand27") + .HasColumnType("int"); + + b.Property("QuantityDemand28") + .HasColumnType("int"); + + b.Property("QuantityDemand29") + .HasColumnType("int"); + + b.Property("QuantityDemand3") + .HasColumnType("int"); + + b.Property("QuantityDemand30") + .HasColumnType("int"); + + b.Property("QuantityDemand31") + .HasColumnType("int"); + + b.Property("QuantityDemand4") + .HasColumnType("int"); + + b.Property("QuantityDemand5") + .HasColumnType("int"); + + b.Property("QuantityDemand6") + .HasColumnType("int"); + + b.Property("QuantityDemand7") + .HasColumnType("int"); + + b.Property("QuantityDemand8") + .HasColumnType("int"); + + b.Property("QuantityDemand9") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_MRP_DATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_MRP_MONTH", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsUpdate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDemand1") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand10") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand11") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand12") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand2") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand3") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand4") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand5") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand6") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand7") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand8") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand9") + .HasColumnType("decimal(18,2)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartMonth") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_MRP_MONTH"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_MRP_STATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("ConfirmTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatQuantity") + .HasColumnType("int"); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DateRequired") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DemandSrate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DemandType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnTimePercentage") + .HasColumnType("int"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDelivery") + .HasColumnType("int"); + + b.Property("QuantityDemand") + .HasColumnType("int"); + + b.Property("QuantityInTransit") + .HasColumnType("int"); + + b.Property("QuantityReceive") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SummaryCreatQuantity") + .HasColumnType("int"); + + b.Property("SummaryQuantityDelivery") + .HasColumnType("int"); + + b.Property("SummaryQuantityInTransit") + .HasColumnType("int"); + + b.Property("SummaryQuantityReceive") + .HasColumnType("int"); + + b.Property("SummarySign") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_MRP_STATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PO", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("Batch") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Country") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DeliveryDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DeliveryPlace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("ItemType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialUnit") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PurchaseOrder") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Purchaser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDelivery") + .HasColumnType("int"); + + b.Property("QuantityDemand") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Supplier") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TradeTerms") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("VoucherDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PO"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_ATTACHMENT_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_ATTACHMENT_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_CPS", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_CPS"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_CSCHEDUL", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("AssemblyMaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ModelCategory") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Models") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MotorMaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnLineDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnLineTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Plant") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SortDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SortTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("Vin") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_CSCHEDUL"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_ENVIRONMENT", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_ENVIRONMENT"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_FIRST_PASSYIELD", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_FIRST_PASSYIELD"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_FLAW", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_FLAW"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_HSCHEDUL", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Models") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnLineTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("Vin") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_HSCHEDUL"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_MATERIAL_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_MATERIAL_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_MATERIAL_STOCK", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_MATERIAL_STOCK"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_OEE_TIME_DETAILS", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_OEE_TIME_DETAILS"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_PLANING", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("Assembly") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Models") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Omterior") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Pattern") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Plant") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Quantity1") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity2") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity3") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity4") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity5") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity6") + .HasColumnType("decimal(18,2)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SalseDepartment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartMonth") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_PLANING"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_PROCESS", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_PROCESS"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_PROCESS_EQUIPMENT", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_PROCESS_EQUIPMENT"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_SCHEDULING", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_SCHEDULING"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_STATION_FIRST_PASSYIELD", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_STATION_FIRST_PASSYIELD"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_TSCHEDUL", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("FinalOnLineTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FinalWorkshop") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Models") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnLineTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("Vin") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_TSCHEDUL"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_RETURN", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DemandPickupTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Feedback") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("Judge") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LotNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PickUpCrossings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PickUpLocation") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Plant") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDelivery") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReturnNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReturnReason") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReturnType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialSrate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_RETURN"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_SA_WEEK", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DateReceived") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PurchasingGroup") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDemand") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ScheduleAgreement") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_SA_WEEK"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_SINV_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DataUpdateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryStatus") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionCycle") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityCurrent") + .HasColumnType("int"); + + b.Property("QuantityPlan") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SafetyStock") + .HasColumnType("int"); + + b.Property("SupplierBatch") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplieryxqDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_SINV_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.TaskConifgure", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("Api") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Corn") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsAuto") + .HasColumnType("bit"); + + b.Property("Module") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TableName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TaskName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("UId"); + + b.ToTable("TaskConifgure"); + }); + + modelBuilder.Entity("TaskManager.Controllers.TaskLog", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Info") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TaskName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("UId"); + + b.ToTable("TaskLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/CherryTaskManager/Migrations/20250526065431_Init.cs b/API/CherryTaskManager/Migrations/20250526065431_Init.cs new file mode 100644 index 0000000..9a04bea --- /dev/null +++ b/API/CherryTaskManager/Migrations/20250526065431_Init.cs @@ -0,0 +1,1039 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace CherryTaskManager.Migrations +{ + /// + public partial class Init : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SUPPLIER_BOM", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_BOM", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_CON_DATE", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SupplierCode = table.Column(type: "nvarchar(max)", nullable: false), + ReleaseEdition = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + FeedbackResults = table.Column(type: "nvarchar(max)", nullable: false), + VentureType = table.Column(type: "nvarchar(max)", nullable: false), + VentureSpecific = table.Column(type: "nvarchar(max)", nullable: false), + Measures = table.Column(type: "nvarchar(max)", nullable: false), + StartDate = table.Column(type: "nvarchar(max)", nullable: false), + QuantityMeet1 = table.Column(type: "int", nullable: false), + QuantityMeet2 = table.Column(type: "int", nullable: false), + QuantityMeet3 = table.Column(type: "int", nullable: false), + QuantityMeet4 = table.Column(type: "int", nullable: false), + QuantityMeet5 = table.Column(type: "int", nullable: false), + QuantityMeet6 = table.Column(type: "int", nullable: false), + QuantityMeet7 = table.Column(type: "int", nullable: false), + QuantityMeet8 = table.Column(type: "int", nullable: false), + QuantityMeet9 = table.Column(type: "int", nullable: false), + QuantityMeet10 = table.Column(type: "int", nullable: false), + QuantityMeet11 = table.Column(type: "int", nullable: false), + QuantityMeet12 = table.Column(type: "int", nullable: false), + QuantityMeet13 = table.Column(type: "int", nullable: false), + QuantityMeet14 = table.Column(type: "int", nullable: false), + QuantityMeet15 = table.Column(type: "int", nullable: false), + QuantityMeet16 = table.Column(type: "int", nullable: false), + QuantityMeet17 = table.Column(type: "int", nullable: false), + QuantityMeet18 = table.Column(type: "int", nullable: false), + QuantityMeet19 = table.Column(type: "int", nullable: false), + QuantityMeet20 = table.Column(type: "int", nullable: false), + QuantityMeet21 = table.Column(type: "int", nullable: false), + QuantityMeet22 = table.Column(type: "int", nullable: false), + QuantityMeet23 = table.Column(type: "int", nullable: false), + QuantityMeet24 = table.Column(type: "int", nullable: false), + QuantityMeet25 = table.Column(type: "int", nullable: false), + QuantityMeet26 = table.Column(type: "int", nullable: false), + QuantityMeet27 = table.Column(type: "int", nullable: false), + QuantityMeet28 = table.Column(type: "int", nullable: false), + QuantityMeet29 = table.Column(type: "int", nullable: false), + QuantityMeet30 = table.Column(type: "int", nullable: false), + QuantityMeet31 = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_CON_DATE", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_CON_MMRP", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SupplierCode = table.Column(type: "nvarchar(max)", nullable: false), + ReleaseEdition = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + FeedbackResults = table.Column(type: "nvarchar(max)", nullable: false), + VentureType = table.Column(type: "nvarchar(max)", nullable: false), + VentureSpecific = table.Column(type: "nvarchar(max)", nullable: false), + Measures = table.Column(type: "nvarchar(max)", nullable: false), + StartMonth = table.Column(type: "nvarchar(max)", nullable: false), + QuantityMeet1 = table.Column(type: "int", nullable: false), + QuantityMeet2 = table.Column(type: "int", nullable: false), + QuantityMeet3 = table.Column(type: "int", nullable: false), + QuantityMeet4 = table.Column(type: "int", nullable: false), + QuantityMeet5 = table.Column(type: "int", nullable: false), + QuantityMeet6 = table.Column(type: "int", nullable: false), + QuantityMeet7 = table.Column(type: "int", nullable: false), + QuantityMeet8 = table.Column(type: "int", nullable: false), + QuantityMeet9 = table.Column(type: "int", nullable: false), + QuantityMeet10 = table.Column(type: "int", nullable: false), + QuantityMeet11 = table.Column(type: "int", nullable: false), + QuantityMeet12 = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_CON_MMRP", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_CON_PO", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SupplierCode = table.Column(type: "nvarchar(max)", nullable: false), + PurchaseOrder = table.Column(type: "nvarchar(max)", nullable: false), + SerialNumber = table.Column(type: "nvarchar(max)", nullable: false), + QuantityMeet = table.Column(type: "int", nullable: false), + FeedbackResults = table.Column(type: "nvarchar(max)", nullable: false), + VentureType = table.Column(type: "nvarchar(max)", nullable: false), + VentureSpecific = table.Column(type: "nvarchar(max)", nullable: false), + Measures = table.Column(type: "nvarchar(max)", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_CON_PO", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_DEL_STATE", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + DeliveryNumber = table.Column(type: "nvarchar(max)", nullable: false), + SerialNumber = table.Column(type: "nvarchar(max)", nullable: false), + SerialSrate = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + ReceivingCrossings = table.Column(type: "nvarchar(max)", nullable: false), + QuantityDelivery = table.Column(type: "int", nullable: false), + DataCreateTime = table.Column(type: "nvarchar(max)", nullable: false), + SupplierReceiveTime = table.Column(type: "nvarchar(max)", nullable: false), + RoadShippedTime = table.Column(type: "nvarchar(max)", nullable: false), + RoadReceiveTime = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_DEL_STATE", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_EMPLOYEE", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_EMPLOYEE", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_INFO", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_INFO", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_INV_DATA", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + PlantName = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + QuantityCurrent = table.Column(type: "int", nullable: false), + StockState = table.Column(type: "nvarchar(max)", nullable: false), + DataUpdateTime = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_INV_DATA", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_MRP_DATE", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + ReleaseEdition = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + PlantName = table.Column(type: "nvarchar(max)", nullable: false), + StartDate = table.Column(type: "nvarchar(max)", nullable: false), + QuantityDemand1 = table.Column(type: "int", nullable: false), + QuantityDemand2 = table.Column(type: "int", nullable: false), + QuantityDemand3 = table.Column(type: "int", nullable: false), + QuantityDemand4 = table.Column(type: "int", nullable: false), + QuantityDemand5 = table.Column(type: "int", nullable: false), + QuantityDemand6 = table.Column(type: "int", nullable: false), + QuantityDemand7 = table.Column(type: "int", nullable: false), + QuantityDemand8 = table.Column(type: "int", nullable: false), + QuantityDemand9 = table.Column(type: "int", nullable: false), + QuantityDemand10 = table.Column(type: "int", nullable: false), + QuantityDemand11 = table.Column(type: "int", nullable: false), + QuantityDemand12 = table.Column(type: "int", nullable: false), + QuantityDemand13 = table.Column(type: "int", nullable: false), + QuantityDemand14 = table.Column(type: "int", nullable: false), + QuantityDemand15 = table.Column(type: "int", nullable: false), + QuantityDemand16 = table.Column(type: "int", nullable: false), + QuantityDemand17 = table.Column(type: "int", nullable: false), + QuantityDemand18 = table.Column(type: "int", nullable: false), + QuantityDemand19 = table.Column(type: "int", nullable: false), + QuantityDemand20 = table.Column(type: "int", nullable: false), + QuantityDemand21 = table.Column(type: "int", nullable: false), + QuantityDemand22 = table.Column(type: "int", nullable: false), + QuantityDemand23 = table.Column(type: "int", nullable: false), + QuantityDemand24 = table.Column(type: "int", nullable: false), + QuantityDemand25 = table.Column(type: "int", nullable: false), + QuantityDemand26 = table.Column(type: "int", nullable: false), + QuantityDemand27 = table.Column(type: "int", nullable: false), + QuantityDemand28 = table.Column(type: "int", nullable: false), + QuantityDemand29 = table.Column(type: "int", nullable: false), + QuantityDemand30 = table.Column(type: "int", nullable: false), + QuantityDemand31 = table.Column(type: "int", nullable: false), + IsUpdate = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "nvarchar(max)", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "nvarchar(max)", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_MRP_DATE", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_MRP_MONTH", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + ReleaseEdition = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + PlantName = table.Column(type: "nvarchar(max)", nullable: false), + StartMonth = table.Column(type: "nvarchar(max)", nullable: false), + QuantityDemand1 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand2 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand3 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand4 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand5 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand6 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand7 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand8 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand9 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand10 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand11 = table.Column(type: "decimal(18,2)", nullable: false), + QuantityDemand12 = table.Column(type: "decimal(18,2)", nullable: false), + IsUpdate = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "nvarchar(max)", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_MRP_MONTH", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_MRP_STATE", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + PlantName = table.Column(type: "nvarchar(max)", nullable: false), + DemandSrate = table.Column(type: "nvarchar(max)", nullable: false), + DemandType = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + SummarySign = table.Column(type: "nvarchar(max)", nullable: false), + DateRequired = table.Column(type: "nvarchar(max)", nullable: false), + QuantityDemand = table.Column(type: "int", nullable: false), + ConfirmTime = table.Column(type: "nvarchar(max)", nullable: false), + CreatQuantity = table.Column(type: "int", nullable: false), + QuantityDelivery = table.Column(type: "int", nullable: false), + QuantityReceive = table.Column(type: "int", nullable: false), + QuantityInTransit = table.Column(type: "int", nullable: false), + OnTimePercentage = table.Column(type: "int", nullable: false), + SummaryCreatQuantity = table.Column(type: "int", nullable: false), + SummaryQuantityDelivery = table.Column(type: "int", nullable: false), + SummaryQuantityReceive = table.Column(type: "int", nullable: false), + SummaryQuantityInTransit = table.Column(type: "int", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_MRP_STATE", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PO", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + PurchaseOrder = table.Column(type: "nvarchar(max)", nullable: false), + SerialNumber = table.Column(type: "nvarchar(max)", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + PlantName = table.Column(type: "nvarchar(max)", nullable: false), + VoucherDate = table.Column(type: "nvarchar(max)", nullable: false), + Purchaser = table.Column(type: "nvarchar(max)", nullable: false), + Supplier = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + QuantityDemand = table.Column(type: "int", nullable: false), + MaterialUnit = table.Column(type: "nvarchar(max)", nullable: false), + DeliveryDate = table.Column(type: "nvarchar(max)", nullable: false), + DeliveryPlace = table.Column(type: "nvarchar(max)", nullable: false), + QuantityDelivery = table.Column(type: "int", nullable: false), + Note = table.Column(type: "nvarchar(max)", nullable: false), + ItemType = table.Column(type: "nvarchar(max)", nullable: false), + TradeTerms = table.Column(type: "nvarchar(max)", nullable: false), + Country = table.Column(type: "nvarchar(max)", nullable: false), + Batch = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "nvarchar(max)", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "nvarchar(max)", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PO", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_ATTACHMENT_DATA", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_ATTACHMENT_DATA", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_CPS", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_CPS", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_CSCHEDUL", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + Models = table.Column(type: "nvarchar(max)", nullable: false), + Vin = table.Column(type: "nvarchar(max)", nullable: false), + ProductionLineId = table.Column(type: "nvarchar(max)", nullable: false), + ProductionLineName = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + SortDate = table.Column(type: "nvarchar(max)", nullable: false), + SortTime = table.Column(type: "nvarchar(max)", nullable: false), + OnLineDate = table.Column(type: "nvarchar(max)", nullable: false), + OnLineTime = table.Column(type: "nvarchar(max)", nullable: false), + ModelCategory = table.Column(type: "nvarchar(max)", nullable: false), + AssemblyMaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MotorMaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + Plant = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_CSCHEDUL", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_DATA", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_DATA", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_ENVIRONMENT", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_ENVIRONMENT", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_FIRST_PASSYIELD", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_FIRST_PASSYIELD", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_FLAW", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_FLAW", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_HSCHEDUL", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + Models = table.Column(type: "nvarchar(max)", nullable: false), + Vin = table.Column(type: "nvarchar(max)", nullable: false), + ProductionLineId = table.Column(type: "nvarchar(max)", nullable: false), + ProductionLineName = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + ProductionType = table.Column(type: "nvarchar(max)", nullable: false), + OnLineTime = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_HSCHEDUL", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_MATERIAL_DATA", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_MATERIAL_DATA", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_MATERIAL_STOCK", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_MATERIAL_STOCK", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_OEE_TIME_DETAILS", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_OEE_TIME_DETAILS", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_PLANING", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Models = table.Column(type: "nvarchar(max)", nullable: false), + Quantity1 = table.Column(type: "decimal(18,2)", nullable: true), + Quantity2 = table.Column(type: "decimal(18,2)", nullable: true), + StartMonth = table.Column(type: "nvarchar(max)", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + Pattern = table.Column(type: "nvarchar(max)", nullable: false), + Omterior = table.Column(type: "nvarchar(max)", nullable: false), + SalseDepartment = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: true), + Type = table.Column(type: "nvarchar(max)", nullable: false), + Quantity3 = table.Column(type: "decimal(18,2)", nullable: true), + ReleaseEdition = table.Column(type: "nvarchar(max)", nullable: false), + Quantity4 = table.Column(type: "decimal(18,2)", nullable: true), + Version = table.Column(type: "int", nullable: false), + Quantity5 = table.Column(type: "decimal(18,2)", nullable: true), + Quantity6 = table.Column(type: "decimal(18,2)", nullable: true), + CreateTime = table.Column(type: "datetime2", nullable: true), + Plant = table.Column(type: "nvarchar(max)", nullable: false), + Assembly = table.Column(type: "nvarchar(max)", nullable: false), + Id = table.Column(type: "nvarchar(max)", nullable: true), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_PLANING", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_PROCESS", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_PROCESS", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_PROCESS_EQUIPMENT", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_PROCESS_EQUIPMENT", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_SCHEDULING", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_SCHEDULING", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_STATION_FIRST_PASSYIELD", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_STATION_FIRST_PASSYIELD", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_PRO_TSCHEDUL", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + Models = table.Column(type: "nvarchar(max)", nullable: false), + Vin = table.Column(type: "nvarchar(max)", nullable: false), + ProductionLineId = table.Column(type: "nvarchar(max)", nullable: false), + ProductionLineName = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + OnLineTime = table.Column(type: "nvarchar(max)", nullable: false), + FinalWorkshop = table.Column(type: "nvarchar(max)", nullable: false), + FinalOnLineTime = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_PRO_TSCHEDUL", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_RETURN", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + ReturnNumber = table.Column(type: "nvarchar(max)", nullable: false), + SerialNumber = table.Column(type: "nvarchar(max)", nullable: false), + SerialSrate = table.Column(type: "nvarchar(max)", nullable: false), + PickUpLocation = table.Column(type: "nvarchar(max)", nullable: false), + DemandPickupTime = table.Column(type: "nvarchar(max)", nullable: false), + PickUpCrossings = table.Column(type: "nvarchar(max)", nullable: false), + Feedback = table.Column(type: "nvarchar(max)", nullable: false), + Plant = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + QuantityDelivery = table.Column(type: "int", nullable: false), + ReturnType = table.Column(type: "nvarchar(max)", nullable: false), + LotNumber = table.Column(type: "nvarchar(max)", nullable: false), + Judge = table.Column(type: "nvarchar(max)", nullable: false), + ReturnReason = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_RETURN", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_SA_WEEK", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Id = table.Column(type: "int", nullable: false), + ScheduleAgreement = table.Column(type: "nvarchar(max)", nullable: false), + SerialNumber = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + PurchasingGroup = table.Column(type: "nvarchar(max)", nullable: false), + PlantId = table.Column(type: "nvarchar(max)", nullable: false), + QuantityDemand = table.Column(type: "int", nullable: false), + DateReceived = table.Column(type: "nvarchar(max)", nullable: false), + CreateByUser = table.Column(type: "nvarchar(max)", nullable: false), + CreateTime = table.Column(type: "datetime2", nullable: false), + UpdateByUser = table.Column(type: "nvarchar(max)", nullable: false), + UpdateTime = table.Column(type: "datetime2", nullable: false), + IsDelete = table.Column(type: "int", nullable: false), + Version = table.Column(type: "int", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_SA_WEEK", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "SUPPLIER_SINV_DATA", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + SupplierCode = table.Column(type: "nvarchar(max)", nullable: false), + SupplierName = table.Column(type: "nvarchar(max)", nullable: false), + MaterialCode = table.Column(type: "nvarchar(max)", nullable: false), + MaterialDescription = table.Column(type: "nvarchar(max)", nullable: false), + MaterialType = table.Column(type: "nvarchar(max)", nullable: false), + QuantityCurrent = table.Column(type: "int", nullable: false), + QuantityPlan = table.Column(type: "int", nullable: false), + InventoryStatus = table.Column(type: "nvarchar(max)", nullable: false), + SafetyStock = table.Column(type: "int", nullable: false), + ProductionCycle = table.Column(type: "nvarchar(max)", nullable: false), + DataUpdateTime = table.Column(type: "nvarchar(max)", nullable: false), + SupplierBatch = table.Column(type: "nvarchar(max)", nullable: false), + SupplieryxqDate = table.Column(type: "nvarchar(max)", nullable: false), + WriteState = table.Column(type: "bit", nullable: false), + ReadState = table.Column(type: "bit", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SUPPLIER_SINV_DATA", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "TaskConifgure", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Api = table.Column(type: "nvarchar(max)", nullable: false), + Corn = table.Column(type: "nvarchar(max)", nullable: false), + Module = table.Column(type: "nvarchar(max)", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false), + TableName = table.Column(type: "nvarchar(max)", nullable: false), + TaskName = table.Column(type: "nvarchar(max)", nullable: false), + Url = table.Column(type: "nvarchar(max)", nullable: false), + IsAuto = table.Column(type: "bit", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TaskConifgure", x => x.UId); + }); + + migrationBuilder.CreateTable( + name: "TaskLogs", + columns: table => new + { + UId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Info = table.Column(type: "nvarchar(max)", nullable: false), + Type = table.Column(type: "nvarchar(max)", nullable: false), + TaskName = table.Column(type: "nvarchar(max)", nullable: false), + CreationTime = table.Column(type: "datetime2", nullable: false), + Remark = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TaskLogs", x => x.UId); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SUPPLIER_BOM"); + + migrationBuilder.DropTable( + name: "SUPPLIER_CON_DATE"); + + migrationBuilder.DropTable( + name: "SUPPLIER_CON_MMRP"); + + migrationBuilder.DropTable( + name: "SUPPLIER_CON_PO"); + + migrationBuilder.DropTable( + name: "SUPPLIER_DEL_STATE"); + + migrationBuilder.DropTable( + name: "SUPPLIER_EMPLOYEE"); + + migrationBuilder.DropTable( + name: "SUPPLIER_INFO"); + + migrationBuilder.DropTable( + name: "SUPPLIER_INV_DATA"); + + migrationBuilder.DropTable( + name: "SUPPLIER_MRP_DATE"); + + migrationBuilder.DropTable( + name: "SUPPLIER_MRP_MONTH"); + + migrationBuilder.DropTable( + name: "SUPPLIER_MRP_STATE"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PO"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_ATTACHMENT_DATA"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_CPS"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_CSCHEDUL"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_DATA"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_ENVIRONMENT"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_FIRST_PASSYIELD"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_FLAW"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_HSCHEDUL"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_MATERIAL_DATA"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_MATERIAL_STOCK"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_OEE_TIME_DETAILS"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_PLANING"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_PROCESS"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_PROCESS_EQUIPMENT"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_SCHEDULING"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_STATION_FIRST_PASSYIELD"); + + migrationBuilder.DropTable( + name: "SUPPLIER_PRO_TSCHEDUL"); + + migrationBuilder.DropTable( + name: "SUPPLIER_RETURN"); + + migrationBuilder.DropTable( + name: "SUPPLIER_SA_WEEK"); + + migrationBuilder.DropTable( + name: "SUPPLIER_SINV_DATA"); + + migrationBuilder.DropTable( + name: "TaskConifgure"); + + migrationBuilder.DropTable( + name: "TaskLogs"); + } + } +} diff --git a/API/CherryTaskManager/Migrations/JobDbContextModelSnapshot.cs b/API/CherryTaskManager/Migrations/JobDbContextModelSnapshot.cs new file mode 100644 index 0000000..2a9ab4f --- /dev/null +++ b/API/CherryTaskManager/Migrations/JobDbContextModelSnapshot.cs @@ -0,0 +1,2194 @@ +// +using System; +using CherryTaskManager; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CherryTaskManager.Migrations +{ + [DbContext(typeof(JobDbContext))] + partial class JobDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_BOM", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_BOM"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_CON_DATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("FeedbackResults") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Measures") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityMeet1") + .HasColumnType("int"); + + b.Property("QuantityMeet10") + .HasColumnType("int"); + + b.Property("QuantityMeet11") + .HasColumnType("int"); + + b.Property("QuantityMeet12") + .HasColumnType("int"); + + b.Property("QuantityMeet13") + .HasColumnType("int"); + + b.Property("QuantityMeet14") + .HasColumnType("int"); + + b.Property("QuantityMeet15") + .HasColumnType("int"); + + b.Property("QuantityMeet16") + .HasColumnType("int"); + + b.Property("QuantityMeet17") + .HasColumnType("int"); + + b.Property("QuantityMeet18") + .HasColumnType("int"); + + b.Property("QuantityMeet19") + .HasColumnType("int"); + + b.Property("QuantityMeet2") + .HasColumnType("int"); + + b.Property("QuantityMeet20") + .HasColumnType("int"); + + b.Property("QuantityMeet21") + .HasColumnType("int"); + + b.Property("QuantityMeet22") + .HasColumnType("int"); + + b.Property("QuantityMeet23") + .HasColumnType("int"); + + b.Property("QuantityMeet24") + .HasColumnType("int"); + + b.Property("QuantityMeet25") + .HasColumnType("int"); + + b.Property("QuantityMeet26") + .HasColumnType("int"); + + b.Property("QuantityMeet27") + .HasColumnType("int"); + + b.Property("QuantityMeet28") + .HasColumnType("int"); + + b.Property("QuantityMeet29") + .HasColumnType("int"); + + b.Property("QuantityMeet3") + .HasColumnType("int"); + + b.Property("QuantityMeet30") + .HasColumnType("int"); + + b.Property("QuantityMeet31") + .HasColumnType("int"); + + b.Property("QuantityMeet4") + .HasColumnType("int"); + + b.Property("QuantityMeet5") + .HasColumnType("int"); + + b.Property("QuantityMeet6") + .HasColumnType("int"); + + b.Property("QuantityMeet7") + .HasColumnType("int"); + + b.Property("QuantityMeet8") + .HasColumnType("int"); + + b.Property("QuantityMeet9") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureSpecific") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_CON_DATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_CON_MMRP", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("FeedbackResults") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Measures") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityMeet1") + .HasColumnType("int"); + + b.Property("QuantityMeet10") + .HasColumnType("int"); + + b.Property("QuantityMeet11") + .HasColumnType("int"); + + b.Property("QuantityMeet12") + .HasColumnType("int"); + + b.Property("QuantityMeet2") + .HasColumnType("int"); + + b.Property("QuantityMeet3") + .HasColumnType("int"); + + b.Property("QuantityMeet4") + .HasColumnType("int"); + + b.Property("QuantityMeet5") + .HasColumnType("int"); + + b.Property("QuantityMeet6") + .HasColumnType("int"); + + b.Property("QuantityMeet7") + .HasColumnType("int"); + + b.Property("QuantityMeet8") + .HasColumnType("int"); + + b.Property("QuantityMeet9") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartMonth") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureSpecific") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_CON_MMRP"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_CON_PO", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("FeedbackResults") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Measures") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PurchaseOrder") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityMeet") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureSpecific") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("VentureType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_CON_PO"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_DEL_STATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DataCreateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DeliveryNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDelivery") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReceivingCrossings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RoadReceiveTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RoadShippedTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialSrate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierReceiveTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_DEL_STATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_EMPLOYEE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_EMPLOYEE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_INFO", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_INFO"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_INV_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DataUpdateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityCurrent") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StockState") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_INV_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_MRP_DATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("IsUpdate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDemand1") + .HasColumnType("int"); + + b.Property("QuantityDemand10") + .HasColumnType("int"); + + b.Property("QuantityDemand11") + .HasColumnType("int"); + + b.Property("QuantityDemand12") + .HasColumnType("int"); + + b.Property("QuantityDemand13") + .HasColumnType("int"); + + b.Property("QuantityDemand14") + .HasColumnType("int"); + + b.Property("QuantityDemand15") + .HasColumnType("int"); + + b.Property("QuantityDemand16") + .HasColumnType("int"); + + b.Property("QuantityDemand17") + .HasColumnType("int"); + + b.Property("QuantityDemand18") + .HasColumnType("int"); + + b.Property("QuantityDemand19") + .HasColumnType("int"); + + b.Property("QuantityDemand2") + .HasColumnType("int"); + + b.Property("QuantityDemand20") + .HasColumnType("int"); + + b.Property("QuantityDemand21") + .HasColumnType("int"); + + b.Property("QuantityDemand22") + .HasColumnType("int"); + + b.Property("QuantityDemand23") + .HasColumnType("int"); + + b.Property("QuantityDemand24") + .HasColumnType("int"); + + b.Property("QuantityDemand25") + .HasColumnType("int"); + + b.Property("QuantityDemand26") + .HasColumnType("int"); + + b.Property("QuantityDemand27") + .HasColumnType("int"); + + b.Property("QuantityDemand28") + .HasColumnType("int"); + + b.Property("QuantityDemand29") + .HasColumnType("int"); + + b.Property("QuantityDemand3") + .HasColumnType("int"); + + b.Property("QuantityDemand30") + .HasColumnType("int"); + + b.Property("QuantityDemand31") + .HasColumnType("int"); + + b.Property("QuantityDemand4") + .HasColumnType("int"); + + b.Property("QuantityDemand5") + .HasColumnType("int"); + + b.Property("QuantityDemand6") + .HasColumnType("int"); + + b.Property("QuantityDemand7") + .HasColumnType("int"); + + b.Property("QuantityDemand8") + .HasColumnType("int"); + + b.Property("QuantityDemand9") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_MRP_DATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_MRP_MONTH", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsUpdate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDemand1") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand10") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand11") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand12") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand2") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand3") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand4") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand5") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand6") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand7") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand8") + .HasColumnType("decimal(18,2)"); + + b.Property("QuantityDemand9") + .HasColumnType("decimal(18,2)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartMonth") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_MRP_MONTH"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_MRP_STATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("ConfirmTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreatQuantity") + .HasColumnType("int"); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DateRequired") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DemandSrate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DemandType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnTimePercentage") + .HasColumnType("int"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDelivery") + .HasColumnType("int"); + + b.Property("QuantityDemand") + .HasColumnType("int"); + + b.Property("QuantityInTransit") + .HasColumnType("int"); + + b.Property("QuantityReceive") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SummaryCreatQuantity") + .HasColumnType("int"); + + b.Property("SummaryQuantityDelivery") + .HasColumnType("int"); + + b.Property("SummaryQuantityInTransit") + .HasColumnType("int"); + + b.Property("SummaryQuantityReceive") + .HasColumnType("int"); + + b.Property("SummarySign") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_MRP_STATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PO", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("Batch") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Country") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DeliveryDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DeliveryPlace") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("ItemType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialUnit") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Note") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PurchaseOrder") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Purchaser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDelivery") + .HasColumnType("int"); + + b.Property("QuantityDemand") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Supplier") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TradeTerms") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("VoucherDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PO"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_ATTACHMENT_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_ATTACHMENT_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_CPS", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_CPS"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_CSCHEDUL", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("AssemblyMaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ModelCategory") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Models") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MotorMaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnLineDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnLineTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Plant") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SortDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SortTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("Vin") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_CSCHEDUL"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_ENVIRONMENT", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_ENVIRONMENT"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_FIRST_PASSYIELD", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_FIRST_PASSYIELD"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_FLAW", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_FLAW"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_HSCHEDUL", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Models") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnLineTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("Vin") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_HSCHEDUL"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_MATERIAL_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_MATERIAL_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_MATERIAL_STOCK", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_MATERIAL_STOCK"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_OEE_TIME_DETAILS", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_OEE_TIME_DETAILS"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_PLANING", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("Assembly") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Id") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Models") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Omterior") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Pattern") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Plant") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Quantity1") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity2") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity3") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity4") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity5") + .HasColumnType("decimal(18,2)"); + + b.Property("Quantity6") + .HasColumnType("decimal(18,2)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("ReleaseEdition") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SalseDepartment") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartMonth") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_PLANING"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_PROCESS", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_PROCESS"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_PROCESS_EQUIPMENT", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_PROCESS_EQUIPMENT"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_SCHEDULING", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_SCHEDULING"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_STATION_FIRST_PASSYIELD", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_STATION_FIRST_PASSYIELD"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_PRO_TSCHEDUL", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("FinalOnLineTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FinalWorkshop") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Models") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OnLineTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionLineName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("Vin") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_PRO_TSCHEDUL"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_RETURN", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DemandPickupTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Feedback") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("Judge") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LotNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PickUpCrossings") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PickUpLocation") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Plant") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDelivery") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReturnNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReturnReason") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ReturnType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialSrate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_RETURN"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_SA_WEEK", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DateReceived") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsDelete") + .HasColumnType("int"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PurchasingGroup") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityDemand") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ScheduleAgreement") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SerialNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateByUser") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("UpdateTime") + .HasColumnType("datetime2"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_SA_WEEK"); + }); + + modelBuilder.Entity("TaskManager.Controllers.SUPPLIER_SINV_DATA", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("DataUpdateTime") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("InventoryStatus") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialDescription") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaterialType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ProductionCycle") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("QuantityCurrent") + .HasColumnType("int"); + + b.Property("QuantityPlan") + .HasColumnType("int"); + + b.Property("ReadState") + .HasColumnType("bit"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SafetyStock") + .HasColumnType("int"); + + b.Property("SupplierBatch") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierCode") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplierName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupplieryxqDate") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("WriteState") + .HasColumnType("bit"); + + b.HasKey("UId"); + + b.ToTable("SUPPLIER_SINV_DATA"); + }); + + modelBuilder.Entity("TaskManager.Controllers.TaskConifgure", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("Api") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Corn") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsAuto") + .HasColumnType("bit"); + + b.Property("Module") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TableName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TaskName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("UId"); + + b.ToTable("TaskConifgure"); + }); + + modelBuilder.Entity("TaskManager.Controllers.TaskLog", b => + { + b.Property("UId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("UId")); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Info") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Remark") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TaskName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("UId"); + + b.ToTable("TaskLogs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/API/CherryTaskManager/Program.cs b/API/CherryTaskManager/Program.cs new file mode 100644 index 0000000..8b77b5d --- /dev/null +++ b/API/CherryTaskManager/Program.cs @@ -0,0 +1,118 @@ + + + +using Hangfire; +using Hangfire.SqlServer; +using Microsoft.AspNetCore.Builder; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Identity.Client; +using System; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +using TaskManager.EntityFramework; + + +var builder = WebApplication.CreateBuilder(args); + + + + +// лȡַ +var defaultConnection = builder.Configuration.GetConnectionString("Default"); + +builder.Services.AddHttpClient(); +//builder.Services.AddScoped(); +//builder.Services.AddScoped(); + +//builder.Services.AddScoped(); + +//builder.Services.AddControllers() +// .AddJsonOptions(options => +// { +// options.JsonSerializerOptions.Converters.Add(new CustomDateTimeConverter("yyyy-MM-dd HH:mm:ss")); +// options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); +// }); +// ӷ +builder.Services.AddControllers(); + +// JSON лѡжȡԣ +var jsonNamingPolicy = builder.Configuration.GetValue("JsonOptions:PropertyNamingPolicy"); +if (jsonNamingPolicy == "CamelCase") +{ + builder.Services.AddControllers().AddJsonOptions(options => + { + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); +} +// ѡ֧ԣ PascalCase +else if (jsonNamingPolicy == "PascalCase") +{ + // ... +} +//builder.Services.AddTransient(); +// DbContext ʹ SQL Server ַ +builder.Services.AddDbContext(options => + options.UseSqlServer(defaultConnection)); + +// Hangfire ʹ SQL Server 洢 +builder.Services.AddHangfire( + + + configuration => configuration + .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) // ʽü԰汾 + .UseSimpleAssemblyNameTypeSerializer() // лѡ + .UseRecommendedSerializerSettings() // ʹƼлãѡ + .UseSqlServerStorage(defaultConnection, new SqlServerStorageOptions + { + // ɴжȡ Hangfire 洢ѡСԲԵȣ + CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), + SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), + QueuePollInterval = TimeSpan.Zero, + UseRecommendedIsolationLevel = true, + DisableGlobalLocks = true + }) + //.UseFilter(builder.Services.BuildServiceProvider().GetRequiredService>()) + ); // ־ѡ + + +// Hangfire ɴжȡ߳ȣ +var workerCount = builder.Configuration.GetValue("Hangfire:ServerOptions:WorkerCount", 10); // Ĭֵ 10 +builder.Services.AddHangfireServer(options => +{ + options.WorkerCount = workerCount; + // ѡöȼ + options.Queues = builder.Configuration.GetSection("Hangfire:ServerOptions:Queues").Get() ?? new[] { "default" }; + +}); + + + + +// Swagger ... +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + + +app.UseHangfireDashboard(); + +// м... +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + + + +app.UseAuthorization(); +app.MapControllers(); +app.Run(); + + +// ʾͷ diff --git a/API/CherryTaskManager/Properties/launchSettings.json b/API/CherryTaskManager/Properties/launchSettings.json new file mode 100644 index 0000000..9f7b7ba --- /dev/null +++ b/API/CherryTaskManager/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:23709", + "sslPort": 0 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5014", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/API/CherryTaskManager/WeatherForecast.cs b/API/CherryTaskManager/WeatherForecast.cs new file mode 100644 index 0000000..bc782b1 --- /dev/null +++ b/API/CherryTaskManager/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace CherryTaskManager +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} diff --git a/API/CherryTaskManager/appsettings.Development.json b/API/CherryTaskManager/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/API/CherryTaskManager/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/API/CherryTaskManager/appsettings.json b/API/CherryTaskManager/appsettings.json new file mode 100644 index 0000000..a5aa839 --- /dev/null +++ b/API/CherryTaskManager/appsettings.json @@ -0,0 +1,55 @@ +{ + "App": { + "CorsOrigins": "https://*.abc.com,http://localhost:9528,http://149.223.116.5:8088" + }, + + "ConnectionStrings": { + "Default": "Server=192.168.1.228;Database=TaskManager;User ID=sa;Password=ChangkeTec@2021;TrustServerCertificate=True" + + }, + + //{ + // "ConnectionStrings": { + // "DefaultConnection": "Server=localhost;Database=HANGFIRE_DEV;User ID=sa;Password=123456;TrustServerCertificate=True" + // }, + // "Hangfire": { + // "ServerOptions": { + // "WorkerCount": 5 // 开发环境使用更少线程 + // } + // } + //} + + + + + + "Hangfire": { + "Dashboard": { + "Path": "/hangfire", // Dashboard 访问路径 + "RequireAuthorization": false // 是否需要授权 + }, + "Server": { + "WorkerCount": 5, // 工作线程数量 + "Queues": [ "default", "critical", "background" ], // 队列优先级 + "SchedulePollingInterval": 15000, // 调度轮询间隔(毫秒) + "HeartbeatInterval": "00:00:15", // 服务器心跳间隔 + "ServerTimeout": "00:05:00", // 服务器超时时间 + "ServerCheckInterval": "00:01:00" // 服务器状态检查间隔 + }, + "Storage": { + "JobExpirationCheckInterval": "00:01:00", // 作业过期检查间隔 + "CountersAggregateInterval": "00:05:00", // 计数器聚合间隔 + "QueuePollInterval": "00:00:15", // 队列轮询间隔 + "PrepareSchemaIfNecessary": true, // 自动创建表结构 + "SlidingInvisibilityTimeout": "00:30:00", // 作业处理超时时间 + "UseRecommendedIsolationLevel": true, // 使用推荐的事务隔离级别 + "EnableHeavyMigrations": false // 是否启用重量级迁移 + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Hangfire": "Information" + } + } + } +} diff --git a/API/TaskManager.Contracts/Dtos/Dtos.cs b/API/TaskManager.Contracts/Dtos/Dtos.cs new file mode 100644 index 0000000..142c353 --- /dev/null +++ b/API/TaskManager.Contracts/Dtos/Dtos.cs @@ -0,0 +1,1020 @@ +using Newtonsoft.Json; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + + +namespace TaskManager.Contracts.Dtos +{ + + + public class PAGE_OUT_DTO + { + /// 数据总数 + [JsonPropertyName("total")] + public int Total { get; set; } + + /// 当前页码(从1开始) + [JsonPropertyName("pageNum")] + public int PageNum { get; set; } + + /// 每页数量(最大值1000) + [JsonPropertyName("pageSize")] + public int PageSize { get; set; } + } + + public class PagedResponse + { + [JsonPropertyName("code")] + public int Code { get; set; } + + [JsonPropertyName("data")] + public DataResponse Data { get; set; } + + [JsonPropertyName("message")] + public string Message { get; set; } + } + + public class DataResponse + { + [JsonPropertyName("total")] + public string Total { get; set; } + + [JsonPropertyName("pageNum")] + public string PageNum { get; set; } + + [JsonPropertyName("pageSize")] + public string PageSize { get; set; } + + [JsonPropertyName("rows")] + public List Rows { get; set; } + } + + public class PAGE_DTO + { + [JsonPropertyName("date")] + public string Date { get; set; } = DateTime.Now.ToString("yyyy-MM-dd"); + + [JsonPropertyName("pageSize")] + public int PageSize { get; set; } = 1000; + + [JsonPropertyName("pageNum")] + public int PageNum { get; set; } = 1; + + [JsonPropertyName("isForce")] + public bool IsForce { get; set; } = false; + } + + #region 整车月度生产计划Dto + public class SUPPLIER_PRO_PLANING_DTO : PAGE_OUT_DTO + { + /// 数据行列表 + [JsonPropertyName("rows")] + public List Rows { get; set; } + } + + + + + public class CherryReadBaseEntityDto + { + + public string Id { get; set; } + + } + + public class SUPPLIER_PRO_PLANING_DETIAL_DTO: CherryReadBaseEntityDto + { + //public string models { get; set; } + //public decimal? quantity1 { get; set; } + //public decimal? quantity2 { get; set; } + //public string startMonth { get; set; } + //public int isDelete { get; set; } + //public string updateByUser { get; set; } + //public string pattern { get; set; } + //public string omterior { get; set; } + //public string salseDepartment { get; set; } + //public string materialCode { get; set; } + + //public DateTime? updateTime { get; set; } + //public string type { get; set; } + //public decimal? quantity3 { get; set; } + //public string releaseEdition { get; set; } + //public decimal? quantity4 { get; set; } + //public int? version { get; set; } + //public decimal? quantity5 { get; set; } + //public decimal? quantity6 { get; set; } + //public DateTime? createTime { get; set; } + //public string plant { get; set; } + //public string assembly { get; set; } + //public string id { get; set; } + //public string createByUser { get; set; } + + [JsonProperty("models")] + public string Models { get; set; } + + [JsonProperty("quantity1")] + public decimal? Quantity1 { get; set; } + + [JsonProperty("quantity2")] + public decimal? Quantity2 { get; set; } + + [JsonProperty("startMonth")] + public string StartMonth { get; set; } + + [JsonProperty("isDelete")] + public int IsDelete { get; set; } + + [JsonProperty("updateByUser")] + public string UpdateByUser { get; set; } + + [JsonProperty("pattern")] + public string Pattern { get; set; } + + [JsonProperty("omterior")] // 可能是拼写错误,保留原始名称 + public string Omterior { get; set; } + + [JsonProperty("salseDepartment")] // 可能是拼写错误,保留原始名称 + public string SalseDepartment { get; set; } + + [JsonProperty("materialCode")] + public string MaterialCode { get; set; } + + [JsonProperty("updateTime")] + public DateTime? UpdateTime { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("quantity3")] + public decimal? Quantity3 { get; set; } + + [JsonProperty("releaseEdition")] + public string ReleaseEdition { get; set; } + + [JsonProperty("quantity4")] + public decimal? Quantity4 { get; set; } + + [JsonProperty("version")] + public int Version { get; set; } + + [JsonProperty("quantity5")] + public decimal? Quantity5 { get; set; } + + [JsonProperty("quantity6")] + public decimal? Quantity6 { get; set; } + + [JsonProperty("createTime")] + public DateTime? CreateTime { get; set; } + + [JsonProperty("plant")] + public string Plant { get; set; } + + [JsonProperty("assembly")] + public string Assembly { get; set; } + + + + [JsonProperty("createByUser")] + public string CreateByUser { get; set; } + + + } + + // 自定义日期转换器(建议单独文件存放) + public class CustomDateTimeConverter : System.Text.Json.Serialization.JsonConverter + { + private const string Format = "yyyy-MM-dd HH:mm:ss"; + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => DateTime.ParseExact(reader.GetString(), Format, CultureInfo.InvariantCulture); + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString(Format, CultureInfo.InvariantCulture)); + } + #endregion + + + + + + #region M+6月物料需求计划. + + + public class SUPPLIER_MRP_MONTH_DETAIL_DTO: CherryReadBaseEntityDto + { + + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PlantId { get; set; } + public string PlantName { get; set; } + public string StartMonth { get; set; } + public int QuantityDemand1 { get; set; } + public int QuantityDemand2 { get; set; } + public int QuantityDemand3 { get; set; } + public int QuantityDemand4 { get; set; } + public int QuantityDemand5 { get; set; } + public int QuantityDemand6 { get; set; } + public int QuantityDemand7 { get; set; } + public int QuantityDemand8 { get; set; } + public int QuantityDemand9 { get; set; } + public int QuantityDemand10 { get; set; } + public int QuantityDemand11 { get; set; } + public int QuantityDemand12 { get; set; } + public string IsUpdate { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public string IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_MRP_MONTH_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + #endregion + #region M+6月物料需求计划风险确认 + + + public class DemandData1 + { + public int Id { get; set; } + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PlantId { get; set; } + public string PlantName { get; set; } + public string StartDate { get; set; } + + // Quantity demands from 1 to 31 + public int QuantityDemand1 { get; set; } + public int QuantityDemand2 { get; set; } + public int QuantityDemand3 { get; set; } + public int QuantityDemand4 { get; set; } + public int QuantityDemand5 { get; set; } + public int QuantityDemand6 { get; set; } + public int QuantityDemand7 { get; set; } + public int QuantityDemand8 { get; set; } + public int QuantityDemand9 { get; set; } + public int QuantityDemand10 { get; set; } + public int QuantityDemand11 { get; set; } + public int QuantityDemand12 { get; set; } + public int QuantityDemand13 { get; set; } + public int QuantityDemand14 { get; set; } + public int QuantityDemand15 { get; set; } + public int QuantityDemand16 { get; set; } + public int QuantityDemand17 { get; set; } + public int QuantityDemand18 { get; set; } + public int QuantityDemand19 { get; set; } + public int QuantityDemand20 { get; set; } + public int QuantityDemand21 { get; set; } + public int QuantityDemand22 { get; set; } + public int QuantityDemand23 { get; set; } + public int QuantityDemand24 { get; set; } + public int QuantityDemand25 { get; set; } + public int QuantityDemand26 { get; set; } + public int QuantityDemand27 { get; set; } + public int QuantityDemand28 { get; set; } + public int QuantityDemand29 { get; set; } + public int QuantityDemand30 { get; set; } + public int QuantityDemand31 { get; set; } + + public string Is_update { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class ResponseModel1 + { + public int Total { get; set; } + public int PageNum { get; set; } + public int PageSize { get; set; } + public List Rows { get; set; } + } + + + + #endregion + #region 计划协议 + + + public class SUPPLIER_SA_WEEK_DETAIL_DTO : CherryReadBaseEntityDto + { + + public string ScheduleAgreement { get; set; } + public string SerialNumber { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PurchasingGroup { get; set; } + public string PlantId { get; set; } + public int QuantityDemand { get; set; } + public string DateReceived { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_SA_WEEK_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + + #endregion + + #region 采购订单 + + public class SUPPLIER_PO_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + public class SUPPLIER_PO_DETAIL_DTO:CherryReadBaseEntityDto + { + + public string PurchaseOrder { get; set; } + public string SerialNumber { get; set; } + public string PlantId { get; set; } + public string PlantName { get; set; } + public string VoucherDate { get; set; } + public string Purchaser { get; set; } + public string Supplier { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public decimal? QuantityDemand { get; set; } + public string MaterialUnit { get; set; } + public string DeliveryDate { get; set; } + public string DeliveryPlace { get; set; } + public decimal? QuantityDelivery { get; set; } + public string Note { get; set; } + public string ItemType { get; set; } + public string TradeTerms { get; set; } + public string Country { get; set; } + public string Batch { get; set; } + public string CreateByUser { get; set; } + public string CreateTime { get; set; } + public string UpdateByUser { get; set; } + public string UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + + #endregion + #region 采购订单风险确认 + #region 输入 + public class RootObject2323 + { + public string batchNo { get; set; } + public int total { get; set; } + public int pageSize { get; set; } + public int pageNum { get; set; } + public List list { get; set; } + } + + public class Item + { + + public string SupplierCode { get; set; } + public string PurchaseOrder { get; set; } + public string SerialNumber { get; set; } + public int QuantityMeet { get; set; } + public string FeedbackResults { get; set; } + public string VentureType { get; set; } + public string VentureSpecific { get; set; } + public string Measures { get; set; } + + + + + + } + #endregion + + #region 输出 + public class Response + { + public string code { get; set; } + public string message { get; set; } + public Data data { get; set; } + } + + public class Data + { + public string batchNo { get; set; } + public string apiName { get; set; } + public int totalGet { get; set; } + public int totalError { get; set; } + public int totalSave { get; set; } + } + #endregion + + + + + #endregion + + + #region 过焊装未过总装(输出) + + + public class SUPPLIER_PRO_HSCHEDUL_DETAIL_DTO : CherryReadBaseEntityDto + { + + public string Models { get; set; } + public string Vin { get; set; } + public string ProductionLineId { get; set; } + public string ProductionLineName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string ProductionType { get; set; } + public string OnLineTime { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_PRO_HSCHEDUL_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + + + + #endregion + #region 过涂装未过总装(输出) + + + + public class SUPPLIER_PRO_TSCHEDUL_DETAIL_DTO : CherryReadBaseEntityDto + { + + public string Models { get; set; } + public string Vin { get; set; } + public string ProductionLineId { get; set; } + public string ProductionLineName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string OnLineTime { get; set; } + public string FinalWorkshop { get; set; } + public string FinalOnLineTime { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_PRO_TSCHEDUL_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + + #endregion + #region 排序供货. + + + public class SUPPLIER_PRO_CSCHEDUL_DETAIL_DTO : CherryReadBaseEntityDto + { + + public string Models { get; set; } + public string Vin { get; set; } + public string ProductionLineId { get; set; } + public string ProductionLineName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string SortDate { get; set; } + public string SortTime { get; set; } + public string OnLineDate { get; set; } + public string OnLineTime { get; set; } + public string ModelCategory { get; set; } + public string AssemblyMaterialCode { get; set; } + public string MotorMaterialCode { get; set; } + public string Plant { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_PRO_CSCHEDUL_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + #endregion + #region 看板配送单(输出). + + public class SUPPLIER_DEL_STATE_DETAIL_DTO : CherryReadBaseEntityDto + { + + public string DeliveryNumber { get; set; } + public string SerialNumber { get; set; } + public string SerialSrate { get; set; } // Matches input, may check for typo (e.g. SerialState?) + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PlantId { get; set; } + public string ReceivingCrossings { get; set; } + public decimal? QuantityDelivery { get; set; } + public string DataCreateTime { get; set; } + public string SupplierReceiveTime { get; set; } + public string RoadShippedTime { get; set; } + public string RoadReceiveTime { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_DEL_STATE_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + + #endregion + #region 退货单(输出). + + + public class SUPPLIER_RETURN_DETAIL_DTO : CherryReadBaseEntityDto + { + + public string ReturnNumber { get; set; } + public string SerialNumber { get; set; } + public string SerialSrate { get; set; } // Matches input, possibly a typo (e.g. SerialState?) + public string PickUpLocation { get; set; } + public string DemandPickupTime { get; set; } + public string PickUpCrossings { get; set; } + public string Feedback { get; set; } + public string Plant { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public decimal? QuantityDelivery { get; set; } + public string ReturnType { get; set; } + public string LotNumber { get; set; } + public string Judge { get; set; } + public string ReturnReason { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_RETURN_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + + + + #endregion + #region 奇瑞RDC共享库存(输出) + + + public class SUPPLIER_INV_DATA_DETAIL_DTO : CherryReadBaseEntityDto + { + + public string PlantId { get; set; } + public string PlantName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public decimal? QuantityCurrent { get; set; } + public string StockState { get; set; } + public string DataUpdateTime { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_INV_DATA_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + + + + #endregion + #region 日MRP状态监控(输出) + + + + public class SUPPLIER_MRP_STATE_DETIAL_DTO : CherryReadBaseEntityDto + { + + public string PlantId { get; set; } + public string PlantName { get; set; } + public string DemandSrate { get; set; } // Matches input, possibly a typo (e.g. DemandState?) + public string DemandType { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string SummarySign { get; set; } + public string DateRequired { get; set; } + public int QuantityDemand { get; set; } + public string ConfirmTime { get; set; } + public decimal? CreatQuantity { get; set; } + public decimal? QuantityDelivery { get; set; } + public decimal? QuantityReceive { get; set; } + public decimal? QuantityInTransit { get; set; } + public decimal? OnTimePercentage { get; set; } + public decimal? SummaryCreatQuantity { get; set; } + public decimal? SummaryQuantityDelivery { get; set; } + public decimal? SummaryQuantityReceive { get; set; } + public decimal? SummaryQuantityInTransit { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_MRP_STATE_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + + + #endregion + #region 日MRP预警推移 + + + +public class SUPPLIER_MRP_WARNING_DETAIL_DTO : CherryReadBaseEntityDto + + { + + public string PlantId { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public decimal? QuantityCurrent { get; set; } + public string ReckonDate { get; set; } + public decimal? QuantityPlanned { get; set; } + public decimal? QuantityPlannedDelivery { get; set; } + public decimal? QuantityInTransit { get; set; } + public decimal? DateGap { get; set; } + public decimal? InventoryGap { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + public class SUPPLIER_MRP_WARNING_DTO : PAGE_OUT_DTO + { + + public List Rows { get; set; } + } + + #endregion + #region M+6月物料需求计划风险确认(输入) + + #region 输入 + public class SUPPLIER_CON_MMRP_DETAIL_DTO + { + public string SupplierCode { get; set; } + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string PlantId { get; set; } + public string FeedbackResults { get; set; } + public string VentureType { get; set; } + public string VentureSpecific { get; set; } + public string Measures { get; set; } + public string StartMonth { get; set; } + public int QuantityMeet1 { get; set; } + public int QuantityMeet2 { get; set; } + public int QuantityMeet3 { get; set; } + public int QuantityMeet4 { get; set; } + public int QuantityMeet5 { get; set; } + public int QuantityMeet6 { get; set; } + public int QuantityMeet7 { get; set; } + public int QuantityMeet8 { get; set; } + public int QuantityMeet9 { get; set; } + public int QuantityMeet10 { get; set; } + public int QuantityMeet11 { get; set; } + public int QuantityMeet12 { get; set; } + } + + public class SUPPLIER_CON_MMRP_DTO + { + public string BatchNo { get; set; } + public int Total { get; set; } + public int PageSize { get; set; } + public int PageNum { get; set; } + public List List { get; set; } + } + #endregion + #region 输出 + public class SUPPLIER_CON_MMRP_DETAIL_OUT_DETAIL_DTO + { + public string BatchNo { get; set; } + public string ApiName { get; set; } + public int TotalGet { get; set; } + public int TotalError { get; set; } + public int TotalSave { get; set; } + } + + public class SUPPLIER_CON_MMRP_OUT_DTO + { + public string Code { get; set; } + public string Message { get; set; } + public SUPPLIER_CON_MMRP_DETAIL_OUT_DETAIL_DTO Data { get; set; } + } + + + + #endregion + + + #endregion + + #region 日物料需求计划 + + public class SUPPLIER_MRP_DATE_DTO : PAGE_OUT_DTO + { + public List Rows { get; set; } + } + + public class SUPPLIER_MRP_DATE_DETAIL_DTO : CherryReadBaseEntityDto + { + + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PlantId { get; set; } + public string PlantName { get; set; } + public string StartDate { get; set; } + + public decimal? QuantityDemand1 { get; set; } + public decimal? QuantityDemand2 { get; set; } + public decimal? QuantityDemand3 { get; set; } + public decimal? QuantityDemand4 { get; set; } + public decimal? QuantityDemand5 { get; set; } + public decimal? QuantityDemand6 { get; set; } + public decimal? QuantityDemand7 { get; set; } + public decimal? QuantityDemand8 { get; set; } + public decimal? QuantityDemand9 { get; set; } + public decimal? QuantityDemand10 { get; set; } + public decimal? QuantityDemand11 { get; set; } + public decimal? QuantityDemand12 { get; set; } + public decimal? QuantityDemand13 { get; set; } + public decimal? QuantityDemand14 { get; set; } + public decimal? QuantityDemand15 { get; set; } + public decimal? QuantityDemand16 { get; set; } + public decimal? QuantityDemand17 { get; set; } + public decimal? QuantityDemand18 { get; set; } + public decimal? QuantityDemand19 { get; set; } + public decimal? QuantityDemand20 { get; set; } + public decimal? QuantityDemand21 { get; set; } + public decimal? QuantityDemand22 { get; set; } + public decimal? QuantityDemand23 { get; set; } + public decimal? QuantityDemand24 { get; set; } + public decimal? QuantityDemand25 { get; set; } + public decimal? QuantityDemand26 { get; set; } + public decimal? QuantityDemand27 { get; set; } + public decimal? QuantityDemand28 { get; set; } + public decimal? QuantityDemand29 { get; set; } + public decimal? QuantityDemand30 { get; set; } + public decimal? QuantityDemand31 { get; set; } + + public string IsUpdate { get; set; } + public string CreateByUser { get; set; } + public string CreateTime { get; set; } + public string UpdateByUser { get; set; } + public string UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + + + #endregion + + + #region 日物料需求计划风险确认 + + #region 输入 + + + public class SUPPLIER_CON_DATE_DETAIL_DTO + { + public string SupplierCode { get; set; } + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string PlantId { get; set; } + public string FeedbackResults { get; set; } + public string VentureType { get; set; } + public string VentureSpecific { get; set; } + public string Measures { get; set; } + public string StartDate { get; set; } + + // QuantityMeet from 1 to 31 + public int QuantityMeet1 { get; set; } + public int QuantityMeet2 { get; set; } + public int QuantityMeet3 { get; set; } + public int QuantityMeet4 { get; set; } + public int QuantityMeet5 { get; set; } + public int QuantityMeet6 { get; set; } + public int QuantityMeet7 { get; set; } + public int QuantityMeet8 { get; set; } + public int QuantityMeet9 { get; set; } + public int QuantityMeet10 { get; set; } + public int QuantityMeet11 { get; set; } + public int QuantityMeet12 { get; set; } + public int QuantityMeet13 { get; set; } + public int QuantityMeet14 { get; set; } + public int QuantityMeet15 { get; set; } + public int QuantityMeet16 { get; set; } + public int QuantityMeet17 { get; set; } + public int QuantityMeet18 { get; set; } + public int QuantityMeet19 { get; set; } + public int QuantityMeet20 { get; set; } + public int QuantityMeet21 { get; set; } + public int QuantityMeet22 { get; set; } + public int QuantityMeet23 { get; set; } + public int QuantityMeet24 { get; set; } + public int QuantityMeet25 { get; set; } + public int QuantityMeet26 { get; set; } + public int QuantityMeet27 { get; set; } + public int QuantityMeet28 { get; set; } + public int QuantityMeet29 { get; set; } + public int QuantityMeet30 { get; set; } + public int QuantityMeet31 { get; set; } + } + + public class SUPPLIER_CON_DATE_DTO + { + public string BatchNo { get; set; } + public int Total { get; set; } + public int PageSize { get; set; } + public int PageNum { get; set; } + public List List { get; set; } + } + #endregion + #region 输出 + public class SUPPLIER_CON_DATE_DETAIL_OUT_DTO + { + public string BatchNo { get; set; } + public string ApiName { get; set; } + public int TotalGet { get; set; } + public int TotalError { get; set; } + public int TotalSave { get; set; } + } + + public class SUPPLIER_CON_DATE_OUT_DTO + { + public string Code { get; set; } + public string Message { get; set; } + public SUPPLIER_CON_DATE_DETAIL_OUT_DTO Data { get; set; } + } + + + + #endregion + + + + #endregion + #region 采购订单风险确认 + + public class SUPPLIER_CON_PO_DETAIL_DTO + { + public string SupplierCode { get; set; } + public string PurchaseOrder { get; set; } + public string SerialNumber { get; set; } + public int QuantityMeet { get; set; } + public string FeedbackResults { get; set; } + public string VentureType { get; set; } + public string VentureSpecific { get; set; } + public string Measures { get; set; } + } + + public class SUPPLIER_CON_PO_DTO + { + public string BatchNo { get; set; } + public int Total { get; set; } + public int PageSize { get; set; } + public int PageNum { get; set; } + public List List { get; set; } + } + #region 输出 + + public class SUPPLIER_CON_PO_DETAIL_OUT_DTO + { + public string BatchNo { get; set; } + public string ApiName { get; set; } + public int TotalGet { get; set; } + public int TotalError { get; set; } + public int TotalSave { get; set; } + } + + public class SUPPLIER_CON_PO_OUT_DTO + { + public string Code { get; set; } + public string Message { get; set; } + public SUPPLIER_CON_PO_DETAIL_OUT_DTO Data { get; set; } + } + + #endregion + + + + + #endregion + #region 供应商共享库存 + + #region 输入 + + + public class SUPPLIER_SINV_DATA_DETAIL_DTO:CherryReadBaseEntityDto + { + public string SupplierCode { get; set; } + public string SupplierName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string MaterialType { get; set; } + public int QuantityCurrent { get; set; } + public int QuantityPlan { get; set; } + public string InventoryStatus { get; set; } + public int SafetyStock { get; set; } + public string ProductionCycle { get; set; } + public string DataUpdateTime { get; set; } + public string SupplierBatch { get; set; } + public string SupplieryxqDate { get; set; } + } + + public class SUPPLIER_SINV_DATA_DTO + { + public string BatchNo { get; set; } + public int Total { get; set; } + public int PageSize { get; set; } + public int PageNum { get; set; } + public List List { get; set; } + } + #endregion + #region 输出 + public class SUPPLIER_SINV_DATA_DETAIL_OUT_DTO + { + public string BatchNo { get; set; } + public string ApiName { get; set; } + public int TotalGet { get; set; } + public int TotalError { get; set; } + public int TotalSave { get; set; } + } + + public class SUPPLIER_SINV_DATA_OUT_DTO + { + public string Code { get; set; } + public string Message { get; set; } + public SUPPLIER_SINV_DATA_DETAIL_OUT_DTO Data { get; set; } + } + #endregion + + + #endregion + + + + + +} + + + diff --git a/API/TaskManager.Contracts/TaskManager.Contracts.csproj b/API/TaskManager.Contracts/TaskManager.Contracts.csproj new file mode 100644 index 0000000..3b5b170 --- /dev/null +++ b/API/TaskManager.Contracts/TaskManager.Contracts.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/API/TaskManager.Entity/Entity.cs b/API/TaskManager.Entity/Entity.cs new file mode 100644 index 0000000..a699322 --- /dev/null +++ b/API/TaskManager.Entity/Entity.cs @@ -0,0 +1,767 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TaskManager.Entity +{ + + + public interface IDoExecute + { + Task ExecuteAsync(string url, string path, string takName); + } + public class TaskConifgure + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long UId { get; set; } + /// + /// 加密用API路径 + /// + public string Api { get; set; } + public string Corn { get; set; } + public string Module { get; set; } + public string Remark { get; set; } + public string TableName { get; set; } + public string TaskName { get; set; } + /// + /// 调用全路径 + /// + public string Url { get; set; } + public bool IsAuto { get; set; } + + } + + public class TaskLog + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long UId { get; set; } + public string Info { get; set; } + public string Type { get; set; } + public string TaskName { get; set; } + public DateTime CreationTime { set; get; } + public string Remark { get; set; } + + } + public class BaseEntity + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long UId { get; set; } + public bool WriteState { get; set; } + public bool ReadState { get; set; } + + public DateTime CreationTime { get; set; } + + public string Remark { get; set; } + } + + public class CherryReadBaseEntity:BaseEntity + { + public string RequestDate { get; set; } + public string Id { get; set; } + + public string TaskId { get; set; } + + + } + + + + + + /// + /// 来料检验数据 + /// + public class SUPPLIER_PRO_MATERIAL_STOCK:BaseEntity + { + } + + /// + /// 排产数据 + /// + public class SUPPLIER_PRO_SCHEDULING : BaseEntity + { + } + + /// + /// 供应商基础信息 + /// + public class SUPPLIER_INFO : BaseEntity + { + } + + /// + /// 人员资质信息 + /// + public class SUPPLIER_EMPLOYEE : BaseEntity + { + } + + /// + /// BOM主数据 + /// + public class SUPPLIER_BOM : BaseEntity + { + } + + /// + /// 过程控制项质量数据 + /// + public class SUPPLIER_PRO_CPS : BaseEntity + { + } + + /// + /// 生产过程数据 + /// + public class SUPPLIER_PRO_DATA : BaseEntity + { + } + + /// + /// 产品一次合格率 + /// + public class SUPPLIER_PRO_FIRST_PASSYIELD : BaseEntity + { + } + + /// + /// 工位一次合格率 + /// + public class SUPPLIER_PRO_STATION_FIRST_PASSYIELD : BaseEntity + { + } + + /// + /// 缺陷业务数据 + /// + public class SUPPLIER_PRO_FLAW : BaseEntity + { + } + + /// + /// 环境业务数据 + /// + public class SUPPLIER_PRO_ENVIRONMENT : BaseEntity + { + } + + /// + /// 设备OEE达成率 + /// + public class SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE : BaseEntity + { + } + + /// + /// OEE时间明细 + /// + public class SUPPLIER_PRO_OEE_TIME_DETAILS : BaseEntity + { + } + + /// + /// 物料主数据 + /// + public class SUPPLIER_PRO_MATERIAL_DATA : BaseEntity + { + } + + /// + /// 附件类数据 + /// + public class SUPPLIER_PRO_ATTACHMENT_DATA : BaseEntity + { + } + + /// + /// 工艺装备 + /// + public class SUPPLIER_PRO_PROCESS_EQUIPMENT : BaseEntity + { + } + + /// + /// 工艺 + /// + public class SUPPLIER_PRO_PROCESS : BaseEntity + { + } + + /// + /// 整车月度生产计划-2 + /// + public class SUPPLIER_PRO_PLANING : CherryReadBaseEntity + { + + [JsonProperty("models")] + public string Models { get; set; } + + [JsonProperty("quantity1")] + public decimal? Quantity1 { get; set; } + + [JsonProperty("quantity2")] + public decimal? Quantity2 { get; set; } + + [JsonProperty("startMonth")] + public string StartMonth { get; set; } + + [JsonProperty("isDelete")] + public int IsDelete { get; set; } + + [JsonProperty("updateByUser")] + public string UpdateByUser { get; set; } + + [JsonProperty("pattern")] + public string Pattern { get; set; } + + [JsonProperty("omterior")] // 可能是拼写错误,保留原始名称 + public string Omterior { get; set; } + + [JsonProperty("salseDepartment")] // 可能是拼写错误,保留原始名称 + public string SalseDepartment { get; set; } + + [JsonProperty("materialCode")] + public string MaterialCode { get; set; } + + [JsonProperty("updateTime")] + public DateTime? UpdateTime { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("quantity3")] + public decimal? Quantity3 { get; set; } + + [JsonProperty("releaseEdition")] + public string ReleaseEdition { get; set; } + + [JsonProperty("quantity4")] + public decimal? Quantity4 { get; set; } + + [JsonProperty("version")] + public int Version { get; set; } + + [JsonProperty("quantity5")] + public decimal? Quantity5 { get; set; } + + [JsonProperty("quantity6")] + public decimal? Quantity6 { get; set; } + + [JsonProperty("createTime")] + public DateTime? CreateTime { get; set; } + + [JsonProperty("plant")] + public string Plant { get; set; } + + [JsonProperty("assembly")] + public string Assembly { get; set; } + + + + [JsonProperty("createByUser")] + public string CreateByUser { get; set; } + } + + /// + /// M+6月物料需求计划 + /// + public class SUPPLIER_MRP_MONTH : CherryReadBaseEntity + { + + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PlantId { get; set; } + public string PlantName { get; set; } + public string StartMonth { get; set; } + public decimal QuantityDemand1 { get; set; } + public decimal QuantityDemand2 { get; set; } + public decimal QuantityDemand3 { get; set; } + public decimal QuantityDemand4 { get; set; } + public decimal QuantityDemand5 { get; set; } + public decimal QuantityDemand6 { get; set; } + public decimal QuantityDemand7 { get; set; } + public decimal QuantityDemand8 { get; set; } + public decimal QuantityDemand9 { get; set; } + public decimal QuantityDemand10 { get; set; } + public decimal QuantityDemand11 { get; set; } + public decimal QuantityDemand12 { get; set; } + public string IsUpdate { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public string IsDelete { get; set; } + public int Version { get; set; } + + + + + + + + } + + /// + /// M+6月物料需求计划风险确认 + /// + public class SUPPLIER_CON_MMRP : BaseEntity + { + public string SupplierCode { get; set; } + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string PlantId { get; set; } + public string FeedbackResults { get; set; } + public string VentureType { get; set; } + public string VentureSpecific { get; set; } + public string Measures { get; set; } + public string StartMonth { get; set; } + public int QuantityMeet1 { get; set; } + public int QuantityMeet2 { get; set; } + public int QuantityMeet3 { get; set; } + public int QuantityMeet4 { get; set; } + public int QuantityMeet5 { get; set; } + public int QuantityMeet6 { get; set; } + public int QuantityMeet7 { get; set; } + public int QuantityMeet8 { get; set; } + public int QuantityMeet9 { get; set; } + public int QuantityMeet10 { get; set; } + public int QuantityMeet11 { get; set; } + public int QuantityMeet12 { get; set; } + } + + /// + /// 日物料需求计划 + /// + public class SUPPLIER_MRP_DATE : CherryReadBaseEntity + { + + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PlantId { get; set; } + public string PlantName { get; set; } + public string StartDate { get; set; } + + public int QuantityDemand1 { get; set; } + public int QuantityDemand2 { get; set; } + public int QuantityDemand3 { get; set; } + public int QuantityDemand4 { get; set; } + public int QuantityDemand5 { get; set; } + public int QuantityDemand6 { get; set; } + public int QuantityDemand7 { get; set; } + public int QuantityDemand8 { get; set; } + public int QuantityDemand9 { get; set; } + public int QuantityDemand10 { get; set; } + public int QuantityDemand11 { get; set; } + public int QuantityDemand12 { get; set; } + public int QuantityDemand13 { get; set; } + public int QuantityDemand14 { get; set; } + public int QuantityDemand15 { get; set; } + public int QuantityDemand16 { get; set; } + public int QuantityDemand17 { get; set; } + public int QuantityDemand18 { get; set; } + public int QuantityDemand19 { get; set; } + public int QuantityDemand20 { get; set; } + public int QuantityDemand21 { get; set; } + public int QuantityDemand22 { get; set; } + public int QuantityDemand23 { get; set; } + public int QuantityDemand24 { get; set; } + public int QuantityDemand25 { get; set; } + public int QuantityDemand26 { get; set; } + public int QuantityDemand27 { get; set; } + public int QuantityDemand28 { get; set; } + public int QuantityDemand29 { get; set; } + public int QuantityDemand30 { get; set; } + public int QuantityDemand31 { get; set; } + + public string IsUpdate { get; set; } + public string CreateByUser { get; set; } + public string CreateTime { get; set; } + public string UpdateByUser { get; set; } + public string UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + + } + + /// + /// 日物料需求计划风险确认 + /// + public class SUPPLIER_CON_DATE : BaseEntity + { + public string SupplierCode { get; set; } + public string ReleaseEdition { get; set; } + public string MaterialCode { get; set; } + public string PlantId { get; set; } + public string FeedbackResults { get; set; } + public string VentureType { get; set; } + public string VentureSpecific { get; set; } + public string Measures { get; set; } + public string StartDate { get; set; } + + // QuantityMeet from 1 to 31 + public int QuantityMeet1 { get; set; } + public int QuantityMeet2 { get; set; } + public int QuantityMeet3 { get; set; } + public int QuantityMeet4 { get; set; } + public int QuantityMeet5 { get; set; } + public int QuantityMeet6 { get; set; } + public int QuantityMeet7 { get; set; } + public int QuantityMeet8 { get; set; } + public int QuantityMeet9 { get; set; } + public int QuantityMeet10 { get; set; } + public int QuantityMeet11 { get; set; } + public int QuantityMeet12 { get; set; } + public int QuantityMeet13 { get; set; } + public int QuantityMeet14 { get; set; } + public int QuantityMeet15 { get; set; } + public int QuantityMeet16 { get; set; } + public int QuantityMeet17 { get; set; } + public int QuantityMeet18 { get; set; } + public int QuantityMeet19 { get; set; } + public int QuantityMeet20 { get; set; } + public int QuantityMeet21 { get; set; } + public int QuantityMeet22 { get; set; } + public int QuantityMeet23 { get; set; } + public int QuantityMeet24 { get; set; } + public int QuantityMeet25 { get; set; } + public int QuantityMeet26 { get; set; } + public int QuantityMeet27 { get; set; } + public int QuantityMeet28 { get; set; } + public int QuantityMeet29 { get; set; } + public int QuantityMeet30 { get; set; } + public int QuantityMeet31 { get; set; } + } + + /// + /// 计划协议 + /// + public class SUPPLIER_SA_WEEK : CherryReadBaseEntity + { + + public string ScheduleAgreement { get; set; } + public string SerialNumber { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PurchasingGroup { get; set; } + public string PlantId { get; set; } + public int QuantityDemand { get; set; } + public string DateReceived { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + /// + /// 采购订单 + /// + public class SUPPLIER_PO : CherryReadBaseEntity + { + + public string PurchaseOrder { get; set; } + public string SerialNumber { get; set; } + public string PlantId { get; set; } + public string PlantName { get; set; } + public string VoucherDate { get; set; } + public string Purchaser { get; set; } + public string Supplier { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public int QuantityDemand { get; set; } + public string MaterialUnit { get; set; } + public string DeliveryDate { get; set; } + public string DeliveryPlace { get; set; } + public int QuantityDelivery { get; set; } + public string Note { get; set; } + public string ItemType { get; set; } + public string TradeTerms { get; set; } + public string Country { get; set; } + public string Batch { get; set; } + public string CreateByUser { get; set; } + public string CreateTime { get; set; } + public string UpdateByUser { get; set; } + public string UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + /// + /// 采购订单风险确认 + /// + public class SUPPLIER_CON_PO : BaseEntity + { + public string SupplierCode { get; set; } + public string PurchaseOrder { get; set; } + public string SerialNumber { get; set; } + public int QuantityMeet { get; set; } + public string FeedbackResults { get; set; } + public string VentureType { get; set; } + public string VentureSpecific { get; set; } + public string Measures { get; set; } + + + } + + /// + /// 过焊装未过总装 + /// + public class SUPPLIER_PRO_HSCHEDUL : CherryReadBaseEntity + { + + public string Models { get; set; } + public string Vin { get; set; } + public string ProductionLineId { get; set; } + public string ProductionLineName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string ProductionType { get; set; } + public string OnLineTime { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + + + + } + + /// + /// 过涂装未过总装 + /// + public class SUPPLIER_PRO_TSCHEDUL : CherryReadBaseEntity + { + + public string Models { get; set; } + public string Vin { get; set; } + public string ProductionLineId { get; set; } + public string ProductionLineName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string OnLineTime { get; set; } + public string FinalWorkshop { get; set; } + public string FinalOnLineTime { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + + + } + + /// + /// 排序供货 + /// + public class SUPPLIER_PRO_CSCHEDUL : CherryReadBaseEntity + { + + public string Models { get; set; } + public string Vin { get; set; } + public string ProductionLineId { get; set; } + public string ProductionLineName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string SortDate { get; set; } + public string SortTime { get; set; } + public string OnLineDate { get; set; } + public string OnLineTime { get; set; } + public string ModelCategory { get; set; } + public string AssemblyMaterialCode { get; set; } + public string MotorMaterialCode { get; set; } + public string Plant { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + /// + /// 看板配送单 + /// + public class SUPPLIER_DEL_STATE : CherryReadBaseEntity + { + + public string DeliveryNumber { get; set; } + public string SerialNumber { get; set; } + public string SerialSrate { get; set; } // Matches input, may check for typo (e.g. SerialState?) + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string PlantId { get; set; } + public string ReceivingCrossings { get; set; } + public int QuantityDelivery { get; set; } + public string DataCreateTime { get; set; } + public string SupplierReceiveTime { get; set; } + public string RoadShippedTime { get; set; } + public string RoadReceiveTime { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + /// + /// 退货单 + /// + public class SUPPLIER_RETURN : CherryReadBaseEntity + { + + public string ReturnNumber { get; set; } + public string SerialNumber { get; set; } + public string SerialSrate { get; set; } // Matches input, possibly a typo (e.g. SerialState?) + public string PickUpLocation { get; set; } + public string DemandPickupTime { get; set; } + public string PickUpCrossings { get; set; } + public string Feedback { get; set; } + public string Plant { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public int QuantityDelivery { get; set; } + public string ReturnType { get; set; } + public string LotNumber { get; set; } + public string Judge { get; set; } + public string ReturnReason { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + /// + /// 奇瑞RDC共享库存 + /// + public class SUPPLIER_INV_DATA : CherryReadBaseEntity + { + + public string PlantId { get; set; } + public string PlantName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public int QuantityCurrent { get; set; } + public string StockState { get; set; } + public string DataUpdateTime { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + + + } + + /// + /// 供应商共享库存 + /// + public class SUPPLIER_SINV_DATA : CherryReadBaseEntity + { + public string SupplierCode { get; set; } + public string SupplierName { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string MaterialType { get; set; } + public int QuantityCurrent { get; set; } + public int QuantityPlan { get; set; } + public string InventoryStatus { get; set; } + public int SafetyStock { get; set; } + public string ProductionCycle { get; set; } + public string DataUpdateTime { get; set; } + public string SupplierBatch { get; set; } + public string SupplieryxqDate { get; set; } + } + + /// + /// 日MRP状态监控 + /// + public class SUPPLIER_MRP_STATE : CherryReadBaseEntity + { + + public string PlantId { get; set; } + public string PlantName { get; set; } + public string DemandSrate { get; set; } // Matches input, possibly a typo (e.g. DemandState?) + public string DemandType { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public string SummarySign { get; set; } + public string DateRequired { get; set; } + public int QuantityDemand { get; set; } + public string ConfirmTime { get; set; } + public int CreatQuantity { get; set; } + public int QuantityDelivery { get; set; } + public int QuantityReceive { get; set; } + public int QuantityInTransit { get; set; } + public int OnTimePercentage { get; set; } + public int SummaryCreatQuantity { get; set; } + public int SummaryQuantityDelivery { get; set; } + public int SummaryQuantityReceive { get; set; } + public int SummaryQuantityInTransit { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + + } + + /// + /// 日MRP预警推移 + /// + public class SUPPLIER_MRP_WARNING : CherryReadBaseEntity + { + + public string PlantId { get; set; } + public string MaterialCode { get; set; } + public string MaterialDescription { get; set; } + public int QuantityCurrent { get; set; } + public string ReckonDate { get; set; } + public int QuantityPlanned { get; set; } + public int QuantityPlannedDelivery { get; set; } + public int QuantityInTransit { get; set; } + public int DateGap { get; set; } + public int InventoryGap { get; set; } + public string CreateByUser { get; set; } + public DateTime CreateTime { get; set; } + public string UpdateByUser { get; set; } + public DateTime UpdateTime { get; set; } + public int IsDelete { get; set; } + public int Version { get; set; } + } + + + + + + + + + + + + + + + + + +} diff --git a/API/TaskManager.Entity/TaskManager.Entity.csproj b/API/TaskManager.Entity/TaskManager.Entity.csproj new file mode 100644 index 0000000..3b5b170 --- /dev/null +++ b/API/TaskManager.Entity/TaskManager.Entity.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/API/TaskManager.EntityFramework/JobDbContext.cs b/API/TaskManager.EntityFramework/JobDbContext.cs new file mode 100644 index 0000000..42abc5f --- /dev/null +++ b/API/TaskManager.EntityFramework/JobDbContext.cs @@ -0,0 +1,265 @@ + +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.Extensions.Configuration; +using System; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TaskManager.Entity; +using Wood.Util; + + + +namespace TaskManager.EntityFramework +{ + public class JobDbContext:DbContext + { + + private const string ConnectionStringName = "DefaultConnection"; + + // 保存配置的字段 + private readonly IConfiguration _configuration; + + // 使用依赖注入的构造函数 + public JobDbContext(DbContextOptions options, IConfiguration configuration) + : base(options) + { + _configuration = configuration; + // 设置命令超时时间 + //this.Database.SetCommandTimeout(TimeSpan.FromMinutes(10)); + } + + public JobDbContext(DbContextOptions options) + : base(options) + { + } + public JobDbContext() + { + this.Database.SetCommandTimeout(System.TimeSpan.FromMinutes(50)); + } + public JobDbContext(string strConn) + { + this.Database.SetCommandTimeout(System.TimeSpan.FromMinutes(50)); + } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + // 配置数据库连接字符串 + //if (!optionsBuilder.IsConfigured) + //{ + // // 从配置中获取连接字符串 + // // var connectionString = _configuration.GetConnectionString("Server=192.168.1.228;Database=TaskManager;User ID=sa;Password=ChangkeTec@2021;TrustServerCertificate=True"); + + // //if (string.IsNullOrEmpty(connectionString)) + // //{ + // // throw new InvalidOperationException("无法从配置中获取数据库连接字符串"); + // //} + + // // 配置SQL Server连接 + // optionsBuilder.UseSqlServer("Server=192.168.1.228;Database=TaskManager;User ID=sa;Password=ChangkeTec@2021;TrustServerCertificate=True"); + //} + optionsBuilder.UseSqlServer(GlobalContext.SystemConfig.CustomerDb); + } + /// + /// 来料检验数据 + /// + public DbSet SupplierProMaterialStock { get; set; } + + /// + /// 排产数据 + /// + public DbSet SupplierProScheduling { get; set; } + + /// + /// 供应商基础信息 + /// + public DbSet SupplierInfo { get; set; } + + /// + /// 人员资质信息 + /// + public DbSet SupplierEmployee { get; set; } + + /// + /// BOM主数据 + /// + public DbSet SupplierBom { get; set; } + + /// + /// 过程控制项质量数据 + /// + public DbSet SupplierProCps { get; set; } + + /// + /// 生产过程数据 + /// + public DbSet SupplierProData { get; set; } + + /// + /// 产品一次合格率 + /// + public DbSet SupplierProFirstPassYield { get; set; } + + /// + /// 工位一次合格率 + /// + public DbSet SupplierProStationFirstPassYield { get; set; } + + /// + /// 缺陷业务数据 + /// + public DbSet SupplierProFlaw { get; set; } + + /// + /// 环境业务数据 + /// + public DbSet SupplierProEnvironment { get; set; } + + /// + /// 设备OEE达成率 + /// + public DbSet SupplierProOeeAchievementRate { get; set; } + + /// + /// OEE时间明细 + /// + public DbSet SupplierProOeeTimeDetails { get; set; } + + /// + /// 物料主数据 + /// + public DbSet SupplierProMaterialData { get; set; } + + /// + /// 附件类数据 + /// + public DbSet SupplierProAttachmentData { get; set; } + + /// + /// 工艺装备 + /// + public DbSet SupplierProProcessEquipment { get; set; } + + /// + /// 工艺 + /// + public DbSet SupplierProProcess { get; set; } + + /// + /// 整车月度生产计划-2 + /// + public DbSet SupplierProPlaning { get; set; } + + /// + /// M+6月物料需求计划 + /// + public DbSet SupplierMrpMonth { get; set; } + + /// + /// M+6月物料需求计划风险确认 + /// + public DbSet SupplierConMmrP { get; set; } + + /// + /// 日物料需求计划 + /// + public DbSet SupplierMrpDate { get; set; } + + /// + /// 日物料需求计划风险确认 + /// + public DbSet SupplierConDate { get; set; } + + /// + /// 计划协议 + /// + public DbSet SupplierSaWeek { get; set; } + + /// + /// 采购订单 + /// + public DbSet SupplierPo { get; set; } + + /// + /// 采购订单风险确认 + /// + public DbSet SupplierConPo { get; set; } + + /// + /// 过焊装未过总装 + /// + public DbSet SupplierProHSchedul { get; set; } + + /// + /// 过涂装未过总装 + /// + public DbSet SupplierProTSchedul { get; set; } + + /// + /// 排序供货 + /// + public DbSet SupplierProCSchedul { get; set; } + + /// + /// 看板配送单 + /// + public DbSet SupplierDelState { get; set; } + + /// + /// 退货单 + /// + public DbSet SupplierReturn { get; set; } + + /// + /// 奇瑞RDC共享库存 + /// + public DbSet SupplierInvData { get; set; } + + /// + /// 供应商共享库存 + /// + public DbSet SupplierSInvData { get; set; } + + /// + /// 日MRP状态监控 + /// + public DbSet SupplierMrpState { get; set; } + + + public DbSet TaskLogs { get; set; } + + + public DbSet TaskConifgure { get; set; } + + //public DbSet TaskConifgures { get; set; } + // 配置实体映射 + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + //modelBuilder.Entity(entity => + //{ + // entity.ToTable("TaskConifgure"); + //}); + + // 配置表名 + + + // 其他配置... + } + + + + + + + } +} + + + + diff --git a/API/TaskManager.EntityFramework/TaskManager.EntityFramework.csproj b/API/TaskManager.EntityFramework/TaskManager.EntityFramework.csproj new file mode 100644 index 0000000..9d3ae29 --- /dev/null +++ b/API/TaskManager.EntityFramework/TaskManager.EntityFramework.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/API/TaskManager.Job/Controllers/LogController.cs b/API/TaskManager.Job/Controllers/LogController.cs new file mode 100644 index 0000000..b46bcad --- /dev/null +++ b/API/TaskManager.Job/Controllers/LogController.cs @@ -0,0 +1,68 @@ + +using Dapper; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class LogController:ControllerBase + { + private readonly JobDbContext _dbContext; + public LogController(JobDbContext dbContext) + { + _dbContext = dbContext; + } + public async Task> GetAll() + { + var log = await _dbContext.TaskLogs.ToListAsync(); + return log; + } + [HttpGet("AddError")] + public async Task AddError(string message,string taskname) + { + _dbContext.TaskLogs.Add(new TaskLog() { Info = message, Type = "错误",TaskName=taskname ,CreationTime=DateTime.Now}); + var result =await _dbContext.SaveChangesAsync(); + if (result > 0) + { + return true; + } + return false; + } + [HttpGet("AddInfo")] + public async Task AddInfo(string message, string taskname) + { + _dbContext.TaskLogs.Add(new TaskLog() { Info = message, Type = "记录", TaskName = taskname, CreationTime = DateTime.Now }); + var result = await _dbContext.SaveChangesAsync(); + if (result > 0) + { + return true; + } + return false; + } + + } + //private readonly IServiceProvider _serviceProvider; + //public LogController(IServiceProvider serviceProvider) + //{ + // _serviceProvider = serviceProvider; + //} + //public async Task> GetLogs() + //{ + // var dbcontext= _serviceProvider.GetRequiredService(); + // var connection=dbcontext.Database.GetDbConnection(); + // connection.Query("select top 10 * from logs"); + //} + + + +} diff --git a/API/TaskManager.Job/Controllers/RecurringJobBaseController.cs b/API/TaskManager.Job/Controllers/RecurringJobBaseController.cs new file mode 100644 index 0000000..1921819 --- /dev/null +++ b/API/TaskManager.Job/Controllers/RecurringJobBaseController.cs @@ -0,0 +1,175 @@ + +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TaskManager.Entity; +using TaskManager.EntityFramework; + + + + +namespace TaskManager.Controllers +{ + public class RecurringJobBaseController :ControllerBase, IDoExecute + { + protected string appKey = "8EG566b9bedd2bf46d"; + protected string appSecret = "48edc4425647425d87f806a1ba492580"; + protected readonly HttpClient _httpClient; + protected readonly JobDbContext _jobDbContext; + protected string Path { set; get; } = "/v2/get/supplierProPlaning"; + protected string Url { set; get; } = "/v2/get/supplierProPlaning"; + protected virtual string TaskName { set; get; } = "SupplierProPlaning"; + protected readonly LogController _logger; + public RecurringJobBaseController( + HttpClient httpClient, + JobDbContext jobDbContext, + LogController log + ) + { + _httpClient = new HttpClient(); + _jobDbContext = jobDbContext; + _logger = log; + } + + /// + /// 提交给接口 + /// + /// + /// 录入DTOJson + /// 返回DTOJson + protected async Task Post(string url, string path, string jsonData) + { + try + { + // 生成签名参数 + string timeStamp = GetCurrentTimestamp(); + string nonce = GenerateNonce(); + var sign = GenerateSign(HttpMethod.Post.Method, path, appKey, appSecret, timeStamp, nonce, jsonData); + // 构建请求 + var request = new HttpRequestMessage(HttpMethod.Post, url); + request.Content = new StringContent(jsonData, Encoding.UTF8, "application/json"); + request.Headers.Add("appKey", appKey); + request.Headers.Add("appSecret", appSecret); + request.Headers.Add("timestamp", timeStamp); + request.Headers.Add("sign", sign); + request.Headers.Add("nonce", nonce); + + // 发送请求 + var response = await _httpClient.SendAsync(request); + response.EnsureSuccessStatusCode(); // 抛出异常处理状态码 + return await response.Content.ReadAsStringAsync(); + } + catch (HttpRequestException ex) + { + await _logger.AddError(ex.Message, this.TaskName); + //error = ex.Message; + return string.Empty; + } + } + + private string GenerateSign(string method, string path, string appKey, string appSecret, string timestamp, string nonce, string jsonBody) + { + + string paramStr = $"method={method.ToUpper()}&path={path}&appKey={appKey}&appSecret={appSecret}×tamp={timestamp}&nonce={nonce}&jsonBody={jsonBody}"; + return ComputeSHA512(paramStr); + + } + private string ComputeSHA512(string input) + { + using (SHA512 sha512 = SHA512.Create()) + { + byte[] bytes = Encoding.UTF8.GetBytes(input); + byte[] hash = sha512.ComputeHash(bytes); + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < hash.Length; i++) + { + builder.Append(hash[i].ToString("x2")); // "x2" 表示小写十六进制 + } + return builder.ToString(); + } + } + private string GetCurrentTimestamp() + { + return ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds).ToString(); + } + private string GenerateNonce() + { + const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + Random random = new Random(); + int length = random.Next(10, 51); + return new string(Enumerable.Repeat(chars, length) + .Select(s => s[random.Next(s.Length)]).ToArray()); + } + + + private async Task BeforeExecuteAsync(string uid) + { + await _logger.AddInfo($"{TaskName}开始执行作业{uid}", TaskName); + } + private async Task AfterExecuteAsync(string uid) + { + await _logger.AddInfo($"{TaskName}结束执行作业{uid}", TaskName); + } + [HttpGet] + public async Task ExecuteAsync(string url, string path, string taskName) + { + var str = DateTime.Now.ToLongTimeString(); + await BeforeExecuteAsync(str); + + await DoExecutingAsync(url, path, taskName); + + await AfterExecuteAsync(str); + + } + protected async virtual Task DoExecutingAsync(string url, string path, string takName) + { + + + + + + + } + protected static string RemoveWhitespace(string input) + { + if (string.IsNullOrEmpty(input)) + return input; + // 使用正则表达式移除空格和换行 + return Regex.Replace(input, @"[\s]+", ""); + } + + + } + + + + + +} + + + + + + + + + + + + + + + diff --git a/API/TaskManager.Job/Controllers/RecurringJobInputPageController.cs b/API/TaskManager.Job/Controllers/RecurringJobInputPageController.cs new file mode 100644 index 0000000..2af1428 --- /dev/null +++ b/API/TaskManager.Job/Controllers/RecurringJobInputPageController.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class RecurringJobInputPageController + { + } +} diff --git a/API/TaskManager.Job/Controllers/RecurringJobOutPageController.cs b/API/TaskManager.Job/Controllers/RecurringJobOutPageController.cs new file mode 100644 index 0000000..5e15069 --- /dev/null +++ b/API/TaskManager.Job/Controllers/RecurringJobOutPageController.cs @@ -0,0 +1,278 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Omu.ValueInjecter; + +using System.Text.Json; +using System.Text.Json.Serialization; +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class RecurringJobOutPageController : RecurringJobBaseController where T : CherryReadBaseEntity, new() where ToutputDetial : CherryReadBaseEntityDto + { + public RecurringJobOutPageController(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + + public async Task> FetchAllDataAsync(string inputdate) + { + var allData = new List(); + int totalItems = 0; + int pageSize = 0; + int currentPage = 1; + string date = !string.IsNullOrEmpty(inputdate) ? inputdate : DateTime.Now.ToString("yyyy-MM-dd"); + + + // 首次请求获取总条数和分页信息 + PagedResponse firstResponse = await GetPageAsync(new PAGE_DTO() { Date = date, IsForce = true }); + + + + + + + + + + if (firstResponse == null || firstResponse.Code != 200) + { + await _logger.AddError("首次请求失败,无法获取分页信息。", TaskName); + return allData; + } + if (firstResponse.Data.Total == "0") + { + await _logger.AddError("首次请求失败,Total为0是否已经全部读取过。", TaskName); + return allData; + + } + + var readedcount = _jobDbContext.Set().Where(p => p.RequestDate == inputdate).Count(); + if (readedcount != int.Parse(firstResponse.Data.Total))//记录数不相等 + { + var ids = _jobDbContext.Set().Where(p => p.RequestDate == inputdate).Select(p => p.Id).ToList();//已经同步的ID + totalItems = int.Parse(firstResponse.Data.Total); + pageSize = int.Parse(firstResponse.Data.PageSize); + List pagefirstList = new List(); + if (readedcount > 0) + { + var listrows = firstResponse.Data.Rows.Where(p => !ids.Contains(p.Id)); + foreach (var itm in firstResponse.Data.Rows) + { + T entity = new T(); + entity.InjectFrom(itm); + entity.CreationTime = DateTime.Now; + pagefirstList.Add(entity); + allData.Add(itm); + } + } + else + { + + foreach (var itm in firstResponse.Data.Rows) + { + T entity = new T(); + entity.InjectFrom(itm); + entity.CreationTime = DateTime.Now; + pagefirstList.Add(entity); + allData.Add(itm); + } + } + + _jobDbContext.BulkInsert(pagefirstList); + + //Console.WriteLine($"总记录数: {totalItems}, 每页大小: {pageSize}"); + + // 计算总页数 + int totalPages = (int)Math.Ceiling((double)totalItems / pageSize); + //Console.WriteLine($"总共需要请求 {totalPages} 页数据"); + + // 循环请求剩余页面 + for (currentPage = 2; currentPage <= totalPages; currentPage++) + { + PAGE_DTO pageinput = new PAGE_DTO() { Date = date, PageNum = currentPage, IsForce = true }; + Console.WriteLine($"正在请求第 {currentPage} 页..."); + PagedResponse pageResponse = await GetPageAsync(pageinput); + if (pageResponse?.Data.Rows != null && pageResponse.Data.Rows.Count > 0) + { + List pageList = new List(); + //foreach (var itm in pageResponse.Data.Rows) + //{ + // T entity = new T(); + // entity.InjectFrom(itm); + // entity.CreationTime = DateTime.Now; + // pageList.Add(entity); + // allData.Add(itm); + //} + if (readedcount > 0) + { + var listrows = pageResponse.Data.Rows.Where(p => !ids.Contains(p.Id)); + foreach (var itm in pageResponse.Data.Rows) + { + T entity = new T(); + entity.InjectFrom(itm); + entity.CreationTime = DateTime.Now; + pageList.Add(entity); + allData.Add(itm); + } + } + else + { + + foreach (var itm in pageResponse.Data.Rows) + { + T entity = new T(); + entity.InjectFrom(itm); + entity.CreationTime = DateTime.Now; + pageList.Add(entity); + allData.Add(itm); + } + } + + + + + _jobDbContext.BulkInsert(pageList); + await _logger.AddInfo($"成功获取 {pageResponse.Data.Rows.Count} 条记录", TaskName); + } + else + { + await _logger.AddError($"第 {currentPage} 页未返回数据", TaskName); + + } + + // 简单的请求间隔,避免过于频繁 + await Task.Delay(200); + } + + + await _logger.AddInfo($"所有数据获取完成,总共获取了 {allData.Count} 条记录", TaskName); + } + + + return allData; + } + + + + + private async Task> GetPageAsync(PAGE_DTO input) + { + try + { + var inputjson = JsonSerializer.Serialize(input, + new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true // 可选,用于格式化输出 + } + ); + inputjson = RemoveWhitespace(inputjson); + var content = await Post(Url, Path, inputjson); + if (!string.IsNullOrEmpty(content)) + { + + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = { + new JsonStringEnumConverter(), // 枚举转换 + new CustomDateTimeConverter("yyyy-MM-dd HH:mm:ss") // 日期转换 + } + }; + + + return JsonSerializer.Deserialize>(content, options); + } + else + { + await _logger.AddError($"调用接口无返回值{Url}", TaskName); + return null; + } + } + catch (Exception ex) + { + await _logger.AddError($"调用接口无返回值错误{ex.Message}", TaskName); + return null; + } + + + + + + + + + + //try + //{ + // var url = $"{_apiUrl}?pageNum={pageNum}"; + // var response = await _httpClient.GetAsync(url); + + // if (response.IsSuccessStatusCode) + // { + // var content = await response.Content.ReadAsStringAsync(); + // return JsonSerializer.Deserialize>(content); + // } + // else + // { + // Console.WriteLine($"请求失败,状态码: {response.StatusCode}"); + // return null; + // } + //} + //catch (Exception ex) + //{ + // Console.WriteLine($"请求发生异常: {ex.Message}"); + // return null; + //} + } + [HttpGet("Test")] + public async Task TestAsync(string url, string path, string taskName, string inputdate) + { + Url = url; + Path = path; + TaskName = taskName; + await FetchAllDataAsync(inputdate); + } + protected override async Task DoExecutingAsync(string url, string path, string takName) + { + Url = url; + Path = path; + TaskName = takName; + await FetchAllDataAsync(string.Empty); + + } + + + + + + // 反序列化时使用 + + + + + + } + public class CustomDateTimeConverter : JsonConverter + { + private readonly string _format; + + public CustomDateTimeConverter(string format) + { + _format = format; + } + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return DateTime.ParseExact(reader.GetString(), _format, null); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(_format)); + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_BOM_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_BOM_CONTROLLER.cs new file mode 100644 index 0000000..3f16b92 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_BOM_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_BOM_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_CON_DATE_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_CON_DATE_CONTROLLER.cs new file mode 100644 index 0000000..e5fcfb6 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_CON_DATE_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_CON_DATE_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_CON_MMRP_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_CON_MMRP_CONTROLLER.cs new file mode 100644 index 0000000..2aed355 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_CON_MMRP_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_CON_MMRP_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_CON_PO_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_CON_PO_CONTROLLER.cs new file mode 100644 index 0000000..ad10033 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_CON_PO_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_CON_PO_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_DEL_STATE_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_DEL_STATE_CONTROLLER.cs new file mode 100644 index 0000000..06c78fe --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_DEL_STATE_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //看板配送单 + public class SUPPLIER_DEL_STATE_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_DEL_STATE_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_EMPLOYEE_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_EMPLOYEE_CONTROLLER.cs new file mode 100644 index 0000000..df8d0bd --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_EMPLOYEE_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_EMPLOYEE_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_INFO_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_INFO_CONTROLLER.cs new file mode 100644 index 0000000..9aaaa65 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_INFO_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_INFO_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_INV_DATA_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_INV_DATA_CONTROLLER.cs new file mode 100644 index 0000000..24c9e80 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_INV_DATA_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //奇瑞RDC共享库存 + public class SUPPLIER_INV_DATA_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_INV_DATA_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_MRP_DATE_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_MRP_DATE_CONTROLLER.cs new file mode 100644 index 0000000..2ee5091 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_MRP_DATE_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //日物料需求计划 + public class SUPPLIER_MRP_DATE_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_MRP_DATE_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_MRP_MONTH_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_MRP_MONTH_CONTROLLER.cs new file mode 100644 index 0000000..20aae5a --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_MRP_MONTH_CONTROLLER.cs @@ -0,0 +1,14 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class SUPPLIER_MRP_MONTH_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_MRP_MONTH_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_MRP_STATE_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_MRP_STATE_CONTROLLER.cs new file mode 100644 index 0000000..4f84882 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_MRP_STATE_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //日MRP状态监控 + public class SUPPLIER_MRP_STATE_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_MRP_STATE_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_MRP_WARNING_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_MRP_WARNING_CONTROLLER.cs new file mode 100644 index 0000000..26af3f7 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_MRP_WARNING_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //日MRP预警推移 + public class SUPPLIER_MRP_WARNING_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_MRP_WARNING_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PO_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PO_CONTROLLER.cs new file mode 100644 index 0000000..2cc5e0c --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PO_CONTROLLER.cs @@ -0,0 +1,14 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class SUPPLIER_PO_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_PO_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_ATTACHMENT_DATA_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_ATTACHMENT_DATA_CONTROLLER.cs new file mode 100644 index 0000000..a84b735 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_ATTACHMENT_DATA_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_ATTACHMENT_DATA_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_CPS_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_CPS_CONTROLLER.cs new file mode 100644 index 0000000..5175727 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_CPS_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_CPS_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_CSCHEDUL_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_CSCHEDUL_CONTROLLER.cs new file mode 100644 index 0000000..dd14ce1 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_CSCHEDUL_CONTROLLER.cs @@ -0,0 +1,14 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_CSCHEDUL_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_PRO_CSCHEDUL_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_DATA_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_DATA_CONTROLLER.cs new file mode 100644 index 0000000..607129a --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_DATA_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_DATA_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_ENVIRONMENT_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_ENVIRONMENT_CONTROLLER.cs new file mode 100644 index 0000000..519281e --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_ENVIRONMENT_CONTROLLER.cs @@ -0,0 +1,5 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_ENVIRONMENT_CONTROLLER { } + +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_FIRST_PASSYIELD_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_FIRST_PASSYIELD_CONTROLLER.cs new file mode 100644 index 0000000..cbfaef0 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_FIRST_PASSYIELD_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_FIRST_PASSYIELD_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_FLAW_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_FLAW_CONTROLLER.cs new file mode 100644 index 0000000..3ca13a2 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_FLAW_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_FLAW_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_HSCHEDUL_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_HSCHEDUL_CONTROLLER.cs new file mode 100644 index 0000000..8549439 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_HSCHEDUL_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //过焊装未过总装 + public class SUPPLIER_PRO_HSCHEDUL_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_PRO_HSCHEDUL_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_MATERIAL_DATA_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_MATERIAL_DATA_CONTROLLER.cs new file mode 100644 index 0000000..fd96f93 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_MATERIAL_DATA_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_MATERIAL_DATA_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_MATERIAL_STOCK_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_MATERIAL_STOCK_CONTROLLER.cs new file mode 100644 index 0000000..922be46 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_MATERIAL_STOCK_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_MATERIAL_STOCK_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_CONTROLLER.cs new file mode 100644 index 0000000..3bca00c --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_OEE_TIME_DETAILS_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_OEE_TIME_DETAILS_CONTROLLER.cs new file mode 100644 index 0000000..9cc55ff --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_OEE_TIME_DETAILS_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_OEE_TIME_DETAILS_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PLANING_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PLANING_CONTROLLER.cs new file mode 100644 index 0000000..a57b45f --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PLANING_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //整车月度生产计划 + public class SUPPLIER_PRO_PLANING_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_PRO_PLANING_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PROCESS_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PROCESS_CONTROLLER.cs new file mode 100644 index 0000000..a14dab7 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PROCESS_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_PROCESS_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PROCESS_EQUIPMENT_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PROCESS_EQUIPMENT_CONTROLLER.cs new file mode 100644 index 0000000..27e7a59 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_PROCESS_EQUIPMENT_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_PROCESS_EQUIPMENT_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_SCHEDULING_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_SCHEDULING_CONTROLLER.cs new file mode 100644 index 0000000..9ab0590 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_SCHEDULING_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_SCHEDULING_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs new file mode 100644 index 0000000..671ed4e --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER + { + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_PRO_TSCHEDUL_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_TSCHEDUL_CONTROLLER.cs new file mode 100644 index 0000000..8a37a6f --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_PRO_TSCHEDUL_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //过涂装未过总装 + public class SUPPLIER_PRO_TSCHEDUL_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_PRO_TSCHEDUL_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_RETURN_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_RETURN_CONTROLLER.cs new file mode 100644 index 0000000..c3cca16 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_RETURN_CONTROLLER.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //退货单 + public class SUPPLIER_RETURN_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_RETURN_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_SA_WEEK_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_SA_WEEK_CONTROLLER.cs new file mode 100644 index 0000000..5b590f8 --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_SA_WEEK_CONTROLLER.cs @@ -0,0 +1,17 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + /// + /// 计划协议 + /// + public class SUPPLIER_SA_WEEK_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_SA_WEEK_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/SUPPLIER_SINV_DATA_CONTROLLER.cs b/API/TaskManager.Job/Controllers/SUPPLIER_SINV_DATA_CONTROLLER.cs new file mode 100644 index 0000000..a92b96b --- /dev/null +++ b/API/TaskManager.Job/Controllers/SUPPLIER_SINV_DATA_CONTROLLER.cs @@ -0,0 +1,14 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class SUPPLIER_SINV_DATA_CONTROLLER : RecurringJobOutPageController + { + public SUPPLIER_SINV_DATA_CONTROLLER(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/TaskManager.Job/Controllers/TOKEN_CONTROLLER.cs b/API/TaskManager.Job/Controllers/TOKEN_CONTROLLER.cs new file mode 100644 index 0000000..e8f35c8 --- /dev/null +++ b/API/TaskManager.Job/Controllers/TOKEN_CONTROLLER.cs @@ -0,0 +1,185 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; + +using System.Threading.Tasks; + + +namespace TaskManager.Controllers +{ + public class TOKEN_CONTROLLER + { + + private readonly HttpClient _httpClient; + private readonly string _appKey = "8EG566b9bedd2bf46d"; + private readonly string _appSecret = "48edc4425647425d87f806a1ba492580"; // 若有密钥需传入 + + public TOKEN_CONTROLLER() + { + _httpClient = new HttpClient(); + + + + } + public async Task ExecuteAsync() + { + try + { + var retult = await GetTokenAsync("https://ediuat.mychery.com/prod-api/auth/public/login/appKey"); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + } + + public async Task GetTokenAsync(string tokenUrl) + { + var parameters = new + { + appKey = _appKey, + appSecret = _appSecret, // 按需传参 + // 其他参数如 grant_type、scope 等根据接口要求调整 + }; + + var content = new StringContent( + JsonConvert.SerializeObject(parameters), + Encoding.UTF8, + "application/json" + ); + var response = await _httpClient.PostAsync(tokenUrl, content); + response.EnsureSuccessStatusCode(); // 抛异常处理错误 + var responseBody = await response.Content.ReadAsStringAsync(); + var result = JsonConvert.DeserializeObject(responseBody); + return result.data.access_token; // 假设返回字段为 access_token + } + + + + } + + //private readonly string _appKey = "8EG566b9bedd2bf46d"; + //private readonly string _appSecret = "48edc4425647425d87f806a1ba492580"; + //private readonly string _tokenEndpoint = "https://ediuat.mychery.com/prod-api/auth/public/login/appKey"; + + //private readonly HttpClient _httpClient; + //private readonly SemaphoreSlim _refreshLock = new SemaphoreSlim(1, 1); + //private string _currentToken; + //private DateTime _tokenExpiry; + //private bool _disposed; + + //public TokenServiceController() + //{ + // _httpClient = new HttpClient(); + // _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + //} + + //public async Task GetTokenAsync(CancellationToken cancellationToken = default) + //{ + // // 检查令牌是否存在且未过期(提前60秒刷新以防止边缘情况) + // if (!string.IsNullOrEmpty(_currentToken) && _tokenExpiry > DateTime.UtcNow.AddSeconds(60)) + // { + // return _currentToken; + // } + + // // 等待获取锁,确保只有一个线程刷新令牌 + // await _refreshLock.WaitAsync(cancellationToken); + // try + // { + // // 再次检查,避免其他线程已经刷新了令牌 + // if (!string.IsNullOrEmpty(_currentToken) && _tokenExpiry > DateTime.UtcNow.AddSeconds(60)) + // { + // return _currentToken; + // } + + // // 调用认证API获取新令牌 + // var tokenResponse = await FetchNewTokenAsync(cancellationToken); + + // // 更新令牌和过期时间 + // _currentToken = tokenResponse.AccessToken; + // _tokenExpiry = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn); + + // return _currentToken; + // } + // finally + // { + // _refreshLock.Release(); + // } + //} + + //private async Task FetchNewTokenAsync(CancellationToken cancellationToken) + //{ + // try + // { + // // 创建请求内容 + // var requestBody = new + // { + // appKey = _appKey, + // appSecret = _appSecret + // }; + + // var content = new StringContent( + // JsonSerializer.Serialize(requestBody), + // Encoding.UTF8, + // "application/json"); + + // // 发送请求 + // var response = await _httpClient.PostAsync(_tokenEndpoint, content, cancellationToken); + // response.EnsureSuccessStatusCode(); + + // // 解析响应 + // var jsonResponse = await response.Content.ReadAsStringAsync(cancellationToken); + // var tokenResponse = JsonSerializer.Deserialize( + // jsonResponse, + // new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + + // if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.AccessToken)) + // { + // throw new InvalidOperationException("Failed to retrieve access token."); + // } + + // return tokenResponse; + // } + // catch (Exception ex) + // { + // Console.WriteLine($"Token acquisition failed: {ex.Message}"); + // throw; + // } + //} + + //// 令牌响应模型 + //private class TokenResponse + //{ + // public string AccessToken { get; set; } + // public int ExpiresIn { get; set; } = 3600; // 默认1小时 + //} + + //public void Dispose() + //{ + // Dispose(true); + // GC.SuppressFinalize(this); + //} + + //protected virtual void Dispose(bool disposing) + //{ + // if (!_disposed) + // { + // if (disposing) + // { + // _httpClient?.Dispose(); + // _refreshLock?.Dispose(); + // } + // _disposed = true; + // } + //} + + //public Task ExecuteAsync() + //{ + // throw new NotImplementedException(); + //} +} diff --git a/API/TaskManager.Job/Controllers/TaskConifgureController.cs b/API/TaskManager.Job/Controllers/TaskConifgureController.cs new file mode 100644 index 0000000..fa942ff --- /dev/null +++ b/API/TaskManager.Job/Controllers/TaskConifgureController.cs @@ -0,0 +1,578 @@ +using Hangfire; +using Microsoft.AspNetCore.Mvc; + + + +//using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO; +using System.Threading.Tasks; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //[ApiController] + //[Route("[controller]")] + public class TaskConifgureController :ControllerBase + { + private readonly JobDbContext _context; + private readonly IServiceProvider _builder; + private readonly IConfiguration _configuration; + public TaskConifgureController(JobDbContext context, IServiceProvider builder, IConfiguration configuration) + { + _builder = builder; + _context = context; + _configuration = configuration; + } + /// + /// 请除所有任务 + /// + /// + [HttpPost(Name = "ClearAllTask")] + public async Task ClearAllTask() + { + var tasks = await _context.TaskConifgure.ToListAsync(); + foreach (var item in tasks) + { + RecurringJob.RemoveIfExists(item.TaskName); + } + } + + + /// + /// 执行铁定任务 + /// + /// + /// + [HttpPost(Name = "ExecuteTask")] + public async Task ExecuteTask(string taskName) + { + var first=await _context.TaskConifgure.FirstOrDefaultAsync(p => p.TaskName == taskName); + var url = first.Url; + var path = first.Api; + var controller = _builder.GetRequiredService(); + + await controller.ExecuteAsync(url,path, taskName); + + + + + + + + } + + /// + /// 执行铁定任务 + /// + /// + /// + [HttpGet(Name = "testTask")] + public async Task testTask(string taskName) + { + var first = await _context.TaskConifgure.FirstOrDefaultAsync(p => p.TaskName == taskName); + var url = first.Url; + var path = first.Api; + var controller = _builder.GetRequiredService(); + + await controller.TestAsync(url, path, taskName,"2025-04-21"); + + + + + + + + } + + + + + + + + public async Task RefreshTaskConfig() + { + + // 从数据库加载所有任务配置 + + var tasks = _context.TaskConifgure.Where(p => p.IsAuto == true && !string.IsNullOrEmpty(p.Corn) + && !string.IsNullOrEmpty(p.Api) && !string.IsNullOrEmpty(p.Url)).ToList(); + var delTasks = _context.TaskConifgure.Where(p => p.IsAuto == false || string.IsNullOrEmpty(p.Corn) + || string.IsNullOrEmpty(p.Api) || string.IsNullOrEmpty(p.Url) + ).ToList(); + + foreach (var task in tasks) + { + var url = task.Url; + var path = task.Api; + + + + switch (task.TaskName) + { + //case "来料检验数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url,path,task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "排产数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "供应商基础信息": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "人员资质信息": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "BOM主数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "过程控制项质量数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "生产过程数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "产品一次合格率": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "工位一次合格率": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "缺陷业务数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "环境业务数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "设备OEE达成率": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "OEE时间明细": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "物料主数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "工艺装备": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "工艺": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + + case "整车月度生产计划1": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "M+6月物料需求计划1": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "整车月度生产计划2": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "M+6月物料需求计划2": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "日物料需求计划": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "计划协议": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "采购订单": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "过焊装未过总装": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "过涂装未过总装": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "排序供货": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "看板配送单": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "退货单": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "奇瑞RDC共享库存": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "日MRP状态监控": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "日MRP预警推移": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "M+6月物料需求计划风险确认": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "日物料需求计划风险确认": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "采购订单风险确认": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "供应商共享库存-上午": + + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "供应商共享库存-晚上": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + + } + + } + foreach (var task in delTasks) + { + + switch (task.TaskName) + { + case "来料检验数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "排产数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "供应商基础信息": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "人员资质信息": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "BOM主数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "过程控制项质量数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "生产过程数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "产品一次合格率": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "工位一次合格率": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "缺陷业务数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "环境业务数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "设备OEE达成率": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "OEE时间明细": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "物料主数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "工艺装备": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "工艺": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "整车月度生产计划1": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "M+6月物料需求计划1": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "整车月度生产计划2": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "M+6月物料需求计划2": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "日物料需求计划": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "计划协议": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "采购订单": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "过焊装未过总装": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "过涂装未过总装": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "排序供货": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "看板配送单": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "退货单": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "奇瑞RDC共享库存": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "日MRP状态监控": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "日MRP预警推移": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "M+6月物料需求计划风险确认": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "日物料需求计划风险确认": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "采购订单风险确认": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "供应商共享库存-上午": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "供应商共享库存-晚上": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + + } + } + + + + + } + + + // 使用 Hangfire 注册定时任务 + // Console.WriteLine($"已注册定时任务: {task.TaskName}, Cron: {task.Corn}"); + } + } + + + diff --git a/API/TaskManager.Job/Controllers/WeatherForecastController.cs b/API/TaskManager.Job/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..10c6914 --- /dev/null +++ b/API/TaskManager.Job/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace TaskManager.Controllers +{ + //[ApiController] + //[Route("[controller]")] + //public class WeatherForecastController : ControllerBase + //{ + // private static readonly string[] Summaries = new[] + // { + // "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + // }; + + // private readonly ILogger _logger; + + // public WeatherForecastController(ILogger logger) + // { + // _logger = logger; + // } + + // [HttpGet(Name = "GetWeatherForecast")] + // public IEnumerable Get() + // { + // return Enumerable.Range(1, 5).Select(index => new WeatherForecast + // { + // Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + // TemperatureC = Random.Shared.Next(-20, 55), + // Summary = Summaries[Random.Shared.Next(Summaries.Length)] + // }) + // .ToArray(); + // } + //} +} diff --git a/API/TaskManager.Job/TaskManager.Job.csproj b/API/TaskManager.Job/TaskManager.Job.csproj new file mode 100644 index 0000000..ae54e50 --- /dev/null +++ b/API/TaskManager.Job/TaskManager.Job.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/API/Wood.Admin.WebApi/DataSeed.sql b/API/Wood.Admin.WebApi/DataSeed.sql new file mode 100644 index 0000000..ad8a0e8 --- /dev/null +++ b/API/Wood.Admin.WebApi/DataSeed.sql @@ -0,0 +1,194 @@ +--用户角色 +INSERT INTO "SysUserBelongRole" ("Id", "UserId", "RoleId", "CreateUserId", "CreateTime") VALUES (1300000002, 1300000002, 1300000001, NULL, '2025-01-19 13:13:56.691'); +INSERT INTO "SysUserBelongRole" ("Id", "UserId", "RoleId", "CreateUserId", "CreateTime") VALUES (1300000003, 1300000003, 1300000002, NULL, '2025-01-19 13:13:56.691'); +INSERT INTO "SysUserBelongRole" ("Id", "UserId", "RoleId", "CreateUserId", "CreateTime") VALUES (1882329230927339520, 1881982901915099136, 1300000001, 0, '2025-01-23 15:27:15.2961165'); +INSERT INTO "SysUserBelongRole" ("Id", "UserId", "RoleId", "CreateUserId", "CreateTime") VALUES (1882356958271512576, 1882356958254735360, 1882356955843010560, 1300000001, '2025-01-23 17:17:26.0105013'); +INSERT INTO "SysUserBelongRole" ("Id", "UserId", "RoleId", "CreateUserId", "CreateTime") VALUES (1884805524378230784, 1300000001, 1300000001, 0, '2025-01-30 11:27:09.6628944'); +INSERT INTO "SysUserBelongRole" ("Id", "UserId", "RoleId", "CreateUserId", "CreateTime") VALUES (1884918908515917824, 1884918908272648192, 1300000001, 0, '2025-01-30 18:57:42.547'); +INSERT INTO "SysUserBelongRole" ("Id", "UserId", "RoleId", "CreateUserId", "CreateTime") VALUES (1884918908520112128, 1884918908272648193, 1300000001, 0, '2025-01-30 18:57:42.548'); +INSERT INTO "SysUserBelongRole" ("Id", "UserId", "RoleId", "CreateUserId", "CreateTime") VALUES (1886588408239890432, 1881984359129554944, 1300000002, 0, '2025-02-04 09:31:42.2990032'); +--用户基本信息 +INSERT INTO "SysUser" ("Id", "Password", "Salt", "OrgId", "PositionId", "LastVisit", "AccountType", "LoginCount", "FirstVisit", "PreviousVisit", "UserName", "RealName", "NickName", "Gender", "Birthday", "Email", "Mobile", "Avatar", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000001, 'gu+qpKMTvW6Z8ooVOfSgzQ==', 'aUyhQl7o7CJFvePL', 1300000001, 0, '2025-02-04 13:55:41.8323838', 9999, 32, '2025-01-30 08:34:49.288', '2025-02-04 13:55:41.6049409', 'superadmin', '超级管理员', '超级管理员', 1, '1992-01-01 01:01:01', '', '123456', '738CC2E1CF6C468B8C8153AEFCD261E9', 1300000000, 1, '', 1300000001, '2025-01-19 13:13:56.649', NULL, '2025-02-04 13:55:41.8328374', NULL, '0'); +INSERT INTO "SysUser" ("Id", "Password", "Salt", "OrgId", "PositionId", "LastVisit", "AccountType", "LoginCount", "FirstVisit", "PreviousVisit", "UserName", "RealName", "NickName", "Gender", "Birthday", "Email", "Mobile", "Avatar", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000002, 'gu+qpKMTvW6Z8ooVOfSgzQ==', '384DjuHkbZm6FW2Q', 1881265290692665344, 1881948006849323008, NULL, 9, 0, NULL, NULL, 'admin', '管理员', '管理员', 1, '1992-01-02 00:00:00', '', '123456', NULL, 1300000000, 1, '', 1300000001, '2025-01-19 13:13:56.650', NULL, '2025-01-22 15:47:37.954337', 1300000001, '0'); +INSERT INTO "SysUser" ("Id", "Password", "Salt", "OrgId", "PositionId", "LastVisit", "AccountType", "LoginCount", "FirstVisit", "PreviousVisit", "UserName", "RealName", "NickName", "Gender", "Birthday", "Email", "Mobile", "Avatar", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000003, 'gu+qpKMTvW6Z8ooVOfSgzQ==', 'GwvjCfaiFnW5ztfI', 1300000001, 0, NULL, 0, 0, NULL, NULL, 'user1', '用户1', '用户1', 1, '1992-01-01 01:01:01.000', '', '', NULL, 1300000000, 1, '', 1300000001, '2025-01-19 13:13:56.651', NULL, '2025-01-22 09:13:07.5703432', 1300000001, '0'); +INSERT INTO "SysUser" ("Id", "Password", "Salt", "OrgId", "PositionId", "LastVisit", "AccountType", "LoginCount", "FirstVisit", "PreviousVisit", "UserName", "RealName", "NickName", "Gender", "Birthday", "Email", "Mobile", "Avatar", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881982901915099136, 'gu+qpKMTvW6Z8ooVOfSgzQ==', '+}HhxENLnwBlg]1T', 1881265290692665344, 1881950674254700544, NULL, 0, 0, NULL, NULL, 'user2', '用户2', '测试用户2', 1, '2025-01-01 00:00:00.000', '', '1234563', '7783596F18544438936EE27596210D1A', 1300000000, 1, NULL, 1300000001, '2025-01-22 16:31:04.0252115', 1300000001, '2025-01-23 15:27:15.285', 1300000001, '0'); +INSERT INTO "SysUser" ("Id", "Password", "Salt", "OrgId", "PositionId", "LastVisit", "AccountType", "LoginCount", "FirstVisit", "PreviousVisit", "UserName", "RealName", "NickName", "Gender", "Birthday", "Email", "Mobile", "Avatar", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881984359129554944, 'gu+qpKMTvW6Z8ooVOfSgzQ==', 'FkTN`kgfXrzAi9R*', 1300000001, 1881948006849323008, '2025-02-04 13:55:41.0875974', 0, 5, '2025-02-04 09:24:01.608', '2025-02-04 11:39:42.3846371', 'user3', '用户3', '用户3', 1, '2024-08-01 00:00:00', '', '123', '6D2A4E33108F40CCBA4E1D856CC87FD1', 1300000000, 1, NULL, 1300000001, '2025-01-22 16:36:51.452712', 1300000001, '2025-02-04 13:55:41.0881672', NULL, '0'); +INSERT INTO "SysUser" ("Id", "Password", "Salt", "OrgId", "PositionId", "LastVisit", "AccountType", "LoginCount", "FirstVisit", "PreviousVisit", "UserName", "RealName", "NickName", "Gender", "Birthday", "Email", "Mobile", "Avatar", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882356958254735360, 'gu+qpKMTvW6Z8ooVOfSgzQ==', 't`2o3qFBS*+yb,MZ', 1882356955780096000, 0, NULL, 991, 0, NULL, NULL, 'UUSER001', '测试用户111', '测试用户111', 0, '2025-01-23 17:17:26.0039908', NULL, NULL, NULL, 1882356955796873216, 1, NULL, 1300000001, '2025-01-23 17:17:26.0059504', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysUser" ("Id", "Password", "Salt", "OrgId", "PositionId", "LastVisit", "AccountType", "LoginCount", "FirstVisit", "PreviousVisit", "UserName", "RealName", "NickName", "Gender", "Birthday", "Email", "Mobile", "Avatar", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1884918908272648192, '', '', 1881265290692665344, 0, NULL, 0, 0, NULL, NULL, 'zhangsan', '张三', '张三', 1, '1900-01-01 00:00:00.000', '1F@foxconn.com', '123456', NULL, 1300000000, 1, NULL, 1300000001, '2025-01-30 18:57:42.491', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysUser" ("Id", "Password", "Salt", "OrgId", "PositionId", "LastVisit", "AccountType", "LoginCount", "FirstVisit", "PreviousVisit", "UserName", "RealName", "NickName", "Gender", "Birthday", "Email", "Mobile", "Avatar", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1884918908272648193, '', '', 1881265290692665344, 0, NULL, 0, 0, NULL, NULL, 'lisi', '李四', '李四', 0, '1900-01-01 00:00:00.000', '1F@foxconn.com', '1F456789', NULL, 1300000000, 1, NULL, 1300000001, '2025-01-30 18:57:42.493', 1300000001, NULL, NULL, '0'); +--租户 +INSERT INTO "SysTenant" ("Id", "TenantName", "OrgId", "Sort", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000000, '默认租户', 1300000001, 10, 1, NULL, 1300000001, '2025-01-19 13:13:56.6721406', NULL, '2025-01-23 17:02:41.7352215', 1300000001, '0'); +INSERT INTO "SysTenant" ("Id", "TenantName", "OrgId", "Sort", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882356955796873216, '测试租户1', 1882356955780096000, 20, 1, NULL, 1300000001, '2025-01-23 17:17:25.4199306', 1300000001, NULL, NULL, '0'); +--角色 +INSERT INTO "SysRole" ("Id", "RoleName", "FormCode", "DataScopeType", "Sort", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000001, '管理员', 'admin_role', 2, 10, 1300000000, 1, NULL, 1300000001, '2025-01-19 13:13:56.681', NULL, '2025-01-21 18:58:09.1905823', 1300000001, '0'); +INSERT INTO "SysRole" ("Id", "RoleName", "FormCode", "DataScopeType", "Sort", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000002, '普通用户', 'normal_role', 8, 20, 1300000000, 1, NULL, 1300000001, '2025-01-19 13:13:56.682', NULL, '2025-02-04 09:34:12.2207514', 1300000001, '0'); +INSERT INTO "SysRole" ("Id", "RoleName", "FormCode", "DataScopeType", "Sort", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882356955843010560, '租管-质量测试部', 'zlcsb_role', 2, 30, 1882356955796873216, 1, NULL, 1300000001, '2025-01-23 17:17:25.431329', 1300000001, NULL, NULL, '0'); +--职位 +INSERT INTO "SysPosition" ("Id", "PositionName", "FormCode", "Sort", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881948006849323008, '董事长', 'dsz', 10, 1300000000, 1, NULL, 1300000001, '2025-01-22 14:12:24.3929755', 1300000001, '2025-01-22 14:21:50.3038159', 1300000001, '0'); +INSERT INTO "SysPosition" ("Id", "PositionName", "FormCode", "Sort", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881950674254700544, '总经理', 'zjl', 20, 1300000000, 1, NULL, 1300000001, '2025-01-22 14:23:00.3525383', 1300000001, NULL, NULL, '0'); +--机构组织部门 +INSERT INTO "SysOrg" ("Id", "ParentId", "OrgName", "FormCode", "ShortName", "Telephone", "Email", "PrincipalUserId", "Sort", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000001, 0, '系统默认', 'default_org', '系统默认', '', '', 1300000002, 10, 1300000000, 1, NULL, 1300000001, '2025-01-19 13:13:56.5661473', NULL, '2025-01-21 08:19:18.4835719', 1300000001, '0'); +INSERT INTO "SysOrg" ("Id", "ParentId", "OrgName", "FormCode", "ShortName", "Telephone", "Email", "PrincipalUserId", "Sort", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881265290692665344, 1300000001, '机构1', 'jg1', 'test01', '', '', 1300000002, 21, 1300000000, 1, NULL, 1300000001, '2025-01-20 16:59:32.1765571', 1300000001, '2025-01-21 08:19:18.4835719', 1300000001, '0'); +INSERT INTO "SysOrg" ("Id", "ParentId", "OrgName", "FormCode", "ShortName", "Telephone", "Email", "PrincipalUserId", "Sort", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882356955780096000, 0, '质量测试部', 'zlcsb', '质量测试部', NULL, NULL, 0, 31, 1882356955796873216, 1, NULL, 1300000001, '2025-01-23 17:17:25.4271006', 1300000001, NULL, NULL, '0'); +--菜单授权 +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886589037070917632, 1300000003, 1300000002, 1300000000, 1, NULL, 1300000001, '2025-02-04 09:34:12.224', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886589037070917633, 1300000001, 1300000002, 1300000000, 1, NULL, 1300000001, '2025-02-04 09:34:12.224', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886589037070917634, 1300000002, 1300000002, 1300000000, 1, NULL, 1300000001, '2025-02-04 09:34:12.224', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886589037070917635, 1886587042893275136, 1300000002, 1300000000, 1, NULL, 1300000001, '2025-02-04 09:34:12.224', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886589037070917636, 1886305270632685568, 1300000002, 1300000000, 1, NULL, 1300000001, '2025-02-04 09:34:12.224', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886589037070917637, 1886587128931033088, 1300000002, 1300000000, 1, NULL, 1300000001, '2025-02-04 09:34:12.224', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886589037070917638, 1884778107420942336, 1300000002, 1300000000, 1, NULL, 1300000001, '2025-02-04 09:34:12.224', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886589037070917639, 1884778243870040064, 1300000002, 1300000000, 1, NULL, 1300000001, '2025-02-04 09:34:12.224', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794611613696, 1300000001, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.540', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794620002304, 1300000002, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.542', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196608, 1886587042893275136, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.542', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196609, 1886305270632685568, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196610, 1886587128931033088, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196611, 1300000003, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196612, 1881222457235480576, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196613, 1881549686175834112, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196614, 1881549758976368640, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196615, 1881549837590208512, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196616, 1881549892451704832, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196617, 1881503648907927552, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196618, 1881550091223965696, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196619, 1881550170370482176, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196620, 1881550231213056000, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196621, 1881550282572308480, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196622, 1881550362545102848, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196623, 1881662579596730368, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196624, 1881662811004870656, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196625, 1881662934095110144, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196626, 1881662997173248000, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196627, 1881663062772162560, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196628, 1881663313054670848, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794624196629, 1884857795430457344, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.543', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390912, 1884857884613943296, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390913, 1881943420327567360, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390914, 1881943540813144064, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390915, 1881943652230635520, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390916, 1881943716881637376, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390917, 1881943791406030848, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390918, 1884778107420942336, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390919, 1884778243870040064, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390920, 1886302722643337216, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390921, 1886305880748728320, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390922, 1886305957932310528, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390923, 1886306037544394752, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390924, 1886306151197450240, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390925, 1886369812943347712, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891794794628390926, 1886613824367370240, 1300000001, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:20:01.544', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938251513856, 1300000001, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.204', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938255708160, 1300000002, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.206', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902464, 1886587042893275136, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.206', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902465, 1886305270632685568, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902466, 1886587128931033088, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902467, 1300000003, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902468, 1881222457235480576, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902469, 1881549686175834112, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902470, 1881549758976368640, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902471, 1881549837590208512, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902472, 1881549892451704832, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902473, 1881503648907927552, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902474, 1881550091223965696, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902475, 1881550170370482176, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902476, 1881550231213056000, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902477, 1881550282572308480, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902478, 1881550362545102848, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902479, 1881662579596730368, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902480, 1881662811004870656, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902481, 1881662934095110144, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902482, 1881662997173248000, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902483, 1881663062772162560, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902484, 1881663313054670848, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938259902485, 1884857795430457344, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096768, 1884857884613943296, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.207', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096769, 1881943420327567360, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096770, 1881943540813144064, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096771, 1881943652230635520, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096772, 1881943716881637376, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096773, 1881943791406030848, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096774, 1884778107420942336, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096775, 1884778243870040064, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096776, 1886302722643337216, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096777, 1886305880748728320, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096778, 1886305957932310528, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096779, 1886306037544394752, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096780, 1886306151197450240, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096781, 1886369812943347712, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenuAuthorize" ("Id", "MenuId", "RoleId", "TenantId", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1891795938264096782, 1886613824367370240, 1882356955843010560, 1300000000, 1, NULL, 1300000001, '2025-02-18 18:24:34.208', 1300000001, NULL, NULL, '0'); + +--菜单 +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000001, 0, '工作台', NULL, '/', 'Layout', 'el-Odometer', '/dashboard', '0', '0', '0', NULL, NULL, 10, 1, 1, NULL, 1300000001, '2025-01-19 13:13:56.700', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000002, 1300000001, '主页', 'dashboardIndex', '/dashboard', '/dashboard/index.vue', 'el-Aim', NULL, '0', '0', '1', NULL, NULL, 10, 2, 1, NULL, 1300000001, '2025-01-19 13:13:56.702', 1300000001, '2025-01-30 19:27:01.3156973', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000003, 0, '系统管理', NULL, '/system', 'Layout', 'el-Setting', NULL, '0', '0', '0', NULL, NULL, 9999, 1, 1, NULL, 1300000001, '2025-01-19 13:13:56.702', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1300000004, 1883382946094784512, '菜单管理', 'menuIndex', '/platform/menuManage', '/system/menu/index.vue', 'el-Guide', NULL, '1', '0', '0', NULL, NULL, 10, 2, 1, NULL, 1300000001, '2025-01-19 13:13:56.702', 1300000001, '2025-01-30 19:27:23.3832916', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881222457235480576, 1300000003, '机构管理', 'orgIndex', '/system/orgManage', '/system/org/index.vue', 'fa-sitemap', '', '1', '0', '0', '', '', 10009, 2, 1, NULL, 1300000001, '2025-01-20 14:09:19.8848362', 1300000001, '2025-01-30 19:25:06.9356138', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881503648907927552, 1300000003, '角色管理', 'roleIndex', '/system/rolemanage', '/system/role/index.vue', 'el-Avatar', '', '1', '0', '0', '', '', 10019, 2, 1, NULL, 1300000001, '2025-01-21 08:46:41.2039094', 1300000001, '2025-01-30 19:25:20.6951188', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881549094716055552, 1300000004, '查询', '', '', '', '', '', '1', '0', '0', '', 'menuIndex:page', 10029, 3, 1, NULL, 1300000001, '2025-01-21 11:47:16.3290049', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881549322898776064, 1300000004, '新增', '', '', '', '', '', '1', '0', '0', '', 'menuIndex:add', 10039, 3, 1, NULL, 1300000001, '2025-01-21 11:48:10.7325507', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881549479568613376, 1300000004, '编辑', '', '', '', '', '', '1', '0', '0', '', 'menuIndex:edit', 10049, 3, 1, NULL, 1300000001, '2025-01-21 11:48:48.0853661', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881549545742147584, 1300000004, '删除', '', '', '', '', '', '1', '0', '0', '', 'menuIndex:delete', 10059, 3, 1, NULL, 1300000001, '2025-01-21 11:49:03.8620944', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881549686175834112, 1881222457235480576, '查询', '', '', '', '', '', '1', '0', '0', '', 'orgIndex:page', 10069, 3, 1, NULL, 1300000001, '2025-01-21 11:49:37.3442189', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881549758976368640, 1881222457235480576, '新增', '', '', '', '', '', '1', '0', '0', '', 'orgIndex:add', 10079, 3, 1, NULL, 1300000001, '2025-01-21 11:49:54.7016825', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881549837590208512, 1881222457235480576, '编辑', '', '', '', '', '', '1', '0', '0', '', 'orgIndex:edit', 10089, 3, 1, NULL, 1300000001, '2025-01-21 11:50:13.4445591', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881549892451704832, 1881222457235480576, '删除', '', '', '', '', '', '1', '0', '0', '', 'orgIndex:delete', 10099, 3, 1, NULL, 1300000001, '2025-01-21 11:50:26.5242161', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881550091223965696, 1881503648907927552, '查询', '', '', '', '', '', '1', '0', '0', '', 'roleIndex:page', 10109, 3, 1, NULL, 1300000001, '2025-01-21 11:51:13.9159157', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881550170370482176, 1881503648907927552, '新增', '', '', '', '', '', '1', '0', '0', '', 'roleIndex:add', 10119, 3, 1, NULL, 1300000001, '2025-01-21 11:51:32.7855608', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881550231213056000, 1881503648907927552, '编辑', '', '', '', '', '', '1', '0', '0', '', 'roleIndex:edit', 10129, 3, 1, NULL, 1300000001, '2025-01-21 11:51:47.2918905', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881550282572308480, 1881503648907927552, '删除', '', '', '', '', '', '1', '0', '0', '', 'roleIndex:delete', 10139, 3, 1, NULL, 1300000001, '2025-01-21 11:51:59.5364969', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881550362545102848, 1881503648907927552, '数据权限', '', '', '', '', '', '1', '0', '0', '', 'roleIndex:data_type', 10149, 3, 1, NULL, 1300000001, '2025-01-21 11:52:18.6037307', 1300000001, '2025-01-21 19:21:20.1639355', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881662579596730368, 1300000003, '用户管理', 'userIndex', '/system/usermanage', '/system/user/index.vue', 'el-UserFilled', '', '1', '0', '0', '', '', 10159, 2, 1, NULL, 1300000001, '2025-01-21 19:18:13.2327844', 1300000001, '2025-01-30 19:25:37.8737317', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881662811004870656, 1881662579596730368, '查询', '', '', '', '', '', '1', '0', '0', '', 'userIndex:page', 10169, 3, 1, NULL, 1300000001, '2025-01-21 19:19:08.4050965', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881662934095110144, 1881662579596730368, '新增', '', '', '', '', '', '1', '0', '0', '', 'userIndex:add', 10179, 3, 1, NULL, 1300000001, '2025-01-21 19:19:37.7524318', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881662997173248000, 1881662579596730368, '编辑', '', '', '', '', '', '1', '0', '0', '', 'userIndex:edit', 10189, 3, 1, NULL, 1300000001, '2025-01-21 19:19:52.7915142', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881663062772162560, 1881662579596730368, '删除', '', '', '', '', '', '1', '0', '0', '', 'userIndex:delete', 10199, 3, 1, NULL, 1300000001, '2025-01-21 19:20:08.4310281', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881663313054670848, 1881662579596730368, '重置密码', '', '', '', '', '', '1', '0', '0', '', 'userIndex:reset_password', 10209, 3, 1, NULL, 1300000001, '2025-01-21 19:21:08.1029911', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881943420327567360, 1300000003, '职位管理', 'positionIndex', '/system/positionmanage', '/system/position/index.vue', 'el-GoldMedal', '', '1', '0', '0', '', '', 10219, 2, 1, NULL, 1300000001, '2025-01-22 13:54:10.8807082', 1300000001, '2025-01-30 19:26:04.5107975', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881943540813144064, 1881943420327567360, '查询', '', '', '', '', '', '1', '0', '0', '', 'positionIndex:page', 10229, 3, 1, NULL, 1300000001, '2025-01-22 13:54:39.6067668', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881943652230635520, 1881943420327567360, '新增', '', '', '', '', '', '1', '0', '0', '', 'positionIndex:add', 10239, 3, 1, NULL, 1300000001, '2025-01-22 13:55:06.1711463', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881943716881637376, 1881943420327567360, '编辑', '', '', '', '', '', '1', '0', '0', '', 'positionIndex:edit', 10249, 3, 1, NULL, 1300000001, '2025-01-22 13:55:21.5858833', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1881943791406030848, 1881943420327567360, '删除', '', '', '', '', '', '1', '0', '0', '', 'positionIndex:delete', 10259, 3, 1, NULL, 1300000001, '2025-01-22 13:55:39.3533765', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882349224964792320, 1883382946094784512, '租户管理', 'tenantIndex', '/platform/tenantmanage', '/system/tenant/index.vue', 'fa-building', '', '1', '0', '0', '', '', 10269, 2, 1, NULL, 1300000001, '2025-01-23 16:46:42.2464421', 1300000001, '2025-01-30 19:28:13.142124', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882349376454664192, 1882349224964792320, '查询', '', '', '', '', '', '1', '0', '0', '', 'tenantIndex:page', 10279, 3, 1, NULL, 1300000001, '2025-01-23 16:47:18.3645334', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882349465847865344, 1882349224964792320, '新增', '', '', '', '', '', '1', '0', '0', '', 'tenantIndex:add', 10289, 3, 1, NULL, 1300000001, '2025-01-23 16:47:39.6768931', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882349519795003392, 1882349224964792320, '删除', '', '', '', '', '', '1', '0', '0', '', 'tenantIndex:delete', 10299, 3, 1, NULL, 1300000001, '2025-01-23 16:47:52.5390664', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882349714918219776, 1882349224964792320, '启/禁用', '', '', '', '', '', '1', '0', '0', '', 'tenantIndex:open_close', 10309, 3, 1, NULL, 1300000001, '2025-01-23 16:48:39.0604536', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882586556456378368, 1883382946094784512, '数据字典', 'dataDictIndex', '/platform/datadictmanage', '/system/dataDict/index.vue', 'el-Files', '', '1', '0', '0', '', '', 10319, 2, 1, NULL, 1300000001, '2025-01-24 08:29:46.4833116', 1300000001, '2025-01-30 19:28:30.2912673', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882586772391731200, 1882586556456378368, '查询', '', '', '', '', '', '1', '0', '0', '', 'dataDictIndex:page', 10329, 3, 1, NULL, 1300000001, '2025-01-24 08:30:37.966009', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882586909759381504, 1882586556456378368, '新增', '', '', '', '', '', '1', '0', '0', '', 'dataDictIndex:add', 10339, 3, 1, NULL, 1300000001, '2025-01-24 08:31:10.7175733', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882586978227200000, 1882586556456378368, '编辑', '', '', '', '', '', '1', '0', '0', '', 'dataDictIndex:edit', 10349, 3, 1, NULL, 1300000001, '2025-01-24 08:31:27.0412233', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882587059437314048, 1882586556456378368, '编辑字典', '', '', '', '', '', '1', '0', '0', '', 'dataDictIndex:edit_dict', 10359, 3, 1, NULL, 1300000001, '2025-01-24 08:31:46.4034167', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1882587136541204480, 1882586556456378368, '删除', '', '', '', '', '', '1', '0', '0', '', 'dataDictIndex:delete', 10369, 3, 1, NULL, 1300000001, '2025-01-24 08:32:04.7865239', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883382946094784512, 0, '平台管理', 'platform', '/platform', 'Layout', 'el-Grid', '', '1', '0', '0', '', '', 10379, 1, 1, NULL, 1300000001, '2025-01-26 13:14:20.5693886', 1300000001, '2025-01-26 13:14:48.4761318', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883383621906210816, 1883382946094784512, 'Job管理', 'autoJobIndex', '/platform/autojobmanage', '/system/autoJob/index.vue', 'el-AlarmClock', '', '1', '0', '0', '', '', 10389, 2, 1, NULL, 1300000001, '2025-01-26 13:17:01.6950007', 1300000001, '2025-01-30 19:28:38.0339324', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883383816484167680, 1883383621906210816, '查询', '', '', '', '', '', '1', '0', '0', '', 'autoJobIndex:page', 10399, 3, 1, NULL, 1300000001, '2025-01-26 13:17:48.0861483', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883383938383224832, 1883383621906210816, '启用/暂停', '', '', '', '', '', '1', '0', '0', '', 'autoJobIndex:start_stop', 10409, 3, 1, NULL, 1300000001, '2025-01-26 13:18:17.1496513', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883384080838565888, 1883383621906210816, '延期', '', '', '', '', '', '1', '0', '0', '', 'autoJobIndex:deferred', 10419, 3, 1, NULL, 1300000001, '2025-01-26 13:18:51.1134849', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883488734456979456, 1883382946094784512, '登录日志', 'logLoginIndex', '/platform/logLogin', '/system/log/logLoginIndex.vue', 'el-Document', '', '1', '0', '0', '', '', 10429, 2, 1, NULL, 1300000001, '2025-01-26 20:14:42.480569', 1300000001, '2025-01-30 19:28:51.5467134', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883488963273039872, 1883488734456979456, '查询', '', '', '', '', '', '1', '0', '0', '', 'logLoginIndex:page', 10439, 3, 1, NULL, 1300000001, '2025-01-26 20:15:37.0342829', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883493046981632000, 1883382946094784512, 'Job日志', 'logJobIndex', '/platform/logJob', '/system/log/logJobIndex.vue', 'el-Document', '', '1', '0', '0', '', '', 10449, 2, 1, NULL, 1300000001, '2025-01-26 20:31:50.6662371', 1300000001, '2025-01-30 19:29:00.4065826', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883493141546409984, 1883493046981632000, '查询', '', '', '', '', '', '1', '0', '0', '', 'logJobIndex:page', 10459, 3, 1, NULL, 1300000001, '2025-01-26 20:32:13.2119815', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883499334012641280, 1883382946094784512, '事件日志', 'logEventIndex', '/platform/logevent', '/system/log/logEventIndex.vue', 'el-Document', '', '1', '0', '0', '', '', 10469, 2, 1, NULL, 1300000001, '2025-01-26 20:56:49.6114059', 1300000001, '2025-01-30 19:29:10.3446137', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883499428980072448, 1883499334012641280, '查询', '', '', '', '', '', '1', '0', '0', '', 'logEventIndex:page', 10479, 3, 1, NULL, 1300000001, '2025-01-26 20:57:12.2535472', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883502055633592320, 1883382946094784512, '差异日志', 'logDiffIndex', '/platform/logDiff', '/system/log/logDiffIndex.vue', 'el-Document', '', '1', '0', '0', '', '', 10489, 2, 1, NULL, 1300000001, '2025-01-26 21:07:38.49629', 1300000001, '2025-01-30 19:29:16.9988189', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883502134012551168, 1883502055633592320, '查询', '', '', '', '', '', '1', '0', '0', '', 'logDiffIndex:page', 10499, 3, 1, NULL, 1300000001, '2025-01-26 21:07:57.1829096', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883505043135668224, 1883382946094784512, '操作日志', 'logOperateIndex', '/platform/logOperate', '/system/log/logOperateIndex.vue', 'el-Document', '', '1', '0', '0', '', '', 10509, 2, 1, NULL, 1300000001, '2025-01-26 21:19:30.7723921', 1300000001, '2025-01-30 19:29:23.9668611', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883505240246984704, 1883382946094784512, '异常日志', 'logExceptionIndex', '/platform/logException', '/system/log/logExceptionIndex.vue', 'el-Document', '', '1', '0', '0', '', '', 10519, 2, 1, NULL, 1300000001, '2025-01-26 21:20:17.766827', 1300000001, '2025-01-30 19:29:30.5989651', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883505350582345728, 1883505043135668224, '查询', '', '', '', '', '', '1', '0', '0', '', 'logOperateIndex:page', 10529, 3, 1, NULL, 1300000001, '2025-01-26 21:20:44.0733588', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1883505428315381760, 1883505240246984704, '查询', '', '', '', '', '', '1', '0', '0', '', 'logExceptionIndex:page', 10539, 3, 1, NULL, 1300000001, '2025-01-26 21:21:02.60669', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1884778107420942336, 1300000003, '个人中心', 'personalCenterIndex', '/system/personalcenter', '/system/personalCenter/index.vue', 'fa-street-view', '', '1', '0', '0', '', '', 10549, 2, 1, NULL, 1300000001, '2025-01-30 09:38:12.9499722', 1300000001, '2025-01-30 19:26:41.1378333', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1884778243870040064, 1884778107420942336, '查询', '', '', '', '', '', '1', '0', '0', '', 'personalCenterIndex:view', 10559, 3, 1, NULL, 1300000001, '2025-01-30 09:38:45.4820811', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1884857795430457344, 1881662579596730368, '导出', '', '', '', '', '', '1', '0', '0', '', 'userIndex:export', 10569, 3, 1, NULL, 1300000001, '2025-01-30 14:54:52.0518358', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1884857884613943296, 1881662579596730368, '导入', '', '', '', '', '', '1', '0', '0', '', 'userIndex:import', 10579, 3, 1, NULL, 1300000001, '2025-01-30 14:55:13.3147822', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886302722643337216, 1300000003, '通知公告', 'publishmessage', '/system/publishmessage', '/system/message/publishIndex.vue', 'fa-desktop', '', '1', '0', '0', '', '', 10589, 2, 1, NULL, 1300000001, '2025-02-03 14:36:29.5449834', 1300000001, '2025-02-03 14:47:59.5327487', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886305270632685568, 1300000001, '站内信', 'receivemessage', '/system/receivemessage', '/system/message/receiveIndex.vue', 'fa-envelope-o', '', '1', '0', '0', '', '', 10599, 2, 1, NULL, 1300000001, '2025-02-03 14:46:37.0335095', 1300000001, '2025-02-03 14:47:18.9547777', 1300000001, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886305880748728320, 1886302722643337216, '查询', '', '', '', '', '', '1', '0', '0', '', 'publishIndex:page', 10609, 3, 1, NULL, 1300000001, '2025-02-03 14:49:02.4964854', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886305957932310528, 1886302722643337216, '新增', '', '', '', '', '', '1', '0', '0', '', 'publishIndex:add', 10619, 3, 1, NULL, 1300000001, '2025-02-03 14:49:20.8983917', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886306037544394752, 1886302722643337216, '编辑', '', '', '', '', '', '1', '0', '0', '', 'publishIndex:edit', 10629, 3, 1, NULL, 1300000001, '2025-02-03 14:49:39.8793455', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886306151197450240, 1886302722643337216, '删除', '', '', '', '', '', '1', '0', '0', '', 'publishIndex:delete', 10639, 3, 1, NULL, 1300000001, '2025-02-03 14:50:06.976169', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886369812943347712, 1886302722643337216, '发布', '', '', '', '', '', '1', '0', '0', '', 'publishIndex:publish', 10649, 3, 1, NULL, 1300000001, '2025-02-03 19:03:05.1189767', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886587042893275136, 1300000002, '查询', '', '', '', '', '', '1', '0', '0', '', 'dashboardIndex:page', 10659, 3, 1, NULL, 1300000001, '2025-02-04 09:26:16.7743615', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886587128931033088, 1886305270632685568, '查询', '', '', '', '', '', '1', '0', '0', '', 'receivemessage:page', 10669, 3, 1, NULL, 1300000001, '2025-02-04 09:26:37.2878619', 1300000001, NULL, NULL, '0'); +INSERT INTO "SysMenu" ("Id", "ParentId", "MenuName", "RouteName", "RoutePath", "ComponentPath", "MenuIcon", "RedirectPath", "IsCache", "OpenNewWindow", "IsAffix", "OutLink", "Permission", "Sort", "MenuType", "Status", "Remark", "CreateOrgId", "CreateTime", "CreateUserId", "UpdateTime", "UpdateUserId", "IsDelete") VALUES (1886613824367370240, 1886302722643337216, '撤回', '', '', '', '', '', '1', '0', '0', '', 'publishIndex:recalled', 10679, 3, 1, NULL, 1300000001, '2025-02-04 11:12:41.9759527', 1300000001, NULL, NULL, '0'); + diff --git a/API/Wood.Admin.WebApi/Filter/ApiAuthorizeAttribute.cs b/API/Wood.Admin.WebApi/Filter/ApiAuthorizeAttribute.cs new file mode 100644 index 0000000..183da84 --- /dev/null +++ b/API/Wood.Admin.WebApi/Filter/ApiAuthorizeAttribute.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; +using System; +using Wood.Util.JwtAuthorization; +using Microsoft.AspNetCore.Mvc.Authorization; +using System.Threading.Tasks; +using Wood.Cache; +using Wood.Entity.SystemManage; +using System.Linq; +using Wood.Data.Repository; +using Wood.Util; +using Wood.Service.SystemManage.Manager; +using Microsoft.AspNetCore.Identity; +using Wood.Entity; + +namespace Wood.Admin.WebApi.Filter +{ + public class ApiAuthorizeFilter : IAsyncAuthorizationFilter + { + private readonly ICache _cache; + private readonly UserManager _userManager; + + + public ApiAuthorizeFilter(ICache cache, UserManager userManager) + { + _cache = cache; + _userManager = userManager; + } + + + public async Task OnAuthorizationAsync(AuthorizationFilterContext context) + { + //控制器允许匿名访问 + if (context.ActionDescriptor.EndpointMetadata.Any(it => it.GetType() == typeof(AllowAnonymousAttribute))) + return; + //实现自定义的验证逻辑 + //有权限时不要设置 context.Result + //错误 + //context.Result = new BadRequestResult(); + //用户信息 + var userInfo = context.HttpContext.UserInfo(); + //用户信息不为空 而且 存在用户的缓存信息 表示用户登录中 + //否则需要重新登录 + if (userInfo != null && userInfo.UserId > 0) + { + //判断用户缓存是否存在 + if (_cache.GetCache(userInfo.CacheKey) != null) + return; + else + { + //缓存不存在 从数据库中重新加载用户信息 + await _userManager.InitCache(userInfo.UserId, DateTime.Now.AddMinutes(GlobalContext.JwtConfig!.TokenExpire)); + return; + } + } + //未授权 + context.Result = new UnauthorizedResult(); + return; + } + } +} diff --git a/API/Wood.Admin.WebApi/Filter/ApiExceptionFilter.cs b/API/Wood.Admin.WebApi/Filter/ApiExceptionFilter.cs new file mode 100644 index 0000000..2e82638 --- /dev/null +++ b/API/Wood.Admin.WebApi/Filter/ApiExceptionFilter.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System.Threading.Tasks; +using Wood.Entity; + +namespace Wood.Admin.WebApi.Filter +{ + /// + /// action 异常捕捉 filter + /// + public class ApiExceptionFilter : IAsyncExceptionFilter + { + /// + /// 异常捕捉 返回 + /// + /// + /// + public async Task OnExceptionAsync(ExceptionContext context) + { + // 设置统一的响应格式 + context.Result = new JsonResult(TData.Error(context.Exception.Message)) + { + StatusCode = StatusCodes.Status200OK + }; + + // 标记异常已处理 + context.ExceptionHandled = true; + + await Task.CompletedTask; + } + } + +} diff --git a/API/Wood.Admin.WebApi/Filter/ApiPerformanceLoggingFilter.cs b/API/Wood.Admin.WebApi/Filter/ApiPerformanceLoggingFilter.cs new file mode 100644 index 0000000..6c7cf1e --- /dev/null +++ b/API/Wood.Admin.WebApi/Filter/ApiPerformanceLoggingFilter.cs @@ -0,0 +1,135 @@ +using Mapster; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Newtonsoft.Json; +using SqlSugar.Extensions; +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.EventBus; +using Wood.EventBus.Events; +using Wood.Util; +using Wood.Util.JwtAuthorization; + +namespace Wood.Admin.WebApi.Filter +{ + /// + /// 性能统计 + /// + public class ApiPerformanceLoggingFilter : ActionFilterAttribute + { + private readonly IEventBus _eventBus; + /// + /// + /// + /// + public ApiPerformanceLoggingFilter(IEventBus eventBus) + { + _eventBus = eventBus; + } + + /// + /// 异步接口日志 + /// + /// + /// + /// + public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + Stopwatch sw = new Stopwatch(); + if (context.ModelState.IsValid) + { + sw.Start(); + var resultContext = await next(); + sw.Stop(); + var user = context.HttpContext.UserInfo(); + #region 保存日志 + LogOperationEntity logOperationEntity = new LogOperationEntity(); + logOperationEntity.RequestUrl = context.HttpContext.Request.Path; + logOperationEntity.Elapsed = (int)sw.ElapsedMilliseconds; + logOperationEntity.Browser = NetHelper.Browser; + logOperationEntity.Os = NetHelper.GetOSVersion(); + logOperationEntity.LogDateTime = DateTime.Now; + logOperationEntity.CreateTime = DateTime.Now; + logOperationEntity.CreateUserId = user?.UserId; + logOperationEntity.UserName = user?.UserName; + logOperationEntity.RealName = user?.RealName; + logOperationEntity.HttpMethod = context.HttpContext.Request.Method.ToUpper(); + logOperationEntity.IpAddress = NetHelper.Ip; + logOperationEntity.ControllerName = context.Controller.GetType().Name; + logOperationEntity.ActionName = context.RouteData.Values["action"]?.ToString(); + logOperationEntity.MethodName = context.ActionDescriptor.DisplayName; + + #region 获取Post参数 + switch (logOperationEntity.HttpMethod) + { + case "GET": + logOperationEntity.RequestParam = context.HttpContext.Request.QueryString.Value; + break; + + case "POST": + default: + if (context.ActionArguments?.Count > 0) + { + logOperationEntity.RequestUrl += context.HttpContext.Request.QueryString.Value; + logOperationEntity.RequestParam = JsonConvert.SerializeObject(context.ActionArguments); + } + else + logOperationEntity.RequestParam = context.HttpContext.Request.QueryString.Value; + break; + } + #endregion + if (resultContext.Exception != null) + { + var logExceptionEntity = logOperationEntity.Adapt(); + + logExceptionEntity.ReturnResult = resultContext.Exception.GetFullExceptionMessage(); + + logExceptionEntity.Exception = resultContext.Exception.GetFullExceptionMessage(); + logExceptionEntity.ExceptionStackTrace = resultContext.Exception.StackTrace; + logExceptionEntity.Source = this.GetType().Name; + + _eventBus.Publish(new LogExceptionEvent(logExceptionEntity)); + } + else + { + ObjectResult? result = resultContext.Result as ObjectResult; + if (result != null) + logOperationEntity.ReturnResult = JsonConvert.SerializeObject(result.Value); + } + _eventBus.Publish(new LogOperationEvent() { Payload = logOperationEntity }); + #endregion + } + else + { + var errors = string.Join("; ", context.ModelState.GetAllErrorMessages()); + + var user = context.HttpContext.UserInfo(); + LogOperationEntity logOperationEntity = new LogOperationEntity(); + logOperationEntity.RequestUrl = context.HttpContext.Request.Path; + logOperationEntity.Elapsed = (int)sw.ElapsedMilliseconds; + logOperationEntity.Browser = NetHelper.Browser; + logOperationEntity.Os = NetHelper.GetOSVersion(); + logOperationEntity.LogDateTime = DateTime.Now; + logOperationEntity.CreateTime = DateTime.Now; + logOperationEntity.CreateUserId = user?.UserId; + logOperationEntity.UserName = user?.UserName; + logOperationEntity.RealName = user?.RealName; + logOperationEntity.HttpMethod = context.HttpContext.Request.Method.ToUpper(); + logOperationEntity.IpAddress = NetHelper.Ip; + logOperationEntity.ControllerName = context.Controller.GetType().Name; + logOperationEntity.ActionName = context.RouteData.Values["action"]?.ToString(); + logOperationEntity.MethodName = context.ActionDescriptor.DisplayName; + logOperationEntity.Message = "ModelStateError"; + logOperationEntity.ReturnResult = errors; + + _eventBus.Publish(new LogOperationEvent() { Payload = logOperationEntity }); + + context.Result = new ObjectResult(TData.Error(errors)); + } + + } + } +} diff --git a/API/Wood.Admin.WebApi/Filter/ApiResponseWrapperFilter.cs b/API/Wood.Admin.WebApi/Filter/ApiResponseWrapperFilter.cs new file mode 100644 index 0000000..47c1650 --- /dev/null +++ b/API/Wood.Admin.WebApi/Filter/ApiResponseWrapperFilter.cs @@ -0,0 +1,117 @@ +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Wood.Entity; +using System.Net; +using Azure; + +namespace Wood.Admin.WebApi.Filter +{ + /// + /// action结果包装filter + /// + public class ApiResponseWrapperFilter : IAsyncResultFilter + { + /// + /// + /// + /// + /// + /// + public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) + { + //检查当前结果是否是 ObjectResult + if (context.Result is ObjectResult objectResult && objectResult.Value != null) + { + if (objectResult.Value is TData) + { + await next(); + return; + } + + var wrappedResponse = TData.Success(); + wrappedResponse.Data = objectResult.Value; + + // 修改响应内容 + context.Result = new JsonResult(wrappedResponse) + { + StatusCode = (int)HttpStatusCode.OK + }; + } + else if (context.Result is EmptyResult) + { + var wrappedResponse = TData.Success(); + // 修改响应内容 + context.Result = new JsonResult(wrappedResponse) + { + StatusCode = (int)HttpStatusCode.OK + }; + } + else if (context.Result is StatusCodeResult statusCodeResult) + { + // 处理非成功的状态码 + var wrappedResponse = new TData + { + Code = 0, + Message = $"Error with status code: {statusCodeResult.StatusCode}" + }; + + context.Result = new JsonResult(wrappedResponse) + { + StatusCode = statusCodeResult.StatusCode + }; + } + else if (context.Result is BadRequestObjectResult badRequestResult) + { + // 处理 Bad Request + var wrappedResponse = new TData + { + Code = 0, + Data = badRequestResult.Value, + Message = "Bad request" + }; + + context.Result = new JsonResult(wrappedResponse) + { + StatusCode = badRequestResult.StatusCode + }; + } + else if (context.Result is NotFoundResult notFoundResult) + { + // 处理 Not Found + var wrappedResponse = new TData + { + Code = 0, + Message = "Resource not found" + }; + + context.Result = new JsonResult(wrappedResponse) + { + StatusCode = StatusCodes.Status404NotFound + }; + } + else if (context.Result is UnauthorizedResult unauthorizedResult) + { + // 处理 Unauthorized + var wrappedResponse = new TData + { + Code = 0, + Message = "Unauthorized access" + }; + + context.Result = new JsonResult(wrappedResponse) + { + StatusCode = StatusCodes.Status401Unauthorized + }; + } + else if (context.Result is FileStreamResult || context.Result is FileResult) + { + //设置头部 否则前端接受不到文件名称 + context.HttpContext.Response.Headers?.Append("Access-Control-Expose-Headers", "Content-Disposition"); + } + // next 必须放在后边 + await next(); + } + } +} diff --git a/API/Wood.Admin.WebApi/Middleware/FileServerMiddleware.cs b/API/Wood.Admin.WebApi/Middleware/FileServerMiddleware.cs new file mode 100644 index 0000000..2fcabba --- /dev/null +++ b/API/Wood.Admin.WebApi/Middleware/FileServerMiddleware.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Http; +using System.Net; +using System.Threading.Tasks; + +namespace Wood.Admin.WebApi.Middleware +{ + public class FileBridgeMiddleware + { + private readonly RequestDelegate _next; + + public FileBridgeMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + if (context.Request.Path.ToString().Contains("fromBucket/xxx(仓储名字)")) + { + //拦截到仓储文件的路径 读取文件返回 + byte[] filebytes = new byte[0]; + context.Response.StatusCode = (int)HttpStatusCode.OK; + await context.Response.Body.WriteAsync(filebytes); + await context.Response.Body.FlushAsync(); + } + else + { + // Call the next delegate/middleware in the pipeline. + await _next(context); + } + } + } +} diff --git a/API/Wood.Admin.WebApi/Middleware/GlobalExceptionMiddleware.cs b/API/Wood.Admin.WebApi/Middleware/GlobalExceptionMiddleware.cs new file mode 100644 index 0000000..00eb4ff --- /dev/null +++ b/API/Wood.Admin.WebApi/Middleware/GlobalExceptionMiddleware.cs @@ -0,0 +1,81 @@ +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json; +using System; +using System.Net; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.EventBus; +using Wood.EventBus.Events; +using Wood.Util; + +namespace Wood.Admin.WebApi.Middleware +{ + /// + /// 全局异常中间件 + /// + public class GlobalExceptionMiddleware + { + private readonly RequestDelegate _next; + private readonly IEventBus _eventBus; + /// + /// 全局异常中间件 + /// + /// + /// + public GlobalExceptionMiddleware(RequestDelegate next, IEventBus eventBus) + { + _next = next; + _eventBus = eventBus; + } + /// + /// + /// + /// + /// + public async Task Invoke(HttpContext context /* other dependencies */) + { + try + { + await _next(context); + } + catch (Exception ex) + { + await HandleExceptionAsync(context, ex); + } + } + /// + /// + /// + /// + /// + /// + private Task HandleExceptionAsync(HttpContext context, Exception exception) + { + var user = GlobalContext.UserInfo; + + var entity = new Entity.SystemManage.LogExceptionEntity + { + UserName = user?.UserName, + RealName = user?.RealName, + HttpMethod = context.Request.Method.ToUpper(), + Browser = NetHelper.Browser, + Os = NetHelper.GetOSVersion(), + Exception = exception.GetFullExceptionMessage(), + ExceptionStackTrace = exception.StackTrace, + Elapsed = 0, + LogDateTime = DateTime.Now, + IpAddress = NetHelper.Ip, + Source = this.GetType().Name, + }; + + entity.RequestUrl = context.Request.Path; + entity.RequestParam = context.Request.QueryString.Value; + _eventBus.Publish(new LogExceptionEvent(entity)); + + var code = HttpStatusCode.OK; + context.Response.ContentType = "application/json"; + context.Response.StatusCode = (int)code; + return context.Response.WriteAsync(JsonConvert.SerializeObject(TData.Error())); + } + } +} diff --git a/API/Wood.Admin.WebApi/Middleware/ModelBindingMetadataProvider.cs b/API/Wood.Admin.WebApi/Middleware/ModelBindingMetadataProvider.cs new file mode 100644 index 0000000..f904bd3 --- /dev/null +++ b/API/Wood.Admin.WebApi/Middleware/ModelBindingMetadataProvider.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; + +namespace Wood.Admin.WebApi.Middleware +{ + /// + /// Controller Model Binding 处理 + /// + public class ModelBindingMetadataProvider : IMetadataDetailsProvider, IDisplayMetadataProvider + { + /// + /// + /// + /// + public void CreateDisplayMetadata(DisplayMetadataProviderContext context) + { + if (context.Key.MetadataKind == ModelMetadataKind.Property) + { + context.DisplayMetadata.ConvertEmptyStringToNull = false; + } + } + } +} diff --git a/API/Wood.Admin.WebApi/Other/AutoRouteConvention.cs b/API/Wood.Admin.WebApi/Other/AutoRouteConvention.cs new file mode 100644 index 0000000..136c714 --- /dev/null +++ b/API/Wood.Admin.WebApi/Other/AutoRouteConvention.cs @@ -0,0 +1,127 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ActionConstraints; +using Microsoft.AspNetCore.Mvc.ApplicationModels; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Routing.Template; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Wood.Util; + +namespace Wood.Admin.WebApi +{ + /// + /// 自动扫描所有带service名称的程序集 + /// 扫描程序集中所有带service后缀的类 + /// 给类中所有public 方法注册路由 + /// + public class AutoRouteConvention : IApplicationModelConvention + { + private readonly string _baseRoutePrefix = "api"; + + /// + /// 应用路由规则 + /// get 开头为 get + /// 其他为post + /// + /// + public void Apply(ApplicationModel application) + { + foreach (var controller in application.Controllers) + { + var controllerName = controller.ControllerName.ToLowerInvariant().Replace("service", ""); + + foreach (var action in controller.Actions) + { + var actionName = action.ActionName.ToLowerInvariant(); + var httpMethod = "POST"; + var isGetMethod = false; + if (!action.Selectors.Any() || !action.Selectors[0].ActionConstraints.Any()) + { + if (actionName.StartsWith("get")) + { + httpMethod = "GET"; + actionName = actionName.Substring(3); + isGetMethod = true; + } + else if (actionName.StartsWith("post")) + { + httpMethod = "POST"; + actionName = actionName.Substring(4); + } + + // 构建路由模板 + var routeTemplate = $"{_baseRoutePrefix}/{controllerName}/{actionName}"; + + if (action.Selectors.Any()) + { + //当前已经有了 Selectors 信息则直接设置 + action.Selectors[0].AttributeRouteModel = new AttributeRouteModel { Template = routeTemplate }; + action.Selectors[0].ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod })); + } + else + { + //当前没有 Selectors 信息则直接新增 + var selectorModel = new SelectorModel + { + AttributeRouteModel = new AttributeRouteModel { Template = routeTemplate }, + }; + selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { httpMethod })); + + action.Selectors.Add(selectorModel); + } + } + else + { + // 构建路由模板 + var routeTemplate = $"{_baseRoutePrefix}/{controllerName}/{actionName}"; + //重新指定路由路径 + action.Selectors[0].AttributeRouteModel = new AttributeRouteModel { Template = routeTemplate }; + //是否get请求 + isGetMethod = action.Attributes.Any(it => it.GetType() == typeof(HttpGetAttribute)); + } + + //查找所有没有绑定来源的参数 + IEnumerable noBindModels = action.Parameters.Where(it => it.BindingInfo == null); + + if (noBindModels.Any()) + { + // 设置参数来源:GET 请求的参数来自 URL,POST 请求的参数来自请求体 + // 只会设置没有明确指定来源的参数 + // Get 会加上 FromQuery + // Post 会加上 FromBody (只有第一个参数加上 Frombody 多个参数会报错!) + if (isGetMethod) + { + foreach (var parameter in noBindModels) + { + var bindId = parameter.BindingInfo?.BindingSource?.Id; + if (string.IsNullOrEmpty(bindId)) + { + // 对于 GET 请求,默认情况下参数应该来自于查询字符串或路径 + parameter.BindingInfo = new BindingInfo() { BindingSource = BindingSource.Query }; + // 对于 GET 请求,默认情况下参数应该来自于 URL + //parameter.BindingInfo = new BindingInfo() { BindingSource = BindingSource.Path }; + } + } + } + else + { + if (noBindModels.Count() > 1) + throw Oops.Oh($"系统不支持Post请求FromBody绑定多个参数,请改成一个。路径:Controller({controller.ControllerName})Action({action.ActionName})"); + else + { + if (action.Parameters.Any(it => it.BindingInfo?.BindingSource?.Id == "Body")) + throw Oops.Oh($"系统不支持Post请求FromBody绑定多个参数,请改成一个。路径:Controller({controller.ControllerName})Action({action.ActionName})"); + noBindModels.First().BindingInfo = new BindingInfo() { BindingSource = BindingSource.Body }; + } + } + } + + } + } + } + } +} diff --git a/API/Wood.Admin.WebApi/Other/ServiceCollectionExtensions.cs b/API/Wood.Admin.WebApi/Other/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..dfeb160 --- /dev/null +++ b/API/Wood.Admin.WebApi/Other/ServiceCollectionExtensions.cs @@ -0,0 +1,214 @@ +using Magicodes.ExporterAndImporter.Core; +using Magicodes.ExporterAndImporter.Excel; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using SqlSugar; +using System; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Wood.AutoJob; +using Wood.Cache; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.EventBus; +using Wood.MemoryCache; +using Wood.RedisCache; +using Wood.Util; + +namespace Wood.Admin.WebApi +{ + /// + /// 服务拓展 + /// + public static class ServiceCollectionExtensions + { + /// + /// 扫描指定程序集中的所有类型,并根据其实现的生命周期接口自动注册到DI容器中。 + /// + /// 服务集合 + /// 要扫描的程序集数组 + public static void ScanAndRegisterLifeTimes(this IServiceCollection services, params Assembly[] assemblies) + { + var lifeTimeServices = typeof(ILifeTimeService); + + foreach (var assembly in assemblies) + { + // 获取实现了 ILifeTimeService 的非抽象类 + var types = assembly.GetTypes() + .Where(t => !t.IsAbstract && t.IsClass && lifeTimeServices.IsAssignableFrom(t)); + + foreach (var type in types) + { + // 查找实现了哪些生命周期接口 + var lifeTimeInterfaces = type.GetInterfaces() + .Where(i => i != lifeTimeServices && lifeTimeServices.IsAssignableFrom(i)) + .ToList(); + + if (!lifeTimeInterfaces.Any()) + { + continue; // 如果没有实现任何生命周期接口,则跳过此类型 + } + + // 根据第一个匹配的生命周期接口注册服务 + var lifeTimeInterface = lifeTimeInterfaces.First(); + if (typeof(ITransient).IsAssignableFrom(lifeTimeInterface)) + { + services.AddTransient(type, type); + } + else if (typeof(IScoped).IsAssignableFrom(lifeTimeInterface)) + { + services.AddScoped(type, type); + } + else if (typeof(ISingleton).IsAssignableFrom(lifeTimeInterface)) + { + services.AddSingleton(type, type); + } + } + } + } + + #region eventbus 初始化 + public static IServiceCollection AddEventBus(this IServiceCollection services) + { + services.AddSingleton(); + return services; + } + + /// + /// 自动注册所有订阅事件 + /// + /// + public static void UseEventBus(this IApplicationBuilder app, Assembly[] assemblies) + { + var eventBus = GlobalContext.ServiceProvider!.GetRequiredService(); + foreach (var assembly in assemblies) + { + var types = assembly.GetTypes() + .Where(t => t.IsClass && !t.IsAbstract) + .SelectMany(t => t.GetInterfaces(), (t, i) => new { Type = t, Interface = i }) + .Where(x => x.Interface.IsGenericType && x.Interface.GetGenericTypeDefinition() == typeof(IIntegrationEventHandler<>)); + + foreach (var type in types) + { + var eventType = type.Interface.GetGenericArguments()[0]; + var handlerType = type.Type; + var handlerInstance = (dynamic)GlobalContext.ServiceProvider!.GetService(handlerType)!; + var eventName = eventType.Name; + var subscribeMethod = typeof(InMemoryEventBus).GetMethod("Subscribe")!.MakeGenericMethod(eventType, handlerType); + subscribeMethod.Invoke(eventBus, new object[] { handlerInstance }); + } + } + } + #endregion + + #region autoJob 初始化 + public static void UseAutoJob(this IApplicationBuilder app) + { + Task.Run(async () => + { + if (GlobalContext.SystemConfig!.RunAutoJob) + { + //延迟 5s + await Task.Delay(5 * 1000); + try + { + + AutoJobCenter jobCenter = new AutoJobCenter(); + jobCenter.ScanJob(); + await jobCenter.AddScheduleJob(); + } + catch (Exception ex) + { + Log.Error(ex, "初始化自动job失败!"); + } + } + }); + } + #endregion + + #region sqlsugar初始化 + // + /// SqlSugar 上下文初始化 + /// + /// + public static void AddSqlSugar(this IServiceCollection services, IConfiguration configuration) + { + // 自定义 SqlSugar 雪花ID算法 + SnowFlakeSingle.WorkId = GlobalContext.SystemConfig!.SnowFlakeWorkerId; + + if (Enum.TryParse(GlobalContext.SystemConfig.DBProvider, true, out SqlSugar.DbType dbType)) + { + services.AddSingleton(s => + { + SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig() + { + ConnectionString = GlobalContext.SystemConfig.DBConnectionString, + DbType = dbType, + IsAutoCloseConnection = true + }, db => + { + SqlSugarDbContext.SetDbDiffLog(db.Context); + SqlSugarDbContext.SetDbAop(db.Context); + }); + return sqlSugar; + }); // 单例注册 + services.AddScoped(typeof(SqlSugarRepository<>)); // 仓储注册 + services.AddTransient(); // 事务与工作单元注册 + + } + else + throw Oops.Oh("不支持的数据库类型!"); + } + + /// + /// 初始化数据库 + /// + /// + public static void UseSqlSugar(this IApplicationBuilder app) + { + var sqlsugar = GlobalContext.ServiceProvider!.GetService(); + // 初始化数据库表结构及种子数据 + SqlSugarDbContext.InitDatabase(sqlsugar!); + } + #endregion + /// + /// 开启缓存 + /// + /// + /// + public static IServiceCollection AddCache(this IServiceCollection services) + { + switch (GlobalContext.SystemConfig!.CacheProvider) + { + case "Redis": services.AddSingleton(); break; + + default: + case "Memory": services.AddSingleton(); break; + } + ; + return services; + } + + /// + /// Magicodes + /// 导入导出 + /// + /// + /// + public static IServiceCollection AddMagicodesIE(this IServiceCollection services) + { + // 注册 Excel 导出器 + services.AddSingleton(); + services.AddSingleton(); + + // 如果需要支持其他格式(如 PDF、Word 等),可以在这里添加相应的导出器 + // services.AddSingleton(); + // services.AddSingleton(); + + return services; + } + } +} diff --git a/API/Wood.Admin.WebApi/Program.cs b/API/Wood.Admin.WebApi/Program.cs new file mode 100644 index 0000000..e60b116 --- /dev/null +++ b/API/Wood.Admin.WebApi/Program.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using Serilog; +using System; + +namespace Wood.Admin.WebApi +{ + /// + /// program + /// + public class Program + { + /// + /// main + /// + /// + public static void Main(string[] args) + { + // 创建并配置Serilog Logger + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Information() // 设置最低日志级别 + .Enrich.FromLogContext() // 增加上下文信息 + .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}") // 输出到控制台模板 + .WriteTo.File("logs\\log.txt", + rollingInterval: RollingInterval.Day,// 按天分割,每天滚动创建新的日志文件 + retainedFileCountLimit: 90,// 只保存最近90天的日志 + fileSizeLimitBytes: 10_485_760, // 文件大小限制为10MB (10 * 1024 * 1024 bytes) + rollOnFileSizeLimit: true, // 达到文件大小限制时滚动 + outputTemplate: "{NewLine}{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff} LogLevel:{Level}{NewLine}{Message}{NewLine}" + new string('-', 50) + "{NewLine}"// 模板 + ) + .CreateLogger(); + try + { + // 创建Host + CreateHostBuilder(args).Build().Run(); + } + catch (Exception ex) + { + Log.Fatal(ex, "Host terminated unexpectedly"); + } + finally + { + Log.CloseAndFlush(); + } + } + + /// + /// 启用 + /// + /// + /// + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .UseSerilog() // 使用Serilog作为日志提供者 + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + + } +} diff --git a/API/Wood.Admin.WebApi/Properties/launchSettings.json b/API/Wood.Admin.WebApi/Properties/launchSettings.json new file mode 100644 index 0000000..008eead --- /dev/null +++ b/API/Wood.Admin.WebApi/Properties/launchSettings.json @@ -0,0 +1,22 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:7001", + "sslPort": 0 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "Wood.Admin.WebApi": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api-doc", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:7001" + } + } +} \ No newline at end of file diff --git a/API/Wood.Admin.WebApi/Startup.cs b/API/Wood.Admin.WebApi/Startup.cs new file mode 100644 index 0000000..90d9121 --- /dev/null +++ b/API/Wood.Admin.WebApi/Startup.cs @@ -0,0 +1,346 @@ +using Hangfire; +using Hangfire.SqlServer; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Quartz; +using Swashbuckle.AspNetCore.Filters; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using TaskManager.Controllers; +using TaskManager.EntityFramework; +using Wood.Admin.WebApi.Filter; +using Wood.Admin.WebApi.Middleware; +using Wood.Util; + +namespace Wood.Admin.WebApi +{ + /// + /// 入口 + /// + public class Startup + { + /// + /// 配置 + /// + public IConfiguration Configuration { get; } + /// + /// 构造函数 + /// + /// + /// + public Startup(IConfiguration configuration, IWebHostEnvironment env) + { + Configuration = configuration; + GlobalContext.LogWhenStart(env); + GlobalContext.HostingEnvironment = env; + } + + /// + /// This method gets called by the runtime. Use this method to add services to the container. + /// + /// + public void ConfigureServices(IServiceCollection services) + { + services.AddHttpContextAccessor(); + + //初始化配置 + GlobalContext.SystemConfig = Configuration.GetSection("SystemConfig").Get()!; + GlobalContext.JwtConfig = Configuration.GetSection("JwtConfig").Get()!; + GlobalContext.Services = services; + GlobalContext.Configuration = Configuration; + //初始化 eventbus + services.AddEventBus(); + + //初始化数据库 + services.AddSqlSugar(Configuration); + + + + + services.AddHttpClient(); + services.AddTransient(); + services.AddTransient(); + + services.AddTransient(); + + // 配置 DbContext 使用 SQL Server 连接字符串 + services.AddDbContext(options => + options.UseSqlServer(GlobalContext.SystemConfig.CustomerDb)); + + // 配置 Hangfire 使用 SQL Server 存储 + services.AddHangfire( + + + configuration => configuration + .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) // 建议显式设置兼容性版本 + .UseSimpleAssemblyNameTypeSerializer() // 简化类型序列化(可选) + .UseRecommendedSerializerSettings() // 使用推荐的序列化设置(可选) + .UseSqlServerStorage(GlobalContext.SystemConfig.CustomerDb, new SqlServerStorageOptions + { + // 可从配置中读取 Hangfire 存储选项(如队列、重试策略等) + CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), + SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), + QueuePollInterval = TimeSpan.Zero, + UseRecommendedIsolationLevel = true, + DisableGlobalLocks = true + }) + //.UseFilter(services.BuildServiceProvider().GetRequiredService>()) + ); // 添加日志过滤器(可选) + services.AddHangfireServer(options => + { + options.WorkerCount = 10; + // 可选:配置队列优先级 + //options.Queues = builder.Configuration.GetSection("Hangfire:ServerOptions:Queues").Get() ?? new[] { "default" }; + + }); + + + + + + //注册控制器 + services.AddControllers(options => + { + //自动扫描注册控制器 + options.Conventions.Add(new AutoRouteConvention()); + //options.ModelMetadataDetailsProviders.Add(new ModelBindingMetadataProvider()); + // 添加全局授权过滤器 + options.Filters.Add(typeof(ApiAuthorizeFilter)); + //options.Filters.Add(typeof(AuthorizeFilter)); + //异常处理 + options.Filters.Add(typeof(ApiExceptionFilter)); + //性能记录,日志记录 + options.Filters.Add(typeof(ApiPerformanceLoggingFilter)); + //结果包装 + options.Filters.Add(typeof(ApiResponseWrapperFilter)); + }) + .AddNewtonsoftJson(options => + { + // Json序列化设置 + options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local; + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; // 时间格式化 + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 忽略循环引用 + //options.SerializerSettings.ContractResolver = new DefaultContractResolver(); //对象属性名大写 + options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // 对象属性名小写 + //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; // 忽略空值 + options.SerializerSettings.Converters.Add(new LongToStringJsonConverter()); // long转string(防止js精度溢出) 超过16位开启 + options.SerializerSettings.Converters.Add(new NullableLongToStringJsonConverter()); // long转string(防止js精度溢出) 超过16位开启 + + //options.SerializerSettings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore; // 解决DateTimeOffset异常 + //options.SerializerSettings.DateParseHandling = DateParseHandling.None; // 解决DateTimeOffset异常 + //options.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = System.Globalization.DateTimeStyles.AssumeUniversal }); // 解决DateTimeOffset异常 + }); + + //添加跨域 + services.AddCors(); + + //添加缓存支持 + services.AddMemoryCache(); + + //初始化缓存 + services.AddCache(); + + //添加 Magicodes.IE 导入导出支持 + services.AddMagicodesIE(); + + //services.AddOptions(); + + //数据保护服务用于加密敏感数据,如身份验证 cookie 和抗请求伪造令牌。 + //默认情况下,数据保护密钥存储在临时目录中,这可能导致在重启后丢失密钥,从而导致用户会话失效等问题 + //通过 PersistKeysToFileSystem 方法,可以将密钥存储在一个指定的目录中,确保密钥在应用程序重启后仍然可用 + //services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(GlobalContext.HostingEnvironment.ContentRootPath + Path.DirectorySeparatorChar + "DataProtection")); + + //默认情况下,.NET Core 不包含所有旧版 Windows 编码(如 GBK、GB2312 等),这些编码通常在处理某些旧系统或特定文件格式时需要。 + //通过注册 CodePagesEncodingProvider,可以启用这些额外的编码支持 + //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // 注册Encoding + + //注册jwt验证服务 + services.AddAuthentication(options => + { + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuer = true, //是否验证Issuer + ValidIssuer = Configuration["JwtConfig:Issuer"], //发行人Issuer + ValidateAudience = true, //是否验证Audience + ValidAudience = Configuration["JwtConfig:Audience"], //订阅人Audience + ValidateIssuerSigningKey = true, //是否验证SecurityKey + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtConfig:SecretKey"]!)), //SecurityKey + ValidateLifetime = true, //是否验证失效时间 + ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值,解决服务器端时间不同步问题(秒) + RequireExpirationTime = true, + }; + }); + + //身份验证 + services.AddAuthorization(); + + // 添加 Quartz 服务 + services.AddQuartz(q => + { + q.UseSimpleTypeLoader(); + }); + + //获取所有Service业务层进行扫描注入 + //业务层命名格式:Wood.xxx.Service + //需要注释的情况下在 Service 业务层开启 xml注释 生成 + Assembly[] assembly = AppDomain.CurrentDomain.GetAssemblies().Where(it => !string.IsNullOrEmpty(it.FullName) && it.FullName.StartsWith("Wood") && it.FullName.Contains(".Service,")).ToArray(); + //扫描依赖注入 + services.ScanAndRegisterLifeTimes(assembly); + + //swagger + services.AddSwaggerGen(options => + { + foreach (var item in assembly) + { + var xmlPath = Path.Combine(AppContext.BaseDirectory, $"{item.GetName().Name}.xml"); + if (File.Exists(xmlPath)) + options.IncludeXmlComments(xmlPath, true); + + options.SwaggerDoc(item.GetName().Name, new OpenApiInfo { Title = "Wood Api", Version = "v1" }); + } + + //根据不同程序集生成不同分组 + options.DocInclusionPredicate((docName, apiDesc) => + { + return apiDesc.ActionDescriptor.DisplayName?.Contains(docName) ?? false; + }); + + #region swagger 身份验证 + // 创建一个新的安全方案对象,用于描述如何进行身份验证。 + var securityScheme = new OpenApiSecurityScheme + { + // 设置安全方案的名称,通常与 HTTP 请求头字段匹配。 + Name = "Authorization", + // 指定安全方案的类型为 API 密钥(在这里特指 JWT Bearer Token)。 + Type = SecuritySchemeType.ApiKey, + // 指定 API 密钥的位置,这里是 HTTP 请求头。 + In = ParameterLocation.Header, + // 提供关于如何使用该安全方案的说明,例如在 Swagger UI 中显示给用户。 + Description = "请在头信息中使用JWT Token进行身份验证 (例如: 'Bearer YOUR_TOKEN_HERE')", + // 设置安全方案的模式,这里是 Bearer 类型的身份验证。 + Scheme = "Bearer", + // 设置 Bearer Token 的格式,这里指定为 JWT。 + //BearerFormat = "JWT" + }; + + // 将创建的安全方案添加到 Swagger 文档中,以便 Swagger UI 可以识别并应用它。 + options.AddSecurityDefinition("Bearer", securityScheme); + // 添加安全要求 + // 添加Jwt验证设置,添加请求头信息 + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "Bearer", + Type = ReferenceType.SecurityScheme + } + }, + new List() + } + }); + + options.OperationFilter(); + options.OperationFilter(); + options.OperationFilter(); + #endregion + }); + } + + /// + /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + /// + /// + /// + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseDeveloperExceptionPage(); + } + + //必须放在最前边 把 根 ServiceProvider 放入到全局 + GlobalContext.ServiceProvider = app.ApplicationServices; + + //初始化sqlsugar数据库结构 + app.UseSqlSugar(); + app.UseHangfireDashboard(); + + //自定义静态文件路径 + //string resource = Path.Combine(env.ContentRootPath, "Resource"); + //FileHelper.CreateDirectory(resource); + + //app.UseStaticFiles(new StaticFileOptions + //{ + // RequestPath = "/Resource", + // FileProvider = new PhysicalFileProvider(resource), + // OnPrepareResponse = GlobalContext.SetCacheControl + //}); + app.UseStaticFiles(); + //全局异常 + app.UseMiddleware(typeof(GlobalExceptionMiddleware)); + //文件拦截中间件 + app.UseMiddleware(); + + app.UseCors(builder => + { + builder.WithOrigins(GlobalContext.SystemConfig!.AllowCorsSite.Split(',')).AllowAnyHeader().AllowAnyMethod().AllowCredentials(); + }); + app.UseRouting(); + + // 使用身份验证中间件 + app.UseAuthentication(); + // 使用授权中间件 + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllerRoute("default", "{controller=ApiHome}/{action=Index}/{id?}"); + }); + + //启用 自动job + app.UseAutoJob(); + + //获取所有Service业务层 扫描事件 + //业务层命名格式:Wood.xxx.Service + Assembly[] assembly = AppDomain.CurrentDomain.GetAssemblies().Where(it => !string.IsNullOrEmpty(it.FullName) && it.FullName.StartsWith("Wood") && it.FullName.Contains(".Service,")).ToArray(); + + app.UseSwagger(c => + { + c.RouteTemplate = "api-doc/{documentName}/swagger.json"; + }); + //根据程序集注册选项 + app.UseSwaggerUI(c => + { + c.RoutePrefix = "api-doc"; + foreach (var assembly in assembly) + c.SwaggerEndpoint(assembly.GetName().Name + "/swagger.json", "Wood Api " + assembly.GetName().Name); + }); + //自动 注册所有事件 + app.UseEventBus(assembly); + } + } +} \ No newline at end of file diff --git a/API/Wood.Admin.WebApi/Wood.Admin.WebApi.csproj b/API/Wood.Admin.WebApi/Wood.Admin.WebApi.csproj new file mode 100644 index 0000000..dd5fcd3 --- /dev/null +++ b/API/Wood.Admin.WebApi/Wood.Admin.WebApi.csproj @@ -0,0 +1,61 @@ + + + + net8.0 + 3.1.0.0 + 3.1.0.0 + WoodAdmin + enable + False + + + + Wood.Admin.WebApi.xml + 1701;1702;1591 + + + + 1701;1702;1591 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/API/Wood.Admin.WebApi/appsettings.Development.json b/API/Wood.Admin.WebApi/appsettings.Development.json new file mode 100644 index 0000000..e203e94 --- /dev/null +++ b/API/Wood.Admin.WebApi/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/API/Wood.Admin.WebApi/appsettings.json b/API/Wood.Admin.WebApi/appsettings.json new file mode 100644 index 0000000..2d7fd71 --- /dev/null +++ b/API/Wood.Admin.WebApi/appsettings.json @@ -0,0 +1,32 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", // Trace,Debug,Information,Warning,Error,Critical + "System": "Information", + "Microsoft": "Information" + } + }, + "AllowedHosts": "*", + "SystemConfig": { + "AllowCorsSite": "http://127.0.0.1:7005", // 允许的其他站点访问Api + "CacheProvider": "Memory", // 缓存使用方式 Memory Redis + "RedisConnectionString": "127.0.0.1:6379", //redis 链接字符串 + "EnableInitDb": true, //是否开启数据库初始化, + "SnowFlakeWorkerId": 2, // SnowFlake 雪花id节点序号 + "DBProvider": "Sqlite", //数据库类型 参照 sqlsugar + "DBConnectionString": "Data Source=../WoodAdmin.db", + "DBCommandTimeout": 180, // 数据库超时时间,单位秒 + "DBBackup": "", // 数据库备份路径 + "DBEnableDiffLog": true, //是否开启差异化日志 + "LogDays": 90, //系统日志保存的天数 + "RunAutoJob": true, //是否执行自动job + "CustomerDb": "Server = 192.168.1.228; Database = TaskManager1; User ID = sa; Password = ChangkeTec@2021; TrustServerCertificate = True" + }, + "JwtConfig": { + "SecretKey": "3c1cac3f546eda35168c3aa3cn91780fbe703f0996c6d123ea96dc85c70bbc0a", // 密钥,string 类型,必须是复杂密钥,长度大于16 + "Issuer": "WebAppIssuer", // 签发方,string 类型 + "Audience": "WebAppAudience", // 签收方,string 类型 + "RefreshTokenExpire": 15, //刷新token有效期限 天 + "TokenExpire": 30 //token有效期限 分钟 + } +} diff --git a/API/Wood.Admin.WebApi/wwwroot/template/用户信息导入模板.xlsx b/API/Wood.Admin.WebApi/wwwroot/template/用户信息导入模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4c945d803a35d5fe4e5218aec2f394dc1e3ad539 GIT binary patch literal 10849 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%0A6A^EDmd**wU%KLKquVSJfkX^`wZ>0DCx< zlqHgoBUuBjVn-T&$6kJzVEl>1AY7>u+7CJnw$y4ro{3AKfW-Up=IY^m__$&fin^`B zalO%zV4t1$5RZn(+7i(X2`vh4{xxod^DG+h4(7xGVVU)!u>$4ZzCU7R#$l2E8A^RY zk3>J@$LA}(>$4*_(i>7#;yTZWYp=u4B1@!zMaf0_aSE3bYT z|35R<-~IePYWvd@%1gid{|(-L_wu`b{iheOm&W + /// Cron表达式 + /// + [AttributeUsage(AttributeTargets.Class)] + public class CronAttribute : Attribute + { + + + public CronAttribute(string args) + { + this.Args = args; + } + /// + /// 触发器Id + /// + public string? TriggerId { get; set; } + + /// + /// 参数 + /// 运行时间间隔 + /// + public string? Args { get; private set; } + + /// + /// 描述信息 + /// + public string? Description { get; set; } + + /// + /// 起始时间 + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime? EndTime { get; set; } + + + /// + /// 最大触发次数(0:不限制,n:N次) + /// + public long MaxNumberOfRuns { get; set; } = 0; + + /// + /// 最大出错次数(0:不限制,n:N次) + /// + public long MaxNumberOfErrors { get; set; } = 0; + + /// + /// 重试次数 + /// + public int NumRetries { get; set; } + + /// + /// 重试间隔时间(ms) + /// + public int RetryTimeout { get; set; } = 60000; + + /// + /// 是否启动时执行一次 + /// + public bool RunOnStart { get; set; } = false; + } +} diff --git a/API/Wood.AutoJob/Attributes/DailyAtAttribute.cs b/API/Wood.AutoJob/Attributes/DailyAtAttribute.cs new file mode 100644 index 0000000..31cb83b --- /dev/null +++ b/API/Wood.AutoJob/Attributes/DailyAtAttribute.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.AutoJob +{ + /// + /// 每天x点执行 + /// + [AttributeUsage(AttributeTargets.Class)] + public class DailyAtAttribute : Attribute + { + /// + /// + /// + /// 示例1:00:00 (0点0分执行) 示例2:23(23点执行) + public DailyAtAttribute(string args) + { + this.Args = args; + } + /// + /// 触发器Id + /// + public string? TriggerId { get; set; } + + /// + /// 参数 + /// 运行时间间隔 + /// + public string? Args { get; private set; } + + /// + /// 描述信息 + /// + public string? Description { get; set; } + + /// + /// 起始时间 + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime? EndTime { get; set; } + + + /// + /// 最大触发次数(0:不限制,n:N次) + /// + public long MaxNumberOfRuns { get; set; } = 0; + + /// + /// 最大出错次数(0:不限制,n:N次) + /// + public long MaxNumberOfErrors { get; set; } = 0; + + /// + /// 重试次数 + /// + public int NumRetries { get; set; } + + /// + /// 重试间隔时间(ms) + /// + public int RetryTimeout { get; set; } = 60000; + + /// + /// 是否启动时执行一次 + /// + public bool RunOnStart { get; set; } = false; + } +} diff --git a/API/Wood.AutoJob/Attributes/JobDetailAttribute.cs b/API/Wood.AutoJob/Attributes/JobDetailAttribute.cs new file mode 100644 index 0000000..2591583 --- /dev/null +++ b/API/Wood.AutoJob/Attributes/JobDetailAttribute.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity.SystemManage; + +namespace Wood.AutoJob +{ + /// + /// Job明细 + /// + [AttributeUsage(AttributeTargets.Class)] + public class JobDetailAttribute : Attribute + { + /// + /// 作业Id + /// + public string? JobId { get; set; } + + /// + /// 组名称 + /// + public string? GroupName { get; set; } = "default"; + + /// + /// 描述信息 + /// + public string? Description { get; set; } + } +} diff --git a/API/Wood.AutoJob/Attributes/PeriodMinutesAttribute.cs b/API/Wood.AutoJob/Attributes/PeriodMinutesAttribute.cs new file mode 100644 index 0000000..1059de2 --- /dev/null +++ b/API/Wood.AutoJob/Attributes/PeriodMinutesAttribute.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.AutoJob +{ + /// + /// 每X分钟执行 + /// + [AttributeUsage(AttributeTargets.Class)] + public class PeriodMinutesAttribute : Attribute + { + + public PeriodMinutesAttribute(int args) + { + this.Args = args.ToString(); + } + /// + /// 触发器Id + /// + public string? TriggerId { get; set; } + + /// + /// 参数 + /// 运行时间间隔 + /// + public string? Args { get;private set; } + + /// + /// 描述信息 + /// + public string? Description { get; set; } + + /// + /// 起始时间 + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime? EndTime { get; set; } + + + /// + /// 最大触发次数(0:不限制,n:N次) + /// + public long MaxNumberOfRuns { get; set; } = 0; + + /// + /// 最大出错次数(0:不限制,n:N次) + /// + public long MaxNumberOfErrors { get; set; } = 0; + + /// + /// 重试次数 + /// + public int NumRetries { get; set; } + + /// + /// 重试间隔时间(ms) + /// + public int RetryTimeout { get; set; } = 60000; + + /// + /// 是否启动时执行一次 + /// + public bool RunOnStart { get; set; } = false; + } +} diff --git a/API/Wood.AutoJob/Attributes/PeriodSecondsAttribute.cs b/API/Wood.AutoJob/Attributes/PeriodSecondsAttribute.cs new file mode 100644 index 0000000..9480755 --- /dev/null +++ b/API/Wood.AutoJob/Attributes/PeriodSecondsAttribute.cs @@ -0,0 +1,73 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; + +namespace Wood.AutoJob +{ + /// + /// 每X秒执行 + /// + [AttributeUsage(AttributeTargets.Class)] + public class PeriodSecondsAttribute:Attribute + { + public PeriodSecondsAttribute(int args) + { + this.Args = args.ToString(); + } + /// + /// 触发器Id + /// + public string? TriggerId { get; set; } + + /// + /// 参数 + /// 运行时间间隔 + /// + public string? Args { get; private set; } + + /// + /// 描述信息 + /// + public string? Description { get; set; } + + /// + /// 起始时间 + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime? EndTime { get; set; } + + + /// + /// 最大触发次数(0:不限制,n:N次) + /// + public long MaxNumberOfRuns { get; set; } = 0; + + /// + /// 最大出错次数(0:不限制,n:N次) + /// + public long MaxNumberOfErrors { get; set; } = 0; + + /// + /// 重试次数 + /// + public int NumRetries { get; set; } + + /// + /// 重试间隔时间(ms) + /// + public int RetryTimeout { get; set; } = 60000; + + /// + /// 是否启动时执行一次 + /// + public bool RunOnStart { get; set; } = false; + } +} diff --git a/API/Wood.AutoJob/AutoJobCenter.cs b/API/Wood.AutoJob/AutoJobCenter.cs new file mode 100644 index 0000000..019df83 --- /dev/null +++ b/API/Wood.AutoJob/AutoJobCenter.cs @@ -0,0 +1,279 @@ +using Mapster; +using Microsoft.Extensions.DependencyInjection; +using Quartz; +using System.Reflection; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.EventBus; +using Wood.Util; + +namespace Wood.AutoJob +{ + public class AutoJobCenter + { + #region 扫描任务计划 + public async void ScanJob() + { + using var scope = GlobalContext.ServiceProvider!.CreateScope(); + var jobTriggerRepository = scope.ServiceProvider.GetRequiredService>(); + var jobDetailRepository = scope.ServiceProvider.GetRequiredService>(); + var eventBus = scope.ServiceProvider.GetRequiredService(); + + var types = Assembly.GetAssembly(typeof(AutoJobCenter))!.GetTypes() + .Where(t => t.IsClass && !t.IsAbstract && t.GetCustomAttributes(typeof(JobDetailAttribute), false).Any()) + .ToList(); + + foreach (var item in types) + { + string jobId = ""; + var jobDetailAttr = item.GetCustomAttribute(); + if (jobDetailAttr != null) + { + var detail = jobDetailAttr.Adapt(); + detail.JobType = item.FullName; + detail.AssemblyName = item.Assembly.FullName; + jobId = detail.JobId!; + var dbDetail = await jobDetailRepository.GetFirstAsync(it => it.JobId == detail.JobId); + + if (!jobDetailRepository.IsAny(it => it.JobId == detail.JobId)) + jobDetailRepository.Insert(detail); + else + { + if (dbDetail.Description != detail.Description || dbDetail.GroupName != detail.GroupName) + { + dbDetail.GroupName = detail.GroupName; + dbDetail.Description = detail.Description; + await jobDetailRepository.UpdateAsync(dbDetail); + } + } + } + else + continue; + + var secondsAtAttr = item.GetCustomAttribute(); + JobTriggerEntity? entity = null; + if (secondsAtAttr != null && entity == null) + { + entity = secondsAtAttr.Adapt(); + entity.TriggerType = TriggerTypeEnum.PeriodSeconds; + } + var minutesAttr = item.GetCustomAttribute(); + if (minutesAttr != null && entity == null) + { + entity = minutesAttr.Adapt(); + entity.TriggerType = TriggerTypeEnum.PeriodMinutes; + } + var dailyAtAttr = item.GetCustomAttribute(); + if (dailyAtAttr != null && entity == null) + { + entity = dailyAtAttr.Adapt(); + entity.TriggerType = TriggerTypeEnum.DailyAt; + } + var cronAttr = item.GetCustomAttribute(); + if (cronAttr != null && entity == null) + { + entity = cronAttr.Adapt(); + entity.TriggerType = TriggerTypeEnum.Cron; + } + if (entity != null) + { + entity.JobId = jobId; + entity.Status = TriggerStatusEnum.Ready; + var trigger = jobTriggerRepository.GetFirst(it => it.TriggerId == entity.TriggerId); + if (trigger == null) + jobTriggerRepository.Insert(entity); + else + { + //只有触发器类型 或者 参数 或者 说明 变更时需要更新触发器数据 + if (trigger.TriggerType != entity.TriggerType || trigger.Args != entity.Args || trigger.Description != entity.Description) + { + entity.Id = trigger.Id; + entity.CreateTime = trigger.CreateTime; + entity.CreateUserId = trigger.CreateUserId; + jobTriggerRepository.Update(entity.Adapt(trigger)); + } + } + } + } + + } + #endregion + + #region 添加任务计划 + + public async Task AddScheduleJob() + { + + using var scope = GlobalContext.ServiceProvider!.CreateScope(); + var schedulerFactory = scope.ServiceProvider.GetRequiredService(); + var jobTriggerRepository = scope.ServiceProvider.GetRequiredService>(); + var jobDetailRepository = scope.ServiceProvider.GetRequiredService>(); + + var jobDetailList = jobDetailRepository.AsQueryable().ClearFilter().ToList(); + + var scheduler = await schedulerFactory.GetScheduler(); + foreach (var detail in jobDetailList) + { + var jobTrigger = await jobTriggerRepository.GetFirstAsync(it => it.JobId == detail.JobId); + + var jobType = this.GetType().Assembly.GetType(detail.JobType!); + if (jobType != null) + { + IJobDetail job = JobBuilder.Create(jobType!).WithIdentity(detail.JobId!, detail.GroupName!).Build(); + job.JobDataMap.Add("DetailId", detail.Id); + job.JobDataMap.Add("TriggerId", jobTrigger.Id); + + var trigger = CreateTrigger(jobTrigger, detail); + //更新下次执行时间 + jobTrigger.NextRunTime = trigger.GetNextFireTimeUtc()?.DateTime.AddHours(8); + jobTrigger.Status = TriggerStatusEnum.Ready; + await jobTriggerRepository.UpdateAsync(jobTrigger); + + await scheduler.ScheduleJob(job, CreateTrigger(jobTrigger, detail)); + } + else + { + jobTrigger.Status = TriggerStatusEnum.Ineffective; + await jobTriggerRepository.UpdateAsync(jobTrigger); + } + } + await scheduler.Start(); + } + + /// + /// 创建trigger + /// + /// + /// + /// + public static ITrigger CreateTrigger(JobTriggerEntity jobTrigger, JobDetailEntity jobDetail) + { + /* + * Cron + withMisfireHandlingInstructionFireAndProceed [MISFIRE_INSTRUCTION_FIRE_ONCE_NOW](默认) + ——以当前时间为触发频率立刻触发一次执行 + ——然后按照Cron频率依次执行 + + withMisfireHandlingInstructionDoNothing [MISFIRE_INSTRUCTION_DO_NOTHING ] + ——不触发立即执行 + ——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行 + + withMisfireHandlingInstructionIgnoreMisfires [MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY] + ——以错过的第一个频率时间立刻开始执行 + ——重做错过的所有频率周期后 + ——当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行 + 即: 忽略所有的超时状态,按照触发器的策略执行。 + + + + WithSimpleSchedule + + withMisfireHandlingInstructionNowWithExistingCount(默认) + ——以当前时间为触发频率立即触发执行 + ——执行至FinalTIme的剩余周期次数 + ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到 + ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值 + + + withMisfireHandlingInstructionFireNow + ——以当前时间为触发频率立即触发执行 + ——执行至FinalTIme的剩余周期次数 + ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到 + ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值 + + + + withMisfireHandlingInstructionIgnoreMisfires + ——以错过的第一个频率时间立刻开始执行 + ——重做错过的所有频率周期 + ——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率 + ——共执行RepeatCount+1次 + + + withMisfireHandlingInstructionNextWithExistingCount + ——不触发立即执行 + ——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数 + ——以startTime为基准计算周期频率,并得到FinalTime + ——即使中间出现pause,resume以后保持FinalTime时间不变 + + withMisfireHandlingInstructionNextWithRemainingCount + ——不触发立即执行 + ——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数 + ——以startTime为基准计算周期频率,并得到FinalTime + ——即使中间出现pause,resume以后保持FinalTime时间不变 + + withMisfireHandlingInstructionNowWithRemainingCount + ——以当前时间为触发频率立即触发执行 + ——执行至FinalTIme的剩余周期次数 + ——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到 + ——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值 + + MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT + ——此指令导致trigger忘记原始设置的starttime和repeat-count + ——触发器的repeat-count将被设置为剩余的次数 + ——这样会导致后面无法获得原始设定的starttime和repeat-count值 + + */ + if (jobTrigger.StartTime == null) + jobTrigger.StartTime = DateTime.Now; + + DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(jobTrigger.StartTime, 1); + + TriggerBuilder triggerBuilder = TriggerBuilder.Create() + .WithIdentity(jobTrigger.TriggerId!, jobDetail.GroupName!); + + if (jobTrigger.TriggerType == Entity.TriggerTypeEnum.DailyAt) + { + string[] times = jobTrigger.Args!.Split(":"); + if (times.Length == 1) + { + if (!jobTrigger.RunOnStart) + triggerBuilder = triggerBuilder.StartAt(starRunTime).WithCronSchedule($"0 0 {times[0]} * * ?", x => x.WithMisfireHandlingInstructionDoNothing()); + else + triggerBuilder = triggerBuilder.StartAt(starRunTime).WithCronSchedule($"0 0 {times[0]} * * ?", x => x.WithMisfireHandlingInstructionFireAndProceed()); + } + else + { + if (!jobTrigger.RunOnStart) + triggerBuilder = triggerBuilder.StartAt(starRunTime).WithCronSchedule($"0 {times[1]} {times[0]} * * ?", x => x.WithMisfireHandlingInstructionDoNothing()); + else + triggerBuilder = triggerBuilder.StartAt(starRunTime).WithCronSchedule($"0 {times[1]} {times[0]} * * ?", x => x.WithMisfireHandlingInstructionFireAndProceed()); + } + } + else if (jobTrigger.TriggerType == Entity.TriggerTypeEnum.PeriodMinutes) + { + int interval = jobTrigger.Args!.ToInt(); + if (!jobTrigger.RunOnStart) + starRunTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddMinutes(interval), 1); + + triggerBuilder = triggerBuilder.StartAt(starRunTime) + .WithSimpleSchedule(x => x + .WithIntervalInMinutes(interval) // 每xm分钟重复一次 + .RepeatForever()); // 无限重复; + + } + else if (jobTrigger.TriggerType == Entity.TriggerTypeEnum.PeriodSeconds) + { + int interval = jobTrigger.Args!.ToInt(); + if (!jobTrigger.RunOnStart) + starRunTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(interval), 1); + + triggerBuilder = triggerBuilder.WithSimpleSchedule(x => x + .WithIntervalInSeconds(interval) // 每x秒重复一次 + .RepeatForever()); // 无限重复; + } + else if (jobTrigger.TriggerType == Entity.TriggerTypeEnum.Cron) + { + if (!jobTrigger.RunOnStart) + triggerBuilder = triggerBuilder.StartAt(starRunTime).WithCronSchedule(jobTrigger.Args!, x => x.WithMisfireHandlingInstructionDoNothing()); + else + triggerBuilder = triggerBuilder.StartAt(starRunTime).WithCronSchedule(jobTrigger.Args!, x => x.WithMisfireHandlingInstructionFireAndProceed()); + } + else + throw Oops.Oh("AutoJob不支持的触发器类型!"); + return triggerBuilder!.Build(); + } + #endregion + } +} diff --git a/API/Wood.AutoJob/AutoJobTask.cs b/API/Wood.AutoJob/AutoJobTask.cs new file mode 100644 index 0000000..bbc0e7f --- /dev/null +++ b/API/Wood.AutoJob/AutoJobTask.cs @@ -0,0 +1,157 @@ +using Microsoft.Extensions.DependencyInjection; +using Quartz; +using Serilog; +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.EventBus; +using Wood.EventBus.Events; +using Wood.Util; + +namespace Wood.AutoJob +{ + public abstract class AutoJobTask : IJob + { + + /// + /// 执行逻辑 + /// + /// + /// + /// + public virtual Task Run(IJobExecutionContext context, IServiceProvider provider) + { + throw new NotImplementedException(); + } + + public async Task Execute(IJobExecutionContext context) + { + DateTime now = DateTime.Now; + using var scope = GlobalContext.ServiceProvider!.CreateScope(); + var jobTriggerRepository = scope.ServiceProvider.GetRequiredService>(); + var eventBus = scope.ServiceProvider.GetRequiredService(); + var logJobRepository = scope.ServiceProvider.GetRequiredService>(); + + JobDataMap jobData = context.JobDetail.JobDataMap; + long detailId = jobData["DetailId"].ToString()?.ToLong() ?? 0; + long triggerId = jobData["TriggerId"].ToString()?.ToLong() ?? 0; + + // 获取数据库中的任务 + JobTriggerEntity triggerEntity = await jobTriggerRepository.GetByIdAsync(triggerId); + + if (triggerEntity != null) + { + var logJob = new LogJobEntity() + { + Elapsed=0, + TriggerId = triggerEntity.TriggerId, + JobId = triggerEntity.JobId, + RetryCount=0, + RunTime = now, + }; + + var planRuntime = triggerEntity.NextRunTime; + triggerEntity.LastRunTime = now; + triggerEntity.NextRunTime = context.NextFireTimeUtc?.DateTime.AddHours(8); + //任务已经暂停 + if (triggerEntity.Status == TriggerStatusEnum.Pause || + triggerEntity.Status == TriggerStatusEnum.Archived || + triggerEntity.Status == TriggerStatusEnum.Overrun || + triggerEntity.Status == TriggerStatusEnum.Panic + ) + { + //job 更新下次执行事时间 + logJob.Status = triggerEntity.Status.GetDescription(); + await logJobRepository.InsertAsync(logJob); + await jobTriggerRepository.UpdateAsync(triggerEntity); + return; + } + else if (triggerEntity.Status == TriggerStatusEnum.Running) + { + //上个任务正在实行 设置为 阻塞 + triggerEntity.Status = TriggerStatusEnum.Blocked; + logJob.Status = triggerEntity.Status.GetDescription(); + await logJobRepository.InsertAsync(logJob); + await jobTriggerRepository.UpdateAsync(triggerEntity); + return; + } + else if (triggerEntity.EndTime.HasValue && now > triggerEntity.EndTime.Value) + { + //超过任务结束时间 设置为归档 + triggerEntity.Status = TriggerStatusEnum.Archived; + logJob.Status = triggerEntity.Status.GetDescription(); + await logJobRepository.InsertAsync(logJob); + await jobTriggerRepository.UpdateAsync(triggerEntity); + return; + } + else + { + triggerEntity.NumberOfRuns++; + + Stopwatch stopwatch = Stopwatch.StartNew(); + //重试次数 + int i = 0; + string status = triggerEntity.Status.GetDescription(); + //只有在 就绪状态才能继续执行 + if (triggerEntity.Status == TriggerStatusEnum.ErrorToReady || triggerEntity.Status == TriggerStatusEnum.Ready || triggerEntity.Status == TriggerStatusEnum.Blocked) + { + triggerEntity.Status = TriggerStatusEnum.Running; //正常开始运行 + + //执行前 job更新状态 + await jobTriggerRepository.UpdateAsync(triggerEntity); + //设置重试次数,最小执行一次 + int retryCount = triggerEntity.NumRetries; + if (triggerEntity.NumRetries == 0) + retryCount = 1; + + for (; i < retryCount; i++) + { + try + { + //执行逻辑 + await Run(context, scope.ServiceProvider); + + status = "执行完成"; + + if (triggerEntity.MaxNumberOfRuns > 0 && triggerEntity.MaxNumberOfRuns <= triggerEntity.NumberOfRuns) + triggerEntity.Status = TriggerStatusEnum.Overrun; + else + triggerEntity.Status = TriggerStatusEnum.Ready; + + break; + } + catch (Exception ex) + { + status = "执行出错"; + + //记录错误信息 + eventBus.Publish(LogExceptionEvent.NewEvent(ex, triggerEntity.JobId!, triggerEntity.TriggerId!, "Execute")); + //出现错误 + triggerEntity.NumberOfErrors++; + if (triggerEntity.MaxNumberOfErrors > 0 && triggerEntity.MaxNumberOfErrors < triggerEntity.NumberOfErrors) + triggerEntity.Status = TriggerStatusEnum.Panic; + else + triggerEntity.Status = TriggerStatusEnum.ErrorToReady; + + Log.Error(ex, $"执行job出错!【{triggerEntity.JobId}】"); + } + await Task.Delay(triggerEntity.RetryTimeout); + } + } + + stopwatch.Stop(); + + logJob.Elapsed = stopwatch.ElapsedMilliseconds; + logJob.Status = "正常执行"; + logJob.RetryCount = i; + await logJobRepository.InsertAsync(logJob); + //job 执行完 更新状态 + await jobTriggerRepository.UpdateAsync(triggerEntity); + } + } + } + } +} diff --git a/API/Wood.AutoJob/Job/DBLogClearJob.cs b/API/Wood.AutoJob/Job/DBLogClearJob.cs new file mode 100644 index 0000000..b63f042 --- /dev/null +++ b/API/Wood.AutoJob/Job/DBLogClearJob.cs @@ -0,0 +1,37 @@ +using Microsoft.Extensions.DependencyInjection; +using Quartz; +using Wood.Data.Repository; +using Wood.Entity.SystemManage; +using Wood.Util; + +namespace Wood.AutoJob +{ + /// + /// 日志清理job + /// + [JobDetail(JobId = "job_DBLogClear", GroupName = "system", Description = "清理日志")] + [PeriodMinutes(480, TriggerId = "trigger_DBLogClear")] + [DisallowConcurrentExecution] + public class DBLogClearJob : AutoJobTask + { + + public override async Task Run(IJobExecutionContext context, IServiceProvider serviceProvider) + { + DateTime startTime = DateTime.Now.AddDays(0 - GlobalContext.SystemConfig!.LogDays); + + var ldRepository = serviceProvider.GetRequiredService>(); + var levRepository = serviceProvider.GetRequiredService>(); + var lexRepository = serviceProvider.GetRequiredService>(); + var ljRepository = serviceProvider.GetRequiredService>(); + var llRepository = serviceProvider.GetRequiredService>(); + var loRepository = serviceProvider.GetRequiredService>(); + + await ldRepository.DeleteAsync(it => it.CreateTime < startTime); + await levRepository.DeleteAsync(it => it.CreateTime < startTime); + await lexRepository.DeleteAsync(it => it.CreateTime < startTime); + await ljRepository.DeleteAsync(it => it.CreateTime < startTime); + await llRepository.DeleteAsync(it => it.CreateTime < startTime); + await loRepository.DeleteAsync(it => it.CreateTime < startTime); + } + } +} diff --git a/API/Wood.AutoJob/Wood.AutoJob.csproj b/API/Wood.AutoJob/Wood.AutoJob.csproj new file mode 100644 index 0000000..5374014 --- /dev/null +++ b/API/Wood.AutoJob/Wood.AutoJob.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/API/Wood.Cache/Wood.Cache.Interface/ICache.cs b/API/Wood.Cache/Wood.Cache.Interface/ICache.cs new file mode 100644 index 0000000..b7a9239 --- /dev/null +++ b/API/Wood.Cache/Wood.Cache.Interface/ICache.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading.Tasks; +using System.Collections.Generic; + +namespace Wood.Cache +{ + public interface ICache + { + bool SetCache(string key, T value, DateTime? expireTime = null); + T? GetCache(string key); + + bool TryGetCache(string key,out T? val); + + bool RemoveCache(string key); + + #region Hash + int SetHashFieldCache(string key, string fieldKey, T fieldValue); + int SetHashFieldCache(string key, Dictionary dict); + T GetHashFieldCache(string key, string fieldKey); + Dictionary GetHashFieldCache(string key, Dictionary dict); + Dictionary GetHashCache(string key); + List GetHashToListCache(string key); + bool RemoveHashFieldCache(string key, string fieldKey); + Dictionary RemoveHashFieldCache(string key, Dictionary dict); + #endregion + } +} diff --git a/API/Wood.Cache/Wood.Cache.Interface/Wood.Cache.Interface.csproj b/API/Wood.Cache/Wood.Cache.Interface/Wood.Cache.Interface.csproj new file mode 100644 index 0000000..3e69084 --- /dev/null +++ b/API/Wood.Cache/Wood.Cache.Interface/Wood.Cache.Interface.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + + + + + + + + + diff --git a/API/Wood.Cache/Wood.MemoryCache/MemoryCacheImp.cs b/API/Wood.Cache/Wood.MemoryCache/MemoryCacheImp.cs new file mode 100644 index 0000000..396f2c2 --- /dev/null +++ b/API/Wood.Cache/Wood.MemoryCache/MemoryCacheImp.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Caching.Memory; +using Wood.Cache; +using Wood.Util; +using Serilog; + +namespace Wood.MemoryCache +{ + public class MemoryCacheImp : ICache + { + private IMemoryCache cache = GlobalContext.ServiceProvider!.GetService()!; + + public bool SetCache(string key, T value, DateTime? expireTime = null) + { + try + { + if (expireTime == null) + { + return cache.Set(key, value) != null; + } + else + { + return cache.Set(key, value, (expireTime.Value - DateTime.Now)) != null; + } + } + catch (Exception ex) + { + Log.Error(ex, "设置缓存失败:key({key})", key); + } + return false; + } + + public bool RemoveCache(string key) + { + cache.Remove(key); + return true; + } + + public T? GetCache(string key) + { + var value = cache.Get(key)!; + return value; + } + + public bool TryGetCache(string key,out T? val) + { + var value = cache.TryGetValue(key,out val)!; + return value; + } + + #region Hash + public int SetHashFieldCache(string key, string fieldKey, T fieldValue) + { + return SetHashFieldCache(key, new Dictionary { { fieldKey, fieldValue } }); + } + + public int SetHashFieldCache(string key, Dictionary dict) + { + int count = 0; + foreach (string fieldKey in dict.Keys) + { + count += cache.Set(key, dict) != null ? 1 : 0; + } + return count; + } + + public T GetHashFieldCache(string key, string fieldKey) + { + var dict = GetHashFieldCache(key, new Dictionary { { fieldKey, default(T)! } }); + return dict[fieldKey]; + } + + public Dictionary GetHashFieldCache(string key, Dictionary dict) + { + var hashFields = cache.Get>(key); + foreach (KeyValuePair keyValuePair in hashFields!.Where(p => dict.Keys.Contains(p.Key))) + { + dict[keyValuePair.Key] = keyValuePair.Value; + } + return dict; + } + + public Dictionary GetHashCache(string key) + { + Dictionary dict = new Dictionary(); + var hashFields = cache.Get>(key); + foreach (string field in hashFields!.Keys) + { + dict[field] = hashFields[field]; + } + return dict; + } + + public List GetHashToListCache(string key) + { + List list = new List(); + var hashFields = cache.Get>(key); + foreach (string field in hashFields!.Keys) + { + list.Add(hashFields[field]); + } + return list; + } + + public bool RemoveHashFieldCache(string key, string fieldKey) + { + Dictionary dict = new Dictionary { { fieldKey, false } }; + dict = RemoveHashFieldCache(key, dict); + return dict[fieldKey]; + } + + public Dictionary RemoveHashFieldCache(string key, Dictionary dict) + { + var hashFields = cache.Get>(key); + foreach (string fieldKey in dict.Keys) + { + dict[fieldKey] = hashFields!.Remove(fieldKey); + } + return dict; + } + #endregion + } +} diff --git a/API/Wood.Cache/Wood.MemoryCache/Wood.MemoryCache.csproj b/API/Wood.Cache/Wood.MemoryCache/Wood.MemoryCache.csproj new file mode 100644 index 0000000..b16f569 --- /dev/null +++ b/API/Wood.Cache/Wood.MemoryCache/Wood.MemoryCache.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + enable + + + + + + + + + + + + + + + diff --git a/API/Wood.Cache/Wood.RedisCache/RedisCacheImp.cs b/API/Wood.Cache/Wood.RedisCache/RedisCacheImp.cs new file mode 100644 index 0000000..86821b8 --- /dev/null +++ b/API/Wood.Cache/Wood.RedisCache/RedisCacheImp.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Serilog; +using StackExchange.Redis; +using Wood.Cache; +using Wood.Util; + +namespace Wood.RedisCache +{ + public class RedisCacheImp : ICache + { + private IDatabase cache; + private ConnectionMultiplexer connection; + + public RedisCacheImp() + { + connection = ConnectionMultiplexer.Connect(GlobalContext.SystemConfig!.RedisConnectionString); + cache = connection.GetDatabase(); + } + + public bool SetCache(string key, T value, DateTime? expireTime = null) + { + try + { + var jsonOption = new JsonSerializerSettings() + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore + }; + string strValue = JsonConvert.SerializeObject(value, jsonOption); + if (string.IsNullOrEmpty(strValue)) + { + return false; + } + if (expireTime == null) + { + return cache.StringSet(key, strValue); + } + else + { + return cache.StringSet(key, strValue, (expireTime.Value - DateTime.Now)); + } + } + catch (Exception ex) + { + Log.Error(ex,"设置缓存失败:key({key})",key); + } + return false; + } + + public bool RemoveCache(string key) + { + return cache.KeyDelete(key); + } + + /// + /// + /// + /// + /// + /// + public T? GetCache(string key) + { + var t = default(T); + try + { + var value = cache.StringGet(key); + if (string.IsNullOrEmpty(value)) + { + return t; + } + t = JsonConvert.DeserializeObject(value!); + } + catch (Exception ex) + { + Log.Error(ex, "获取缓存失败:key({key})", key); + } + return t; + } + public bool TryGetCache(string key,out T? val) + { + val = default(T); + try + { + var value = cache.StringGet(key); + if (string.IsNullOrEmpty(value)) + { + return false; + } + val = JsonConvert.DeserializeObject(value!); + return true; + } + catch (Exception ex) + { + Log.Error(ex, "获取缓存失败:key({key})", key); + } + return false; + } + + + #region Hash + public int SetHashFieldCache(string key, string fieldKey, T fieldValue) + { + return SetHashFieldCache(key, new Dictionary { { fieldKey, fieldValue } }); + } + + public int SetHashFieldCache(string key, Dictionary dict) + { + int count = 0; + var jsonOption = new JsonSerializerSettings() + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore + }; + foreach (string fieldKey in dict.Keys) + { + string fieldValue = JsonConvert.SerializeObject(dict[fieldKey], jsonOption); + count += cache.HashSet(key, fieldKey, fieldValue) ? 1 : 0; + } + return count; + } + + public T GetHashFieldCache(string key, string fieldKey) + { + var dict = GetHashFieldCache(key, new Dictionary { { fieldKey, default(T)! } }); + return dict[fieldKey]; + } + + public Dictionary GetHashFieldCache(string key, Dictionary dict) + { + foreach (string fieldKey in dict.Keys) + { + string? fieldValue = cache.HashGet(key, fieldKey); + if(fieldValue != null) + dict[fieldKey] = JsonConvert.DeserializeObject(fieldValue)!; + } + return dict; + } + + public Dictionary GetHashCache(string key) + { + Dictionary dict = new Dictionary(); + var hashFields = cache.HashGetAll(key); + foreach (HashEntry field in hashFields) + { + dict[field.Name!] = JsonConvert.DeserializeObject(field.Value!)!; + } + return dict; + } + + public List GetHashToListCache(string key) + { + List list = new List(); + var hashFields = cache.HashGetAll(key); + foreach (HashEntry field in hashFields) + { + list.Add(JsonConvert.DeserializeObject(field.Value!)!); + } + return list; + } + + public bool RemoveHashFieldCache(string key, string fieldKey) + { + Dictionary dict = new Dictionary { { fieldKey, false } }; + dict = RemoveHashFieldCache(key, dict); + return dict[fieldKey]; + } + + public Dictionary RemoveHashFieldCache(string key, Dictionary dict) + { + foreach (string fieldKey in dict.Keys) + { + dict[fieldKey] = cache.HashDelete(key, fieldKey); + } + return dict; + } + #endregion + + public void Dispose() + { + if (connection != null) + { + connection.Close(); + } + GC.SuppressFinalize(this); + } + } +} diff --git a/API/Wood.Cache/Wood.RedisCache/Wood.RedisCache.csproj b/API/Wood.Cache/Wood.RedisCache/Wood.RedisCache.csproj new file mode 100644 index 0000000..1e5c49c --- /dev/null +++ b/API/Wood.Cache/Wood.RedisCache/Wood.RedisCache.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + enable + + + + + + + + + + + + + + + diff --git a/API/Wood.Data.Repository/DataSeed/UserDataSeed.cs b/API/Wood.Data.Repository/DataSeed/UserDataSeed.cs new file mode 100644 index 0000000..dee9df6 --- /dev/null +++ b/API/Wood.Data.Repository/DataSeed/UserDataSeed.cs @@ -0,0 +1,31 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity.SystemManage; +using Wood.Util; + +namespace Wood.Data.Repository.DataSeed +{ + public class UserDataSeed + { + public static void InitData(ISqlSugarClient db) + { + string dataSeedPath = Path.Combine(GlobalContext.HostingEnvironment!.ContentRootPath, "DataSeed.sql"); + + if (File.Exists(dataSeedPath)) + { + var lines = File.ReadAllLines(dataSeedPath); + foreach (var item in lines) + { + if (item.StartsWith("INSERT")) + { + db.Ado.ExecuteCommand(item); + } + } + } + } + } +} diff --git a/API/Wood.Data.Repository/DbContext/SqlSugarDbContext.cs b/API/Wood.Data.Repository/DbContext/SqlSugarDbContext.cs new file mode 100644 index 0000000..273305f --- /dev/null +++ b/API/Wood.Data.Repository/DbContext/SqlSugarDbContext.cs @@ -0,0 +1,234 @@ +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Serilog; +using SqlSugar; +using System.Data; +using System.Reflection; +using Wood.Cache; +using Wood.Data.Repository.DataSeed; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Util; + +namespace Wood.Data.Repository +{ + public static class SqlSugarDbContext + { + #region aop + /// + /// 配置Aop + /// + /// + public static void SetDbAop(SqlSugarProvider db) + { + var config = db.CurrentConnectionConfig; + + // 设置超时时间 + db.Ado.CommandTimeOut = GlobalContext.SystemConfig!.DBCommandTimeout; + + // 打印SQL语句 + db.Aop.OnLogExecuting = (sql, pars) => + { + Log.Information("【执行SQL】" + UtilMethods.GetSqlString(config.DbType, sql, pars)); + }; + db.Aop.OnError = ex => + { + if (ex.Parametres == null) return; + var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value)); + Log.Error("【错误SQL】" + UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + Environment.NewLine + pars); + }; + + // 数据审计 + db.Aop.DataExecuting = (oldValue, entityInfo) => + { + var user = GlobalContext.UserInfo; + // 演示环境判断 + if (entityInfo.OperationType == DataFilterType.InsertByObject) + { + // 主键(long类型)且没有值的---赋值雪花Id + if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long)) + { + var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue); + if (id == null || (long)id == 0) + entityInfo.SetValue(IdGeneratorHelper.Instance.GetId()); + } + if (entityInfo.PropertyName == "CreateTime") + entityInfo.SetValue(DateTime.Now); + if (user != null) + { + if (entityInfo.PropertyName == "TenantId") + { + var tenantId = ((dynamic)entityInfo.EntityValue).TenantId; + if (tenantId == null || tenantId == 0) + entityInfo.SetValue(user?.TenantId); + } + if (entityInfo.PropertyName == "CreateUserId") + { + var createUserId = ((dynamic)entityInfo.EntityValue).CreateUserId; + if (createUserId == 0 || createUserId == null) + entityInfo.SetValue(user?.UserId); + } + + if (entityInfo.PropertyName == "CreateOrgId") + { + var createOrgId = ((dynamic)entityInfo.EntityValue).CreateOrgId; + if (createOrgId == 0 || createOrgId == null) + entityInfo.SetValue(user?.OrgId); + } + } + } + if (entityInfo.OperationType == DataFilterType.UpdateByObject) + { + if (entityInfo.PropertyName == "UpdateTime") + entityInfo.SetValue(DateTime.Now); + if (entityInfo.PropertyName == "UpdateUserId") + entityInfo.SetValue(user?.UserId); + } + }; + + // 配置实体假删除过滤器 + db.QueryFilter.AddTableFilter(u => u.IsDelete == false); + + var user = GlobalContext.UserInfo; + // 超管 排除过滤器 + if (user != null && user.IsSuperAdmin) + return; + + // 配置租户过滤器 + var tenantId = user?.TenantId; + if (tenantId > 0) + db.QueryFilter.AddTableFilter(u => u.TenantId == tenantId); + + // 配置用户机构(数据范围)过滤器 + if (user != null) + { + if (!user.IsAdmin) + { + var icache = GlobalContext.ServiceProvider!.GetRequiredService(); + var userCache = icache.GetCache(user.CacheKey); + if (userCache != null) + { + //根据org列表筛选数据 + if (userCache!.DataScopeType == DataScopeTypeEnum.Custom || + userCache!.DataScopeType == DataScopeTypeEnum.MyOrg || + userCache!.DataScopeType == DataScopeTypeEnum.MyOrgAndLower) + db.QueryFilter.AddTableFilter(u => userCache.DataScopeOrgs.Contains(u.CreateOrgId!.Value)); + //仅本人数据过滤器 + //本人创建,而且在本人所属部门的数据 + else if (userCache!.DataScopeType == DataScopeTypeEnum.MySelf) + { + db.QueryFilter.AddTableFilter(u => u.CreateOrgId!.Value == userCache.OrgId); + db.QueryFilter.AddTableFilter(u => u.CreateUserId!.Value == userCache.Id); + } + } + // else 全部数据不做筛选 + } + } + // 其他配置自定义过滤器 + + } + + + /// + /// 开启库表差异化日志 + /// + /// + /// + public static void SetDbDiffLog(SqlSugarProvider db) + { + if (!GlobalContext.SystemConfig!.DBEnableDiffLog) + return; + + //程序启动时注册 开启差异化记录 + StaticConfig.CompleteInsertableFunc = + StaticConfig.CompleteUpdateableFunc = + StaticConfig.CompleteDeleteableFunc = obj => //it是具体的对象Updateable等是个object + { + //反射的方法可能多个就需要用GetMethods().Where + if (obj.GetType().GenericTypeArguments[0].GetInterfaces().Any(it => it == typeof(IDiff))) + { + var method = obj.GetType().GetMethod("EnableDiffLogEvent"); + method?.Invoke(obj, new object?[] { null }); + } + + //技巧: + //可以定义一个接口只要是这个接口的才走这个逻辑 + //if(db.GetType().GenericTypeArguments[0].GetInterfaces().Any(it=>it==typeof(IDiff)) + //可以根据类型写if + //if(x.GetType().GenericTypeArguments[0] = typeof(Order)) { } + }; + + db.Aop.OnDiffLogEvent = async u => + { + var tables = u.AfterData.Select(it => it.TableName).Distinct(); + if(u.BeforeData!=null) + tables = tables.Union(u.BeforeData.Select(it => it.TableName)).Distinct(); + + var logDiff = new LogDiffEntity + { + Tables = string.Join(", ", tables), + // 操作后记录(字段描述、列名、值、表名、表描述) + AfterData = JsonConvert.SerializeObject(u.AfterData), + // 操作前记录(字段描述、列名、值、表名、表描述) + BeforeData = (u.BeforeData != null ? JsonConvert.SerializeObject(u.BeforeData) : null), + // 传进来的对象 + BusinessData = JsonConvert.SerializeObject(u.BusinessData), + // 枚举(insert、update、delete) + DiffType = u.DiffType.ToString(), + Sql = UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, u.Sql, u.Parameters), + Parameters = JsonConvert.SerializeObject(u.Parameters), + Elapsed = u.Time == null ? 0 : (long)u.Time.Value.TotalMilliseconds + }; + //防止表格过多入库失败 + if (logDiff.Tables.Length > 256) + logDiff.Tables = logDiff.Tables.Substring(255); + + await db.Insertable(logDiff).ExecuteCommandAsync(); + Log.Information($"*****差异日志开始*****{Environment.NewLine}{Environment.NewLine}{JsonConvert.SerializeObject(logDiff)}{Environment.NewLine}*****差异日志结束*****"); + }; + } + #endregion + + #region 初始化 + + /// + /// 初始化数据库 + /// + /// + public static void InitDatabase(ISqlSugarClient db) + { + if (!GlobalContext.SystemConfig!.EnableInitDb) return; + + var dbProvider = db; + + + // 创建数据库 + if (db.CurrentConnectionConfig.DbType != SqlSugar.DbType.Oracle) + { + dbProvider.DbMaintenance.CreateDatabase(); + } + var tables = dbProvider.DbMaintenance.GetTableInfoList(); + + // 获取所有实体表-初始化表结构 + var entityTypes = Assembly.GetAssembly(typeof(EntityBase))!.GetTypes().Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false)).ToList(); + if (!entityTypes.Any()) return; + foreach (var entityType in entityTypes) + { + var sugarTable = entityType.GetCustomAttribute(); + //只有首次创建的表需要初始化 + //变更请通过手动处理 + if (!tables.Any(it => string.Equals(it.Name, sugarTable!.TableName, StringComparison.OrdinalIgnoreCase))) + { + if (entityType.GetCustomAttribute() == null) + dbProvider.CodeFirst.InitTables(entityType); + else + dbProvider.CodeFirst.SplitTables().InitTables(entityType); + } + } + //第一次初始化数据 seed + if (tables.Count < 1) + UserDataSeed.InitData(db); + } + #endregion + } +} \ No newline at end of file diff --git a/API/Wood.Data.Repository/Extension/DatabaseExtension.cs b/API/Wood.Data.Repository/Extension/DatabaseExtension.cs new file mode 100644 index 0000000..df6865e --- /dev/null +++ b/API/Wood.Data.Repository/Extension/DatabaseExtension.cs @@ -0,0 +1,277 @@ +using Serilog; +using System.Collections; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Data.Common; +using System.Dynamic; +using System.Linq.Expressions; +using System.Reflection; +using Wood.Util; + +namespace Wood.Data.Repository +{ + public static class DatabasesExtension + { + /// + /// 将DataReader数据转为Dynamic对象 + /// + /// + /// + public static dynamic DataFillDynamic(IDataReader reader) + { + using (reader) + { + dynamic d = new ExpandoObject(); + for (int i = 0; i < reader.FieldCount; i++) + { + try + { + ((IDictionary)d).Add(reader.GetName(i), reader.GetValue(i)); + } + catch + { + ((IDictionary)d).Add(reader.GetName(i), null); + } + } + return d; + } + } + + /// + /// 获取模型对象集合 + /// + /// + /// + public static List DataFillDynamicList(IDataReader reader) + { + using (reader) + { + List list = new List(); + if (reader != null && !reader.IsClosed) + { + while (reader.Read()) + { + list.Add(DataFillDynamic(reader)); + } + reader.Close(); + reader.Dispose(); + } + return list; + } + } + + /// + /// 将IDataReader转换为集合 + /// + /// + /// + /// + public static List IDataReaderToList(IDataReader reader) + { + using (reader) + { + List field = new List(reader.FieldCount); + for (int i = 0; i < reader.FieldCount; i++) + { + field.Add(reader.GetName(i).ToLower()); + } + List list = new List(); + while (reader.Read()) + { + T model = Activator.CreateInstance(); + if (model != null) + { + var properties = ReflectionHelper.GetProperties(model.GetType()); + if (properties != null) + { + foreach (PropertyInfo property in properties) + { + if (field.Contains(property.Name.ToLower())) + { + if (!IsNullOrDBNull(reader[property.Name])) + { + property.SetValue(model, HackType(reader[property.Name], property.PropertyType), null); + } + } + } + } + list.Add(model); + } + } + reader.Close(); + reader.Dispose(); + return list; + } + } + + /// + /// 将IDataReader转换为DataTable + /// + /// + /// + public static DataTable IDataReaderToDataTable(IDataReader reader) + { + using (reader) + { + DataTable objDataTable = new DataTable("Table"); + int intFieldCount = reader.FieldCount; + for (int intCounter = 0; intCounter < intFieldCount; ++intCounter) + { + objDataTable.Columns.Add(reader.GetName(intCounter).ToLower(), reader.GetFieldType(intCounter)); + } + objDataTable.BeginLoadData(); + object[] objValues = new object[intFieldCount]; + while (reader.Read()) + { + reader.GetValues(objValues); + objDataTable.LoadDataRow(objValues, true); + } + reader.Close(); + reader.Dispose(); + objDataTable.EndLoadData(); + return objDataTable; + } + } + + /// + /// 获取实体类键值(缓存) + /// + /// + /// + /// + public static Hashtable GetPropertyInfo(T entity) + { + Hashtable ht = new Hashtable(); + PropertyInfo[]? props = ReflectionHelper.GetProperties(entity!.GetType()); + if (props != null) + { + foreach (PropertyInfo prop in props) + { + bool flag = true; + foreach (Attribute attr in prop.GetCustomAttributes(true)) + { + NotMappedAttribute? notMapped = attr as NotMappedAttribute; + if (notMapped != null) + { + flag = false; + break; + } + } + if (flag) + { + string name = prop.Name; + object? value = prop?.GetValue(entity, null); + ht[name] = value; + } + } + } + return ht; + } + + public static IQueryable AppendSort(IQueryable tempData, string sort, bool isAsc) + { + string[] sortArr = sort.Split(','); + MethodCallExpression? resultExpression = null; + for (int index = 0; index < sortArr.Length; index++) + { + string[] oneSortArr = sortArr[index].Trim().Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); + string sortField = oneSortArr[0]; + bool sortAsc = isAsc; + if (oneSortArr.Length == 2) + { + sortAsc = string.Equals(oneSortArr[1], "asc", StringComparison.OrdinalIgnoreCase) ? true : false; + } + var parameter = Expression.Parameter(typeof(T), "t"); + var property = ReflectionHelper.GetProperties(typeof(T))!.Where(p => p.Name.ToLower() == sortField.ToLower()).FirstOrDefault(); + var propertyAccess = Expression.MakeMemberAccess(parameter, property!); + var orderByExpression = Expression.Lambda(propertyAccess, parameter); + if (index == 0) + { + resultExpression = Expression.Call(typeof(Queryable), sortAsc ? "OrderBy" : "OrderByDescending", new Type[] { typeof(T), property!.PropertyType }, tempData.Expression, Expression.Quote(orderByExpression)); + } + else + { + resultExpression = Expression.Call(typeof(Queryable), sortAsc ? "ThenBy" : "ThenByDescending", new Type[] { typeof(T), property!.PropertyType }, tempData.Expression, Expression.Quote(orderByExpression)); + } + tempData = tempData.Provider.CreateQuery(resultExpression); + } + return tempData; + } + + //这个类对可空类型进行判断转换,要不然会报错 + public static object? HackType(object value, Type conversionType) + { + if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) + { + if (value == null) + return null; + NullableConverter nullableConverter = new NullableConverter(conversionType); + conversionType = nullableConverter.UnderlyingType; + } + return Convert.ChangeType(value, conversionType); + } + + public static bool IsNullOrDBNull(object obj) + { + return ((obj is DBNull) || string.IsNullOrEmpty(obj.ToString())) ? true : false; + } + + /// + /// 获取使用Linq生成的Sql + /// + /// + /// + /// + //public static string GetSql(this IQueryable query) + //{ + // var enumerator = query.Provider.Execute>(query.Expression).GetEnumerator(); + // var relationalCommandCache = enumerator.Private("_relationalCommandCache"); + // var selectExpression = relationalCommandCache.Private("_selectExpression"); + // var factory = relationalCommandCache.Private("_querySqlGeneratorFactory"); + + // var sqlGenerator = factory.Create(); + // var command = sqlGenerator.GetCommand(selectExpression); + + // string sql = command.CommandText; + // return sql; + //} + + /// + /// 获取运行时的Sql + /// + /// + /// + public static string GetCommandText(this DbCommand dbCommand) + { + var sql = dbCommand.CommandText; + foreach (DbParameter parameter in dbCommand.Parameters) + { + try + { + string? value = string.Empty; + switch (parameter.DbType) + { + case DbType.Date: + value = parameter.Value?.ToString()?.ToDateTime()?.ToString("yyyy-MM-dd HH:mm:ss"); + break; + default: + value = parameter.Value?.ToString(); + break; + } + sql = sql.Replace(parameter.ParameterName, value); + } + catch (Exception ex) + { + Log.Error(ex, "获取SQL语句时,组装sqlparameter参数失败:sql({sql}),DbType({DbType}),ParameterName({ParameterName}),ParameterValue({ParameterValue})",sql,parameter.DbType.ToString(), parameter.ParameterName, parameter.Value?.ToString()); + } + } + return sql; + } + + #region 私有方法 + private static object Private(this object obj, string privateField) => obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj)!; + private static T Private(this object obj, string privateField) => (T)obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj)!; + #endregion + } +} diff --git a/API/Wood.Data.Repository/Extension/DatabasePageExtension.cs b/API/Wood.Data.Repository/Extension/DatabasePageExtension.cs new file mode 100644 index 0000000..74357cd --- /dev/null +++ b/API/Wood.Data.Repository/Extension/DatabasePageExtension.cs @@ -0,0 +1,110 @@ +using System; +using System.Text; +using System.Data.Common; +using Wood.Util; +using System.Text.RegularExpressions; +using Newtonsoft.Json.Linq; + +namespace Wood.Data.Repository +{ + public class DatabasePageExtension + { + public static StringBuilder SqlServerPageSql(string strSql, string sort, int pageSize, int pageIndex) + { + CheckSqlParam(sort); + + StringBuilder sb = new StringBuilder(); + if (pageIndex == 0) + { + pageIndex = 1; + } + int startNum = (pageIndex - 1) * pageSize; + int endNum = (pageIndex) * pageSize; + string orderBy = string.Empty; + + if (!string.IsNullOrEmpty(sort)) + { + + orderBy = " ORDER BY " + sort; + } + else + { + orderBy = "ORDERE BY (SELECT 0)"; + } + sb.Append("SELECT * FROM (SELECT ROW_NUMBER() Over (" + orderBy + ")"); + sb.Append(" AS ROWNUM, * From (" + strSql + ") t ) AS N WHERE ROWNUM > " + startNum + " AND ROWNUM <= " + endNum + ""); + return sb; + } + + public static StringBuilder OraclePageSql(string strSql, string sort, int pageSize, int pageIndex) + { + CheckSqlParam(sort); + + StringBuilder sb = new StringBuilder(); + if (pageIndex == 0) + { + pageIndex = 1; + } + int startNum = (pageIndex - 1) * pageSize; + int endNum = (pageIndex) * pageSize; + string orderBy = string.Empty; + + if (!string.IsNullOrEmpty(sort)) + { + orderBy = " ORDER BY " + sort; + } + sb.Append("SELECT * From (SELECT ROWNUM AS n,"); + sb.Append(" T.* From (" + strSql + orderBy + ") t ) N WHERE n > " + startNum + " AND n <= " + endNum + ""); + return sb; + } + + public static StringBuilder MySqlPageSql(string strSql, string sort, int pageSize, int pageIndex) + { + CheckSqlParam(sort); + + StringBuilder sb = new StringBuilder(); + if (pageIndex == 0) + { + pageIndex = 1; + } + int num = (pageIndex - 1) * pageSize; + string orderBy = string.Empty; + + if (!string.IsNullOrEmpty(sort)) + { + orderBy = " ORDER BY " + sort; + } + sb.Append(strSql + orderBy); + sb.Append(" LIMIT " + num + "," + pageSize + ""); + return sb; + } + + public static string GetCountSql(string strSql) + { + string countSql = string.Empty; + string strSqlCopy = strSql.ToLower(); + int selectIndex = strSqlCopy.IndexOf("SELECT "); + int lastFromIndex = strSqlCopy.LastIndexOf(" FROM "); + if (selectIndex >= 0 && lastFromIndex >= 0) + { + int backFromIndex = strSqlCopy.LastIndexOf(" FROM ", lastFromIndex); + int backSelectIndex = strSqlCopy.LastIndexOf("SELECT ", lastFromIndex); + if (backSelectIndex == selectIndex) + { + countSql = "SELECT COUNT(*) " + strSql.Substring(lastFromIndex); + return countSql; + } + } + countSql = "SELECT COUNT(1) FROM (" + strSql + ") t"; + return countSql; + } + + private static void CheckSqlParam(string param) + { + if (!Regex.IsMatch(param, @"[-|;|,|\/|\(|\)|\[|\]|\}|\{|%|@|\*|!|\']")) + { + throw new ArgumentException("含有Sql注入的参数"); + } + } + } +} diff --git a/API/Wood.Data.Repository/Extension/RepositoryExtension.cs b/API/Wood.Data.Repository/Extension/RepositoryExtension.cs new file mode 100644 index 0000000..f1e5d04 --- /dev/null +++ b/API/Wood.Data.Repository/Extension/RepositoryExtension.cs @@ -0,0 +1,169 @@ +using SqlSugar; +using System.Linq.Expressions; +using System.Reflection; +using Wood.Entity; +using Wood.Util; + +namespace Wood.Data.Repository +{ + + public static class RepositoryExtension + { + #region 过滤器清除 + /// + /// 清除delete 过滤器 + /// + /// ISugarQueryable + public static ISugarQueryable ClearDeleteFilter(this SimpleClient repository) where T : EntityBase, new() + { + return repository.AsQueryable().ClearFilter(); + } + + /// + /// 清除 数据范围 过滤器 + /// + /// ISugarQueryable + public static ISugarQueryable ClearDataScopeFilter(this SimpleClient repository) where T : EntityBase, new() + { + return repository.AsQueryable().ClearFilter(); + } + + /// + /// 设置自定义 status 过滤器 + /// + /// ISugarQueryable + public static ISugarQueryable AddStatusFilter(this SimpleClient repository, int status = 1) where T : EntityBaseExtra, new() + { + var query = repository.AsQueryable(); + return query.Where(it => status == it.Status); + } + + /// + /// 设置自定义 status 过滤器 + /// + /// ISugarQueryable + public static ISugarQueryable AddStatusFilter(this SimpleClient repository, params int[] status) where T : EntityBaseExtra, new() + { + var query = repository.AsQueryable(); + return query.Where(it => status.Contains(it.Status)); + } + + #endregion + + /// + /// 实体假删除异步 _rep.FakeDeleteAsync(entity) + /// + /// + /// + /// 要删除的实体 + /// + public static Task FakeDeleteAsync(this SimpleClient repository, T entity) where T : EntityBase, new() + { + entity.IsDelete = true; + return repository.Context.Updateable(entity).UpdateColumns(it => new { it.IsDelete, it.UpdateTime, it.UpdateUserId }).ExecuteCommandAsync(); + } + + /// + /// 实体假删除 db.FakeDelete(entity) + /// + /// + /// + /// + /// + public static Task FakeDeleteAsync(this SimpleClient repository, Expression> whereExpression) where T : EntityBase, new() + { + long? userId = GlobalContext.UserInfo?.UserId; + return repository.Context.Updateable() + .AS() + .SetColumns("IsDelete", true) + .SetColumns("UpdateUserId", userId) + .SetColumns("UpdateTime", DateTime.Now) + .Where(whereExpression) + .ExecuteCommandAsync(); + } + + + /// + /// 实体假删除 db.FakeDelete(entity) + /// + /// + /// + /// + /// + public static Task FakeDeleteAsync(this SimpleClient repository, List entity) where T : EntityBase, new() + { + foreach (var item in entity) + item.IsDelete = true; + return repository.Context.Updateable(entity).UpdateColumns(it => new { it.IsDelete, it.UpdateTime, it.UpdateUserId }).ExecuteCommandAsync(); + } + + /// + /// 根据表名查询 + /// + /// + /// + public static ISugarQueryable AS(this ISugarQueryable queryable) + { + var info = GetTableInfo(); + return queryable.AS($"{info}"); + } + + /// + /// 根据表名查询 + /// + /// + /// + /// + /// + public static ISugarQueryable AS(this ISugarQueryable queryable) + { + var info = GetTableInfo(); + return queryable.AS($"{info}"); + } + + /// + /// 根据表名更新 + /// + /// + /// + public static IUpdateable AS(this IUpdateable updateable) where T : EntityBase, new() + { + var info = GetTableInfo(); + return updateable.AS($"{info}"); + } + + /// + /// 根据表名新增 + /// + /// + /// + public static IInsertable AS(this IInsertable insertable) where T : EntityBase, new() + { + var info = GetTableInfo(); + return insertable.AS($"{info}"); + } + + /// + /// 根据表名删除 + /// + /// + /// + public static IDeleteable AS(this IDeleteable deleteable) where T : EntityBase, new() + { + var info = GetTableInfo(); + return deleteable.AS($"{info}"); + } + + /// + /// 根据实体类型获取表信息 + /// + /// + /// + private static string? GetTableInfo() + { + var entityType = typeof(T); + var tableName = entityType.GetCustomAttribute()?.TableName; + return tableName; + } + } +} diff --git a/API/Wood.Data.Repository/Extension/SqlSugarPagedExtensions.cs b/API/Wood.Data.Repository/Extension/SqlSugarPagedExtensions.cs new file mode 100644 index 0000000..5eac6db --- /dev/null +++ b/API/Wood.Data.Repository/Extension/SqlSugarPagedExtensions.cs @@ -0,0 +1,146 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; + +namespace Wood.Data.Repository +{ + /// + /// 分页拓展类 + /// + public static class SqlSugarPagedExtensions + { + /// + /// 分页拓展 + /// + /// 对象 + /// 当前页码,从1开始 + /// 页码容量 + /// 查询结果 Select 表达式 + /// + public static TDataPaged ToPagedList(this ISugarQueryable query, int pageIndex, int pageSize, + Expression> expression) + { + var total = 0; + var items = query.ToPageList(pageIndex, pageSize, ref total, expression); + return CreateSqlSugarPagedList(items, total, pageIndex, pageSize); + } + + /// + /// 分页拓展 + /// + /// 对象 + /// 当前页码,从1开始 + /// 页码容量 + /// + public static TDataPaged ToPagedList(this ISugarQueryable query, int pageIndex, int pageSize) + { + var total = 0; + var items = query.ToPageList(pageIndex, pageSize, ref total); + return CreateSqlSugarPagedList(items, total, pageIndex, pageSize); + } + + /// + /// 分页拓展 + /// + /// 对象 + /// 当前页码,从1开始 + /// 页码容量 + /// 查询结果 Select 表达式 + /// + public static async Task> ToPagedListAsync(this ISugarQueryable query, int pageIndex, int pageSize, + Expression> expression) + { + RefAsync total = 0; + var items = await query.ToPageListAsync(pageIndex, pageSize, total, expression); + return CreateSqlSugarPagedList(items, total, pageIndex, pageSize); + } + + /// + /// 分页拓展 + /// + /// 对象 + /// 当前页码,从1开始 + /// 页码容量 + /// + public static async Task> ToPagedListAsync(this ISugarQueryable query, int pageIndex, int pageSize) + { + RefAsync total = 0; + var items = await query.ToPageListAsync(pageIndex, pageSize, total); + return CreateSqlSugarPagedList(items, total, pageIndex, pageSize); + } + + /// + /// 分页拓展 + /// + /// 对象 + /// 当前页码,从1开始 + /// 页码容量 + /// 查询结果 Select 表达式 + /// + public static async Task> ToPagedListAsync(this ISugarQueryable query, Pagination pagination, + Expression> expression) + { + RefAsync total = 0; + var items = await query.OrderBy(pagination.Sort).ToPageListAsync(pagination.PageIndex, pagination.PageSize, total, expression); + return CreateSqlSugarPagedList(items, total, pagination.PageIndex, pagination.PageSize); + } + + /// + /// 分页拓展 + /// + /// 对象 + /// 当前页码,从1开始 + /// 页码容量 + /// + public static async Task> ToPagedListAsync(this ISugarQueryable query, Pagination pagination) + { + RefAsync total = 0; + + var items = await query.OrderBy(pagination.Sort).ToPageListAsync(pagination.PageIndex, pagination.PageSize, total); + return CreateSqlSugarPagedList(items, total, pagination.PageIndex, pagination.PageSize); + } + + /// + /// 分页拓展 + /// + /// 集合对象 + /// 当前页码,从1开始 + /// 页码容量 + /// + public static TDataPaged ToPagedList(this IEnumerable list, int pageIndex, int pageSize) + { + var total = list.Count(); + var items = list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); + return CreateSqlSugarPagedList(items, total, pageIndex, pageSize); + } + + /// + /// 创建 对象 + /// + /// + /// 分页内容的对象集合 + /// 总条数 + /// 当前页码,从1开始 + /// 页码容量 + /// + public static TDataPaged CreateSqlSugarPagedList(IEnumerable items, int total, int pageIndex, int pageSize) + { + var totalPages = pageSize > 0 ? (int)Math.Ceiling(total / (double)pageSize) : 0; + return new TDataPaged + { + Page = pageIndex, + PageSize = pageSize, + Data = items, + Total = total, + TotalPages = totalPages, + HasNextPage = pageIndex < totalPages, + HasPrevPage = pageIndex - 1 > 0 + }; + } + } +} diff --git a/API/Wood.Data.Repository/Repository.cs b/API/Wood.Data.Repository/Repository.cs new file mode 100644 index 0000000..a76eef4 --- /dev/null +++ b/API/Wood.Data.Repository/Repository.cs @@ -0,0 +1,92 @@ +using SqlSugar; +using System.Data; +using System.Data.Common; +using System.Text; +using Wood.Entity; +using Wood.Util; + +namespace Wood.Data.Repository +{ + /// + /// 创建人:admin + /// 日 期:2018.10.18 + /// 描 述:定义仓储模型中的数据标准操作接口 + /// + public class SqlSugarRepository : SimpleClient where T : class, new() + { + #region 构造函数 + public SqlSugarRepository(ISqlSugarClient sqlSugarClient) + { + base.Context = sqlSugarClient; + } + #endregion + + #region 执行 SQL 语句 + public async Task ExecuteBySql(string strSql) + { + return await Context.Ado.ExecuteCommandAsync(strSql); + } + public async Task ExecuteBySql(string strSql, params DbParameter[] dbParameter) + { + return await Context.Ado.ExecuteCommandAsync(strSql, dbParameter); + } + public async Task ExecuteByProc(string procName) + { + return await Context.Ado.UseStoredProcedure().ExecuteCommandAsync(procName); + } + public async Task ExecuteByProc(string procName, params DbParameter[] dbParameter) + { + return await Context.Ado.UseStoredProcedure().ExecuteCommandAsync(procName, dbParameter); + } + #endregion + + #region 数据源 查询 + public async Task FindTable(string strSql) + { + return await Context.Ado.GetDataTableAsync(strSql); + } + public async Task FindTable(string strSql, DbParameter[] dbParameter) + { + return await Context.Ado.GetDataTableAsync(strSql, dbParameter); + } + public async Task FindTable(string strSql, Pagination pagination) + { + var data = await FindTable(strSql, pagination.Sort, pagination.PageSize, pagination.PageIndex); + pagination.TotalCount = data.total; + return data.Item2; + } + public async Task FindTable(string strSql, DbParameter[] dbParameter, Pagination pagination) + { + var data = await FindTable(strSql, dbParameter, pagination.Sort, pagination.PageSize, pagination.PageIndex); + pagination.TotalCount = data.total; + return data.Item2; + } + private async Task<(int total, DataTable)> FindTable(string strSql, string sort, int pageSize, int pageIndex) + { + return await FindTable(strSql, null, sort, pageSize, pageIndex); + } + private async Task<(int total, DataTable)> FindTable(string strSql, DbParameter[]? dbParameter, string sort, int pageSize, int pageIndex) + { + StringBuilder sb = new StringBuilder(); + if (Context.CurrentConnectionConfig.DbType == SqlSugar.DbType.MySql) + sb.Append(DatabasePageExtension.MySqlPageSql(strSql, sort, pageSize, pageIndex)); + else if (Context.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle) + sb.Append(DatabasePageExtension.OraclePageSql(strSql, sort, pageSize, pageIndex)); + else if (Context.CurrentConnectionConfig.DbType == SqlSugar.DbType.SqlServer) + sb.Append(DatabasePageExtension.SqlServerPageSql(strSql, sort, pageSize, pageIndex)); + else + sb.Append(DatabasePageExtension.MySqlPageSql(strSql, sort, pageSize, pageIndex)); + + object tempTotal = await Context.Ado.ExecuteCommandAsync("SELECT COUNT(1) FROM (" + strSql + ") T", dbParameter); + int total = tempTotal?.ToString()?.ToInt()??0; + if (total > 0) + { + var table = await Context.Ado.GetDataTableAsync(sb.ToString(), dbParameter); + return (total, table); + } + else + return (total, new DataTable()); + } + #endregion + } +} diff --git a/API/Wood.Data.Repository/UnitOfWork/IUnitOfWork.cs b/API/Wood.Data.Repository/UnitOfWork/IUnitOfWork.cs new file mode 100644 index 0000000..1a95550 --- /dev/null +++ b/API/Wood.Data.Repository/UnitOfWork/IUnitOfWork.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Data.Repository +{ + /// + /// 工作单元依赖接口 + /// + public interface IUnitOfWork + { + /// + /// 开启工作单元处理 + /// + void BeginTransaction(); + + /// + /// 提交工作单元处理 + /// + void CommitTransaction(); + + /// + /// 回滚工作单元处理 + /// + void RollbackTransaction(); + + /// + /// 执行完毕(无论成功失败) + /// + void OnCompleted(); + } +} diff --git a/API/Wood.Data.Repository/UnitOfWork/SqlSugarUnitOfWork.cs b/API/Wood.Data.Repository/UnitOfWork/SqlSugarUnitOfWork.cs new file mode 100644 index 0000000..95f123b --- /dev/null +++ b/API/Wood.Data.Repository/UnitOfWork/SqlSugarUnitOfWork.cs @@ -0,0 +1,79 @@ +// 麻省理工学院许可证 +// +// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995 +// +// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。 +// +// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。 +// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。 + +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using SqlSugar; +using System.Reflection; +using System.Transactions; + +namespace Wood.Data.Repository; + +/// +/// SqlSugar 事务和工作单元 +/// +public sealed class SqlSugarUnitOfWork : IUnitOfWork +{ + /// + /// SqlSugar 对象 + /// + private readonly ISqlSugarClient _sqlSugarClient; + + /// + /// 构造函数 + /// + /// + public SqlSugarUnitOfWork(ISqlSugarClient sqlSugarClient) + { + _sqlSugarClient = sqlSugarClient; + } + + /// + /// 开启工作单元处理 + /// + /// + /// + public void BeginTransaction() + { + _sqlSugarClient.AsTenant().BeginTran(); + } + + /// + /// 提交工作单元处理 + /// + /// + /// + public void CommitTransaction() + { + _sqlSugarClient.AsTenant().CommitTran(); + } + + /// + /// 回滚工作单元处理 + /// + /// + /// + public void RollbackTransaction() + { + _sqlSugarClient.AsTenant().RollbackTran(); + } + + /// + /// 执行完毕(无论成功失败) + /// + /// + /// + public void OnCompleted() + { + _sqlSugarClient.Dispose(); + } +} + diff --git a/API/Wood.Data.Repository/UnitOfWork/UnitOfWorkAttribute.cs b/API/Wood.Data.Repository/UnitOfWork/UnitOfWorkAttribute.cs new file mode 100644 index 0000000..d67c07b --- /dev/null +++ b/API/Wood.Data.Repository/UnitOfWork/UnitOfWorkAttribute.cs @@ -0,0 +1,123 @@ +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Serilog; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace Wood.Data.Repository +{ + /// + /// 工作单元配置特性 + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class UnitOfWorkAttribute : Attribute, IAsyncActionFilter, IOrderedFilter + { + /// + /// MiniProfiler 分类名 + /// + private const string MiniProfilerCategory = "unitOfWork"; + + /// + /// 过滤器排序 + /// + private const int FilterOrder = 9999; + + /// + /// 排序属性 + /// + public int Order => FilterOrder; + + /// + /// 构造函数 + /// + public UnitOfWorkAttribute() + { + } + + /// + /// 拦截请求 + /// + /// 动作方法上下文 + /// 中间件委托 + /// + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + // 获取动作方法描述器 + var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; + var method = actionDescriptor?.MethodInfo; + IUnitOfWork? unitOfWork = null; + try + { + + // 开始事务 + BeginTransaction(context, method, out unitOfWork); + + // 获取执行 Action 结果 + var resultContext = await next(); + + // 提交事务 + CommitTransaction( unitOfWork, resultContext); + } + catch (Exception ex) + { + //logger.LogError(ex, "Transaction Failed."); + Log.Error(ex, "事务执行失败!URL({url})",context.HttpContext.Request); + throw; + } + } + + /// + /// 开始事务 + /// + /// + /// + /// + /// + private static void BeginTransaction(FilterContext context, MethodInfo? method, out IUnitOfWork _unitOfWork) + { + // 解析工作单元服务 + _unitOfWork = context.HttpContext.RequestServices.GetRequiredService(); + + // 获取工作单元特性 + //unitOfWorkAttribute = method.GetCustomAttribute(); + + // 调用开启事务方法 + _unitOfWork.BeginTransaction(); + + } + + /// + /// 提交事务 + /// + /// + /// + /// + /// + private static void CommitTransaction(IUnitOfWork _unitOfWork, FilterContext resultContext) + { + // 获取动态结果上下文 + dynamic dynamicResultContext = resultContext; + + if (dynamicResultContext.Exception == null) + { + // 调用提交事务方法 + _unitOfWork.CommitTransaction(); + } + else + { + // 调用回滚事务方法 + _unitOfWork.RollbackTransaction(); + } + + // 调用执行完毕方法 + _unitOfWork.OnCompleted(); + } + } +} diff --git a/API/Wood.Data.Repository/Wood.Data.Repository.csproj b/API/Wood.Data.Repository/Wood.Data.Repository.csproj new file mode 100644 index 0000000..84b0066 --- /dev/null +++ b/API/Wood.Data.Repository/Wood.Data.Repository.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + diff --git a/API/Wood.Entity/BaseIdParam.cs b/API/Wood.Entity/BaseIdParam.cs new file mode 100644 index 0000000..749eb50 --- /dev/null +++ b/API/Wood.Entity/BaseIdParam.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Wood.Entity +{ + public class BaseIdParam + { + /// + /// 主键id + /// + [Required(ErrorMessage = "id不能为空")] + public virtual long Id { get; set; } = 0; + } + + public class BaseIdListParam + { + /// + /// 主键id 列表 + /// + public virtual List Ids { get; set; } = new List(); + } + + public class BaseStatusParam : BaseIdParam + { + public int Status { get; set; } = 0; + } +} diff --git a/API/Wood.Entity/ElDto.cs b/API/Wood.Entity/ElDto.cs new file mode 100644 index 0000000..71fef8c --- /dev/null +++ b/API/Wood.Entity/ElDto.cs @@ -0,0 +1,74 @@ +using Newtonsoft.Json; +using SqlSugar; + +namespace Wood.Entity +{ + /// + /// element plus + /// Select 选择器 dto + /// + public class ElSelectDto + { + /// + /// 显示文本 + /// + public string? Label { get; set; } + /// + /// 值 + /// + public string? Value { get; set; } + /// + /// 是否禁用 + /// + public bool Disabled { get; set; } + } + + /// + /// element plus + /// tree 型结构 dto + /// + public class ElTreeDto : ElTreeDto + { + } + + /// + /// element plus + /// tree 型结构 dto + /// + public class ElTreeDto + { + /// + /// 值 + /// + [SugarColumn(IsTreeKey = true)] //设置关联字段 + public long Id { get; set; } + /// + /// 显示文本 + /// + public string? Label { get; set; } + /// + /// 是否禁用 + /// + public bool Disabled { get; set; } + + [JsonIgnore] + public long ParentId { get; set; } + + public List? Children { get; set; } + } + + /// + /// 导入数据错误信息 + /// + public class ImportErrorDto + { + /// + /// 行号 + /// + public int Index { get; set; } + /// + /// 错误信息 + /// + public string? Errors { get; set; } + } +} diff --git a/API/Wood.Entity/EntityBase.cs b/API/Wood.Entity/EntityBase.cs new file mode 100644 index 0000000..35cf361 --- /dev/null +++ b/API/Wood.Entity/EntityBase.cs @@ -0,0 +1,143 @@ +using SqlSugar; +using System; + +namespace Wood.Entity; + +/// +/// 框架实体基类Id +/// +public abstract class EntityIdBase +{ + /// + /// 雪花Id + /// 如果没有赋值则会自动生成,值为[null,0]时会自动生成 + /// + [SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true, IsIdentity = false)] + public virtual long Id { get; set; } +} + +#region 非租户 +/// +/// 框架实体基类 创建 +/// +public abstract class EntityCreateBase : EntityIdBase, ICreateUserIdFilter +{ + /// + /// 创建者Id + /// + [SugarColumn(ColumnDescription = "创建者Id", IsOnlyIgnoreUpdate = true, IsNullable = true)] + public virtual long? CreateUserId { get; set; } + /// + /// 创建时间 + /// + [SugarColumn(ColumnDescription = "创建时间", IsOnlyIgnoreUpdate = true, IsNullable = true)] + public virtual DateTime? CreateTime { get; set; } +} +/// +/// 框架实体基类 +/// 包括 创建者信息,修改者信息,删除标记 +/// +public abstract class EntityBase : EntityIdBase, IDeletedFilter, IOrgIdFilter, ICreateUserIdFilter +{ + /// + /// 创建者部门Id + /// + [SugarColumn(ColumnDescription = "创建者部门Id", IsOnlyIgnoreUpdate = true, IsNullable = true)] + public virtual long? CreateOrgId { get; set; } + /// + /// 创建时间 + /// + [SugarColumn(ColumnDescription = "创建时间", IsOnlyIgnoreUpdate = true, IsNullable = true)] + public virtual DateTime? CreateTime { get; set; } + + /// + /// 创建者Id + /// + [SugarColumn(ColumnDescription = "创建者Id", IsOnlyIgnoreUpdate = true, IsNullable = true)] + public virtual long? CreateUserId { get; set; } + + /// + /// 更新时间 + /// + [SugarColumn(ColumnDescription = "更新时间", IsOnlyIgnoreInsert = true, IsNullable = true)] + public virtual DateTime? UpdateTime { get; set; } + + /// + /// 修改者Id + /// + [SugarColumn(ColumnDescription = "修改者Id", IsOnlyIgnoreInsert = true, IsNullable = true)] + public virtual long? UpdateUserId { get; set; } + + /// + /// 软删除 + /// + [SugarColumn(ColumnDescription = "软删除")] + public virtual bool IsDelete { get; set; } = false; +} + +/// +/// 框架实体基类 +/// 包括 创建者信息,修改者信息,删除标记 +/// 额外包括 状态 Status 1有效 0无效 +/// 额外包括 备注 Remark +/// +public abstract class EntityBaseExtra : EntityBase,IStatusFilter +{ + /// + /// 状态 + /// 1有效 0无效 + /// + [SugarColumn(ColumnDescription = "状态 1有效 0无效", DefaultValue = "1")] + public int Status { get; set; } = 1; + + /// + /// 备注 + /// + [SugarColumn(ColumnDescription = "备注", Length = 128,IsNullable =true)] + public string? Remark { get; set; } +} +#endregion + +#region 租户 + +/// +/// 框架实体基类 +/// 包括 租户信息,创建者信息,修改者信息,删除标记 +/// +public abstract class EntityTenantBase : EntityBase, ITenantIdFilter +{ + /// + /// 租户Id + /// + [SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true, IsNullable = true,DefaultValue ="0")] + public virtual long TenantId { get; set; } = 0; +} + +/// +/// 框架实体基类 +/// 包括 租户信息,创建者信息,修改者信息,删除标记 +/// 额外包括 状态 Status 1有效 0无效 +/// 额外包括 备注 Remark +/// +public abstract class EntityTenantBaseExtra : EntityBaseExtra, ITenantIdFilter +{ + /// + /// 租户Id + /// + [SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true, IsNullable = true, DefaultValue = "0")] + public virtual long TenantId { get; set; } = 0; +} +/// +/// 框架实体基类 +/// 包括 租户信息,创建者信息 +/// +public abstract class EntityTenantCreateBase : EntityCreateBase, ITenantIdFilter +{ + /// + /// 租户Id + /// + [SugarColumn(ColumnDescription = "租户Id", IsOnlyIgnoreUpdate = true, IsNullable = true)] + public virtual long TenantId { get; set; } +} +#endregion + diff --git a/API/Wood.Entity/Enum/SysManageEnum.cs b/API/Wood.Entity/Enum/SysManageEnum.cs new file mode 100644 index 0000000..bcc3e83 --- /dev/null +++ b/API/Wood.Entity/Enum/SysManageEnum.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Entity +{ + /// + /// 登录状态 + /// + public enum LoginStatusEnum + { + /// + /// 失败 + /// + [Description("失败")] + Failed = 0, + /// + /// 成功 + /// + [Description("成功")] + Success = 1, + /// + /// 密码错误 + /// + [Description("密码错误")] + PasswordError = 2, + /// + /// 账户已经冻结 + /// + [Description("账户已经冻结")] + Frozen = 3, + /// + /// 刷新成功 + /// + [Description("刷新成功")] + RefreshSuccess = 4, + /// + /// 没有用户 + /// + [Description("没有用户")] + NoAccount = 5, + } + /// + /// 用户类别 + /// + public enum AccountTypeEnum + { + /// + /// 超级管理员 + /// + [Description("超级管理员")] + SuperAdmin = 9999, + /// + /// 租管 + /// + [Description("租管")] + TenantAdmin = 991, + /// + /// 管理员 + /// + [Description("管理员")] + Admin = 9, + /// + /// 用户 + /// + [Description("用户")] + User = 0 + } + + /// + /// 触发器时间类型 + /// + public enum TriggerTypeEnum + { + /// + /// cron 表达式 + /// + Cron = 0, + /// + /// 每天时间 + /// 23:50 + /// + DailyAt = 1, + /// + /// 间隔分钟 + /// + PeriodMinutes = 2, + /// + /// 间隔秒钟 + /// + PeriodSeconds = 3 + } + + /// + /// 作业触发器状态 + /// + public enum TriggerStatusEnum + { + /// + /// 无效 + /// + [Description("无效")] + Ineffective = 0, + /// + /// 就绪 + /// + [Description("就绪")] + Ready = 1, + + /// + /// 正在运行 + /// + [Description("正在运行")] + Running = 2, + + /// + /// 暂停 + /// + [Description("暂停")] + Pause = 3, + + /// + /// 阻塞 + /// + /// 本该执行但是没有执行 + [Description("阻塞")] + Blocked = 4, + + /// + /// 由失败进入就绪 + /// + /// 运行错误当并未超出最大错误数,进入下一轮就绪 + [Description("由失败进入就绪")] + ErrorToReady = 5, + + /// + /// 归档 + /// + /// 结束时间小于当前时间 + [Description("归档")] + Archived = 6, + + /// + /// 崩溃 + /// + /// 错误次数超出了最大错误数 + [Description("崩溃")] + Panic = 7, + + /// + /// 超限 + /// + /// 运行次数超出了最大限制 + [Description("超限")] + Overrun = 8 + } + + + public enum MenuTypeEnum + { + [Description("目录")] + Directory = 1, + + [Description("页面")] + Menu = 2, + + [Description("按钮")] + Button = 3 + } + /// + /// 数据范围 + /// + public enum DataScopeTypeEnum + { + /// + /// 本人数据 + /// + [Description("本人数据")] + MySelf = 1, + /// + /// 所有数据 + /// + [Description("所有数据")] + All = 2, + /// + /// 本部门数据 + /// + [Description("本部门数据")] + MyOrg = 4, + /// + /// 本部门及以下数据 + /// + [Description("本部门及以下数据")] + MyOrgAndLower = 8, + /// + /// 自定义数据 + /// + [Description("自定义数据")] + Custom = 16 + } + + /// + /// 系统消息类型 + /// + public enum MessageTypeEnum + { + /// + /// 系统通知 + /// + [Description("系统通知")] + SystemNotification, + /// + /// 公告 + /// + [Description("公告")] + Announcement, + /// + /// 私信 + /// + [Description("私信")] + PrivateMessages, + } + + /// + /// 通知公告状态枚举 + /// + public enum MessageStatusEnum + { + /// + /// 草稿 + /// + [Description("草稿")] + Draft = 0, + + /// + /// 发布 + /// + [Description("发布")] + Published = 1, + + /// + /// 撤回 + /// + [Description("撤回")] + Cancel = 2, + + /// + /// 删除 + /// + [Description("删除")] + Delete = 3 + } +} diff --git a/API/Wood.Entity/IEntityFilter.cs b/API/Wood.Entity/IEntityFilter.cs new file mode 100644 index 0000000..3f6c6a3 --- /dev/null +++ b/API/Wood.Entity/IEntityFilter.cs @@ -0,0 +1,59 @@ + +namespace Wood.Entity; + +/// +/// 假删除接口过滤器 +/// +public interface IDeletedFilter +{ + /// + /// 软删除 + /// + bool IsDelete { get; set; } +} + +/// +/// 状态过滤器 +/// +public interface IStatusFilter +{ + /// + /// 状态过滤器 + /// 默认 1 有效 0无效 + /// 可设置其他状态 + /// + int Status { get; set; } +} + +/// +/// 租户Id接口过滤器 +/// +public interface ITenantIdFilter +{ + /// + /// 租户Id + /// + long TenantId { get; set; } +} + +/// +/// 机构Id接口过滤器 +/// +public interface IOrgIdFilter +{ + /// + /// 创建者部门Id + /// + long? CreateOrgId { get; set; } +} + +/// +/// 创建人Id接口过滤器 +/// +public interface ICreateUserIdFilter +{ + /// + /// 创建者部门Id + /// + long? CreateUserId { get; set; } +} diff --git a/API/Wood.Entity/Interface/IDiff.cs b/API/Wood.Entity/Interface/IDiff.cs new file mode 100644 index 0000000..a11d6c4 --- /dev/null +++ b/API/Wood.Entity/Interface/IDiff.cs @@ -0,0 +1,9 @@ +namespace Wood.Entity +{ + /// + /// 标记目标 实体 记录差异日志 + /// + public interface IDiff + { + } +} diff --git a/API/Wood.Entity/Interface/ILifeTimeService.cs b/API/Wood.Entity/Interface/ILifeTimeService.cs new file mode 100644 index 0000000..3a731fc --- /dev/null +++ b/API/Wood.Entity/Interface/ILifeTimeService.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Entity +{ + /// + /// 生命周期接口 + /// + public interface ILifeTimeService + { + } +} diff --git a/API/Wood.Entity/Interface/IScoped.cs b/API/Wood.Entity/Interface/IScoped.cs new file mode 100644 index 0000000..3f6022c --- /dev/null +++ b/API/Wood.Entity/Interface/IScoped.cs @@ -0,0 +1,10 @@ + +namespace Wood.Entity +{ + /// + /// 标记为 scoped 注入 + /// + public interface IScoped: ILifeTimeService + { + } +} diff --git a/API/Wood.Entity/Interface/ISingleton.cs b/API/Wood.Entity/Interface/ISingleton.cs new file mode 100644 index 0000000..edd4e13 --- /dev/null +++ b/API/Wood.Entity/Interface/ISingleton.cs @@ -0,0 +1,10 @@ + +namespace Wood.Entity +{ + /// + /// 标记为 singleton 注入 + /// + public interface ISingleton : ILifeTimeService + { + } +} diff --git a/API/Wood.Entity/Interface/ITransient.cs b/API/Wood.Entity/Interface/ITransient.cs new file mode 100644 index 0000000..3b035ff --- /dev/null +++ b/API/Wood.Entity/Interface/ITransient.cs @@ -0,0 +1,10 @@ + +namespace Wood.Entity +{ + /// + /// 标记为 transient 注入 + /// + public interface ITransient : ILifeTimeService + { + } +} diff --git a/API/Wood.Entity/Pagination.cs b/API/Wood.Entity/Pagination.cs new file mode 100644 index 0000000..ba57a5d --- /dev/null +++ b/API/Wood.Entity/Pagination.cs @@ -0,0 +1,50 @@ +namespace Wood.Entity +{ + /// + /// 分页参数 + /// + public class Pagination + { + public Pagination() + { + Sort = "Id Desc"; // 默认按Id排序 + PageIndex = 1; + PageSize = 20; + } + + /// + /// 每页行数 + /// + public int PageSize { get; set; } + /// + /// 当前页 + /// + public int PageIndex { get; set; } + /// + /// 排序列 + /// 多列 使用 , 号分割 + /// + public string Sort { get; set; } + /// + /// 总记录数 + /// + public int TotalCount { get; set; } + /// + /// 总页数 + /// + public int TotalPage + { + get + { + if (TotalCount > 0) + { + return TotalCount % this.PageSize == 0 ? TotalCount / this.PageSize : TotalCount / this.PageSize + 1; + } + else + { + return 0; + } + } + } + } +} diff --git a/API/Wood.Entity/SystemManage/DataDictDetailEntity.cs b/API/Wood.Entity/SystemManage/DataDictDetailEntity.cs new file mode 100644 index 0000000..4d9b790 --- /dev/null +++ b/API/Wood.Entity/SystemManage/DataDictDetailEntity.cs @@ -0,0 +1,48 @@ +using SqlSugar; +using System; +using System.ComponentModel.DataAnnotations; +using WoodWood.Util.Validations; + +namespace Wood.Entity.SystemManage +{ + /// + /// 字典详细信息 + /// + [SugarTable("SysDataDictDetail", "字典详细信息")] + [SugarIndex("SysDataDictDetail_DictKey", nameof(DictKey), OrderByType.Desc, true)] + public class DataDictDetailEntity : EntityBaseExtra + { + /// + /// 字典类型 + /// + [SugarColumn(ColumnDescription = "字典类型")] + [Required] + public long DictTypeId { get; set; } + /// + /// 字典键 + /// + /// + [SugarColumn(ColumnDescription = "字典键", Length = 32)] + [Required] + [UniqueValue(ErrorMessage ="字典Key不能重复!")] + public string DictKey { get; set; } = ""; + /// + /// 字典值 + /// + /// + [SugarColumn(ColumnDescription = "字典值", Length = 32)] + [Required] + public string DictValue { get; set; } = ""; + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } = 0; + + /// + /// DataDictEntity + /// + [Navigate(NavigateType.OneToOne, nameof(DictTypeId), nameof(DataDictEntity.Id))] + public DataDictEntity? DataDict{ get; set; }//不要给get set赋值 + } +} diff --git a/API/Wood.Entity/SystemManage/DataDictEntity.cs b/API/Wood.Entity/SystemManage/DataDictEntity.cs new file mode 100644 index 0000000..dabcc7b --- /dev/null +++ b/API/Wood.Entity/SystemManage/DataDictEntity.cs @@ -0,0 +1,43 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using WoodWood.Util.Validations; + +namespace Wood.Entity.SystemManage +{ + /// + /// 字典类型信息 + /// + [SugarTable("SysDataDict", "字典类型信息")] + [SugarIndex("SysDataDict_FormCode", nameof(FormCode), OrderByType.Desc, true)] + public class DataDictEntity : EntityBaseExtra + { + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称",Length =64)] + [Required(ErrorMessage = "必须填写字典类型名称!")] + public string DictName { get; set; } = ""; + + /// + /// 编码 + /// + [SugarColumn(ColumnDescription = "编码", Length = 32)] + [Required] + [UniqueValue(ErrorMessage ="编码不能重复!")] + public string FormCode { get; set; } = ""; + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } = 0; + + /// + /// 字典明细信息 + /// + [Navigate( NavigateType.OneToMany, nameof(DataDictDetailEntity.DictTypeId))]//注意顺序 + public List? Details { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/FileEntity.cs b/API/Wood.Entity/SystemManage/FileEntity.cs new file mode 100644 index 0000000..4d56491 --- /dev/null +++ b/API/Wood.Entity/SystemManage/FileEntity.cs @@ -0,0 +1,68 @@ +using SqlSugar; +using System.ComponentModel.DataAnnotations; + +namespace Wood.Entity.SystemManage +{ + /// + /// 附件信息 + /// + [SugarTable("SysFile", "附件信息")] + [SugarIndex("sysfile_packageCode_index",nameof(PackageCode),OrderByType.Asc)] + public class FileEntity:EntityBase + { + /// + /// 打包Guid + /// + [SugarColumn(ColumnDescription = "打包Guid", Length = 32,IsNullable =true)] + [MaxLength(32)] + public string? PackageCode { get; set; } + /// + /// 提供者 + /// + [SugarColumn(ColumnDescription = "提供者", Length = 128, IsNullable = true)] + [MaxLength(128)] + public string? Provider { get; set; } + + /// + /// 仓储名称 + /// + [SugarColumn(ColumnDescription = "仓储名称", Length = 128, IsNullable = true)] + [MaxLength(128)] + public string? BucketName { get; set; } + + /// + /// 文件名称(上传时名称) + /// 文件名称 + [SugarColumn(ColumnDescription = "文件名称", Length = 128)] + [MaxLength(128)] + public string FileName { get; set; } = ""; + + /// + /// 文件后缀 + /// + [SugarColumn(ColumnDescription = "文件后缀", Length = 16, IsNullable = true)] + [MaxLength(16)] + public string? Suffix { get; set; } + + /// + /// 存储路径 + /// + [SugarColumn(ColumnDescription = "存储路径", Length = 128)] + [MaxLength(128)] + public string FilePath { get; set; } = ""; + + /// + /// 文件大小KB + /// + [SugarColumn(ColumnDescription = "文件大小KB", Length = 16)] + [MaxLength(16)] + public float SizeKb { get; set; } = 0; + + /// + /// 文件大小信息-计算后的 + /// + [SugarColumn(ColumnDescription = "文件大小信息", Length = 64, IsNullable = true)] + [MaxLength(64)] + public string? SizeInfo { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/JobDetailEntity.cs b/API/Wood.Entity/SystemManage/JobDetailEntity.cs new file mode 100644 index 0000000..9fa1807 --- /dev/null +++ b/API/Wood.Entity/SystemManage/JobDetailEntity.cs @@ -0,0 +1,40 @@ +using SqlSugar; + +namespace Wood.Entity.SystemManage; + +/// +/// 系统作业信息表 +/// +[SugarTable("SysJobDetail", "系统作业信息表")] +public class JobDetailEntity : EntityBaseExtra +{ + /// + /// 作业Id + /// + [SugarColumn(ColumnDescription = "作业Id", Length = 64)] + public virtual string JobId { get; set; } = ""; + + /// + /// 组名称 + /// + [SugarColumn(ColumnDescription = "组名称", Length = 128)] + public string GroupName { get; set; } = "default"; + + /// + /// 作业类型FullName + /// + [SugarColumn(ColumnDescription = "作业类型", Length = 128,IsNullable =true)] + public string? JobType { get; set; } + + /// + /// 程序集Name + /// + [SugarColumn(ColumnDescription = "程序集", Length = 128, IsNullable = true)] + public string? AssemblyName { get; set; } + + /// + /// 描述信息 + /// + [SugarColumn(ColumnDescription = "描述信息", Length = 128, IsNullable = true)] + public string? Description { get; set; } +} \ No newline at end of file diff --git a/API/Wood.Entity/SystemManage/JobTriggerEntity.cs b/API/Wood.Entity/SystemManage/JobTriggerEntity.cs new file mode 100644 index 0000000..1773eed --- /dev/null +++ b/API/Wood.Entity/SystemManage/JobTriggerEntity.cs @@ -0,0 +1,114 @@ +using SqlSugar; +using System; + +namespace Wood.Entity.SystemManage; + +/// +/// 系统作业触发器表 +/// +[SugarTable("SysJobTrigger", "系统作业触发器表")] +public class JobTriggerEntity : EntityCreateBase +{ + /// + /// 触发器Id + /// + [SugarColumn(ColumnDescription = "触发器Id", Length = 64)] + public virtual string TriggerId { get; set; } = ""; + + /// + /// 作业Id + /// + [SugarColumn(ColumnDescription = "作业Id", Length = 64)] + public virtual string JobId { get; set; } = ""; + + /// + /// 触发器类型FullName + /// + [SugarColumn(ColumnDescription = "触发器类型")] + public TriggerTypeEnum TriggerType { get; set; } = TriggerTypeEnum.Cron; + + /// + /// 参数 + /// 运行时间间隔 + /// + [SugarColumn(ColumnDescription = "参数", Length = 128)] + public string Args { get; set; } = ""; + + /// + /// 描述信息 + /// + [SugarColumn(ColumnDescription = "描述信息", Length = 128, IsNullable = true)] + public string? Description { get; set; } + + /// + /// 状态 + /// + [SugarColumn(ColumnDescription = "状态")] + public TriggerStatusEnum Status { get; set; } = TriggerStatusEnum.Ready; + + /// + /// 起始时间 + /// + [SugarColumn(ColumnDescription = "起始时间", IsNullable = true)] + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + [SugarColumn(ColumnDescription = "结束时间", IsNullable = true)] + public DateTime? EndTime { get; set; } + + /// + /// 最近运行时间 + /// + [SugarColumn(ColumnDescription = "最近运行时间", IsNullable = true)] + public DateTime? LastRunTime { get; set; } + + /// + /// 下一次运行时间 + /// + [SugarColumn(ColumnDescription = "下一次运行时间", IsNullable = true)] + public DateTime? NextRunTime { get; set; } + + /// + /// 触发次数 + /// + [SugarColumn(ColumnDescription = "触发次数")] + public long NumberOfRuns { get; set; } = 0; + + /// + /// 最大触发次数(0:不限制,n:N次) + /// + [SugarColumn(ColumnDescription = "最大触发次数")] + public long MaxNumberOfRuns { get; set; } = 0; + + /// + /// 出错次数 + /// + [SugarColumn(ColumnDescription = "出错次数")] + public long NumberOfErrors { get; set; } = 0; + + /// + /// 最大出错次数(0:不限制,n:N次) + /// + [SugarColumn(ColumnDescription = "最大出错次数")] + public long MaxNumberOfErrors { get; set; } = 0; + + /// + /// 重试次数 + /// + [SugarColumn(ColumnDescription = "重试次数")] + public int NumRetries { get; set; } = 0; + + /// + /// 重试间隔时间(ms) + /// + [SugarColumn(ColumnDescription = "重试间隔时间(ms)")] + public int RetryTimeout { get; set; } = 60000; + + /// + /// 是否启动时执行一次 + /// + [SugarColumn(ColumnDescription = "是否启动时执行一次")] + public bool RunOnStart { get; set; } = false; +} \ No newline at end of file diff --git a/API/Wood.Entity/SystemManage/LogDiffEntity.cs b/API/Wood.Entity/SystemManage/LogDiffEntity.cs new file mode 100644 index 0000000..b8c9faa --- /dev/null +++ b/API/Wood.Entity/SystemManage/LogDiffEntity.cs @@ -0,0 +1,57 @@ +using SqlSugar; + +namespace Wood.Entity.SystemManage; + +/// +/// 系统差异日志表 +/// +[SugarTable("SysLogDiff", "系统差异日志表")] +public class LogDiffEntity : EntityCreateBase +{ + /// + /// 影响表 + /// + [SugarColumn(ColumnDescription = "操作前记录", IsNullable = true)] + public string? Tables { get; set; } + /// + /// 操作前记录 + /// + [SugarColumn(ColumnDescription = "操作前记录", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? BeforeData { get; set; } + + /// + /// 操作后记录 + /// + [SugarColumn(ColumnDescription = "操作后记录", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? AfterData { get; set; } + + /// + /// Sql + /// + [SugarColumn(ColumnDescription = "Sql", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? Sql { get; set; } + + /// + /// 参数 手动传入的参数 + /// + [SugarColumn(ColumnDescription = "参数", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? Parameters { get; set; } + + /// + /// 业务对象 + /// + [SugarColumn(ColumnDescription = "业务对象", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? BusinessData { get; set; } + + /// + /// 差异操作 + /// + [SugarColumn(ColumnDescription = "差异操作", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? DiffType { get; set; } + + /// + /// 耗时 + /// + [SugarColumn(ColumnDescription = "耗时")] + public long Elapsed { get; set; } = 0; +} \ No newline at end of file diff --git a/API/Wood.Entity/SystemManage/LogEventEntity.cs b/API/Wood.Entity/SystemManage/LogEventEntity.cs new file mode 100644 index 0000000..2bbb51a --- /dev/null +++ b/API/Wood.Entity/SystemManage/LogEventEntity.cs @@ -0,0 +1,64 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Entity.SystemManage +{ + /// + /// 事件执行记录 + /// + [SugarTable("SysLogEvent", "事件执行记录")] + public class LogEventEntity : EntityCreateBase + { + /// + /// 事件名 + /// + [SugarColumn(ColumnDescription = "事件名", Length = 32)] + public string EventName { get; set; } = ""; + + /// + /// 事件id + /// + [SugarColumn(ColumnDescription = "事件id", Length = 32)] + public string EventId { get; set; } = ""; + + /// + /// 发布时间 + /// + [SugarColumn(ColumnDescription = "发布时间", IsNullable = true)] + public DateTime? PublishDateTime { get; set; } + + /// + /// 发布内容 + /// + [SugarColumn(ColumnDescription = "发布内容", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? PublishContent { get; set; } + + /// + /// 状态 + /// + [SugarColumn(ColumnDescription = "状态", IsNullable = true, Length = 16)] + public string? Status { get; set; } + + /// + /// 执行时间 + /// + [SugarColumn(ColumnDescription = "执行时间")] + public long Elapsed { get; set; } = 0; + + /// + /// 重试次数 + /// + [SugarColumn(ColumnDescription = "重试次数")] + public int RetryCount { get; set; } = 0; + + /// + /// 备注 + /// + [SugarColumn(ColumnDescription = "备注", Length = 2048, IsNullable = true)] + public string? Remark { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/LogExceptionEntity.cs b/API/Wood.Entity/SystemManage/LogExceptionEntity.cs new file mode 100644 index 0000000..17c2ac6 --- /dev/null +++ b/API/Wood.Entity/SystemManage/LogExceptionEntity.cs @@ -0,0 +1,36 @@ +using SqlSugar; + +namespace Wood.Entity.SystemManage +{ + /// + /// 错误日志 + /// + [SugarTable("SysLogException", "错误日志")] + public class LogExceptionEntity : LogOperationEntity + { + + /// + /// 错误路径信息 + /// + [SugarColumn(ColumnDescription = "请求类型", Length = 32, IsNullable = true)] + public string? Source { get; set; } + + /// + /// 错误信息 + /// + [SugarColumn(ColumnDescription = "错误信息", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? Exception { get; set; } + + /// + /// 错误路径信息 + /// + [SugarColumn(ColumnDescription = "请求类型", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? ExceptionStackTrace { get; set; } + + /// + /// 错误备注 + /// + [SugarColumn(ColumnDescription = "错误备注", IsNullable = true)] + public string? Remark { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/LogJobEntity.cs b/API/Wood.Entity/SystemManage/LogJobEntity.cs new file mode 100644 index 0000000..1e8b5c5 --- /dev/null +++ b/API/Wood.Entity/SystemManage/LogJobEntity.cs @@ -0,0 +1,55 @@ +using SqlSugar; + +namespace Wood.Entity.SystemManage +{ + /// + /// JOB操作日志 + /// + [SugarTable("SysLogJob", "JOB操作日志")] + public class LogJobEntity : EntityCreateBase + { + + /// + /// 触发器Id + /// + [SugarColumn(ColumnDescription = "触发器Id", Length = 64)] + public string TriggerId { get; set; } = ""; + + /// + /// 作业Id + /// + [SugarColumn(ColumnDescription = "作业Id", Length = 64)] + public string JobId { get; set; } = ""; + + /// + /// 运行时间 + /// + [SugarColumn(ColumnDescription = "运行时间", IsNullable = true)] + public DateTime? RunTime { get; set; } + + /// + /// 状态 + /// + [SugarColumn(ColumnDescription = "状态", IsNullable = true)] + public string? Status { get; set; } + + /// + /// 执行时间 + /// + [SugarColumn(ColumnDescription = "执行时间")] + public long Elapsed { get; set; } = 0; + + /// + /// 重试次数 + /// + [SugarColumn(ColumnDescription = "重试次数")] + public int RetryCount { get; set; } = 0; + + + /// + /// 备注 + /// + [SugarColumn(ColumnDescription = "备注", Length = 256, IsNullable = true)] + public string? Remark { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/LogLoginEntity.cs b/API/Wood.Entity/SystemManage/LogLoginEntity.cs new file mode 100644 index 0000000..eedebcd --- /dev/null +++ b/API/Wood.Entity/SystemManage/LogLoginEntity.cs @@ -0,0 +1,42 @@ +using SqlSugar; + +namespace Wood.Entity.SystemManage +{ + /// + /// 登录操作日志 + /// + [SugarTable("SysLogLogin", "登录操作日志")] + public class LogLoginEntity : EntityCreateBase + { + /// + /// 用户账号 + /// + [SugarColumn(ColumnDescription = "用户账号", Length = 64)] + public string Account { get; set; } = ""; + /// + /// 登录状态 + /// + [SugarColumn(ColumnDescription = "登录状态")] + public LoginStatusEnum LogStatus { get; set; } = LoginStatusEnum.Success; + /// + /// ip + /// + [SugarColumn(ColumnDescription = "ip", Length = 128, IsNullable = true)] + public string? IpAddress { get; set; } + /// + /// 浏览器 + /// + [SugarColumn(ColumnDescription = "浏览器", Length = 1024, IsNullable = true)] + public string? Browser { get; set; } + /// + /// 系统 + /// + [SugarColumn(ColumnDescription = "系统", IsNullable = true)] + public string? Os { get; set; } + /// + /// 登录状态 + /// + [SugarColumn(ColumnDescription = "登录信息", Length = 32, IsNullable = true)] + public string? Message { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/LogOperationEntity.cs b/API/Wood.Entity/SystemManage/LogOperationEntity.cs new file mode 100644 index 0000000..afec6d4 --- /dev/null +++ b/API/Wood.Entity/SystemManage/LogOperationEntity.cs @@ -0,0 +1,97 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Entity.SystemManage +{ + /// + /// 操作日志 + /// + [SugarTable("SysLogOperate", "操作日志")] + public class LogOperationEntity : EntityCreateBase + { + /// + /// 请求类型 + /// + [SugarColumn(ColumnDescription = "请求类型",Length =8, IsNullable = true)] + public string? HttpMethod { get; set; } + /// + /// 请求Url + /// + [SugarColumn(ColumnDescription = "请求Url", IsNullable = true)] + public string? RequestUrl { get; set; } + /// + /// 请求内容 + /// + [SugarColumn(ColumnDescription = "请求内容", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? RequestParam { get; set; } + /// + /// 返回内容 + /// + [SugarColumn(ColumnDescription = "返回内容", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? ReturnResult { get; set; } + /// + /// 信息 + /// + [SugarColumn(ColumnDescription = "信息", ColumnDataType = StaticConfig.CodeFirst_BigString, IsNullable = true)] + public string? Message { get; set; } + /// + /// Controller + /// + [SugarColumn(ColumnDescription = "Controller", Length =64, IsNullable = true)] + public string? ControllerName { get; set; } + /// + /// Action + /// + [SugarColumn(ColumnDescription = "Action", Length = 64, IsNullable = true)] + public string? ActionName { get; set; } + + /// + /// MethodName + /// + [SugarColumn(ColumnDescription = "Action", Length = 256, IsNullable = true)] + public string? MethodName { get; set; } + /// + /// 浏览器 + /// + [SugarColumn(ColumnDescription = "浏览器", Length = 1024, IsNullable = true)] + public string? Browser { get; set; } + /// + /// 系统 + /// + [SugarColumn(ColumnDescription = "系统", IsNullable = true)] + public string? Os { get; set; } + /// + /// 请求时间 + /// + [SugarColumn(ColumnDescription = "请求时间")] + public int Elapsed { get; set; } = 0; + /// + /// ip + /// + [SugarColumn(ColumnDescription = "ip",Length =128, IsNullable = true)] + public string? IpAddress { get; set; } + + /// + /// log 时间 + /// + [SugarColumn(ColumnDescription = "log 时间", IsNullable = true)] + public DateTime? LogDateTime { get; set; } + + /// + /// 用户账号 + /// + [SugarColumn(ColumnDescription = "用户账号", Length = 64, IsNullable = true)] + public string? UserName { get; set; } + + /// + /// 用户姓名 + /// + [SugarColumn(ColumnDescription = "用户姓名", Length = 16, IsNullable = true)] + public string? RealName { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/MenuAuthorizeEntity.cs b/API/Wood.Entity/SystemManage/MenuAuthorizeEntity.cs new file mode 100644 index 0000000..25a9e16 --- /dev/null +++ b/API/Wood.Entity/SystemManage/MenuAuthorizeEntity.cs @@ -0,0 +1,23 @@ +using SqlSugar; + +namespace Wood.Entity.SystemManage +{ + /// + /// 角色授权 + /// + [SugarTable("SysMenuAuthorize", "角色授权")] + public class MenuAuthorizeEntity : EntityTenantBaseExtra + { + /// + /// 菜单id + /// + [SugarColumn(ColumnDescription = "菜单id")] + public long MenuId { get; set; } = 0; + + /// + /// 角色id + /// + [SugarColumn(ColumnDescription = "角色id")] + public long RoleId { get; set; } = 0; + } +} diff --git a/API/Wood.Entity/SystemManage/MenuEntity.cs b/API/Wood.Entity/SystemManage/MenuEntity.cs new file mode 100644 index 0000000..e557255 --- /dev/null +++ b/API/Wood.Entity/SystemManage/MenuEntity.cs @@ -0,0 +1,96 @@ +using SqlSugar; +using System.ComponentModel.DataAnnotations; +using WoodWood.Util.Validations; + +namespace Wood.Entity.SystemManage +{ + /// + /// 菜单信息 + /// + [SugarTable("SysMenu", "菜单信息")] + public class MenuEntity : EntityBaseExtra + { + /// + /// 父级id + /// + [SugarColumn(ColumnDescription = "父级id", DefaultValue = "0")] + public long ParentId { get; set; } = 0; + + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称", DefaultValue = "0",Length =32)] + [Required] + public string MenuName { get; set; } = ""; + + /// + /// 路由名称 + /// + [SugarColumn(ColumnDescription = "路由名称", DefaultValue = "0", Length = 32, IsNullable = true)] + public string? RouteName { get; set; } + + /// + /// 路由路径 + /// + [SugarColumn(ColumnDescription = "路由路径", DefaultValue = "0", IsNullable = true)] + public string? RoutePath { get; set; } + + /// + /// 组件路径 + /// + [SugarColumn(ColumnDescription = "组件路径", DefaultValue = "0", IsNullable = true)] + public string? ComponentPath { get; set; } + + /// + /// 菜单图标 + /// + [SugarColumn(ColumnDescription = "菜单图标", DefaultValue = "0", Length = 32, IsNullable = true)] + public string? MenuIcon { get; set; } + + /// + /// 重定向路径 + /// + [SugarColumn(ColumnDescription = "重定向路径", DefaultValue = "0", IsNullable = true)] + public string? RedirectPath { get; set; } + + /// + /// 是否缓存 + /// + [SugarColumn(ColumnDescription = "是否缓存")] + public bool IsCache { get; set; } = false; + + /// + /// 是否新页面打开 + /// + [SugarColumn(ColumnDescription = "是否新页面打开")] + public bool OpenNewWindow { get; set; } = false; + + /// + /// 是否固定 + /// + [SugarColumn(ColumnDescription = "是否固定")] + public bool IsAffix { get; set; } = false; + /// + /// 外链 + /// + [SugarColumn(ColumnDescription = "外链", Length = 256, IsNullable = true)] + public string? OutLink { get; set; } + /// + /// 权限标识 + /// + [SugarColumn(ColumnDescription = "权限标识", Length = 128, IsNullable = true)] + [UniqueValue(ErrorMessage ="权限标识不能重复!")] + public string? Permission { get; set; } + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序", DefaultValue = "0")] + public int Sort { get; set; } = 0; + + /// + /// 菜单类型 1 目录 2 菜单 3 按钮 + /// + [SugarColumn(ColumnDescription = "菜单类型 1 目录 2 菜单 3 按钮", DefaultValue = "1")] + public MenuTypeEnum MenuType { get; set; } = MenuTypeEnum.Directory; + } +} diff --git a/API/Wood.Entity/SystemManage/MessageEntity.cs b/API/Wood.Entity/SystemManage/MessageEntity.cs new file mode 100644 index 0000000..cf7251a --- /dev/null +++ b/API/Wood.Entity/SystemManage/MessageEntity.cs @@ -0,0 +1,71 @@ +using SqlSugar; + +namespace Wood.Entity.SystemManage +{ + /// + /// 系统消息主表实体 + /// + [SugarTable("SysMessage", "系统消息主表实体")] + public class MessageEntity : EntityTenantBase + { + /// + /// 消息标题(最大长度128字符) + /// + [SugarColumn(ColumnDescription = "消息标题", Length = 128)] + public string? Title { get; set; } + + /// + /// 消息内容(TEXT类型) + /// + [SugarColumn(ColumnDescription = "消息内容", ColumnDataType = StaticConfig.CodeFirst_BigString)] + public string? Content { get; set; } + + /// + /// 消息类型(0-系统通知 1-公告 2-私信) + /// + [SugarColumn(ColumnDescription = "消息类型(0-系统通知 1-公告 2-私信)", DefaultValue = "0")] + public MessageTypeEnum MessageType { get; set; } + + /// + /// 消息状态 + /// + [SugarColumn(ColumnDescription = "消息状态", DefaultValue = "0")] + public MessageStatusEnum Status { get; set; } + + /// + /// 发布时间 + /// + [SugarColumn(ColumnDescription = "发布时间", IsNullable = true)] + public DateTime? PublishAt { get; set; } + + /// + /// 发布人 + /// + [SugarColumn(ColumnDescription = "发布人", IsNullable = true)] + public long? PublisherId { get; set; } + + /// + /// 发布人 + /// + [SugarColumn(ColumnDescription = "发布人", IsNullable = true)] + public string? PublisherName { get; set; } + + /// + /// 发布机构 + /// + [SugarColumn(ColumnDescription = "发布机构", IsNullable = true)] + public long? PublisherOrgId { get; set; } + + /// + /// 发布机构 + /// + [SugarColumn(ColumnDescription = "发布机构", IsNullable = true)] + public string? PublisherOrgName { get; set; } + + /// + /// 撤回时间 + /// + [SugarColumn(ColumnDescription = "撤回时间", IsNullable = true)] + public DateTime? RecalledAt { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/OrgEntity.cs b/API/Wood.Entity/SystemManage/OrgEntity.cs new file mode 100644 index 0000000..a9f76b3 --- /dev/null +++ b/API/Wood.Entity/SystemManage/OrgEntity.cs @@ -0,0 +1,58 @@ +using SqlSugar; +using System.ComponentModel.DataAnnotations; +using WoodWood.Util.Validations; + +namespace Wood.Entity.SystemManage +{ + /// + /// 部门组织信息 + /// + [SugarTable("SysOrg", "部门组织信息")] + public class OrgEntity : EntityTenantBaseExtra + { + /// + /// 父级id + /// + [SugarColumn(ColumnDescription = "父级id", DefaultValue = "0")] + public long ParentId { get; set; } = 0; + /// + /// 部门名称 + /// + [SugarColumn(ColumnDescription = "部门名称", Length = 16)] + [Required] + public string OrgName { get; set; } = ""; + /// + /// 部门编码 + /// + [SugarColumn(ColumnDescription = "部门编码", Length = 16)] + [Required] + [UniqueValue(ErrorMessage = "机构编码不能重复!")] + public string FormCode { get; set; } = ""; + /// + /// 部门简写 + /// + [SugarColumn(ColumnDescription = "部门简写", Length = 16, IsNullable = true)] + public string? ShortName { get; set; } + /// + /// 部门电话 + /// + [SugarColumn(ColumnDescription = "部门电话", Length = 16, IsNullable = true)] + public string? Telephone { get; set; } + /// + /// 邮箱 + /// + [SugarColumn(ColumnDescription = "邮箱", Length = 64, IsNullable = true)] + public string? Email { get; set; } + /// + /// 负责人 + /// + [SugarColumn(ColumnDescription = "负责人", DefaultValue = "0")] + public long PrincipalUserId { get; set; } = 0; + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序", DefaultValue = "0")] + public int Sort { get; set; } = 0; + } +} diff --git a/API/Wood.Entity/SystemManage/PositionEntity.cs b/API/Wood.Entity/SystemManage/PositionEntity.cs new file mode 100644 index 0000000..5ab8962 --- /dev/null +++ b/API/Wood.Entity/SystemManage/PositionEntity.cs @@ -0,0 +1,38 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WoodWood.Util.Validations; + +namespace Wood.Entity.SystemManage +{ + /// + /// 职位表 + /// + [SugarTable("SysPosition", "职位表")] + public class PositionEntity : EntityTenantBaseExtra + { + /// + /// 职位名 + /// + [SugarColumn(ColumnDescription = "职位名", Length = 32)] + [Required] + public string PositionName { get; set; } = ""; + /// + /// 职位编码 + /// + [SugarColumn(ColumnDescription = "职位编码", Length = 32)] + [Required] + [UniqueValue(ErrorMessage ="职位编码不能重复!")] + public string FormCode { get; set; } = ""; + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序",DefaultValue ="0")] + public int Sort { get; set; } = 0; + } +} diff --git a/API/Wood.Entity/SystemManage/RoleDataScopeEntity.cs b/API/Wood.Entity/SystemManage/RoleDataScopeEntity.cs new file mode 100644 index 0000000..0bf05e8 --- /dev/null +++ b/API/Wood.Entity/SystemManage/RoleDataScopeEntity.cs @@ -0,0 +1,27 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Entity.SystemManage +{ + /// + /// 角色数据范围 + /// + [SugarTable("SysRoleDataScope", "角色数据范围")] + public class RoleDataScopeEntity:EntityCreateBase + { + /// + /// 角色Id + /// + [SugarColumn(ColumnDescription = "角色Id")] + public long RoleId { get; set; } = 0; + /// + /// 部门Id + /// + [SugarColumn(ColumnDescription = "部门Id")] + public long OrgId { get; set; } = 0; + } +} diff --git a/API/Wood.Entity/SystemManage/RoleEntity.cs b/API/Wood.Entity/SystemManage/RoleEntity.cs new file mode 100644 index 0000000..70644f8 --- /dev/null +++ b/API/Wood.Entity/SystemManage/RoleEntity.cs @@ -0,0 +1,52 @@ +using SqlSugar; +using System.ComponentModel.DataAnnotations; +using WoodWood.Util.Validations; + +namespace Wood.Entity.SystemManage +{ + + public class RoleEntityShared : EntityTenantBaseExtra + { + + /// + /// 角色名 + /// + [SugarColumn(ColumnDescription = "角色名", Length = 16)] + [Required] + public string RoleName { get; set; } = ""; + + /// + /// 编码 + /// + [SugarColumn(ColumnDescription = "编码", Length = 16)] + [Required] + [UniqueValue(EntityType=typeof(RoleEntity), ErrorMessage ="角色编码不能重复!")] + public string FormCode { get; set; } = ""; + + + /// + /// 数据范围类型 + /// + [SugarColumn(ColumnDescription = "数据范围类型", Length = 16)] + [Required] + public DataScopeTypeEnum DataScopeType { get; set; } = DataScopeTypeEnum.All; + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序", DefaultValue = "0")] + public int Sort { get; set; } = 0; + } + /// + /// 角色 + /// + [SugarTable("SysRole", "角色")] + public class RoleEntity : RoleEntityShared + { + /// + /// 用户信息 + /// + [Navigate(typeof(UserBelongRoleEntity), nameof(UserBelongRoleEntity.RoleId), nameof(UserBelongRoleEntity.UserId))]//注意顺序 + public List? Users { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/TenantEntity.cs b/API/Wood.Entity/SystemManage/TenantEntity.cs new file mode 100644 index 0000000..5205c6a --- /dev/null +++ b/API/Wood.Entity/SystemManage/TenantEntity.cs @@ -0,0 +1,32 @@ +using SqlSugar; +using System.ComponentModel.DataAnnotations; + +namespace Wood.Entity.SystemManage; + +/// +/// 系统租户表 +/// +[SugarTable("SysTenant", "系统租户表")] +[SugarIndex("SysTenant_TenantName", nameof(TenantName), OrderByType.Desc, true)] +public class TenantEntity : EntityBaseExtra +{ + /// + /// 租户名称 + /// + [SugarColumn(ColumnDescription = "租户名称", IsNullable = true,Length =32)] + [Required] + public string TenantName { get; set; } = ""; + + /// + /// 租户机构 + /// + [SugarColumn(ColumnDescription = "租户机构")] + public long OrgId { get; set; } + + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } = 100; + +} \ No newline at end of file diff --git a/API/Wood.Entity/SystemManage/UserBelongRoleEntity.cs b/API/Wood.Entity/SystemManage/UserBelongRoleEntity.cs new file mode 100644 index 0000000..047c038 --- /dev/null +++ b/API/Wood.Entity/SystemManage/UserBelongRoleEntity.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Entity.SystemManage +{ + /// + /// 用户所属角色 + /// + [SugarTable("SysUserBelongRole", "用户所属角色")] + public class UserBelongRoleEntity : EntityCreateBase + { + /// + /// 用户id + /// + [SugarColumn(ColumnDescription = "用户id")] + public long UserId { get; set; } = 0; + + /// + /// 角色id + /// + [SugarColumn(ColumnDescription = "角色id")] + public long RoleId { get; set; } = 0; + } +} diff --git a/API/Wood.Entity/SystemManage/UserEntity.cs b/API/Wood.Entity/SystemManage/UserEntity.cs new file mode 100644 index 0000000..9714ef7 --- /dev/null +++ b/API/Wood.Entity/SystemManage/UserEntity.cs @@ -0,0 +1,140 @@ +using SqlSugar; +using System.ComponentModel.DataAnnotations; +using WoodWood.Util.Validations; + +namespace Wood.Entity.SystemManage +{ + /// + /// 用户共享信息 + /// + public class UserEntityShared : EntityTenantBaseExtra + { + /// + /// 用户名 + /// + [SugarColumn(ColumnDescription = "用户名", Length = 16)] + [Required] + [UniqueValue(EntityType=typeof(UserEntity),ErrorMessage ="用户名不能重复!")] + public string UserName { get; set; } = ""; + + /// + /// 真实姓名 + /// + [SugarColumn(ColumnDescription = "真实姓名", Length = 16, IsNullable = true)] + [Required] + public string? RealName { get; set; } + + /// + /// 昵称 + /// + [SugarColumn(ColumnDescription = "昵称", Length = 32, IsNullable = true)] + public string? NickName { get; set; } + /// + /// 性别 1 男 0 女 + /// + [SugarColumn(ColumnDescription = "性别 1 男 0 女", DefaultValue = "0")] + [Required] + public int Gender { get; set; } = 0; + /// + /// 出生日期 + /// + [SugarColumn(ColumnDescription = "出生日期",IsNullable =true)] + public DateTime? Birthday { get; set; } + + /// + /// 邮箱 + /// + [SugarColumn(ColumnDescription = "邮箱", Length = 64, IsNullable = true)] + public string? Email { get; set; } + /// + /// 手机号码 + /// + [SugarColumn(ColumnDescription = "手机号码", Length = 16, IsNullable = true)] + [Required] + public string? Mobile { get; set; } + + /// + /// 头像 + /// + [SugarColumn(ColumnDescription = "头像", Length = 32, IsNullable = true)] + public string? Avatar { get; set; } + } + + /// + /// 用户信息表 + /// + [SugarTable("SysUser", "用户信息表")] + public class UserEntity : UserEntityShared,IDiff + { + /// + /// 密码 + /// + [SugarColumn(ColumnDescription = "密码", Length = 512)] + public string Password { get; set; } = ""; + + /// + /// 加密盐值 + /// + [SugarColumn(ColumnDescription = "加密盐值", Length = 16)] + public string Salt { get; set; } = ""; + + /// + /// 部门id + /// + [SugarColumn(ColumnDescription = "部门id", DefaultValue = "0")] + public long OrgId { get; set; } = 0; + + /// + /// 职位id + /// + [SugarColumn(ColumnDescription = "职位id", DefaultValue = "0")] + public long PositionId { get; set; } = 0; + + /// + /// 最近登录时间 + /// + [SugarColumn(ColumnDescription = "最近登录时间", IsNullable = true)] + public DateTime? LastVisit { get; set; } + + /// + /// 账号类型 + /// + [SugarColumn(ColumnDescription = "账号类型", DefaultValue = "0")] + public AccountTypeEnum AccountType { get; set; } = 0; + + /// + /// 登录次数 + /// + [SugarColumn(ColumnDescription = "登录次数", DefaultValue = "0")] + public int LoginCount { get; set; } = 0; + /// + /// 第一次登录时间 + /// + [SugarColumn(ColumnDescription = "第一次登录时间", IsNullable = true)] + public DateTime? FirstVisit { get; set; } + /// + /// 上次登录时间 + /// + [SugarColumn(ColumnDescription = "前次登录时间", IsNullable = true)] + public DateTime? PreviousVisit { get; set; } + + /// + /// 部门信息 + /// + [Navigate(NavigateType.OneToOne, nameof(OrgId))] + public OrgEntity? Org { get; set; } + + /// + /// 职位信息 + /// + [Navigate(NavigateType.OneToOne, nameof(PositionId))] + public PositionEntity? Position { get; set; } + + + /// + /// 角色信息 + /// + [Navigate(typeof(UserBelongRoleEntity), nameof(UserBelongRoleEntity.UserId), nameof(UserBelongRoleEntity.RoleId))]//注意顺序 + public List? Roles { get; set; } + } +} diff --git a/API/Wood.Entity/SystemManage/UserMessageEntity.cs b/API/Wood.Entity/SystemManage/UserMessageEntity.cs new file mode 100644 index 0000000..0176f17 --- /dev/null +++ b/API/Wood.Entity/SystemManage/UserMessageEntity.cs @@ -0,0 +1,47 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Entity.SystemManage +{ + /// + /// 用户消息关系实体 + /// + [SugarTable("SysUserMessage", "用户消息关系实体")] + public class UserMessageEntity : EntityCreateBase + { + /// + /// 接收用户ID(关联用户表主键) + /// + [SugarColumn(ColumnDescription = "接收用户ID")] + public long UserId { get; set; } + + /// + /// 消息ID(关联消息主表) + /// + [SugarColumn(ColumnDescription = "消息ID")] + public long MessageId { get; set; } + + /// + /// 阅读状态(true-已读,false-未读) + /// + [SugarColumn(ColumnDescription = "阅读状态")] + public bool IsRead { get; set; } + + /// + /// 阅读时间(可为空,未读时无值) + /// + [SugarColumn(ColumnDescription = "阅读时间",IsNullable =true)] + public DateTime? ReadTime { get; set; } + + /// + /// 导航属性 - 关联的消息主体(OneToOne 一对一关系) + /// + [Navigate(NavigateType.OneToOne, nameof(MessageId))] + public MessageEntity? Message { get; set; } + } + +} diff --git a/API/Wood.Entity/SystemManage/UserRefreshTokenEntity.cs b/API/Wood.Entity/SystemManage/UserRefreshTokenEntity.cs new file mode 100644 index 0000000..d0e7bf6 --- /dev/null +++ b/API/Wood.Entity/SystemManage/UserRefreshTokenEntity.cs @@ -0,0 +1,46 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Entity.SystemManage +{ + /// + /// 用户的refreshtoken + /// + [SugarTable("SysRefreshToken", "用户的refreshtoken")] + public class RefreshTokenEntity : EntityCreateBase + { + /// + /// 用户id + /// + [SugarColumn(ColumnDescription = "用户id")] + public long UserId { get; set; } = 0; + + /// + /// RefreshToken + /// + [SugarColumn(ColumnDescription = "RefreshToken", Length = 256)] + public string RefreshToken { get; set; } = ""; + + /// + /// 过期时间 + /// + [SugarColumn(ColumnDescription = "过期时间")] + public DateTime ExpiresAt { get; set; } = DateTime.Now; + + /// + /// 签发时间 + /// + [SugarColumn(ColumnDescription = "签发时间")] + public DateTime IssuedAt { get; set; } = DateTime.Now; + + /// + /// 撤销时间 + /// + [SugarColumn(ColumnDescription = "撤销时间",IsNullable = true)] + public DateTime? RevokedAt { get; set; } + } +} diff --git a/API/Wood.Entity/TData.cs b/API/Wood.Entity/TData.cs new file mode 100644 index 0000000..6291b9a --- /dev/null +++ b/API/Wood.Entity/TData.cs @@ -0,0 +1,190 @@ +using System.Collections.Generic; + +namespace Wood.Entity +{ + /// + /// 数据传输对象 + /// + public class TData + { + /// + /// 操作结果,Code为1代表成功,0代表失败,其他的验证返回结果,可根据需要设置 + /// 正确代码 [1 - 100] + /// 没有权限 [401] + /// 错误代码 !=401,[<0,>100] + /// + public int Code { get; set; } = 0; + + /// + /// 提示信息或异常信息 + /// + public string? Message { get; set; } + + /// + /// 扩展Message + /// + public string? Description { get; set; } + + #region 普通 + /// + /// 成功 + /// + /// 成功代码 + /// 信息 + public static TData Success(int code, string message) + { + return new TData() { Code = 1, Message = message }; + } + /// + /// 成功 + /// + /// 信息 + public static TData Success(string message) + { + return new TData() { Code = 1, Message = message }; + } + + /// + /// 成功 + /// + public static TData Success() + { + return new TData() { Code = 1, Message = "操作成功!" }; + } + + /// + /// 失败 + /// + public static TData Error() + { + return new TData() { Code = 0, Message = "操作失败!" }; + } + + /// + /// 失败 + /// + /// 信息 + public static TData Error(string message) + { + return new TData() { Code = 0, Message = message }; + } + /// + /// 失败 + /// + /// 错误代码 + /// 信息 + public static TData Error(int code,string message) + { + return new TData() { Code = 0, Message = message }; + } + #endregion + + #region 泛型 + /// + /// 成功 + /// + /// 信息 + public static TData Success(string message) + { + return new TData() { Code = 1, Message = message }; + } + + /// + /// 成功 + /// + /// 成功代码 + /// 信息 + public static TData Success(int code,string message) + { + return new TData() { Code = 1, Message = message }; + } + + /// + /// 成功 + /// + public static TData Success() + { + return new TData() { Code = 1, Message = "操作成功!" }; + } + + /// + /// 失败 + /// + public static TData Error() + { + return new TData() { Code = 0, Message = "操作失败!" }; + } + + /// + /// 失败 + /// + /// 信息 + public static TData Error(string message) + { + return new TData() { Code = 0, Message = message }; + } + + /// + /// 失败 + /// + /// 失败代码 + /// 信息 + public static TData Error(int code,string message) + { + return new TData() { Code = 0, Message = message }; + } + #endregion + } + + public class TData : TData + { + /// + /// 列表的记录数 + /// + public int Total { get; set; } = 0; + + /// + /// 数据 + /// + public T? Data { get; set; } + + } + + public class TDataPaged + { + /// + /// 页码 + /// + public int Page { get; set; } = 0; + + /// + /// 页容量 + /// + public int PageSize { get; set; } = 0; + + /// + /// 总条数 + /// + public int Total { get; set; } = 0; + + /// + /// 总页数 + /// + public int TotalPages { get; set; } = 0; + + /// + /// 是否有上一页 + /// + public bool HasPrevPage { get; set; } = false; + + /// + /// 是否有下一页 + /// + public bool HasNextPage { get; set; } = false; + + /// + /// 当前页集合 + /// + public IEnumerable? Data { get; set; } + } +} diff --git a/API/Wood.Entity/UserCache.cs b/API/Wood.Entity/UserCache.cs new file mode 100644 index 0000000..3c53380 --- /dev/null +++ b/API/Wood.Entity/UserCache.cs @@ -0,0 +1,82 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity.SystemManage; + +namespace Wood.Entity +{ + /// + /// 用户缓存信息 + /// + public class UserCache + { + /// + /// ID + /// + public long Id { get; set; } + /// + /// 租户 + /// + public long? TenantId { get; set; } + /// + /// 用户名 + /// + public string UserName { get; set; } = ""; + + /// + /// 真实姓名 + /// + public string? RealName { get; set; } + + /// + /// 昵称 + /// + public string? NickName { get; set; } + + /// + /// 邮箱 + /// + public string? Email { get; set; } + /// + /// 手机号码 + /// + public string? Mobile { get; set; } + /// + /// 加密Salt + /// + public string Salt { get; set; } = ""; + + /// + /// 部门id + /// + public long OrgId { get; set; } = 0; + + /// + /// 职位id + /// + public long PositionId { get; set; } = 0; + + /// + /// 账号类型 + /// + public AccountTypeEnum AccountType { get; set; } = 0; + + /// + /// 用户角色id + /// + public List Roles { get; set; } = new List(); + + /// + /// 用户数据范围类型 + /// + public DataScopeTypeEnum DataScopeType { get; set; } + + /// + /// 用户数据范围部门列表 + /// + public List DataScopeOrgs { get; set; } = new List(); + } +} diff --git a/API/Wood.Entity/Wood.Entity.csproj b/API/Wood.Entity/Wood.Entity.csproj new file mode 100644 index 0000000..9c9f6d0 --- /dev/null +++ b/API/Wood.Entity/Wood.Entity.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/API/Wood.EventBus/Events/LogExceptionEvent.cs b/API/Wood.EventBus/Events/LogExceptionEvent.cs new file mode 100644 index 0000000..a51fa7f --- /dev/null +++ b/API/Wood.EventBus/Events/LogExceptionEvent.cs @@ -0,0 +1,49 @@ +using Wood.Entity.SystemManage; +using Wood.Util; + +namespace Wood.EventBus.Events +{ + public class LogExceptionEvent : IntegrationEvent + { + public LogExceptionEvent(object? payload) + { + Payload = payload; + } + + public static LogExceptionEvent NewEvent() + { + LogExceptionEntity entity = new LogExceptionEntity(); + entity.LogDateTime = DateTime.Now; + return new LogExceptionEvent(entity); + } + + public static LogExceptionEvent NewEvent(Exception ex) + { + LogExceptionEntity entity = new LogExceptionEntity(); + entity.LogDateTime = DateTime.Now; + entity.ExceptionStackTrace = ex.StackTrace; + entity.Exception = ex.Message; + entity.Message = ex.GetFullExceptionMessage(); + return new LogExceptionEvent(entity); + } + /// + /// 发布错误日志事件 + /// + /// 错误信息 + /// 来源url 或者 jobid + /// 来源controller 或者 job class name + /// 来源action 或者 job method name + public static LogExceptionEvent NewEvent(Exception ex, string requestUrl, string controller, string action) + { + LogExceptionEntity entity = new LogExceptionEntity(); + entity.LogDateTime = DateTime.Now; + entity.ExceptionStackTrace = ex.StackTrace; + entity.Exception = ex.Message; + entity.Message = ex.GetFullExceptionMessage(); + entity.ControllerName = controller; + entity.ActionName = action; + entity.RequestUrl = requestUrl; + return new LogExceptionEvent(entity); + } + } +} diff --git a/API/Wood.EventBus/Events/LogOperationEvent.cs b/API/Wood.EventBus/Events/LogOperationEvent.cs new file mode 100644 index 0000000..9591487 --- /dev/null +++ b/API/Wood.EventBus/Events/LogOperationEvent.cs @@ -0,0 +1,6 @@ +namespace Wood.EventBus.Events +{ + public class LogOperationEvent : IntegrationEvent + { + } +} diff --git a/API/Wood.EventBus/IEventBus.cs b/API/Wood.EventBus/IEventBus.cs new file mode 100644 index 0000000..5c32478 --- /dev/null +++ b/API/Wood.EventBus/IEventBus.cs @@ -0,0 +1,10 @@ +namespace Wood.EventBus +{ + public interface IEventBus + { + void Subscribe(TH handler) where T : IntegrationEvent where TH : IIntegrationEventHandler; + void Unsubscribe() where T : IntegrationEvent where TH : IIntegrationEventHandler; + Task PublishAsync(T @event) where T : IntegrationEvent; + void Publish(T @event) where T : IntegrationEvent; + } +} diff --git a/API/Wood.EventBus/IEventLog.cs b/API/Wood.EventBus/IEventLog.cs new file mode 100644 index 0000000..4b9594d --- /dev/null +++ b/API/Wood.EventBus/IEventLog.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.EventBus +{ + /// + /// 记录事件日志 + /// 实现这个接口将会对事件记录日志 + /// + public interface IEventLog + { + } +} diff --git a/API/Wood.EventBus/IIntegrationEventHandler.cs b/API/Wood.EventBus/IIntegrationEventHandler.cs new file mode 100644 index 0000000..01a6316 --- /dev/null +++ b/API/Wood.EventBus/IIntegrationEventHandler.cs @@ -0,0 +1,98 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Serilog; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Data.Repository; +using Wood.Entity.SystemManage; +using Wood.EventBus.Events; +using Wood.Util; + +namespace Wood.EventBus +{ + + /// + /// 事件处理器 接口 + /// + /// + public interface IIntegrationEventHandler + { + Task Handle(T @event); + } + + /// + /// 事件处理器 + /// 重写Run 方法 + /// 带有日志记录 + /// + /// + public class IntegrationEventHandler : IIntegrationEventHandler where T : IntegrationEvent + { + public async Task Handle(T @event) + { + using var scope= GlobalContext.ServiceProvider!.CreateScope(); + var logEventRepository= scope.ServiceProvider.GetRequiredService>(); + var logExRepository= scope.ServiceProvider.GetRequiredService>(); + string status = "执行完成"; + string errorMsg = ""; + Stopwatch sw = new Stopwatch(); + try + { + sw.Start(); + await Run(@event, scope); + sw.Stop(); + } + catch (Exception exception) + { + sw.Stop(); + var exEntity = new LogExceptionEntity + { + Exception = exception.GetFullExceptionMessage(), + ExceptionStackTrace = exception.StackTrace, + Elapsed =(int)sw.ElapsedMilliseconds, + RequestParam = JsonConvert.SerializeObject(@event), + LogDateTime = DateTime.Now, + ActionName=@event.GetType().Name, + ControllerName=@event.GetType().Name, + Source = GetType().Name, + }; + + await logExRepository.InsertAsync(exEntity); + status = "错误"; + errorMsg = exEntity.Exception; + + Log.Error(exception, $"执行事件出错!【{exEntity.RequestParam}】"); + } + + #region 保存日志 + if (@event.GetType().GetInterfaces().Any(it => it == typeof(IEventLog))) + { + LogEventEntity entity = new LogEventEntity() + { + Elapsed = (int)sw.ElapsedMilliseconds, + PublishDateTime = @event.CreateTime, + CreateTime = DateTime.Now, + PublishContent = JsonConvert.SerializeObject(@event), + EventName = typeof(T).Name, + EventId = @event.Id, + RetryCount = 0, + Status = status, + Remark = errorMsg + }; + await logEventRepository.InsertAsync(entity); + } + #endregion + } + + public virtual Task Run(T @event,IServiceScope scope) + { + throw new NotImplementedException(); + } + } +} diff --git a/API/Wood.EventBus/InMemoryEventBus.cs b/API/Wood.EventBus/InMemoryEventBus.cs new file mode 100644 index 0000000..18c5840 --- /dev/null +++ b/API/Wood.EventBus/InMemoryEventBus.cs @@ -0,0 +1,65 @@ +using Serilog; +using System; +using System.Collections.Concurrent; +using Wood.EventBus.Events; +using Wood.Util; + +namespace Wood.EventBus +{ + public class InMemoryEventBus : IEventBus + { + private readonly ConcurrentDictionary> _handlersMap = new(); + + public void Subscribe(TH handler) where T : IntegrationEvent where TH : IIntegrationEventHandler + { + var eventName = typeof(T).Name; + if (!_handlersMap.TryGetValue(eventName, out var handlers)) + { + handlers = new List(); + _handlersMap.TryAdd(eventName, handlers); + } + handlers.Add(handler); + } + + public void Unsubscribe() where T : IntegrationEvent where TH : IIntegrationEventHandler + { + var eventName = typeof(T).Name; + if (_handlersMap.TryGetValue(eventName, out var handlers)) + { + handlers.RemoveAll(h => h is TH); + } + } + + public async Task PublishAsync(T @event) where T : IntegrationEvent + { + var eventName = typeof(T).Name; + if (_handlersMap.TryGetValue(eventName, out var handlers)) + { + foreach (var handler in handlers) + { + var methodInfo = handler.GetType().GetMethods().FirstOrDefault(m => m.Name == "Handle" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(T)); + if (methodInfo != null) + { + await (Task)methodInfo.Invoke(handler, new object[] { @event })!; + } + } + } + } + + public void Publish(T @event) where T : IntegrationEvent + { + var eventName = typeof(T).Name; + if (_handlersMap.TryGetValue(eventName, out var handlers)) + { + foreach (var handler in handlers) + { + var methodInfo = handler.GetType().GetMethods().FirstOrDefault(m => m.Name == "Handle" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(T)); + if (methodInfo != null) + { + methodInfo.Invoke(handler, new object[] { @event }); + } + } + } + } + } +} diff --git a/API/Wood.EventBus/IntegrationEvent.cs b/API/Wood.EventBus/IntegrationEvent.cs new file mode 100644 index 0000000..20572d3 --- /dev/null +++ b/API/Wood.EventBus/IntegrationEvent.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using Wood.Util; + +namespace Wood.EventBus +{ + public class IntegrationEvent + { + /// + /// id + /// + public string Id { get; } = IdGeneratorHelper.Instance.GetGuid(); + + /// + /// 发布时间 + /// + public DateTime CreateTime { get; } = DateTime.Now; + + /// + /// 携带数据 + /// + public object? Payload { get; init; } + + public T? GetPayload() + { + if (Payload == null) + return default(T); + + return (T)Payload; + } + } +} diff --git a/API/Wood.EventBus/Wood.EventBus.csproj b/API/Wood.EventBus/Wood.EventBus.csproj new file mode 100644 index 0000000..036b5f3 --- /dev/null +++ b/API/Wood.EventBus/Wood.EventBus.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/API/Wood.Service/BaseService/ApiCRUDService.cs b/API/Wood.Service/BaseService/ApiCRUDService.cs new file mode 100644 index 0000000..8051a07 --- /dev/null +++ b/API/Wood.Service/BaseService/ApiCRUDService.cs @@ -0,0 +1,63 @@ +using Mapster; +using Microsoft.AspNetCore.Mvc; +using Wood.Data.Repository; +using Wood.Entity; + +namespace Wood.Service.BaseService +{ + public class ApiCRUDService : ApiService + where T : EntityBase, new() + where TAddParam : class, new() + where TUpdateParam : class, new() + { + protected SqlSugarRepository _repository { get; set; } + + public ApiCRUDService(SqlSugarRepository repository) + { + _repository = repository; + } + + /// + /// 获取明细 + /// + /// + public virtual async Task GetDetail(BaseIdParam param) + { + var dto = await _repository.GetByIdAsync(param.Id); + return dto.Adapt(); + } + + /// + /// 新增 + /// + /// + [UnitOfWork] + public virtual async Task Add(TAddParam param) + { + var input = param.Adapt(); + await _repository.InsertAsync(input); + } + /// + /// 更新 + /// + /// + [UnitOfWork] + public virtual async Task Update(TUpdateParam param) + { + var input = param.Adapt(); + await _repository.UpdateAsync(input); + } + + /// + /// 批量删除 + /// 假删除 + /// + /// + [UnitOfWork] + public virtual async Task Delete(BaseIdListParam param) + { + if(param.Ids.Any()) + await _repository.FakeDeleteAsync(it=>param.Ids.Contains(it.Id)); + } + } +} diff --git a/API/Wood.Service/BaseService/ApiManager.cs b/API/Wood.Service/BaseService/ApiManager.cs new file mode 100644 index 0000000..7fda068 --- /dev/null +++ b/API/Wood.Service/BaseService/ApiManager.cs @@ -0,0 +1,36 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Data.Repository; + +namespace Wood.Service +{ + /// + /// Manager父类 + /// + /// + public class ApiManager where T : class, new() + { + private readonly SqlSugarRepository _repository; + /// + /// 可查询对象 + /// + public ISugarQueryable AsQueryable() => _repository.AsQueryable(); + /// + /// 仓储 + /// + public SqlSugarRepository AsRepository() => _repository; + /// + /// 构造函数 + /// + /// + public ApiManager(SqlSugarRepository repository) + { + _repository = repository; + } + + } +} diff --git a/API/Wood.Service/BaseService/ApiService.cs b/API/Wood.Service/BaseService/ApiService.cs new file mode 100644 index 0000000..82898a7 --- /dev/null +++ b/API/Wood.Service/BaseService/ApiService.cs @@ -0,0 +1,47 @@ +using Magicodes.ExporterAndImporter.Core.Extension; +using Magicodes.ExporterAndImporter.Core.Models; +using Magicodes.ExporterAndImporter.Excel; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Service.SystemManage.Param; + +namespace Wood.Service +{ + /// + /// service基础类 + /// + public class ApiService : ControllerBase + { + protected async Task ExportFile(ICollection dtos,string fileName) where T : class, new() + { + var excelExporter = HttpContext.RequestServices.GetRequiredService(); + var res = await excelExporter.ExportAsByteArray(dtos); + return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") +"_"+ fileName }; + } + + protected async Task> ImportFile(IFormFile file,List errors) where T : class, new() + { + var excelImporter = HttpContext.RequestServices.GetRequiredService(); + + ImportResult result = await excelImporter.Import(file.OpenReadStream()); + if (result.HasError) + { + foreach (var item in result.RowErrors) + errors.Add(new ImportErrorDto { Index = item.RowIndex, Errors = string.Join(';', item.FieldErrors.Values.ToArray()) }); + foreach (var item in result.TemplateErrors) + errors.Add(new ImportErrorDto { Index = 0, Errors = item.RequireColumnName + "," + item.Message }); + } + + return result; + } + } +} diff --git a/API/Wood.Service/Controllers/LogController.cs b/API/Wood.Service/Controllers/LogController.cs new file mode 100644 index 0000000..c37e785 --- /dev/null +++ b/API/Wood.Service/Controllers/LogController.cs @@ -0,0 +1,67 @@ + + +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class LogController:ControllerBase + { + private readonly JobDbContext _dbContext; + public LogController(JobDbContext dbContext) + { + _dbContext = dbContext; + } + public async Task> GetAll() + { + var log = await _dbContext.TaskLogs.ToListAsync(); + return log; + } + [HttpGet("AddError")] + public async Task AddError(string message,string taskname) + { + _dbContext.TaskLogs.Add(new TaskLog() { Info = message, Type = "错误",TaskName=taskname ,CreationTime=DateTime.Now}); + var result =await _dbContext.SaveChangesAsync(); + if (result > 0) + { + return true; + } + return false; + } + [HttpGet("AddInfo")] + public async Task AddInfo(string message, string taskname) + { + _dbContext.TaskLogs.Add(new TaskLog() { Info = message, Type = "记录", TaskName = taskname, CreationTime = DateTime.Now }); + var result = await _dbContext.SaveChangesAsync(); + if (result > 0) + { + return true; + } + return false; + } + + } + //private readonly IServiceProvider _serviceProvider; + //public LogController(IServiceProvider serviceProvider) + //{ + // _serviceProvider = serviceProvider; + //} + //public async Task> GetLogs() + //{ + // var dbcontext= _serviceProvider.GetRequiredService(); + // var connection=dbcontext.Database.GetDbConnection(); + // connection.Query("select top 10 * from logs"); + //} + + + +} diff --git a/API/Wood.Service/Controllers/RecurringJobBaseController.cs b/API/Wood.Service/Controllers/RecurringJobBaseController.cs new file mode 100644 index 0000000..1921819 --- /dev/null +++ b/API/Wood.Service/Controllers/RecurringJobBaseController.cs @@ -0,0 +1,175 @@ + +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using TaskManager.Entity; +using TaskManager.EntityFramework; + + + + +namespace TaskManager.Controllers +{ + public class RecurringJobBaseController :ControllerBase, IDoExecute + { + protected string appKey = "8EG566b9bedd2bf46d"; + protected string appSecret = "48edc4425647425d87f806a1ba492580"; + protected readonly HttpClient _httpClient; + protected readonly JobDbContext _jobDbContext; + protected string Path { set; get; } = "/v2/get/supplierProPlaning"; + protected string Url { set; get; } = "/v2/get/supplierProPlaning"; + protected virtual string TaskName { set; get; } = "SupplierProPlaning"; + protected readonly LogController _logger; + public RecurringJobBaseController( + HttpClient httpClient, + JobDbContext jobDbContext, + LogController log + ) + { + _httpClient = new HttpClient(); + _jobDbContext = jobDbContext; + _logger = log; + } + + /// + /// 提交给接口 + /// + /// + /// 录入DTOJson + /// 返回DTOJson + protected async Task Post(string url, string path, string jsonData) + { + try + { + // 生成签名参数 + string timeStamp = GetCurrentTimestamp(); + string nonce = GenerateNonce(); + var sign = GenerateSign(HttpMethod.Post.Method, path, appKey, appSecret, timeStamp, nonce, jsonData); + // 构建请求 + var request = new HttpRequestMessage(HttpMethod.Post, url); + request.Content = new StringContent(jsonData, Encoding.UTF8, "application/json"); + request.Headers.Add("appKey", appKey); + request.Headers.Add("appSecret", appSecret); + request.Headers.Add("timestamp", timeStamp); + request.Headers.Add("sign", sign); + request.Headers.Add("nonce", nonce); + + // 发送请求 + var response = await _httpClient.SendAsync(request); + response.EnsureSuccessStatusCode(); // 抛出异常处理状态码 + return await response.Content.ReadAsStringAsync(); + } + catch (HttpRequestException ex) + { + await _logger.AddError(ex.Message, this.TaskName); + //error = ex.Message; + return string.Empty; + } + } + + private string GenerateSign(string method, string path, string appKey, string appSecret, string timestamp, string nonce, string jsonBody) + { + + string paramStr = $"method={method.ToUpper()}&path={path}&appKey={appKey}&appSecret={appSecret}×tamp={timestamp}&nonce={nonce}&jsonBody={jsonBody}"; + return ComputeSHA512(paramStr); + + } + private string ComputeSHA512(string input) + { + using (SHA512 sha512 = SHA512.Create()) + { + byte[] bytes = Encoding.UTF8.GetBytes(input); + byte[] hash = sha512.ComputeHash(bytes); + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < hash.Length; i++) + { + builder.Append(hash[i].ToString("x2")); // "x2" 表示小写十六进制 + } + return builder.ToString(); + } + } + private string GetCurrentTimestamp() + { + return ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds).ToString(); + } + private string GenerateNonce() + { + const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + Random random = new Random(); + int length = random.Next(10, 51); + return new string(Enumerable.Repeat(chars, length) + .Select(s => s[random.Next(s.Length)]).ToArray()); + } + + + private async Task BeforeExecuteAsync(string uid) + { + await _logger.AddInfo($"{TaskName}开始执行作业{uid}", TaskName); + } + private async Task AfterExecuteAsync(string uid) + { + await _logger.AddInfo($"{TaskName}结束执行作业{uid}", TaskName); + } + [HttpGet] + public async Task ExecuteAsync(string url, string path, string taskName) + { + var str = DateTime.Now.ToLongTimeString(); + await BeforeExecuteAsync(str); + + await DoExecutingAsync(url, path, taskName); + + await AfterExecuteAsync(str); + + } + protected async virtual Task DoExecutingAsync(string url, string path, string takName) + { + + + + + + + } + protected static string RemoveWhitespace(string input) + { + if (string.IsNullOrEmpty(input)) + return input; + // 使用正则表达式移除空格和换行 + return Regex.Replace(input, @"[\s]+", ""); + } + + + } + + + + + +} + + + + + + + + + + + + + + + diff --git a/API/Wood.Service/Controllers/RecurringJobInputPageController.cs b/API/Wood.Service/Controllers/RecurringJobInputPageController.cs new file mode 100644 index 0000000..2af1428 --- /dev/null +++ b/API/Wood.Service/Controllers/RecurringJobInputPageController.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class RecurringJobInputPageController + { + } +} diff --git a/API/Wood.Service/Controllers/RecurringJobOutPageController.cs b/API/Wood.Service/Controllers/RecurringJobOutPageController.cs new file mode 100644 index 0000000..5e15069 --- /dev/null +++ b/API/Wood.Service/Controllers/RecurringJobOutPageController.cs @@ -0,0 +1,278 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Omu.ValueInjecter; + +using System.Text.Json; +using System.Text.Json.Serialization; +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class RecurringJobOutPageController : RecurringJobBaseController where T : CherryReadBaseEntity, new() where ToutputDetial : CherryReadBaseEntityDto + { + public RecurringJobOutPageController(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + + public async Task> FetchAllDataAsync(string inputdate) + { + var allData = new List(); + int totalItems = 0; + int pageSize = 0; + int currentPage = 1; + string date = !string.IsNullOrEmpty(inputdate) ? inputdate : DateTime.Now.ToString("yyyy-MM-dd"); + + + // 首次请求获取总条数和分页信息 + PagedResponse firstResponse = await GetPageAsync(new PAGE_DTO() { Date = date, IsForce = true }); + + + + + + + + + + if (firstResponse == null || firstResponse.Code != 200) + { + await _logger.AddError("首次请求失败,无法获取分页信息。", TaskName); + return allData; + } + if (firstResponse.Data.Total == "0") + { + await _logger.AddError("首次请求失败,Total为0是否已经全部读取过。", TaskName); + return allData; + + } + + var readedcount = _jobDbContext.Set().Where(p => p.RequestDate == inputdate).Count(); + if (readedcount != int.Parse(firstResponse.Data.Total))//记录数不相等 + { + var ids = _jobDbContext.Set().Where(p => p.RequestDate == inputdate).Select(p => p.Id).ToList();//已经同步的ID + totalItems = int.Parse(firstResponse.Data.Total); + pageSize = int.Parse(firstResponse.Data.PageSize); + List pagefirstList = new List(); + if (readedcount > 0) + { + var listrows = firstResponse.Data.Rows.Where(p => !ids.Contains(p.Id)); + foreach (var itm in firstResponse.Data.Rows) + { + T entity = new T(); + entity.InjectFrom(itm); + entity.CreationTime = DateTime.Now; + pagefirstList.Add(entity); + allData.Add(itm); + } + } + else + { + + foreach (var itm in firstResponse.Data.Rows) + { + T entity = new T(); + entity.InjectFrom(itm); + entity.CreationTime = DateTime.Now; + pagefirstList.Add(entity); + allData.Add(itm); + } + } + + _jobDbContext.BulkInsert(pagefirstList); + + //Console.WriteLine($"总记录数: {totalItems}, 每页大小: {pageSize}"); + + // 计算总页数 + int totalPages = (int)Math.Ceiling((double)totalItems / pageSize); + //Console.WriteLine($"总共需要请求 {totalPages} 页数据"); + + // 循环请求剩余页面 + for (currentPage = 2; currentPage <= totalPages; currentPage++) + { + PAGE_DTO pageinput = new PAGE_DTO() { Date = date, PageNum = currentPage, IsForce = true }; + Console.WriteLine($"正在请求第 {currentPage} 页..."); + PagedResponse pageResponse = await GetPageAsync(pageinput); + if (pageResponse?.Data.Rows != null && pageResponse.Data.Rows.Count > 0) + { + List pageList = new List(); + //foreach (var itm in pageResponse.Data.Rows) + //{ + // T entity = new T(); + // entity.InjectFrom(itm); + // entity.CreationTime = DateTime.Now; + // pageList.Add(entity); + // allData.Add(itm); + //} + if (readedcount > 0) + { + var listrows = pageResponse.Data.Rows.Where(p => !ids.Contains(p.Id)); + foreach (var itm in pageResponse.Data.Rows) + { + T entity = new T(); + entity.InjectFrom(itm); + entity.CreationTime = DateTime.Now; + pageList.Add(entity); + allData.Add(itm); + } + } + else + { + + foreach (var itm in pageResponse.Data.Rows) + { + T entity = new T(); + entity.InjectFrom(itm); + entity.CreationTime = DateTime.Now; + pageList.Add(entity); + allData.Add(itm); + } + } + + + + + _jobDbContext.BulkInsert(pageList); + await _logger.AddInfo($"成功获取 {pageResponse.Data.Rows.Count} 条记录", TaskName); + } + else + { + await _logger.AddError($"第 {currentPage} 页未返回数据", TaskName); + + } + + // 简单的请求间隔,避免过于频繁 + await Task.Delay(200); + } + + + await _logger.AddInfo($"所有数据获取完成,总共获取了 {allData.Count} 条记录", TaskName); + } + + + return allData; + } + + + + + private async Task> GetPageAsync(PAGE_DTO input) + { + try + { + var inputjson = JsonSerializer.Serialize(input, + new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true // 可选,用于格式化输出 + } + ); + inputjson = RemoveWhitespace(inputjson); + var content = await Post(Url, Path, inputjson); + if (!string.IsNullOrEmpty(content)) + { + + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = { + new JsonStringEnumConverter(), // 枚举转换 + new CustomDateTimeConverter("yyyy-MM-dd HH:mm:ss") // 日期转换 + } + }; + + + return JsonSerializer.Deserialize>(content, options); + } + else + { + await _logger.AddError($"调用接口无返回值{Url}", TaskName); + return null; + } + } + catch (Exception ex) + { + await _logger.AddError($"调用接口无返回值错误{ex.Message}", TaskName); + return null; + } + + + + + + + + + + //try + //{ + // var url = $"{_apiUrl}?pageNum={pageNum}"; + // var response = await _httpClient.GetAsync(url); + + // if (response.IsSuccessStatusCode) + // { + // var content = await response.Content.ReadAsStringAsync(); + // return JsonSerializer.Deserialize>(content); + // } + // else + // { + // Console.WriteLine($"请求失败,状态码: {response.StatusCode}"); + // return null; + // } + //} + //catch (Exception ex) + //{ + // Console.WriteLine($"请求发生异常: {ex.Message}"); + // return null; + //} + } + [HttpGet("Test")] + public async Task TestAsync(string url, string path, string taskName, string inputdate) + { + Url = url; + Path = path; + TaskName = taskName; + await FetchAllDataAsync(inputdate); + } + protected override async Task DoExecutingAsync(string url, string path, string takName) + { + Url = url; + Path = path; + TaskName = takName; + await FetchAllDataAsync(string.Empty); + + } + + + + + + // 反序列化时使用 + + + + + + } + public class CustomDateTimeConverter : JsonConverter + { + private readonly string _format; + + public CustomDateTimeConverter(string format) + { + _format = format; + } + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return DateTime.ParseExact(reader.GetString(), _format, null); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(_format)); + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_BOM_CONTROLLER.cs b/API/Wood.Service/Controllers/SUPPLIER_BOM_CONTROLLER.cs new file mode 100644 index 0000000..3f16b92 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_BOM_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_BOM_CONTROLLER + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_CON_DATE_CONTROLLER.cs b/API/Wood.Service/Controllers/SUPPLIER_CON_DATE_CONTROLLER.cs new file mode 100644 index 0000000..e5fcfb6 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_CON_DATE_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_CON_DATE_CONTROLLER + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_CON_MMRP_CONTROLLER.cs b/API/Wood.Service/Controllers/SUPPLIER_CON_MMRP_CONTROLLER.cs new file mode 100644 index 0000000..2aed355 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_CON_MMRP_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_CON_MMRP_CONTROLLER + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_CON_PO_CONTROLLER.cs b/API/Wood.Service/Controllers/SUPPLIER_CON_PO_CONTROLLER.cs new file mode 100644 index 0000000..ad10033 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_CON_PO_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_CON_PO_CONTROLLER + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_DEL_STATE_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_DEL_STATE_Service.cs new file mode 100644 index 0000000..2e7cc45 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_DEL_STATE_Service.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //看板配送单 + public class SUPPLIER_DEL_STATE_Service : RecurringJobOutPageController + { + public SUPPLIER_DEL_STATE_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_EMPLOYEE_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_EMPLOYEE_Service.cs new file mode 100644 index 0000000..ad71f47 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_EMPLOYEE_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_EMPLOYEE_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_INFO_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_INFO_Service.cs new file mode 100644 index 0000000..080a23f --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_INFO_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_INFO_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_INV_DATA_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_INV_DATA_Service.cs new file mode 100644 index 0000000..520ad2a --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_INV_DATA_Service.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //奇瑞RDC共享库存 + public class SUPPLIER_INV_DATA_Service : RecurringJobOutPageController + { + public SUPPLIER_INV_DATA_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_MRP_DATE_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_MRP_DATE_Service.cs new file mode 100644 index 0000000..e3948e6 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_MRP_DATE_Service.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //日物料需求计划 + public class SUPPLIER_MRP_DATE_Service : RecurringJobOutPageController + { + public SUPPLIER_MRP_DATE_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_MRP_MONTH_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_MRP_MONTH_Service.cs new file mode 100644 index 0000000..212ec6c --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_MRP_MONTH_Service.cs @@ -0,0 +1,14 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class SUPPLIER_MRP_MONTH_Service : RecurringJobOutPageController + { + public SUPPLIER_MRP_MONTH_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_MRP_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_MRP_Service.cs new file mode 100644 index 0000000..c67512f --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_MRP_Service.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //日MRP状态监控 + public class SUPPLIER_MRP_Service : RecurringJobOutPageController + { + public SUPPLIER_MRP_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_MRP_WARNING_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_MRP_WARNING_Service.cs new file mode 100644 index 0000000..462476f --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_MRP_WARNING_Service.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //日MRP预警推移 + public class SUPPLIER_MRP_WARNING_Service : RecurringJobOutPageController + { + public SUPPLIER_MRP_WARNING_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PO_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PO_Service.cs new file mode 100644 index 0000000..42e45ec --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PO_Service.cs @@ -0,0 +1,14 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class SUPPLIER_PO_Service : RecurringJobOutPageController + { + public SUPPLIER_PO_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_ATTACHMENT_DATA_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_ATTACHMENT_DATA_Service.cs new file mode 100644 index 0000000..a744872 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_ATTACHMENT_DATA_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_ATTACHMENT_DATA_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_CPS_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_CPS_Service.cs new file mode 100644 index 0000000..795a21d --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_CPS_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_CPS_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_CSCHEDUL_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_CSCHEDUL_Service.cs new file mode 100644 index 0000000..012a488 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_CSCHEDUL_Service.cs @@ -0,0 +1,14 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_CSCHEDUL_Service : RecurringJobOutPageController + { + public SUPPLIER_PRO_CSCHEDUL_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_DATA_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_DATA_Service.cs new file mode 100644 index 0000000..2d820c4 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_DATA_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_DATA_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_ENVIRONMENT_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_ENVIRONMENT_Service.cs new file mode 100644 index 0000000..e77d442 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_ENVIRONMENT_Service.cs @@ -0,0 +1,5 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_ENVIRONMENT_Service { } + +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_FIRST_PASSYIELD_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_FIRST_PASSYIELD_Service.cs new file mode 100644 index 0000000..fc380e6 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_FIRST_PASSYIELD_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_FIRST_PASSYIELD_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_FLAW_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_FLAW_Service.cs new file mode 100644 index 0000000..36d35ca --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_FLAW_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_FLAW_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_HSCHEDUL_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_HSCHEDUL_Service.cs new file mode 100644 index 0000000..1545a5b --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_HSCHEDUL_Service.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //过焊装未过总装 + public class SUPPLIER_PRO_HSCHEDUL_Service : RecurringJobOutPageController + { + public SUPPLIER_PRO_HSCHEDUL_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_MATERIAL_DATA_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_MATERIAL_DATA_Service.cs new file mode 100644 index 0000000..6b62c23 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_MATERIAL_DATA_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_MATERIAL_DATA_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_MATERIAL_STOCK_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_MATERIAL_STOCK_Service.cs new file mode 100644 index 0000000..5b11b49 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_MATERIAL_STOCK_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_MATERIAL_STOCK_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_Service.cs new file mode 100644 index 0000000..93502fc --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_OEE_ACHIEVEMENT_RATE_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_OEE_TIME_DETAILS_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_OEE_TIME_DETAILS_Service.cs new file mode 100644 index 0000000..bcdd87d --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_OEE_TIME_DETAILS_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_OEE_TIME_DETAILS_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_PLANING_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_PLANING_Service.cs new file mode 100644 index 0000000..24f4879 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_PLANING_Service.cs @@ -0,0 +1,18 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //整车月度生产计划 + + + + public class SupplierProPlaningService : RecurringJobOutPageController + { + public SupplierProPlaningService(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_PROCESS_EQUIPMENT_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_PROCESS_EQUIPMENT_Service.cs new file mode 100644 index 0000000..3d0968f --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_PROCESS_EQUIPMENT_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_PROCESS_EQUIPMENT_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_PROCESS_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_PROCESS_Service.cs new file mode 100644 index 0000000..1cb10d0 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_PROCESS_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_PROCESS_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_SCHEDULING_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_SCHEDULING_Service.cs new file mode 100644 index 0000000..a35b5c6 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_SCHEDULING_Service.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_SCHEDULING_Service + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs new file mode 100644 index 0000000..671ed4e --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER.cs @@ -0,0 +1,6 @@ +namespace TaskManager.Controllers +{ + public class SUPPLIER_PRO_STATION_FIRST_PASSYIELD_CONTROLLER + { + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_PRO_TSCHEDUL_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_PRO_TSCHEDUL_Service.cs new file mode 100644 index 0000000..7581659 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_PRO_TSCHEDUL_Service.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //过涂装未过总装 + public class SUPPLIER_PRO_TSCHEDUL_Service : RecurringJobOutPageController + { + public SUPPLIER_PRO_TSCHEDUL_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_RETURN_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_RETURN_Service.cs new file mode 100644 index 0000000..134beb1 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_RETURN_Service.cs @@ -0,0 +1,15 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //退货单 + public class SUPPLIER_RETURN_Service : RecurringJobOutPageController + { + public SUPPLIER_RETURN_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_SA_WEEK_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_SA_WEEK_Service.cs new file mode 100644 index 0000000..6f4aec1 --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_SA_WEEK_Service.cs @@ -0,0 +1,17 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + /// + /// 计划协议 + /// + public class SUPPLIER_SA_WEEK_Service : RecurringJobOutPageController + { + public SUPPLIER_SA_WEEK_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/SUPPLIER_SINV_DATA_Service.cs b/API/Wood.Service/Controllers/SUPPLIER_SINV_DATA_Service.cs new file mode 100644 index 0000000..38b96cc --- /dev/null +++ b/API/Wood.Service/Controllers/SUPPLIER_SINV_DATA_Service.cs @@ -0,0 +1,14 @@ +using TaskManager.Contracts.Dtos; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + public class SUPPLIER_SINV_DATA_Service : RecurringJobOutPageController + { + public SUPPLIER_SINV_DATA_Service(HttpClient httpClient, JobDbContext jobDbContext, LogController log) : base(httpClient, jobDbContext, log) + { + } + } +} diff --git a/API/Wood.Service/Controllers/TOKEN_CONTROLLER.cs b/API/Wood.Service/Controllers/TOKEN_CONTROLLER.cs new file mode 100644 index 0000000..e8f35c8 --- /dev/null +++ b/API/Wood.Service/Controllers/TOKEN_CONTROLLER.cs @@ -0,0 +1,185 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; + +using System.Threading.Tasks; + + +namespace TaskManager.Controllers +{ + public class TOKEN_CONTROLLER + { + + private readonly HttpClient _httpClient; + private readonly string _appKey = "8EG566b9bedd2bf46d"; + private readonly string _appSecret = "48edc4425647425d87f806a1ba492580"; // 若有密钥需传入 + + public TOKEN_CONTROLLER() + { + _httpClient = new HttpClient(); + + + + } + public async Task ExecuteAsync() + { + try + { + var retult = await GetTokenAsync("https://ediuat.mychery.com/prod-api/auth/public/login/appKey"); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + } + + public async Task GetTokenAsync(string tokenUrl) + { + var parameters = new + { + appKey = _appKey, + appSecret = _appSecret, // 按需传参 + // 其他参数如 grant_type、scope 等根据接口要求调整 + }; + + var content = new StringContent( + JsonConvert.SerializeObject(parameters), + Encoding.UTF8, + "application/json" + ); + var response = await _httpClient.PostAsync(tokenUrl, content); + response.EnsureSuccessStatusCode(); // 抛异常处理错误 + var responseBody = await response.Content.ReadAsStringAsync(); + var result = JsonConvert.DeserializeObject(responseBody); + return result.data.access_token; // 假设返回字段为 access_token + } + + + + } + + //private readonly string _appKey = "8EG566b9bedd2bf46d"; + //private readonly string _appSecret = "48edc4425647425d87f806a1ba492580"; + //private readonly string _tokenEndpoint = "https://ediuat.mychery.com/prod-api/auth/public/login/appKey"; + + //private readonly HttpClient _httpClient; + //private readonly SemaphoreSlim _refreshLock = new SemaphoreSlim(1, 1); + //private string _currentToken; + //private DateTime _tokenExpiry; + //private bool _disposed; + + //public TokenServiceController() + //{ + // _httpClient = new HttpClient(); + // _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + //} + + //public async Task GetTokenAsync(CancellationToken cancellationToken = default) + //{ + // // 检查令牌是否存在且未过期(提前60秒刷新以防止边缘情况) + // if (!string.IsNullOrEmpty(_currentToken) && _tokenExpiry > DateTime.UtcNow.AddSeconds(60)) + // { + // return _currentToken; + // } + + // // 等待获取锁,确保只有一个线程刷新令牌 + // await _refreshLock.WaitAsync(cancellationToken); + // try + // { + // // 再次检查,避免其他线程已经刷新了令牌 + // if (!string.IsNullOrEmpty(_currentToken) && _tokenExpiry > DateTime.UtcNow.AddSeconds(60)) + // { + // return _currentToken; + // } + + // // 调用认证API获取新令牌 + // var tokenResponse = await FetchNewTokenAsync(cancellationToken); + + // // 更新令牌和过期时间 + // _currentToken = tokenResponse.AccessToken; + // _tokenExpiry = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn); + + // return _currentToken; + // } + // finally + // { + // _refreshLock.Release(); + // } + //} + + //private async Task FetchNewTokenAsync(CancellationToken cancellationToken) + //{ + // try + // { + // // 创建请求内容 + // var requestBody = new + // { + // appKey = _appKey, + // appSecret = _appSecret + // }; + + // var content = new StringContent( + // JsonSerializer.Serialize(requestBody), + // Encoding.UTF8, + // "application/json"); + + // // 发送请求 + // var response = await _httpClient.PostAsync(_tokenEndpoint, content, cancellationToken); + // response.EnsureSuccessStatusCode(); + + // // 解析响应 + // var jsonResponse = await response.Content.ReadAsStringAsync(cancellationToken); + // var tokenResponse = JsonSerializer.Deserialize( + // jsonResponse, + // new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + + // if (tokenResponse == null || string.IsNullOrEmpty(tokenResponse.AccessToken)) + // { + // throw new InvalidOperationException("Failed to retrieve access token."); + // } + + // return tokenResponse; + // } + // catch (Exception ex) + // { + // Console.WriteLine($"Token acquisition failed: {ex.Message}"); + // throw; + // } + //} + + //// 令牌响应模型 + //private class TokenResponse + //{ + // public string AccessToken { get; set; } + // public int ExpiresIn { get; set; } = 3600; // 默认1小时 + //} + + //public void Dispose() + //{ + // Dispose(true); + // GC.SuppressFinalize(this); + //} + + //protected virtual void Dispose(bool disposing) + //{ + // if (!_disposed) + // { + // if (disposing) + // { + // _httpClient?.Dispose(); + // _refreshLock?.Dispose(); + // } + // _disposed = true; + // } + //} + + //public Task ExecuteAsync() + //{ + // throw new NotImplementedException(); + //} +} diff --git a/API/Wood.Service/Controllers/TaskConifgureController.cs b/API/Wood.Service/Controllers/TaskConifgureController.cs new file mode 100644 index 0000000..63facb5 --- /dev/null +++ b/API/Wood.Service/Controllers/TaskConifgureController.cs @@ -0,0 +1,578 @@ +using Hangfire; +using Microsoft.AspNetCore.Mvc; + + + +//using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO; +using System.Threading.Tasks; +using TaskManager.Controllers; +using TaskManager.Entity; +using TaskManager.EntityFramework; + +namespace TaskManager.Controllers +{ + //[ApiController] + //[Route("[controller]")] + public class TaskConifgureController :ControllerBase + { + private readonly JobDbContext _context; + private readonly IServiceProvider _builder; + private readonly IConfiguration _configuration; + public TaskConifgureController(JobDbContext context, IServiceProvider builder, IConfiguration configuration) + { + _builder = builder; + _context = context; + _configuration = configuration; + } + /// + /// 请除所有任务 + /// + /// + [HttpPost(Name = "ClearAllTask")] + public async Task ClearAllTask() + { + var tasks = await _context.TaskConifgure.ToListAsync(); + foreach (var item in tasks) + { + RecurringJob.RemoveIfExists(item.TaskName); + } + } + + + /// + /// 执行铁定任务 + /// + /// + /// + [HttpPost(Name = "ExecuteTask")] + public async Task ExecuteTask(string taskName) + { + var first=await _context.TaskConifgure.FirstOrDefaultAsync(p => p.TaskName == taskName); + var url = first.Url; + var path = first.Api; + var controller = _builder.GetRequiredService(); + + await controller.ExecuteAsync(url,path, taskName); + + + + + + + + } + + /// + /// 执行铁定任务 + /// + /// + /// + [HttpGet(Name = "testTask")] + public async Task testTask(string taskName) + { + var first = await _context.TaskConifgure.FirstOrDefaultAsync(p => p.TaskName == taskName); + var url = first.Url; + var path = first.Api; + var controller = _builder.GetRequiredService(); + + await controller.TestAsync(url, path, taskName,"2025-04-21"); + + + + + + + + } + + + + + + + + public async Task RefreshTaskConfig() + { + + // 从数据库加载所有任务配置 + + var tasks = _context.TaskConifgure.Where(p => p.IsAuto == true && !string.IsNullOrEmpty(p.Corn) + && !string.IsNullOrEmpty(p.Api) && !string.IsNullOrEmpty(p.Url)).ToList(); + var delTasks = _context.TaskConifgure.Where(p => p.IsAuto == false || string.IsNullOrEmpty(p.Corn) + || string.IsNullOrEmpty(p.Api) || string.IsNullOrEmpty(p.Url) + ).ToList(); + + foreach (var task in tasks) + { + var url = task.Url; + var path = task.Api; + + + + switch (task.TaskName) + { + //case "来料检验数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url,path,task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "排产数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "供应商基础信息": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "人员资质信息": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "BOM主数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "过程控制项质量数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "生产过程数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "产品一次合格率": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "工位一次合格率": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "缺陷业务数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "环境业务数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "设备OEE达成率": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "OEE时间明细": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "物料主数据": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "工艺装备": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + //case "工艺": + // RecurringJob.AddOrUpdate( + // task.TaskName, + // x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + // task.Corn, + // TimeZoneInfo.Local + // ); + // break; + + case "整车月度生产计划1": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "M+6月物料需求计划1": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "整车月度生产计划2": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "M+6月物料需求计划2": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "日物料需求计划": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "计划协议": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "采购订单": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "过焊装未过总装": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "过涂装未过总装": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "排序供货": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "看板配送单": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "退货单": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "奇瑞RDC共享库存": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "日MRP状态监控": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "日MRP预警推移": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "M+6月物料需求计划风险确认": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "日物料需求计划风险确认": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "采购订单风险确认": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "供应商共享库存-上午": + + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + case "供应商共享库存-晚上": + RecurringJob.AddOrUpdate( + task.TaskName, + x => ((IDoExecute)x).ExecuteAsync(url, path, task.TaskName), + task.Corn, + TimeZoneInfo.Local + ); + break; + + } + + } + foreach (var task in delTasks) + { + + switch (task.TaskName) + { + case "来料检验数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "排产数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "供应商基础信息": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "人员资质信息": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "BOM主数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "过程控制项质量数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "生产过程数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "产品一次合格率": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "工位一次合格率": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "缺陷业务数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "环境业务数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "设备OEE达成率": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "OEE时间明细": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "物料主数据": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "工艺装备": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "工艺": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "整车月度生产计划1": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "M+6月物料需求计划1": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "整车月度生产计划2": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "M+6月物料需求计划2": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "日物料需求计划": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "计划协议": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "采购订单": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "过焊装未过总装": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "过涂装未过总装": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "排序供货": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "看板配送单": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "退货单": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "奇瑞RDC共享库存": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "日MRP状态监控": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "日MRP预警推移": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "M+6月物料需求计划风险确认": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "日物料需求计划风险确认": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "采购订单风险确认": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "供应商共享库存-上午": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + case "供应商共享库存-晚上": + // 移除指定的定时任务 + RecurringJob.RemoveIfExists(task.TaskName); + break; + + } + } + + + + + } + + + // 使用 Hangfire 注册定时任务 + // Console.WriteLine($"已注册定时任务: {task.TaskName}, Cron: {task.Corn}"); + } + } + + + diff --git a/API/Wood.Service/Controllers/WeatherForecastController.cs b/API/Wood.Service/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..10c6914 --- /dev/null +++ b/API/Wood.Service/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace TaskManager.Controllers +{ + //[ApiController] + //[Route("[controller]")] + //public class WeatherForecastController : ControllerBase + //{ + // private static readonly string[] Summaries = new[] + // { + // "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + // }; + + // private readonly ILogger _logger; + + // public WeatherForecastController(ILogger logger) + // { + // _logger = logger; + // } + + // [HttpGet(Name = "GetWeatherForecast")] + // public IEnumerable Get() + // { + // return Enumerable.Range(1, 5).Select(index => new WeatherForecast + // { + // Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + // TemperatureC = Random.Shared.Next(-20, 55), + // Summary = Summaries[Random.Shared.Next(Summaries.Length)] + // }) + // .ToArray(); + // } + //} +} diff --git a/API/Wood.Service/Events/LogExceptionEventHandler.cs b/API/Wood.Service/Events/LogExceptionEventHandler.cs new file mode 100644 index 0000000..fbeed61 --- /dev/null +++ b/API/Wood.Service/Events/LogExceptionEventHandler.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.EventBus; +using Wood.EventBus.Events; +using Wood.Util; + +namespace Wood.Service.Events +{ + /// + /// 异常日志保存事件 + /// + public class LogExceptionEventHandler : IntegrationEventHandler, ISingleton + { + /// + /// 保存异常信息 + /// + /// + /// + /// + public override async Task Run(LogExceptionEvent @event,IServiceScope scope) + { + await scope.ServiceProvider.GetRequiredService>().InsertAsync(@event.GetPayload()!); + } + } +} diff --git a/API/Wood.Service/Events/LogOperationEventHandler.cs b/API/Wood.Service/Events/LogOperationEventHandler.cs new file mode 100644 index 0000000..7caf2fb --- /dev/null +++ b/API/Wood.Service/Events/LogOperationEventHandler.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.EventBus; +using Wood.EventBus.Events; +using Wood.Util; + +namespace Wood.Service.Events +{ + public class LogOperationEventHandler : IntegrationEventHandler, ISingleton + { + /// + /// 保存日志 + /// + /// + /// + /// + public override async Task Run(LogOperationEvent @event, IServiceScope scope) + { + await scope.ServiceProvider.GetRequiredService>().InsertAsync(@event.GetPayload()!); + } + } +} diff --git a/API/Wood.Service/SystemManage/AutoJobService.cs b/API/Wood.Service/SystemManage/AutoJobService.cs new file mode 100644 index 0000000..920f840 --- /dev/null +++ b/API/Wood.Service/SystemManage/AutoJobService.cs @@ -0,0 +1,115 @@ +using Microsoft.AspNetCore.Mvc; +using Quartz; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.AutoJob; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Param; + +namespace Wood.Service.SystemManage +{ + public class AutoJobService : ApiService + { + private readonly SqlSugarRepository _jobTriggerRepository; + private readonly SqlSugarRepository _jobDetailRepository; + + private readonly ISchedulerFactory _iSchedulerFactory; + + public AutoJobService(SqlSugarRepository jobTriggerRepository, ISchedulerFactory iSchedulerFactory, SqlSugarRepository jobDetailRepository) + { + _jobTriggerRepository = jobTriggerRepository; + _iSchedulerFactory = iSchedulerFactory; + _jobDetailRepository = jobDetailRepository; + } + + /// + /// 自动任务列表 + /// + /// + /// + public async Task> Paged(AutoJobPagedParam param) + { + return await _jobTriggerRepository.AsQueryable() + .LeftJoin((it, jd) => it.JobId == jd.JobId) + .WhereIF(!string.IsNullOrEmpty(param.Description), it => it.Description!.Contains(param.Description!)) + .Select((it, jd) => new AutoJobDto + { + Id = it.Id.SelectAll(), + GroupName = jd.GroupName, + JobType = jd.JobType, + AssemblyName = jd.AssemblyName, + JobDescription = jd.Description, + }) + .ToPagedListAsync(param); + } + + /// + /// 启动 + /// + /// + /// + [HttpGet] + public async Task Start(BaseIdParam param) + { + var jobTrigger = await _jobTriggerRepository.GetByIdAsync(param.Id); + //var jobDetail = await _jobDetailRepository.GetFirstAsync(it => it.JobId == jobTrigger.JobId); + jobTrigger.Status = TriggerStatusEnum.Ready; + await _jobTriggerRepository.UpdateAsync(jobTrigger); + + //var scheduler = await _iSchedulerFactory.GetScheduler(); + + //var jobType = typeof(AutoJobCenter).Assembly.GetType(jobDetail.JobType!); + //if (jobType != null) + //{ + // IJobDetail job = JobBuilder.Create(jobType!).WithIdentity(jobDetail.JobId!, jobDetail.GroupName!).Build(); + // job.JobDataMap.Add("DetailId", jobDetail.Id); + // job.JobDataMap.Add("TriggerId", jobTrigger.Id); + + // await scheduler.ScheduleJob(job, AutoJobCenter.CreateTrigger(jobTrigger, jobDetail)); + //} + } + /// + /// 暂停 + /// + /// + /// + [HttpGet] + public async Task Stop(BaseIdParam param) + { + var jobTrigger = await _jobTriggerRepository.GetByIdAsync(param.Id); + //var jobDetail = await _jobDetailRepository.GetFirstAsync(it => it.JobId == jobTrigger.JobId); + jobTrigger.Status = TriggerStatusEnum.Pause; + await _jobTriggerRepository.UpdateAsync(jobTrigger); + //var scheduler = await _iSchedulerFactory.GetScheduler(); + + //JobKey jk = new JobKey(jobDetail.JobId,jobDetail.GroupName); + //TriggerKey tk=new TriggerKey(jobTrigger.TriggerId, jobDetail.GroupName); + + //if (await scheduler.CheckExists(tk)) + // await scheduler.UnscheduleJob(tk); + + //if (await scheduler.CheckExists(jk)) + // await scheduler.DeleteJob(jk); + } + + /// + /// 延期任务 + /// + /// + /// + public async Task Deferred(AutoJobDeferredParam param) + { + var jobTrigger = await _jobTriggerRepository.GetByIdAsync(param.Id); + jobTrigger.EndTime = param.EndTime; + jobTrigger.Status = TriggerStatusEnum.Ready; + await _jobTriggerRepository.UpdateAsync(jobTrigger); + } + } +} diff --git a/API/Wood.Service/SystemManage/DataDictDetailService.cs b/API/Wood.Service/SystemManage/DataDictDetailService.cs new file mode 100644 index 0000000..415120e --- /dev/null +++ b/API/Wood.Service/SystemManage/DataDictDetailService.cs @@ -0,0 +1,48 @@ +using System .Linq.Expressions; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Param; +using Wood.Util; + +namespace Wood.Service.SystemManage +{ + public class DataDictDetailService : ApiCRUDService + { + public DataDictDetailService(SqlSugarRepository repository) : base(repository) + { + } + + public async Task> Paged(DataDictDetailPagedParam param) + { + return await _repository.AsQueryable() + .WhereIF(param.DictId>0,it=>it.DictTypeId==param.DictId) + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.DictValue.Contains(param.Name!)||it.DictKey.Contains(param.Name!)) + .ToPagedListAsync(param); + } + + /// + /// 获取字典信息列表用于选择 + /// + /// + public async Task> GetSelectList(string code) + { + return await _repository.AddStatusFilter(1) + .Where(it=>it.DataDict!.FormCode==code) + .Select(it => new ElSelectDto() + { + Label = it.DictValue, + Disabled = false, + Value = it.DictKey + }).ToListAsync(); + } + + public async Task GetMaxSort() + { + var result = await this._repository.AsQueryable().MaxAsync(it => it.Sort); + return result + 10; + } + + } +} diff --git a/API/Wood.Service/SystemManage/DataDictService.cs b/API/Wood.Service/SystemManage/DataDictService.cs new file mode 100644 index 0000000..6f0172e --- /dev/null +++ b/API/Wood.Service/SystemManage/DataDictService.cs @@ -0,0 +1,45 @@ +using System.Linq.Expressions; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Param; +using Wood.Util; + +namespace Wood.Service.SystemManage +{ + public class DataDictService : ApiCRUDService + { + private readonly SqlSugarRepository _dataDictDetailRepository; + + public DataDictService(SqlSugarRepository repository, SqlSugarRepository dataDictDetailRepository) : base(repository) + { + _dataDictDetailRepository = dataDictDetailRepository; + } + + + #region 获取数据 + public async Task> Paged(DataDictPagedParam param) + { + return await _repository.AsQueryable() + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.DictName.Contains(param.Name!)) + .ToPagedListAsync(param); + } + + public async Task GetMaxSort() + { + var result = await this._repository.AsQueryable().MaxAsync(it => it.Sort); + return result + 10; + } + #endregion + + public override async Task Delete(BaseIdListParam param) + { + if (param.Ids.Any()) + { + await _repository.FakeDeleteAsync(it => param.Ids.Contains(it.Id)); + await _dataDictDetailRepository.FakeDeleteAsync(it => param.Ids.Contains(it.DictTypeId)); + } + } + } +} diff --git a/API/Wood.Service/SystemManage/Dto/AutoJobDto.cs b/API/Wood.Service/SystemManage/Dto/AutoJobDto.cs new file mode 100644 index 0000000..4f2d21c --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/AutoJobDto.cs @@ -0,0 +1,39 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity.SystemManage; +using Wood.Util; + +namespace Wood.Service.SystemManage.Dto +{ + public class AutoJobDto:JobTriggerEntity + { + /// + /// 组名称 + /// + public string GroupName { get; set; } = "default"; + + /// + /// 作业类型FullName + /// + public string? JobType { get; set; } + + /// + /// 程序集Name + /// + public string? AssemblyName { get; set; } + + /// + /// 描述信息 + /// + public string? JobDescription { get; set; } + + /// + /// 状态文本 + /// + public string? StatusText { get => Status.GetDescription(); } + } +} diff --git a/API/Wood.Service/SystemManage/Dto/FileDto.cs b/API/Wood.Service/SystemManage/Dto/FileDto.cs new file mode 100644 index 0000000..e286948 --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/FileDto.cs @@ -0,0 +1,65 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Dto +{ + public class FileDto : EntityIdBase + { + /// + /// 打包Guid + /// + public string? PackageCode { get; set; } + + /// + /// 仓储名称 + /// + public string? BucketName { get; set; } + + /// + /// 文件名称(上传时名称) + /// 文件名称 + public string? FileName { get; set; } + + /// + /// 文件后缀 + /// + public string? Suffix { get; set; } + + /// + /// 存储路径 + /// + public string? FilePath { get; set; } + + /// + /// 文件大小KB + /// + public string? SizeKb { get; set; } + + /// + /// 文件大小信息-计算后的 + /// + public string? SizeInfo { get; set; } + + /// + /// 桥接 图片路径 + /// 用于区别访问不同仓储的图片 + /// + public string? BridgeFilePath + { + get + { + if (BucketName == "local") + return "\\" + FilePath!.Trim('\\'); + else + return "\\fromBucket/" + BucketName + "\\" + FilePath!.Trim('\\'); + } + } + } +} diff --git a/API/Wood.Service/SystemManage/Dto/LogDto.cs b/API/Wood.Service/SystemManage/Dto/LogDto.cs new file mode 100644 index 0000000..62030cc --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/LogDto.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity.SystemManage; +using Wood.Util; + +namespace Wood.Service.SystemManage.Dto +{ + public class LogLoginDto : LogLoginEntity + { + public string LogStatusText + { + get + { + return LogStatus.GetDescription(); + } + } + } +} diff --git a/API/Wood.Service/SystemManage/Dto/MenuDto.cs b/API/Wood.Service/SystemManage/Dto/MenuDto.cs new file mode 100644 index 0000000..0eadf19 --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/MenuDto.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Dto +{ + public class MenuTreeListDto:MenuEntity + { + public List? Children { get; set; } + } + + public class ElTreeExtraDto : ElTreeDto + { + public int Type { get; set; } + } +} diff --git a/API/Wood.Service/SystemManage/Dto/MessageDto.cs b/API/Wood.Service/SystemManage/Dto/MessageDto.cs new file mode 100644 index 0000000..3eb7f56 --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/MessageDto.cs @@ -0,0 +1,65 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Util; + +namespace Wood.Service.SystemManage.Dto +{ + public class MessagePageReceivedDto : UserMessageEntity + { + /// + /// 消息标题(最大长度128字符) + /// + public string? Title { get; set; } + + /// + /// 发布人 + /// + public string? PublisherName { get; set; } + + /// + /// 发布机构 + /// + public string? PublisherOrgName { get; set; } + + /// + /// 消息类型(0-系统通知 1-公告 2-私信) + /// + public MessageTypeEnum MessageType { get; set; } + + public string MessageTypeText + { + get + { + return MessageType.GetDescription(); + } + } + + public DateTime? PublishAt { get; set; } + } + + + public class MessagePagedPublishDto : MessageEntity + { + public string MessageTypeText + { + get + { + return MessageType.GetDescription(); + } + } + public string StatusText + { + get + { + return Status.GetDescription(); + } + } + } + +} diff --git a/API/Wood.Service/SystemManage/Dto/OrgDto.cs b/API/Wood.Service/SystemManage/Dto/OrgDto.cs new file mode 100644 index 0000000..f9b12ff --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/OrgDto.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Dto +{ + public class OrgTreeDto:OrgEntity + { + public List Children { get; set; } = new List(); + } +} diff --git a/API/Wood.Service/SystemManage/Dto/RoleDto.cs b/API/Wood.Service/SystemManage/Dto/RoleDto.cs new file mode 100644 index 0000000..6358250 --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/RoleDto.cs @@ -0,0 +1,41 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Util; + +namespace Wood.Service.SystemManage.Dto +{ + public class RolePagedDto : RoleEntityShared + { + public string DataScopeTypeText + { + get + { + return DataScopeType.GetDescription(); + } + } + } + + public class RoleDetailDto : RoleEntityShared + { + /// + /// 授权菜单 + /// + public List Menus { get; set; } = new List(); + + /// + /// 授权按钮功能 + /// + public List Btns { get; set; } = new List(); + + /// + /// 授权部门列表 + /// + public List Orgs { get; set; } = new List(); + } +} diff --git a/API/Wood.Service/SystemManage/Dto/TenantDto.cs b/API/Wood.Service/SystemManage/Dto/TenantDto.cs new file mode 100644 index 0000000..683952e --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/TenantDto.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Dto +{ + public class TenantDetailDto:TenantEntity + { + /// + /// 机构组织名称 + /// + public string OrgName { get; set; } = ""; + } + + public class TenantPagedDto :TenantEntity + { + /// + /// 机构组织名称 + /// + public string OrgName { get; set; } = ""; + } +} diff --git a/API/Wood.Service/SystemManage/Dto/UserDto.cs b/API/Wood.Service/SystemManage/Dto/UserDto.cs new file mode 100644 index 0000000..76eebae --- /dev/null +++ b/API/Wood.Service/SystemManage/Dto/UserDto.cs @@ -0,0 +1,146 @@ +using Magicodes.ExporterAndImporter.Core; +using Magicodes.ExporterAndImporter.Excel; +using Mapster; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; +using WoodWood.Util.Validations; + +namespace Wood.Service.SystemManage.Dto +{ + + /// + /// 验证码 + /// + public class UserCaptchaDto + { + public string Guid { get; set; } = ""; + + public string Img { get; set; } = ""; + + } + + public class UserPagedDto : UserEntityShared + { + /// + /// 用户角色 + /// + public string Roles { get; set; } = ""; + /// + /// 用户机构部门 + /// + public string OrgName { get; set; } = ""; + } + + public class UserDetailDto : UserEntityShared + { + /// + /// 部门id + /// + public long? OrgId { get; set; } + + /// + /// 职位id + /// + public long? PositionId { get; set; } + /// + /// 用户权限 + /// + [AdaptIgnore] + public List Roles { get; set; } = new List(); + } + /// + /// 用户信息导出 + /// + [ExcelExporter(Name = "测试2", TableStyle = OfficeOpenXml.Table.TableStyles.None, AutoFitAllColumn = true)] + public class UserExportDto + { + /// + /// 雪花Id + /// + [ExporterHeader(IsIgnore = true)] + public long Id { get; set; } + /// + /// 用户名 + /// + [ExporterHeader(DisplayName = "学生编号")] + public string UserName { get; set; } = ""; + + /// + /// 姓名 + /// + [ExporterHeader(DisplayName = "姓名")] + public string? RealName { get; set; } + + /// + /// 昵称 + /// + [ExporterHeader(DisplayName = "昵称")] + public string? NickName { get; set; } + /// + /// 性别 1 男 0 女 + /// + [ExporterHeader(IsIgnore = true)] + public int Gender { get; set; } = 0; + /// + /// 性别文本 1 男 0 女 + /// + [ExporterHeader(DisplayName = "性别")] + public string GenderText + { + get + { + if (Gender == 0) return "女"; + return "男"; + } + } + /// + /// 出生日期 + /// + [ExporterHeader(DisplayName = "出生日期")] + public DateTime Birthday { get; set; } + + /// + /// 邮箱 + /// + [ExporterHeader(DisplayName = "邮箱")] + public string? Email { get; set; } + + /// + /// 手机号码 + /// + [ExporterHeader(DisplayName = "手机号码")] + public string? Mobile { get; set; } + + /// + /// 部门 + /// + [ExporterHeader(DisplayName = "部门")] + public string? Org { get; set; } + + /// + /// 职位 + /// + [ExporterHeader(DisplayName = "职位")] + public string? Position { get; set; } + + /// + /// 角色 + /// + [ExporterHeader(DisplayName = "角色")] + public string? Roles { get; set; } + + /// + /// 最近登录时间 + /// + [ExporterHeader(DisplayName = "最近登录时间", Format = "yyyy-MM-dd HH:mm:ss")] + public DateTime? LastVisit { get; set; } + + } +} diff --git a/API/Wood.Service/SystemManage/FileService.cs b/API/Wood.Service/SystemManage/FileService.cs new file mode 100644 index 0000000..89d4ea5 --- /dev/null +++ b/API/Wood.Service/SystemManage/FileService.cs @@ -0,0 +1,95 @@ +using Mapster; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Data.Repository; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Manager; +using Wood.Util; + +namespace Wood.Service.SystemManage +{ + /// + /// 上传文件 + /// + public class FileService : ApiService + { + private readonly FileManager _fileManager; + + public FileService(FileManager fileManager) + { + _fileManager = fileManager; + } + + + /// + /// 上传文件 + /// + /// + /// 存储的仓储 默认:local 本地存储 + /// + public async Task Upload(IFormFile file, [FromQuery]string? bucket="local") + { + if (file == null || file.Length == 0) + throw Oops.Oh("没有可以保存的文件!"); + + var folder = Path.Combine(GlobalContext.HostingEnvironment!.WebRootPath, "uploads", DateTime.Now.ToString("yyyy_MM_dd")); + if (!Directory.Exists(folder)) + Directory.CreateDirectory(folder); + var ext = Path.GetExtension(file.FileName); + var uniqueFileName = $"{IdGeneratorHelper.Instance.GetGuid("N")}{ext}"; + var filePath = Path.Combine(folder, uniqueFileName); + + using (var stream = new FileStream(filePath, FileMode.Create)) + await file.CopyToAsync(stream); + + FileEntity fileEntity = new FileEntity() + { + BucketName = bucket, + Provider = "", + FileName = file.FileName, + FilePath = Path.GetRelativePath(GlobalContext.HostingEnvironment!.WebRootPath, filePath), + SizeKb =(file.Length / 1024.0F), + SizeInfo = "", + Suffix = ext, + }; + + await _fileManager.AsRepository().InsertAsync(fileEntity); + + return fileEntity.Adapt(); + } + + /// + /// 根据code 获取文件列表 + /// + /// + /// + public async Task> GetFilesByCode(string code) + { + if (string.IsNullOrEmpty(code)) + return new List(); + + var files= await _fileManager.GetByCode(code); + + var dtos= files.Adapt>(); + + return dtos; + } + + /// + /// 根据code 获取文件列表 + /// + /// + /// + public async Task> GetFilePathsByCode(string code) + { + return await _fileManager.GetFilePathsByCode(code); + } + } +} diff --git a/API/Wood.Service/SystemManage/LogService.cs b/API/Wood.Service/SystemManage/LogService.cs new file mode 100644 index 0000000..246dd6f --- /dev/null +++ b/API/Wood.Service/SystemManage/LogService.cs @@ -0,0 +1,118 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Param; + +namespace Wood.Service.SystemManage +{ + /// + /// 日志信息 + /// + public class LogService : ApiService + { + private readonly SqlSugarRepository _logLoginRepository; + private readonly SqlSugarRepository _logJobRepository; + private readonly SqlSugarRepository _logEventRepository; + private readonly SqlSugarRepository _logExceptionRepository; + private readonly SqlSugarRepository _logOperationRepository; + private readonly SqlSugarRepository _logDiffRepository; + + public LogService(SqlSugarRepository logLoginRepository, SqlSugarRepository logJobRepository, SqlSugarRepository logEventRepository, SqlSugarRepository logExceptionRepository, SqlSugarRepository logDiffRepository, SqlSugarRepository logOperationRepository) + { + _logLoginRepository = logLoginRepository; + _logJobRepository = logJobRepository; + _logEventRepository = logEventRepository; + _logExceptionRepository = logExceptionRepository; + _logDiffRepository = logDiffRepository; + _logOperationRepository = logOperationRepository; + } + /// + /// 登录日志 + /// + /// + /// + public async Task> PagedLogin(LogLoginParam param) + { + return await _logLoginRepository.AsQueryable() + .Where(it => it.CreateTime >= param.StartTime && it.CreateTime <= param.EndTime) + .WhereIF(!string.IsNullOrEmpty(param.UserName), it => it.Account == param.UserName!) + .Select(it => new LogLoginDto() + { + Id = it.Id.SelectAll() + }) + .ToPagedListAsync(param); + } + /// + /// job日志 + /// + /// + /// + public async Task> PagedJob(LogJobParam param) + { + return await _logJobRepository.AsQueryable() + .Where(it => it.CreateTime >= param.StartTime && it.CreateTime <= param.EndTime) + .WhereIF(!string.IsNullOrEmpty(param.JobId), it => it.JobId == param.JobId!) + .ToPagedListAsync(param); + } + /// + /// 事件日志 + /// + /// + /// + public async Task> PagedEvent(LogEventParam param) + { + return await _logEventRepository.AsQueryable() + .Where(it => it.CreateTime >= param.StartTime && it.CreateTime <= param.EndTime) + .WhereIF(!string.IsNullOrEmpty(param.EventName), it => it.EventName == param.EventName!) + .ToPagedListAsync(param); + } + /// + /// 错误日志 + /// + /// + /// + public async Task> PagedException(LogExceptionParam param) + { + return await _logExceptionRepository.AsQueryable() + .Where(it => it.CreateTime >= param.StartTime && it.CreateTime <= param.EndTime) + .WhereIF(!string.IsNullOrEmpty(param.ControllerName), it => it.ControllerName == param.ControllerName!) + .WhereIF(!string.IsNullOrEmpty(param.RequestUrl), it => it.RequestUrl == param.RequestUrl!) + .WhereIF(!string.IsNullOrEmpty(param.Source), it => it.Source == param.Source!) + .WhereIF(!string.IsNullOrEmpty(param.ActionName), it => it.ActionName == param.ActionName!) + .ToPagedListAsync(param); + } + /// + /// 操作日志 + /// + /// + /// + public async Task> PagedOperation(LogOperationParam param) + { + return await _logOperationRepository.AsQueryable() + .Where(it => it.CreateTime >= param.StartTime && it.CreateTime <= param.EndTime) + .WhereIF(!string.IsNullOrEmpty(param.ControllerName), it => it.ControllerName == param.ControllerName!) + .WhereIF(!string.IsNullOrEmpty(param.ActionName), it => it.ActionName == param.ActionName!) + .WhereIF(!string.IsNullOrEmpty(param.RequestUrl), it => it.RequestUrl == param.RequestUrl!) + .ToPagedListAsync(param); + } + /// + /// 差异日志 + /// + /// + /// + public async Task> PagedDiff(LogDiffParam param) + { + return await _logDiffRepository.AsQueryable() + .Where(it => it.CreateTime >= param.StartTime && it.CreateTime <= param.EndTime) + .WhereIF(!string.IsNullOrEmpty(param.TableName), it => it.Tables!.Contains(param.TableName!)) + .ToPagedListAsync(param); + } + } +} diff --git a/API/Wood.Service/SystemManage/Manager/FileManager.cs b/API/Wood.Service/SystemManage/Manager/FileManager.cs new file mode 100644 index 0000000..e6d985c --- /dev/null +++ b/API/Wood.Service/SystemManage/Manager/FileManager.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity.SystemManage; +using Wood.Entity; +using Wood.Data.Repository; +using Wood.Service.SystemManage.Dto; +using Mapster; +using Wood.Util; +using NetTaste; + +namespace Wood.Service.SystemManage.Manager +{ + public class FileManager : ApiManager, ITransient + { + public FileManager(SqlSugarRepository repository) : base(repository) + { + } + + /// + /// 把指定的批次code的附件进行更新 + /// 针对一对多附件时使用 + /// + /// code,为空会生成新的code + /// 新附件id列表,空时为清空批次文件 + /// + public async Task UpdateFile(string? code, List? newFiles) + { + if (string.IsNullOrEmpty(code)) + return await AddFile(newFiles); + else + { + //更新附件 置为不可用 + //把批次 code 不在 newFiles 中的附件标记为删除 + await AsRepository().AsUpdateable() + .SetColumns(it => new FileEntity() { IsDelete = true }) + .Where(it => it.PackageCode == code) + .WhereIF(newFiles != null && newFiles.Any(), it => !newFiles!.Contains(it.Id)) + .ExecuteCommandAsync(); + if (newFiles != null && newFiles.Count > 0) + //更新附件 置为可用 + //把批次在 newFiles 中的附件标记为可用 并把 批次更新为 code + await AsRepository().AsUpdateable() + .SetColumns(it => new FileEntity() { PackageCode = code, IsDelete = false }) + .Where(it => newFiles.Contains(it.Id)).ExecuteCommandAsync(); + return code; + } + } + + /// + /// 把指定的批次code的附件进行更新 + /// 针对一对一附件时使用 + /// + /// code,为空会生成新的code + /// 新文件,0时为清空批次文件 + /// + public async Task UpdateFile(string? code, long? newFile) + { + if (string.IsNullOrEmpty(code)) + return await AddFile(newFile); + else + { + //更新附件 置为不可用 + //把批次 code 不在 newFiles 中的附件标记为删除 + await AsRepository().AsUpdateable() + .SetColumns(it => new FileEntity() { IsDelete = true }) + .Where(it => it.PackageCode == code) + .ExecuteCommandAsync(); + if (newFile > 0) + //更新附件 置为可用 + //把批次在 newFiles 中的附件标记为可用 并把 批次更新为 code + await AsRepository().AsUpdateable() + .SetColumns(it => new FileEntity() { PackageCode = code, IsDelete = false }) + .Where(it => it.Id == newFile).ExecuteCommandAsync(); + return code; + } + } + + /// + /// 把附件加到指定的批次code中 + /// 针对一对多附件时使用 + /// + /// 要添加的附件id列表 + /// 返回一个批次编码 + public async Task AddFile(List? files) + { + if (files != null && files.Count > 0) + { + string code = IdGeneratorHelper.Instance.GetGuid("N"); + //更新附件 + await AsRepository().AsUpdateable() + .SetColumns(it => new FileEntity() { PackageCode = code, IsDelete = false }) + .Where(it => files.Contains(it.Id)).ExecuteCommandAsync(); + + return code; + } + else + return string.Empty; + + } + + /// + /// 把附件加到指定的批次code中 + /// 针对一对一附件时使用 + /// + /// 要添加的附件 + /// 返回一个批次编码 + public async Task AddFile(long? file) + { + if (file != null && file > 0) + { + string code = IdGeneratorHelper.Instance.GetGuid("N"); + //更新附件 + await AsRepository().AsUpdateable() + .SetColumns(it => new FileEntity() { PackageCode = code, IsDelete = false }) + .Where(it => it.Id == file).ExecuteCommandAsync(); + return code; + } + else + return string.Empty; + } + + /// + /// 根据批次code获取文件 + /// + /// + /// + public async Task> GetByCode(string? code) + { + if (string.IsNullOrEmpty(code)) + return new List(); + + var files = await AsRepository().GetListAsync(it => it.PackageCode == code); + + var dtos = files.Adapt>(); + + return dtos; + } + + /// + /// 根据批次code获取文件 + /// + /// + /// + public async Task> GetByCode(List? codes) + { + if (codes == null || !codes.Any()) + return new List(); + var files = await AsRepository().GetListAsync(it => codes.Contains(it.PackageCode!)); + var dtos = files.Adapt>(); + + return dtos; + } + + /// + /// 返回批次code文件的所有路径 + /// + /// + /// + public async Task> GetFilePathsByCode(string? code) + { + if (string.IsNullOrEmpty(code)) + return new List(); + List result = new List(); + var files = await GetByCode(code); + foreach (var item in files) + { + if (item.BucketName == "local") + result.Add("/" + item.FilePath!.Trim('/')); + else + result.Add("/fromBucket/" + item.BucketName + "/" + item.FilePath!.Trim('/')); + } + return result; + } + } +} diff --git a/API/Wood.Service/SystemManage/Manager/OrgManager.cs b/API/Wood.Service/SystemManage/Manager/OrgManager.cs new file mode 100644 index 0000000..f461050 --- /dev/null +++ b/API/Wood.Service/SystemManage/Manager/OrgManager.cs @@ -0,0 +1,52 @@ +using SqlSugar; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Manager +{ + /// + /// orgManager + /// + public class OrgManager : ApiManager, ITransient + { + /// + /// orgManager + /// + /// + public OrgManager(SqlSugarRepository repository) : base(repository) + { + } + + /// + /// 获取所有的子id 包括自己 + /// + /// 父级id + /// + public async Task> GetChildrenIds(long orgId) + { + return (await AsQueryable().ToChildListAsync(it => it.ParentId, orgId)).Select(it => it.Id).ToList(); + } + + /// + /// 根据名称获取机构部门 + /// + /// 路径 以/分割 + /// + public async Task> GetOrgsByPath(string path) + { + string[] paths = path.Split('/'); + List? es =await AsRepository().GetListAsync(it => paths.Contains( it.OrgName)); + if (paths.Length == 1) + return es; + else + { + IEnumerable parent = es.Where(it => it.OrgName == paths[0]); + for (int i = 1; i < paths.Length; i++) + parent= es.Where(it=>it.OrgName == paths[i]&&parent.Any(p=>p.Id==it.ParentId)); + + return parent.ToList(); + } + } + } +} diff --git a/API/Wood.Service/SystemManage/Manager/UserManager.cs b/API/Wood.Service/SystemManage/Manager/UserManager.cs new file mode 100644 index 0000000..44ab2a5 --- /dev/null +++ b/API/Wood.Service/SystemManage/Manager/UserManager.cs @@ -0,0 +1,129 @@ +using Microsoft.AspNetCore.Http; +using Wood.Cache; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Util; +using Wood.Util.JwtAuthorization; + +namespace Wood.Service.SystemManage.Manager +{ + public class UserManager : ApiManager, ITransient + { + private readonly ICache _cache; + private readonly SqlSugarRepository _orgRepository; + private readonly SqlSugarRepository _userRepository; + private readonly IHttpContextAccessor _httpContextAccessor; + public UserManager(SqlSugarRepository repository, ICache cache, SqlSugarRepository orgRepository, SqlSugarRepository userRepository, IHttpContextAccessor httpContextAccessor) : base(repository) + { + _cache = cache; + _orgRepository = orgRepository; + _userRepository = userRepository; + _httpContextAccessor = httpContextAccessor; + } + + public async Task InitCache(long userId, DateTime tokenExpiresTime) + { + UserEntity? userInfo = await _userRepository.AsQueryable() + .Includes(it => it.Roles) + .Includes(it => it.Org) + .Includes(it => it.Position) + .Where(it => it.Id == userId) + .FirstAsync(); + + await InitCache(userInfo, tokenExpiresTime); + } + + public async Task InitCache(UserEntity userInfo, DateTime tokenExpiresTime) + { + string cacheKey = userInfo.Id + "-" + userInfo.TenantId; + + string roleName = userInfo!.AccountType.GetDescription(); + if (userInfo!.Roles != null && userInfo!.Roles.Any()) + roleName = string.Join(',', userInfo.Roles.Select(it => it.RoleName)); + + UserCache userCache = new UserCache() + { + RealName = userInfo.RealName, + TenantId = userInfo.TenantId, + AccountType = userInfo.AccountType, + Email = userInfo.Email, + Id = userInfo.Id, + Mobile = userInfo.Mobile, + NickName = userInfo.NickName, + OrgId = userInfo.OrgId, + Salt = userInfo.Salt, + UserName = userInfo.UserName, + PositionId = userInfo.PositionId + }; + + userCache.Roles = userInfo.Roles!.Select(it => it.Id).ToList(); + + var dataScopeType = 0; + foreach (var item in userInfo.Roles!) + dataScopeType |= (int)item.DataScopeType; + + //拥有全部数据访问权限则直接返回即可 + if ((dataScopeType & (int)DataScopeTypeEnum.All) == 1) + { + userCache.DataScopeType = DataScopeTypeEnum.All; + _cache.SetCache(cacheKey, userCache, tokenExpiresTime); + } + else + { + List customScope = new List(); + //有自定义的部门权限 + if ((dataScopeType & (int)DataScopeTypeEnum.Custom) == 1) + { + var ids = userInfo.Roles.Where(it => it.DataScopeType == DataScopeTypeEnum.Custom).Select(it => it.Id).ToList(); + var childs = await _orgRepository.AsQueryable().ToChildListAsync(it => it.ParentId, ids); + customScope = childs.Select(it => it.Id).ToList(); + } + + List orgScope = new List(); + if ((dataScopeType & (int)DataScopeTypeEnum.MyOrgAndLower) == 1) + { + var childs = await _orgRepository.AsQueryable().ToChildListAsync(it => it.ParentId, userInfo.OrgId); + orgScope = childs.Select(it => it.Id).ToList(); + } + else if ((dataScopeType & (int)DataScopeTypeEnum.MyOrg) == 1) + orgScope.Add(userInfo.OrgId); + else if ((dataScopeType & (int)DataScopeTypeEnum.MySelf) == 1) + orgScope.Add(userInfo.OrgId); + + userCache.DataScopeOrgs = orgScope.Union(customScope).Distinct().ToList(); + _cache.SetCache(cacheKey, userCache, tokenExpiresTime); + } + } + + /// + /// 获取自己所管理的员工id列表 + /// + /// + public async Task> GetOwnUserIdList() + { + var user = UserInfo(); + if (user == null) + return new List(); + if (user!.IsSuperAdmin) + return await _userRepository.AsQueryable().Where(it => it.Id != user.UserId).Select(it => it.Id).ToListAsync(); + else if (user!.IsTenantAdmin) + return await _userRepository.AsQueryable().Where(it => it.Id != user.UserId && it.TenantId == user.TenantId).Select(it => it.Id).ToListAsync(); + else if (user.IsAdmin) + return await _userRepository.AsQueryable().Where(it => it.Id != user.UserId && it.OrgId == user.OrgId).Select(it => it.Id).ToListAsync(); + else + return new List(); + } + + + public JwtUserInfo? UserInfo() => _httpContextAccessor.UserInfo(); + + public UserCache? CacheInfo() + { + var user = UserInfo(); + if (user == null) return null; + else + return _cache.GetCache(user.CacheKey); + } + } +} diff --git a/API/Wood.Service/SystemManage/MenuService.cs b/API/Wood.Service/SystemManage/MenuService.cs new file mode 100644 index 0000000..7252d5f --- /dev/null +++ b/API/Wood.Service/SystemManage/MenuService.cs @@ -0,0 +1,211 @@ +using SqlSugar; +using Wood.Cache; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Param; +using Wood.Util; +using Wood.Util.JwtAuthorization; + +namespace Wood.Service.SystemManage +{ + /// + /// 菜单管理 + /// + public class MenuService : ApiCRUDService + { + public readonly SqlSugarRepository _menuRepository; + public readonly SqlSugarRepository _menuAuthorizeRepository; + private readonly ICache _cache; + + public MenuService(SqlSugarRepository menuRepository, SqlSugarRepository menuAuthorizeEntity, ICache cache) : base(menuRepository) + { + _menuRepository = menuRepository; + _menuAuthorizeRepository = menuAuthorizeEntity; + _cache = cache; + } + + #region 获取数据 + /// + /// 获取所有菜单 + /// + /// 树形结构 + public async Task> TreeList(MenuTreeListParam param) + { + var user = this.UserInfo(); + List? menuIds = null; + //非超级管理员只能查看自己有权限的菜单 + if (!user!.IsSuperAdmin) + { + var userCache = _cache.GetCache(user!.CacheKey); + menuIds = await _menuAuthorizeRepository.AsQueryable() + .Where(it => userCache!.Roles.Contains(it.RoleId)) + .Select(it => it.MenuId) + .Distinct().ToListAsync(); + } + var query = _menuRepository.AsQueryable() + .WhereIF(menuIds != null, it => menuIds!.Contains(it.Id)) + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.MenuName.Contains(param.Name!)) + .WhereIF(param.TreeType == 1, it => it.MenuType == MenuTypeEnum.Directory) + .WhereIF(param.TreeType == 2, it => it.MenuType == MenuTypeEnum.Directory || it.MenuType == MenuTypeEnum.Menu) + .OrderBy(it => it.Sort) + .Select(it => new MenuTreeListDto() + { + Id = it.Id.SelectAll() + }); + + if (param.HasCondition()) + return await query.ToListAsync(); + else + return await query.ToTreeAsync(it => it.Children, it => it.ParentId, 0); + } + + /// + /// 获取所有菜单 + /// 用于El树形结构 + /// + /// 用于El树形结构 + public async Task> ElTreeList(MenuTreeListParam param) + { + var user = this.UserInfo(); + List? menuIds = null; + //非超级管理员只能查看自己有权限的菜单 + if (!user!.IsSuperAdmin) + { + var userCache = _cache.GetCache(user!.CacheKey); + menuIds = await _menuAuthorizeRepository.AsQueryable() + .Where(it => userCache!.Roles.Contains(it.RoleId)) + .Select(it => it.MenuId) + .Distinct().ToListAsync(); + } + var query = _menuRepository.AsQueryable() + .WhereIF(menuIds != null, it => menuIds!.Contains(it.Id)) + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.MenuName.Contains(param.Name!)) + .WhereIF(param.TreeType == 1, it => it.MenuType == MenuTypeEnum.Directory) + .WhereIF(param.TreeType == 2, it => it.MenuType == MenuTypeEnum.Directory || it.MenuType == MenuTypeEnum.Menu) + .OrderBy(it => it.Sort) + .Select(it => new ElTreeExtraDto() + { + Id = it.Id, + Label = it.MenuName, + ParentId = it.ParentId, + Disabled = (it.Status == 0), + Type = (int)it.MenuType + }); + + if (param.HasCondition()) + return await query.ToListAsync(); + else + return await query.ToTreeAsync(it => it.Children, it => it.ParentId, 0); + } + /// + /// 获取一个最大的排序号码 + /// + /// + public async Task GetMaxSort() + { + var result = await this._menuRepository.AsQueryable().MaxAsync(it => it.Sort); + return result + 10; + } + + #endregion + + #region 提交数据 + /// + /// 新增菜单 + /// + /// + /// + public override async Task Add(MenuAddParam entity) + { + if (await _menuRepository.IsAnyAsync(it => it.ParentId == entity.ParentId && it.MenuName == entity.MenuName)) + throw Oops.Oh("名称重复!无法添加。"); + + MenuEntity? parentEntity = null; + if (entity.ParentId != 0) parentEntity = await _menuRepository.GetByIdAsync(entity.ParentId); + + if (entity.MenuType == MenuTypeEnum.Directory) + { + if (parentEntity != null && parentEntity.MenuType != MenuTypeEnum.Directory) + throw Oops.Oh("错误!目录的父级必须是目录!"); + } + else if (entity.MenuType == MenuTypeEnum.Menu) + { + if (parentEntity == null) + throw Oops.Oh("错误!菜单必须有所属目录!"); + else if (parentEntity.MenuType != MenuTypeEnum.Directory) + throw Oops.Oh("错误!菜单的父级必须是目录!"); + } + else + { + if (parentEntity == null) + throw Oops.Oh("错误!按钮必须有所属菜单!"); + else if (parentEntity.MenuType != MenuTypeEnum.Menu) + throw Oops.Oh("错误!按钮的父级必须是菜单!"); + } + + await base.Add(entity); + } + /// + /// 更新菜单 + /// + /// + /// + public override async Task Update(MenuUpdateParam entity) + { + if (await _menuRepository.IsAnyAsync(it => it.ParentId == entity.ParentId && it.MenuName == entity.MenuName && it.Id != entity.Id)) + throw Oops.Oh("名称重复!无法更新。"); + + MenuEntity? parentEntity = null; + if (entity.ParentId != 0) parentEntity = await _menuRepository.GetByIdAsync(entity.ParentId); + + if (entity.MenuType == MenuTypeEnum.Directory) + { + if (parentEntity != null && parentEntity.MenuType != MenuTypeEnum.Directory) + throw Oops.Oh("错误!目录的父级必须是目录!"); + } + else if (entity.MenuType == MenuTypeEnum.Menu) + { + if (parentEntity == null) + throw Oops.Oh("错误!菜单必须有所属目录!"); + else if (parentEntity.MenuType != MenuTypeEnum.Directory) + throw Oops.Oh("错误!菜单的父级必须是目录!"); + } + else + { + if (parentEntity == null) + throw Oops.Oh("错误!按钮必须有所属菜单!"); + else if (parentEntity.MenuType != MenuTypeEnum.Menu) + throw Oops.Oh("错误!按钮的父级必须是菜单!"); + } + + await base.Update(entity); + } + + /// + /// 删除菜单 会联动删除菜单角色授权信息 + /// 也会删除子集菜单 + /// + /// + /// + [UnitOfWork] + public override async Task Delete(BaseIdListParam param) + { + if (param.Ids.Any()) + { + foreach (var item in param.Ids) + { + var childs = await _menuRepository.AsQueryable().ToChildListAsync(it => it.ParentId, item); + var childIds = childs.Select(it => it.Id).ToList(); + + await _menuRepository.DeleteAsync(it => childIds.Contains(it.Id)); + await _menuAuthorizeRepository.DeleteAsync(it => childIds.Contains(it.MenuId)); + } + } + } + #endregion + + } +} diff --git a/API/Wood.Service/SystemManage/MessageService.cs b/API/Wood.Service/SystemManage/MessageService.cs new file mode 100644 index 0000000..51e1ac4 --- /dev/null +++ b/API/Wood.Service/SystemManage/MessageService.cs @@ -0,0 +1,198 @@ +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.Security.Policy; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Manager; +using Wood.Service.SystemManage.Param; +using Wood.Util; +using Wood.Util.JwtAuthorization; + +namespace Wood.Service.SystemManage +{ + public class MessageService : ApiCRUDService + { + private UserManager _userManager { get; } + private SqlSugarRepository _userMessageRepository { get; } + private OrgManager _orgManager { get; } + + public MessageService(SqlSugarRepository repository, UserManager userManager, SqlSugarRepository userMessageRepository, OrgManager orgManager) : base(repository) + { + _userManager = userManager; + _userMessageRepository = userMessageRepository; + _orgManager = orgManager; + } + + /// + /// 发布通知公告 + /// + /// + /// + public async Task Publish(MessagePublishParam param) + { + var user = this.UserInfo(); + if (!user!.IsAdmin) + throw Oops.Oh("非管理员,无法发布!"); + + var message = await _repository.GetByIdAsync(param.Id); + if (message == null) + throw Oops.Oh("没有找到可发布的通知公告!"); + + message.Status = MessageStatusEnum.Published; + message.PublishAt = DateTime.Now; + message.PublisherId = user.UserId; + message.PublisherName = user.RealName; + message.PublisherOrgId = user.OrgId; + message.PublisherOrgName = (await _orgManager.AsRepository().GetByIdAsync(user.OrgId))?.OrgName; + message.MessageType = param.MessageType; + + // 更新发布状态和时间 + await _repository.UpdateAsync(message); + + if (param.UserIds.Any()) + { + var ums = param.UserIds.Select(it => new UserMessageEntity + { + IsRead = false, + MessageId = param.Id, + UserId = it, + }); + + await _userMessageRepository.InsertRangeAsync(ums.ToArray()); + } + else + { + var ids = await _userManager.GetOwnUserIdList(); + var ums = ids.Select(it => new UserMessageEntity + { + IsRead = false, + MessageId = param.Id, + UserId = it, + }); + await _userMessageRepository.InsertRangeAsync(ums.ToArray()); + } + + } + + /// + /// 设置通知公告已读状态 + /// + /// + /// + [HttpGet] + public async Task SetRead(BaseIdParam param) + { + await _userMessageRepository.UpdateAsync(u => new UserMessageEntity + { + IsRead = true, + ReadTime = DateTime.Now + }, u => u.Id == param.Id); + } + + /// + /// 设置通知公告已读状态 + /// + /// + [HttpGet] + public async ValueTask MessageCount() + { + var user = this.UserInfo(); + return await _userMessageRepository.CountAsync(it => !it.IsRead && it.UserId == user!.UserId); + } + + /// + /// 设置所有通知公告已读状态 + /// + /// + [HttpGet] + public async Task SetAllRead() + { + var user = this.UserInfo(); + await _userMessageRepository.UpdateAsync(u => new UserMessageEntity + { + IsRead = true, + ReadTime = DateTime.Now + }, u => u.UserId == user!.UserId); + } + + /// + /// 获取接收的通知公告 + /// + /// + /// + public async Task> PagedReceived(MessagePageReceivedParam param) + { + var user = this.UserInfo(); + return await _userMessageRepository.AsQueryable().Includes(u => u.Message) + .Where(u => u.UserId == user!.UserId) + .WhereIF(!string.IsNullOrWhiteSpace(param.Title), u => u.Message!.Title!.Contains(param.Title! + .Trim())) + .WhereIF(param.Type.HasValue, u => u.Message!.MessageType == param.Type) + .OrderBy(u => u.CreateTime, OrderByType.Desc) + .Select(u => new MessagePageReceivedDto + { + Id = u.Id.SelectAll(), + PublisherName = u.Message!.PublisherName, + PublisherOrgName = u.Message!.PublisherOrgName, + PublishAt=u.Message.PublishAt, + Title = u.Message!.Title, + MessageType = u.Message!.MessageType, + }) + .ToPagedListAsync(param.PageIndex, param.PageSize); + } + + /// + /// 获取发布的通知公告 + /// + /// + /// + public async Task> PagedPublish(MessagePagePublishParam param) + { + var user = this.UserInfo(); + return await _repository.AsQueryable() + .Where(u => u.CreateUserId == user!.UserId) + .WhereIF(!string.IsNullOrWhiteSpace(param.Title), u => u!.Title!.Contains(param.Title! + .Trim())) + .WhereIF(param.Type.HasValue, u => u!.MessageType == param.Type) + .OrderBy(u => u.CreateTime, OrderByType.Desc) + .Select(it => new MessagePagedPublishDto + { + Id = it.Id.SelectAll() + }) + .ToPagedListAsync(param.PageIndex, param.PageSize); + } + + /// + /// 删除 + /// + /// + /// + public override async Task Delete(BaseIdListParam param) + { + if (param.Ids.Any()) + { + await _repository.FakeDeleteAsync(it => param.Ids.Contains(it.Id)); + await _userMessageRepository.DeleteAsync(it => param.Ids.Contains(it.MessageId)); + } + } + + /// + /// 撤回 + /// + /// + /// + public async Task Recalled(BaseIdListParam param) + { + if (param.Ids.Any()) + { + await _repository.AsUpdateable() + .SetColumns(it => new MessageEntity { Status = MessageStatusEnum.Cancel, RecalledAt = DateTime.Now }) + .Where(it => param.Ids.Contains(it.Id)).ExecuteCommandAsync(); + await _userMessageRepository.DeleteAsync(it => param.Ids.Contains(it.MessageId)); + } + } + } +} diff --git a/API/Wood.Service/SystemManage/OrgService.cs b/API/Wood.Service/SystemManage/OrgService.cs new file mode 100644 index 0000000..f834972 --- /dev/null +++ b/API/Wood.Service/SystemManage/OrgService.cs @@ -0,0 +1,108 @@ +using SqlSugar; +using Wood.Cache; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Manager; +using Wood.Service.SystemManage.Param; +using Wood.Util; +using Wood.Util.JwtAuthorization; + +namespace Wood.Service.SystemManage +{ + /// + /// 机构管理 + /// + public class OrgService : ApiCRUDService + { + private readonly OrgManager _orgManager; + private readonly SqlSugarRepository _tenantRepository; + + public OrgService(OrgManager orgManager, SqlSugarRepository tenantRepository):base(orgManager.AsRepository()) + { + _orgManager = orgManager; + _tenantRepository = tenantRepository; + } + public async Task> TreeList(OrgTreeListParam param) + { + var user = this.UserInfo(); + long rootId = user!.OrgId; + //超级管理员可以看到所有机构 + if (user.IsSuperAdmin) + rootId = 0; + //租户管理员可以看到当下租户的所有机构 + else if (user.IsTenantAdmin) + { + var tenant = await _tenantRepository.GetByIdAsync(user.TenantId); + rootId = tenant.OrgId; + } + var query = _orgManager.AsQueryable() + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.OrgName.Contains(param.Name!) || it.FormCode.Contains(param.Name!)) + .Select(it => new OrgTreeDto() + { + Id = it.Id.SelectAll() + }); + + if (param.HasCondition()) + return await query.ToListAsync(); + else + return await query.ToTreeAsync(it => it.Children, it => it.ParentId, 0); + } + + /// + /// 获取所有机构 + /// 用于El树形结构 + /// + /// 用于El树形结构 + public async Task> ElTreeList(OrgTreeListParam param) + { + var user = this.UserInfo(); + long rootId = user!.OrgId; + //超级管理员可以看到所有机构 + if (user.IsSuperAdmin) + rootId = 0; + //租户管理员可以看到当下租户的所有机构 + else if (user.IsTenantAdmin) + { + var tenant = await _tenantRepository.GetByIdAsync(user.TenantId); + rootId = tenant.OrgId; + } + var query = _orgManager.AsQueryable() + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.OrgName.Contains(param.Name!) || it.FormCode.Contains(param.Name!)) + .Select(it => new ElTreeDto() + { + Id = it.Id, + Label = it.OrgName, + ParentId = it.ParentId, + Disabled = (it.Status == 0) + }); + + if (param.HasCondition()) + return await query.ToListAsync(); + else + return await query.ToTreeAsync(it => it.Children, it => it.ParentId, 0); + } + + public async Task GetMaxSort() + { + var result = await this._orgManager.AsQueryable().MaxAsync(it => it.Sort); + return result + 10; + } + + [UnitOfWork] + public override async Task Delete(BaseIdListParam param) + { + if (param.Ids.Any()) + { + foreach (var item in param.Ids) + { + var childs = await _orgManager.AsQueryable().ToChildListAsync(it => it.ParentId, item); + var childIds = childs.Select(it => it.Id).ToList(); + await _orgManager.AsRepository().FakeDeleteAsync(it => childIds.Contains(it.Id)); + } + } + } + } +} diff --git a/API/Wood.Service/SystemManage/Param/AutoJobParam.cs b/API/Wood.Service/SystemManage/Param/AutoJobParam.cs new file mode 100644 index 0000000..b1edd64 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/AutoJobParam.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; + +namespace Wood.Service.SystemManage.Param +{ + public class AutoJobPagedParam : Pagination + { + /// + /// 描述 + /// + public string? Description { get; set; } + + } + + public class AutoJobDeferredParam : BaseIdParam + { + public DateTime? EndTime { get; set; } + } +} diff --git a/API/Wood.Service/SystemManage/Param/DataDictDetailParam.cs b/API/Wood.Service/SystemManage/Param/DataDictDetailParam.cs new file mode 100644 index 0000000..0192ba0 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/DataDictDetailParam.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Param +{ + public class DataDictDetailAddParam : DataDictDetailEntity + { + } + public class DataDictDetailUpdateParam : DataDictDetailAddParam + { + } + + public class DataDictDetailPagedParam : Pagination + { + /// + /// 字典类型id + /// + public long DictId { get; set; } + /// + /// 字典名称 + /// + public string Name { get; set; } = ""; + } +} diff --git a/API/Wood.Service/SystemManage/Param/DataDictParam.cs b/API/Wood.Service/SystemManage/Param/DataDictParam.cs new file mode 100644 index 0000000..4012501 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/DataDictParam.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Param +{ + public class DataDictPagedParam : Pagination + { + public string? Name { get; internal set; } + } + + public class DataDictAddParam : DataDictEntity + { + } + + public class DataDictUpdateParam : DataDictAddParam { } +} diff --git a/API/Wood.Service/SystemManage/Param/LogParam.cs b/API/Wood.Service/SystemManage/Param/LogParam.cs new file mode 100644 index 0000000..6d16ec0 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/LogParam.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; + +namespace Wood.Service.SystemManage.Param +{ + public class LogLoginParam:Pagination + { + public string? UserName { get; set; } + [Required(ErrorMessage ="必须填写开始时间!")] + public DateTime StartTime { get; set; } + [Required(ErrorMessage = "必须填写结束时间!")] + public DateTime EndTime { get; set; } + } + public class LogJobParam : Pagination + { + public string? JobId { get; set; } + [Required(ErrorMessage = "必须填写开始时间!")] + public DateTime StartTime { get; set; } + [Required(ErrorMessage = "必须填写结束时间!")] + public DateTime EndTime { get; set; } + } + public class LogEventParam : Pagination + { + public string? EventName { get; set; } + [Required(ErrorMessage = "必须填写开始时间!")] + public DateTime StartTime { get; set; } + [Required(ErrorMessage = "必须填写结束时间!")] + public DateTime EndTime { get; set; } + } + public class LogExceptionParam : Pagination + { + public string? RequestUrl { get; set; } + public string? Source { get; set; } + public string? ControllerName { get; set; } + public string? ActionName { get; set; } + [Required(ErrorMessage = "必须填写开始时间!")] + public DateTime StartTime { get; set; } + [Required(ErrorMessage = "必须填写结束时间!")] + public DateTime EndTime { get; set; } + } + public class LogOperationParam : Pagination + { + public string? RequestUrl { get; set; } + public string? ControllerName { get; set; } + public string? ActionName { get; set; } + [Required(ErrorMessage = "必须填写开始时间!")] + public DateTime StartTime { get; set; } + [Required(ErrorMessage = "必须填写结束时间!")] + public DateTime EndTime { get; set; } + } + public class LogDiffParam : Pagination + { + public string? TableName { get; set; } + [Required(ErrorMessage = "必须填写开始时间!")] + public DateTime StartTime { get; set; } + [Required(ErrorMessage = "必须填写结束时间!")] + public DateTime EndTime { get; set; } + } +} diff --git a/API/Wood.Service/SystemManage/Param/MenuParam.cs b/API/Wood.Service/SystemManage/Param/MenuParam.cs new file mode 100644 index 0000000..cf65985 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/MenuParam.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Param +{ + public class MenuTreeListParam + { + public string? Name { get; set; } + + /// + /// 树型结构类型 + /// 1: 目录 + /// 2: 目录-菜单 + /// 其他: 目录-菜单-按钮 + /// + public int? TreeType { get; set; } = 0; + + public bool HasCondition() + { + return !string.IsNullOrEmpty(Name); + } + } + + public class MenuAddParam : MenuEntity + { + + } + + public class MenuUpdateParam : MenuAddParam + { + + } +} diff --git a/API/Wood.Service/SystemManage/Param/MessageParam.cs b/API/Wood.Service/SystemManage/Param/MessageParam.cs new file mode 100644 index 0000000..1db4fb9 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/MessageParam.cs @@ -0,0 +1,43 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Param +{ + public class MessageAddParam : MessageEntity + { + } + + public class MessageUpdateParam: MessageAddParam + { + } + + public class MessagePublishParam : BaseIdParam + { + public List UserIds { get; set; } = new List(); + + /// + /// 消息类型(0-系统通知 1-公告 2-私信) + /// + public MessageTypeEnum MessageType { get; set; } + } + + public class MessagePageReceivedParam : Pagination + { + public string? Title { get; set; } + + public MessageTypeEnum? Type { get; set; } + } + + public class MessagePagePublishParam : Pagination + { + + public string? Title { get; set; } + public MessageTypeEnum? Type { get; set; } + } +} diff --git a/API/Wood.Service/SystemManage/Param/OrgParam.cs b/API/Wood.Service/SystemManage/Param/OrgParam.cs new file mode 100644 index 0000000..13dea7b --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/OrgParam.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Param +{ + public class OrgTreeListParam + { + public string? Name { get; set; } + + public bool HasCondition() + { + return !string.IsNullOrEmpty(Name); + } + } + + public class OrgAddParam : OrgEntity + { + + } + + public class OrgUpdateParam : OrgAddParam { } +} diff --git a/API/Wood.Service/SystemManage/Param/PositionParam.cs b/API/Wood.Service/SystemManage/Param/PositionParam.cs new file mode 100644 index 0000000..5df98c8 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/PositionParam.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Param +{ + public class PositionPagedParam : Pagination + { + /// + /// 职位名称 + /// + public string? Name { get; set; } + } + + public class PositionAddParam : PositionEntity + { + + } + + public class PositionUpdateParam : PositionAddParam + { + + } +} diff --git a/API/Wood.Service/SystemManage/Param/RoleParam.cs b/API/Wood.Service/SystemManage/Param/RoleParam.cs new file mode 100644 index 0000000..9b4dd4c --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/RoleParam.cs @@ -0,0 +1,42 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Param +{ + public class RolePagedParam : Pagination + { + /// + /// 名称 + /// + public string? Name { get; set; } + } + + public class RoleAddParam : RoleEntityShared + { + /// + /// 授权菜单 + /// + public List Menus { get; set; } = new List(); + } + + public class RoleUpdateParam : RoleAddParam { } + + + public class RoleUpdateDataTypeParam : BaseIdParam { + + /// + /// 数据范围类型 + /// + public DataScopeTypeEnum DataScopeType { get; set; } = DataScopeTypeEnum.All; + /// + /// 部门数据 + /// + public List Orgs { get; set; } + } +} diff --git a/API/Wood.Service/SystemManage/Param/TenantParam.cs b/API/Wood.Service/SystemManage/Param/TenantParam.cs new file mode 100644 index 0000000..5bc6682 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/TenantParam.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Entity.SystemManage; + +namespace Wood.Service.SystemManage.Param +{ + public class TenantPagedParam : Pagination { + public string Name { get; set; } = ""; + } + public class TenantAddParam:TenantEntity + { + /// + /// 租管账号 + /// + [Required(ErrorMessage = "请输入租管账号。")] + public string UserName { get; set; } = ""; + /// + /// 租管账号 + /// + [Required(ErrorMessage = "租管姓名。")] + public string RealName { get; set; } = ""; + /// + /// 机构名称 + /// + [Required(ErrorMessage = "机构名称。")] + public string OrgName { get; set; } = ""; + /// + /// 机构编码 + /// + [Required(ErrorMessage = "机构编码。")] + public string OrgFormCode { get; set; } = ""; + } + + public class TenantUpdateParam : TenantEntity + { + } +} diff --git a/API/Wood.Service/SystemManage/Param/UserParam.cs b/API/Wood.Service/SystemManage/Param/UserParam.cs new file mode 100644 index 0000000..d05c587 --- /dev/null +++ b/API/Wood.Service/SystemManage/Param/UserParam.cs @@ -0,0 +1,204 @@ +using Magicodes.ExporterAndImporter.Core; +using Magicodes.ExporterAndImporter.Excel; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.SystemManage.Dto; +using WoodWood.Util.Validations; + +namespace Wood.Service.SystemManage.Param +{ + /// + /// + /// + public class UserAddParam : UserEntityShared + { + /// + /// 部门id + /// + [Required] + public long OrgId { get; set; } = 0; + + /// + /// 职位id + /// + public long PositionId { get; set; } = 0; + /// + /// 用户权限 + /// + [Required] + public List Roles { get; set; } = new List(); + + /// + /// 头像id + /// + public long? AvatarImgId { get; set; } + + } + /// + /// + /// + public class UserUpdateParam : UserAddParam { } + /// + /// + /// + public class UserPagedParam : Pagination + { + /// + /// 用户名 + /// + public string? UserName { get; set; } + /// + /// 手机号 + /// + public string? Mobile { get; set; } + /// + /// 用户状态 + /// + public int? Status { get; set; } + /// + /// 部门 + /// + public long? OrgId { get; set; } + } + /// + /// + /// + public class UserChangePasswordParam + { + /// + /// 用户id + /// + public long? Id { get; set; } + /// + /// 旧密码 + /// + public string Password { get; set; } = ""; + /// + /// 新密码 + /// + public string NewPassword { get; set; } = ""; + /// + /// 确认新密码 + /// + public string ConfirmPassword { get; set; } = ""; + } + + /// + /// 登录参数 + /// + public class UserLoginParam + { + [Required(ErrorMessage = "必须填写用户名!")] + public string UserName { get; set; } = ""; + + [Required(ErrorMessage = "必须填写密码!")] + public string Password { get; set; } = ""; + + [Required(ErrorMessage = "必须填写验证码!")] + public string CaptchaCode { get; set; } = ""; + + [Required(ErrorMessage = "验证码已经过期!")] + public string Captcha { get; set; } = ""; + } + + /// + /// 登录参数 + /// + public class UserRefreshLoginParam + { + [Required(ErrorMessage = "RefreshToken不能为空!")] + public string RefreshToken { get; set; } = ""; + } + + /// + /// 登录参数 + /// + public class UserTenantLoginParam + { + [Required(ErrorMessage = "必须填写用户名!")] + public string UserName { get; set; } = ""; + + [Required(ErrorMessage = "必须填写密码!")] + public string Password { get; set; } = ""; + + [Required(ErrorMessage = "没有找到租户信息!")] + public long TenantId { get; set; } = 0; + [Required(ErrorMessage = "登录失败!")] + public string Captcha { get; set; } = ""; + } + + + public class UserSelectListParam + { + public string? Name { get; set; } + public List Ids { get; set; } = new List(); + } + + /// + /// IsLabelingError:是否标注数据错误 + /// + [ExcelImporter(IsLabelingError = true, HeaderRowIndex = 2)] + public class UserImportParam + { + /// + /// 用户名 + /// + [ImporterHeader(Name = "用户名")] + [Required(ErrorMessage = "用户名不能为空")] + public string UserName { get; set; } = ""; + + /// + /// 真实姓名 + /// + [ImporterHeader(Name = "姓名")] + [Required(ErrorMessage = "姓名不能为空")] + public string? RealName { get; set; } + + /// + /// 性别 1 男 0 女 + /// + [ImporterHeader(Name = "性别")] + public string? Gender { get; set; } + + /// + /// 出生日期 + /// + [ImporterHeader(Name = "出生日期")] + public string? Birthday { get; set; } + + /// + /// 邮箱 + /// + [ImporterHeader(Name = "邮箱")] + public string? Email { get; set; } + /// + /// 手机号码 + /// + [ImporterHeader(Name = "手机号码")] + public string? Mobile { get; set; } + + /// + /// 部门 + /// + [ImporterHeader(Name = "部门")] + [Required(ErrorMessage = "部门不能为空")] + public string? Org { get; set; } + + /// + /// 职位 + /// + [ImporterHeader(Name = "职位")] + public string? Position { get; set; } + + /// + /// 角色 + /// + [ImporterHeader(Name = "角色")] + [Required(ErrorMessage = "角色不能为空")] + public string? Roles { get; set; } + } +} diff --git a/API/Wood.Service/SystemManage/PositionService.cs b/API/Wood.Service/SystemManage/PositionService.cs new file mode 100644 index 0000000..f1b284e --- /dev/null +++ b/API/Wood.Service/SystemManage/PositionService.cs @@ -0,0 +1,58 @@ +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Param; +using Wood.Util; + +namespace Wood.Service.SystemManage +{ + /// + /// 职位管理 + /// + public class PositionService : ApiCRUDService + { + public PositionService(SqlSugarRepository repository) : base(repository) + { + } + + /// + /// 分页查询职位 + /// + /// + /// + public async Task> Paged(PositionPagedParam param) + { + return await _repository.AsQueryable() + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.PositionName.Contains(param.Name!) || it.FormCode.Contains(param.Name!)) + .ToPagedListAsync(param); + } + + /// + /// 获取职位信息列表用于选择 + /// + /// + public async Task> SelectList() + { + return await _repository.AsQueryable() + .Where(it => it.Status == 1) + .Select(it => new ElSelectDto() + { + Label = it.PositionName, + Disabled = false, + Value = it.Id.ToString() + }).ToListAsync(); + } + + /// + /// 获取一个最大的sort数字 + /// + /// + public async Task GetMaxSort() + { + var result = await _repository.AsQueryable().MaxAsync(it => it.Sort); + return result + 10; + } + + } +} diff --git a/API/Wood.Service/SystemManage/RoleService.cs b/API/Wood.Service/SystemManage/RoleService.cs new file mode 100644 index 0000000..f5c8643 --- /dev/null +++ b/API/Wood.Service/SystemManage/RoleService.cs @@ -0,0 +1,141 @@ +using Mapster; +using SqlSugar; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Param; +using Wood.Util; + +namespace Wood.Service.SystemManage +{ + /// + /// 角色管理 + /// + public class RoleService : ApiService + { + private readonly SqlSugarRepository _roleRepository; + private readonly SqlSugarRepository _menuAuthorizeRepository; + private readonly SqlSugarRepository _roleDataScopeRepository; + private readonly SqlSugarRepository _userBelongRoleRepository; + public RoleService(SqlSugarRepository roleRepository, SqlSugarRepository menuAuthorizeRepository, SqlSugarRepository roleDataScopeRepository, SqlSugarRepository userBelongRoleRepository) + { + _roleRepository = roleRepository; + _menuAuthorizeRepository = menuAuthorizeRepository; + _roleDataScopeRepository = roleDataScopeRepository; + _userBelongRoleRepository = userBelongRoleRepository; + } + + public async Task> Paged(RolePagedParam param) + { + return await _roleRepository.AsQueryable() + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.RoleName.Contains(param.Name!) || it.FormCode.Contains(param.Name!)) + .Select(it => new RolePagedDto() + { + Id = it.Id.SelectAll() + }) + .ToPagedListAsync(param); + } + + /// + /// 获取角色信息列表用于选择 + /// + /// + public async Task> SelectList() + { + return await _roleRepository.AsQueryable() + .Where(it => it.Status == 1) + .Select(it => new ElSelectDto() + { + Label = it.RoleName, + Disabled = false, + Value = it.Id.ToString() + }).ToListAsync(); + } + + public async Task GetDetail(BaseIdParam param) + { + var entity = await _roleRepository.GetByIdAsync(param.Id); + var dto = entity.Adapt(); + + dto.Menus = await _menuAuthorizeRepository.AsQueryable() + .LeftJoin((it,me)=>it.MenuId==me.Id) + .Where((it,me) => it.RoleId == param.Id&&me.MenuType!=MenuTypeEnum.Button).Select(it => it.MenuId).ToListAsync(); + + dto.Btns = await _menuAuthorizeRepository.AsQueryable() + .LeftJoin((it, me) => it.MenuId == me.Id) + .Where((it, me) => it.RoleId == param.Id && me.MenuType == MenuTypeEnum.Button).Select(it => it.MenuId).ToListAsync(); + + dto.Orgs = await _roleDataScopeRepository.AsQueryable().Where(it => it.RoleId == param.Id).Select(it => it.OrgId).ToListAsync(); + return dto; + } + + public async Task GetMaxSort() + { + var result = await _roleRepository.AsQueryable().MaxAsync(it => it.Sort); + return result + 10; + } + + [UnitOfWork] + public async Task Add(RoleAddParam entity) + { + await _roleRepository.InsertAsync(entity.Adapt()); + + await _menuAuthorizeRepository.InsertRangeAsync( + entity.Menus.Select(it => new MenuAuthorizeEntity() { RoleId = entity.Id, MenuId = it }).ToList() + ); + } + + [UnitOfWork] + public async Task Update(RoleUpdateParam entity) + { + await _roleRepository.UpdateAsync(entity.Adapt()); + await _menuAuthorizeRepository.DeleteAsync(it => it.RoleId == entity.Id); + await _menuAuthorizeRepository.InsertRangeAsync( + entity.Menus.Select(it => new MenuAuthorizeEntity() { RoleId = entity.Id, MenuId = it }).ToList() + ); + } + /// + /// 更新数据权限 + /// + /// + /// + [UnitOfWork] + public async Task UpdateRoleDataType(RoleUpdateDataTypeParam param) + { + var role = await _roleRepository.GetByIdAsync(param.Id); + role.DataScopeType = param.DataScopeType; + await _roleRepository.UpdateAsync(role); + await _roleDataScopeRepository.DeleteAsync(it => it.RoleId == param.Id); + if (role.DataScopeType == DataScopeTypeEnum.Custom) + { + var scopeList = param.Orgs.Select(it => new RoleDataScopeEntity() { OrgId = it, RoleId = param.Id }).ToList(); + + await _roleDataScopeRepository.InsertRangeAsync(scopeList); + } + } + + /// + /// 删除角色 + /// + /// + /// + [UnitOfWork] + public async Task Delete(BaseIdListParam param) + { + //删除角色信息 + await _roleRepository.DeleteAsync(it => param.Ids.Contains(it.Id)); + //删除角色授权菜单信息 + await _menuAuthorizeRepository.DeleteAsync(it => param.Ids.Contains(it.RoleId)); + //删除角色数据范围信息 + await _roleDataScopeRepository.DeleteAsync(it => param.Ids.Contains(it.RoleId)); + //删除用户角色信息 + await _userBelongRoleRepository.DeleteAsync(it => param.Ids.Contains(it.RoleId)); + } + + #region 私有方法 + + #endregion + } +} diff --git a/API/Wood.Service/SystemManage/SystemService.cs b/API/Wood.Service/SystemManage/SystemService.cs new file mode 100644 index 0000000..3e0b29d --- /dev/null +++ b/API/Wood.Service/SystemManage/SystemService.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Wood.Entity; +using Wood.Service.BaseService; +using Wood.Util; + +namespace Wood.Service.SystemManage +{ + /// + /// 系统其他接口 + /// + public partial class SystemService : ApiService + { + /// + /// 获取指定枚举的 key ,value 列表 + /// 需要在 Wood.Entity 中定义枚举 + /// + /// 枚举名称 + /// + public dynamic GetEnumOptions(string name) + { + var type= Assembly.Load("Wood.Entity").GetTypes() + .Where(it => it.IsEnum && string.Equals(it.Name, name, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault(); + if (type != null) + return type.EnumToDictionary().Select(it => new { it.Key,it.Value}).ToList(); + return "[]"; + } + } +} diff --git a/API/Wood.Service/SystemManage/TenantService.cs b/API/Wood.Service/SystemManage/TenantService.cs new file mode 100644 index 0000000..0ea0a1c --- /dev/null +++ b/API/Wood.Service/SystemManage/TenantService.cs @@ -0,0 +1,205 @@ +using Mapster; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.BaseService; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Manager; +using Wood.Service.SystemManage.Param; +using Wood.Util; + +namespace Wood.Service.SystemManage +{ + /// + /// 租户管理 + /// + public class TenantService : ApiService + { + private readonly SqlSugarRepository _tenantRepository; + private readonly OrgManager _orgManager; + private readonly UserManager _userManager; + private readonly SqlSugarRepository _roleRepository; + private readonly SqlSugarRepository _menuAuthorizeRepository; + private readonly SqlSugarRepository _menuRepository; + private readonly SqlSugarRepository _userBelongRoleRepository; + + public TenantService(SqlSugarRepository tenantRepository, OrgManager orgManager, UserManager userManager, SqlSugarRepository roleRepository, SqlSugarRepository menuAuthorizeRepository, SqlSugarRepository menuRepository, SqlSugarRepository userBelongRoleRepository) + { + _tenantRepository = tenantRepository; + _orgManager = orgManager; + _userManager = userManager; + _roleRepository = roleRepository; + _menuAuthorizeRepository = menuAuthorizeRepository; + _menuRepository = menuRepository; + _userBelongRoleRepository = userBelongRoleRepository; + } + + /// + /// 分页查询职位 + /// + /// + /// + public async Task> Paged(TenantPagedParam param) + { + var dtos = await _tenantRepository.AsQueryable() + .LeftJoin((it, oe) => it.OrgId == oe.Id) + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.TenantName.Contains(param.Name!)) + .Select((it, oe) => new TenantPagedDto() + { + Id = it.Id.SelectAll(), + OrgName = oe.OrgName + }) + .ToPagedListAsync(param); + + return dtos; + } + + /// + /// 新建租户 + /// 初始化信息 + /// + /// + /// + [UnitOfWork] + public async Task Add(TenantAddParam param) + { + if (await _tenantRepository.IsAnyAsync(it => it.TenantName == param.TenantName)) + throw Oops.Oh("租户名称不能重复!"); + var orgId = IdGeneratorHelper.Instance.GetId(); + //建立租户 + TenantEntity tenantEntity = new TenantEntity() + { + TenantName = param.TenantName, + OrgId = orgId, + Sort = (await _tenantRepository.AsQueryable().MaxAsync(x => x.Sort)) + 10, + }; + await _tenantRepository.InsertAsync(tenantEntity); + //建立机构部门 + OrgEntity entity = new OrgEntity() + { + Id = orgId, + OrgName = param.OrgName, + ShortName = param.OrgName, + FormCode = param.OrgFormCode, + Sort = (await _orgManager.AsQueryable().MaxAsync(x => x.Sort)) + 10, + TenantId = tenantEntity.Id + }; + await _orgManager.AsRepository().InsertAsync(entity); + //建立租户管理员角色 + RoleEntity roleEntity = new RoleEntity() + { + FormCode = "zg_admin_" + param.OrgFormCode, + DataScopeType = DataScopeTypeEnum.All, + Sort = (await _roleRepository.AsQueryable().MaxAsync(x => x.Sort)) + 10, + RoleName = "租管-" + param.OrgName, + TenantId = tenantEntity.Id, + }; + await _roleRepository.InsertAsync(roleEntity); + + //给角色赋值 基础 权限 + string[] defaultMenus = ["工作台", "主页", "系统管理", "机构管理", "角色管理", "用户管理", "职位管理", "个人中心"]; + var menus = await _menuRepository.GetListAsync(it => defaultMenus.Contains(it.MenuName)); + + foreach (var item in menus) + { + var menuAndBtns = await _menuRepository.AsQueryable().ToChildListAsync(it => it.ParentId, item.Id); + var menuAuthorizeEntities = menuAndBtns.Select(it => new MenuAuthorizeEntity() + { + RoleId = roleEntity.Id, + MenuId = it.Id, + TenantId = tenantEntity.Id, + }); + await _menuAuthorizeRepository.InsertRangeAsync(menuAuthorizeEntities.ToArray()); + } + + //建立租户管理员账号 + UserEntity userEntity = new UserEntity() + { + AccountType = AccountTypeEnum.TenantAdmin, + NickName = param.RealName, + UserName = param.UserName, + Salt = CryptogramHelper.GenerateRandomString(16), + Password = CryptogramHelper.GMSM4Encrypt("123456"), + RealName = param.RealName, + Birthday = DateTime.Now, + OrgId = orgId, + TenantId = tenantEntity.Id + }; + await _userManager.AsRepository().InsertAsync(userEntity); + + //关联账号和角色信息 + UserBelongRoleEntity belongRoleEntity = new UserBelongRoleEntity() + { + RoleId = roleEntity.Id, + UserId = userEntity.Id, + }; + await _userBelongRoleRepository.InsertAsync(belongRoleEntity); + } + + /// + /// 获取明细 + /// + /// + /// + public async Task GetDetail(BaseIdParam param) + { + return await _tenantRepository.AsQueryable() + .LeftJoin((it, oe) => it.OrgId == oe.Id) + .Where(it => it.Id == param.Id) + .Select((it, oe) => new TenantDetailDto() + { + Id = it.Id.SelectAll(), + OrgName = oe.OrgName + }).FirstAsync(); + } + + /// + /// 假删除 + /// + /// + [UnitOfWork] + public async Task Delete(BaseIdParam param) + { + if (param.Id > 0) + await _tenantRepository.FakeDeleteAsync(it => param.Id == it.Id); + } + /// + /// 启用租户 + /// + /// + /// + [HttpGet] + public async Task Open(BaseIdParam param) + { + var tenant = await _tenantRepository.GetByIdAsync(param.Id); + tenant.Status = 1; + await _tenantRepository.UpdateAsync(tenant); + } + /// + /// 禁用租户 + /// + /// + /// + [HttpGet] + public async Task Close(BaseIdParam param) + { + var tenant = await _tenantRepository.GetByIdAsync(param.Id); + tenant.Status = 0; + await _tenantRepository.UpdateAsync(tenant); + } + + public async Task GetMaxSort() + { + var result = await this._tenantRepository.AsQueryable().MaxAsync(it => it.Sort); + return result + 10; + } + } +} diff --git a/API/Wood.Service/SystemManage/UserService.cs b/API/Wood.Service/SystemManage/UserService.cs new file mode 100644 index 0000000..40320bd --- /dev/null +++ b/API/Wood.Service/SystemManage/UserService.cs @@ -0,0 +1,611 @@ +using Mapster; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.Text; +using Wood.Cache; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Entity.SystemManage; +using Wood.Service.SystemManage.Dto; +using Wood.Service.SystemManage.Manager; +using Wood.Service.SystemManage.Param; +using Wood.Util; +using Wood.Util.JwtAuthorization; + +namespace Wood.Service.SystemManage +{ + /// + /// 用户管理 + /// + public class UserService : ApiService + { + private readonly UserManager _userManager; + private readonly SqlSugarRepository _tenantRepository; + private readonly SqlSugarRepository _roleRepository; + private readonly SqlSugarRepository _positionRepository; + private readonly SqlSugarRepository _menuAuthorizeRepository; + private readonly SqlSugarRepository _menuRepository; + private readonly SqlSugarRepository _refreshTokenRepository; + private readonly SqlSugarRepository _logLoginRepository; + private readonly FileManager _fileManager; + private readonly OrgManager _orgManager; + private readonly ICache _cache; + + + + + private SqlSugarRepository _userRepository => _userManager.AsRepository(); + + public UserService(UserManager userManager, SqlSugarRepository roleRepository, SqlSugarRepository tenantRepository, ICache cache, SqlSugarRepository refreshTokenRepository, SqlSugarRepository menuAuthorizeRepository, SqlSugarRepository menuRepository, FileManager fileManager, SqlSugarRepository logLoginRepository, OrgManager orgManager, SqlSugarRepository positionRepository) + { + _userManager = userManager; + _roleRepository = roleRepository; + _tenantRepository = tenantRepository; + _cache = cache; + _refreshTokenRepository = refreshTokenRepository; + _menuAuthorizeRepository = menuAuthorizeRepository; + _menuRepository = menuRepository; + _fileManager = fileManager; + _logLoginRepository = logLoginRepository; + _orgManager = orgManager; + _positionRepository = positionRepository; + } + /// + /// 分页获取用户数据 + /// + /// + /// + public async Task> Paged(UserPagedParam param) + { + return await BuildQuery(param) + .Select(it => new UserPagedDto + { + Id = it.Id.SelectAll(), + OrgName = it.Org!.OrgName, + Roles = SqlFunc.Subqueryable() + .LeftJoin((ur, ro) => ur.RoleId == ro.Id) + .Where((ur, ro) => ur.UserId == it.Id) + .SelectStringJoin((ur, ro) => ro.RoleName, ","), + }) + .ToPagedListAsync(param); + } + + /// + /// 获取用户信息列表用于选择 + /// + /// + public async Task> SelectList(UserSelectListParam param) + { + return await _userRepository.AsQueryable() + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.RealName!.Contains(param.Name!) || it.UserName.Contains(param.Name!)) + .WhereIF(param.Ids.Any(), it => param.Ids.Contains(it.Id)) + .Where(it => it.AccountType != AccountTypeEnum.SuperAdmin) + .Select(it => new ElSelectDto() + { + Label = it.RealName + "(" + it.UserName + ")", + Disabled = it.Status == 0, + Value = it.Id.ToString() + }).ToListAsync(); + } + + /// + /// 是否存在用户 + /// + /// + /// + public async Task GetExist(string userName) + { + return await _userRepository.IsAnyAsync(it => it.UserName == userName); + } + + /// + /// 获取验证码 + /// + /// + [AllowAnonymous] + public UserCaptchaDto GetCaptcha() + { + var tuple = CaptchaHelper.GetCaptchaCode(); + + var image = CaptchaHelper.CreateCaptchaImage(tuple.Item1); + UserCaptchaDto dto = new UserCaptchaDto() + { + Guid = IdGeneratorHelper.Instance.GetGuid(), + Img = Convert.ToBase64String(image) + }; + _cache.SetCache(dto.Guid, tuple.Item2, DateTime.Now.AddMinutes(2)); + + return dto; + } + + /// + /// 用户登录 + /// + /// 可用租户信息 + [AllowAnonymous] + public async Task Login(UserLoginParam param) + { + if (!(int.TryParse(param.CaptchaCode, out int val) && _cache.TryGetCache(param.Captcha, out int cacheVal) && val == cacheVal)) + { + _cache.RemoveCache(param.Captcha); + throw Oops.Oh("验证码错误!"); + } + + _cache.SetCache(param.Captcha, param.UserName, DateTime.Now.AddMinutes(5)); + + var users = await _userRepository.AsQueryable() + .Where(it => it.UserName == param.UserName) + .Where(it => it.Status == 1) + .ToListAsync(); + + if (users == null || users.Count < 1) + throw Oops.Oh($"不存在用户【{param.UserName}】!"); + List passOk = new List(); //密码验证通过的账户信息 + foreach (var item in users) + { + if (param!.Password == CryptogramHelper.GMSM4Decrypt(item.Password)) + passOk.Add(item); + } + + if (passOk.Any()) + { + var tenantIds = passOk.Select(it => it.TenantId).ToList(); + var tenants = await _tenantRepository.AsQueryable() + .Where(it => tenantIds.Contains(it.Id)) + .Select(it => new { it.Id, it.TenantName, it.Status }) + .ToListAsync(); + + if (tenants.All(it => it.Status != 1)) + throw Oops.Oh("登录失败,账号已经冻结!"); + + return tenants; + } + throw Oops.Oh("登录失败,没有相关用户信息!"); + } + + /// + /// 用户租户登录 + /// + [AllowAnonymous] + public async Task TenantLogin(UserTenantLoginParam param) + { + if (_cache.TryGetCache(param.Captcha, out string? cacheVal) && cacheVal == param.UserName) + { + LogLoginEntity logLoginEntity = new LogLoginEntity() + { + Account = param.UserName, + Browser = NetHelper.Browser, + IpAddress = NetHelper.Ip, + LogStatus = LoginStatusEnum.Failed, + Os = NetHelper.GetOSVersion() + }; + + _cache.RemoveCache(param.Captcha); + var user = await _userRepository.GetFirstAsync(it => it.UserName == param.UserName); + if (user == null) + { + logLoginEntity.LogStatus = LoginStatusEnum.NoAccount; + logLoginEntity.Message = $"不存在用户【{param.UserName}】!"; + await _logLoginRepository.InsertAsync(logLoginEntity); + throw Oops.Oh($"不存在用户【{param.UserName}】!"); + } + if (user!.Status != 1) + { + logLoginEntity.LogStatus = LoginStatusEnum.Frozen; + logLoginEntity.Message = $"登录失败,账号已经冻结!"; + await _logLoginRepository.InsertAsync(logLoginEntity); + throw Oops.Oh("登录失败,账号已经冻结!"); + } + if (param!.Password != CryptogramHelper.GMSM4Decrypt(user.Password)) + { + logLoginEntity.LogStatus = LoginStatusEnum.PasswordError; + logLoginEntity.Message = $"密码不正确!"; + await _logLoginRepository.InsertAsync(logLoginEntity); + throw Oops.Oh("密码不正确!"); + } + + var tenant = await _tenantRepository.GetByIdAsync(param.TenantId); + if (tenant.Status == 1) + { + var token = await DoLogin(user.Id); + + logLoginEntity.LogStatus = LoginStatusEnum.Success; + await _logLoginRepository.InsertAsync(logLoginEntity); + return token; + } + throw Oops.Oh("无效租户!"); + } + else + { + _cache.RemoveCache(param.Captcha); + throw Oops.Oh("登录失败!验证码无效。"); + } + } + + /// + /// 用户登录 + /// + /// 可用租户信息 + [AllowAnonymous] + public async Task RefreshLogin(UserRefreshLoginParam param) + { + var refreshToken = await _refreshTokenRepository.GetFirstAsync(it => it.RefreshToken == param.RefreshToken); + if (refreshToken == null) + throw Oops.Oh("登录过期,请重新登录!"); + //refreshToken已经撤销 + if (refreshToken.RevokedAt != null && refreshToken.RevokedAt.Value < DateTime.Now) + throw Oops.Oh("登录过期,请重新登录!"); + //refreshToken已经过期 + if (refreshToken.ExpiresAt < DateTime.Now) + throw Oops.Oh("登录过期,请重新登录!"); + + var token = await DoLogin(refreshToken.UserId); + + var userInfo = await _userRepository.GetByIdAsync(refreshToken.UserId); + LogLoginEntity logLoginEntity = new LogLoginEntity() + { + Account = userInfo!.UserName, + Browser = NetHelper.Browser, + IpAddress = NetHelper.Ip, + LogStatus = LoginStatusEnum.RefreshSuccess, + Os = NetHelper.GetOSVersion(), + Message = param.RefreshToken + }; + await _logLoginRepository.InsertAsync(logLoginEntity); + + + //重置refreshToken有效期 + token.RefreshToken = param.RefreshToken; + + refreshToken.ExpiresAt = token.RefreshTokenExpiresTime; + await _refreshTokenRepository.UpdateAsync(refreshToken); + + return token; + } + + /// + /// 修改密码 + /// + /// + /// + public async Task ResetPassword(UserChangePasswordParam param) + { + var user = await _userRepository.GetByIdAsync(param.Id); + if (user != null) + { + if (param!.Password == CryptogramHelper.GMSM4Decrypt(user.Password)) + { + if (param.NewPassword == param.ConfirmPassword) + { + if (param.Password != param.NewPassword) + { + user.Password = CryptogramHelper.GMSM4Encrypt(param.Password); + await _userRepository.UpdateAsync(user); + } + else + throw Oops.Oh("旧密码不能和新密码一样!"); + } + else + throw Oops.Oh("两次输入密码不一致!"); + } + else + throw Oops.Oh("密码错误!"); + } + else + throw Oops.Oh("用户不存在!"); + } + + /// + /// 获取当前用户的基本信息 + /// + /// + public async Task GetCurrentUserInfo() + { + var user = this.UserInfo(); + var userInfo = await _userRepository.AsQueryable() + .Includes(it => it.Roles) + .Includes(it => it.Org) + .Includes(it => it.Position) + .Where(it => it.Id == user!.UserId) + .FirstAsync(); + string roleName = userInfo!.AccountType.GetDescription(); + if (userInfo!.Roles != null && userInfo!.Roles.Any()) + roleName = string.Join(',', userInfo.Roles.Select(it => it.RoleName)); + var avatorInfo = await _fileManager.GetFilePathsByCode(userInfo.Avatar!); + return new + { + userInfo.Id, + userInfo.UserName, + userInfo.TenantId, + userInfo.OrgId, + userInfo.RealName, + userInfo.NickName, + userInfo.AccountType, + Avatar = avatorInfo.FirstOrDefault(), + roleName, + userInfo.Position?.PositionName, + userInfo.PositionId, + userInfo.Remark, + userInfo.LastVisit, + userInfo.Org?.OrgName, + }; + } + + /// + /// 获取当前用户的菜单权限信息 + /// + /// + public async Task> GetCurrentRoleAuthorizeInfo() + { + var user = this.UserInfo(); + //超级管理员 + if (user!.IsSuperAdmin) + { + return await _menuRepository.AsQueryable().Where(it => it.Status == 1).OrderBy(it => it.Sort).ToListAsync(); + } + else + { + var usercache = _cache.GetCache(user!.CacheKey); + var menuIds = await _menuAuthorizeRepository.AsQueryable() + .Where(it => usercache!.Roles.Contains(it.RoleId)) + .Select(it => it.MenuId) + .Distinct().ToListAsync(); + + return await _menuRepository.AsQueryable() + .Where(it => it.Status == 1) + .Where(it => menuIds.Contains(it.Id)) + .OrderBy(it => it.Sort) + .ToListAsync(); + } + } + + /// + /// 删除用户 + /// + /// + /// + [UnitOfWork] + public async Task Delete(BaseIdListParam param) + { + if (param.Ids.Any()) + { + //用户标记为删除 + await _userRepository.FakeDeleteAsync(it => param.Ids.Contains(it.Id)); + //清空 refrshtoken + await _refreshTokenRepository.DeleteAsync(it => param.Ids.Contains(it.UserId)); + } + } + + /// + /// 新增 + /// + /// + [UnitOfWork] + public async Task Add(UserAddParam param) + { + var entity = param.Adapt(); + + entity.AccountType = AccountTypeEnum.User; + entity.LoginCount = 0; + entity.Roles = await _roleRepository.GetListAsync(it => param.Roles.Contains(it.Id)); + entity.Salt = CryptogramHelper.GenerateRandomString(16); + entity.Password = CryptogramHelper.GMSM4Encrypt("123456"); + + entity.Avatar = await _fileManager.AddFile(param.AvatarImgId); + + await _userRepository.AsSugarClient().InsertNav(entity).Include(it => it.Roles).ExecuteCommandAsync(); + } + /// + /// 更新 + /// + /// + [UnitOfWork] + public async Task Update([FromBody] UserUpdateParam param) + { + var entity = await _userRepository.GetByIdAsync(param.Id); + param.Adapt(entity); + entity.Roles = await _roleRepository.GetListAsync(it => param.Roles.Contains(it.Id)); + + entity.Avatar = await _fileManager.UpdateFile(entity.Avatar, param.AvatarImgId); + + //更新A表和 关系表 + await _userRepository.AsSugarClient().UpdateNav(entity) + .Include(it => it.Roles, new UpdateNavOptions() + { + ManyToManyIsUpdateA = true + }).ExecuteCommandAsync(); + } + + /// + /// 获取明细 + /// + /// + /// + public async Task GetDetail(BaseIdParam param) + { + var entity = await _userRepository.AsQueryable() + .Includes(it => it.Roles) + .Where(it => it.Id == param.Id).FirstAsync(); + var dto = entity.Adapt(); + dto.Roles = entity.Roles!.Select(it => it.Id).ToList(); + return dto; + } + + /// + /// 导出 + /// + /// + public async Task Export(UserPagedParam param) + { + var dtos = await BuildQuery(param) + .Select(it => new UserExportDto + { + Id = it.Id.SelectAll(), + Roles = SqlFunc.Subqueryable() + .LeftJoin((ur, ro) => ur.RoleId == ro.Id) + .Where((ur, ro) => ur.UserId == it.Id) + .SelectStringJoin((ur, ro) => ro.RoleName, ","), + Position = it.Position!.PositionName, + Org = it.Org!.OrgName + }) + .ToListAsync(); + + return await ExportFile(dtos, "用户信息.xlsx"); + } + /// + /// 导入 + /// + /// + [UnitOfWork] + public async Task> ImportAsync(IFormCollection fileList) + { + if (fileList.Files.Count == 0) + throw Oops.Oh("没有可导入的文件!"); + + List errors = new List(); + var imports = await ImportFile(fileList.Files[0], errors); + if (errors.Count > 0) + return errors; + + var positionDict = (await _positionRepository.GetListAsync()).ToDictionary(it => it.PositionName, it => it); + + var roleDict = (await _roleRepository.GetListAsync()).ToDictionary(it => it.RoleName, it => it); + + Dictionary orgDict = new Dictionary(); + List users = new List(); + int headerIndex = 2 + 1; + StringBuilder msgBuilder = new StringBuilder(); + for (int i = 0; i < imports.Data.Count; i++) + { + msgBuilder.Clear(); + var item = imports.Data.ElementAt(i); + UserEntity userEntity = new UserEntity + { + UserName = item.UserName, + RealName = item.RealName, + NickName = item.RealName, + Mobile = item.Mobile, + AccountType = AccountTypeEnum.User, + Email = item.Email, + Gender = item.Gender == "男" ? 1 : 0, + }; + + if (!string.IsNullOrEmpty(item.Position)) + { + if (positionDict.ContainsKey(item.Position!)) + userEntity.Position = positionDict[item.Position]; + else + msgBuilder.Append($";找不到职位:【{item.Position}】!"); + } + if (!string.IsNullOrEmpty(item.Birthday)) + { + if (DateTime.TryParse(item.Birthday, out DateTime r)) + userEntity.Birthday = r; + else if (double.TryParse(item.Birthday, out double d)) + userEntity.Birthday = DateTime.FromOADate(d); + else + msgBuilder.Append(";出生日期格式错误!"); + } + + string[] roles = item.Roles!.Split(','); + userEntity.Roles = new List(); + foreach (var r in roles) + { + if (roleDict.ContainsKey(r)) + userEntity.Roles.Add(roleDict[r]); + else + msgBuilder.Append($";没有找到角色【{r}】!"); + } + + if (orgDict.ContainsKey(item.Org!)) + userEntity.Org = orgDict[item.Org!]; + else + { + var org = await _orgManager.GetOrgsByPath(item.Org!); + if (org.Count == 1) + { + userEntity.Org = org.First(); + orgDict.Add(item.Org!, org.First()); + } + else if (org.Count == 0) + msgBuilder.Append($";没有找到机构【{item.Org}】!"); + else + msgBuilder.Append($";找到多个机构【{item.Org}】!"); + } + + if (msgBuilder.Length > 0) + errors.Add(new ImportErrorDto { Index = headerIndex + i, Errors = msgBuilder.ToString().Substring(1) }); + else + users.Add(userEntity); + } + //没有错误信息再进行入库 + if (!errors.Any()) + await _userRepository.AsSugarClient().InsertNav(users).Include(it => it.Org).Include(it => it.Position).Include(it => it.Roles).ExecuteCommandAsync(); + + return errors; + } + + #region 私有方法 + + private ISugarQueryable BuildQuery(UserPagedParam param) + { + return _userRepository.AsQueryable() + .WhereIF(!string.IsNullOrEmpty(param.Mobile), it => it.Mobile!.Contains(param.Mobile!)) + .WhereIF(!string.IsNullOrEmpty(param.UserName), it => it.UserName.Contains(param.UserName!)) + .WhereIF(param.Status > 0, it => it.Status == param.Status) + .WhereIF(param.OrgId > 0, it => it.OrgId == param.OrgId) + .Where(it => it.AccountType != AccountTypeEnum.SuperAdmin); + } + + /// + /// 生成Token信息 + /// + /// 用户id + /// JwtToken + private async Task DoLogin(long userId) + { + UserEntity? userInfo = await _userRepository.AsQueryable() + .Includes(it => it.Roles) + .Includes(it => it.Org) + .Includes(it => it.Position) + .Where(it => it.Id == userId) + .FirstAsync(); + + userInfo.LoginCount += 1; + if (userInfo.FirstVisit == null) + userInfo.FirstVisit = DateTime.Now; + userInfo.PreviousVisit = userInfo.LastVisit; + userInfo.LastVisit = DateTime.Now; + + await _userRepository.UpdateAsync(userInfo); + //生成 jwtToken + JwtHelper jwtHelper = new JwtHelper(); + JwtToken? token = jwtHelper.CreateToken(new JwtUserInfo() + { + UserName = userInfo!.UserName, + AccountType = (int)userInfo.AccountType, + NickName = userInfo.NickName, + RealName = userInfo.RealName, + TenantId = userInfo.TenantId, + OrgId = userInfo.OrgId, + UserId = userInfo.Id, + }); + //增加对应用户的refreshtoken + await _refreshTokenRepository.InsertAsync(new RefreshTokenEntity() + { + ExpiresAt = token.RefreshTokenExpiresTime, + IssuedAt = token.IssuedAt, + RevokedAt = null, + RefreshToken = token.RefreshToken!, + UserId = userInfo.Id + }); + //缓存用户信息 + await _userManager.InitCache(userInfo, token.TokenExpiresTime); + + return token; + } + #endregion + } +} diff --git a/API/Wood.Service/Wood.Service.csproj b/API/Wood.Service/Wood.Service.csproj new file mode 100644 index 0000000..c192923 --- /dev/null +++ b/API/Wood.Service/Wood.Service.csproj @@ -0,0 +1,44 @@ + + + + net8.0 + enable + enable + True + + + + 1701;1702;1591 + + + + 1701;1702;1591 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/API/Wood.Test.Service/TestService.cs b/API/Wood.Test.Service/TestService.cs new file mode 100644 index 0000000..893b369 --- /dev/null +++ b/API/Wood.Test.Service/TestService.cs @@ -0,0 +1,105 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Wood.Data.Repository; +using Wood.Entity; +using Wood.Service; +using Wood.Service.BaseService; + +namespace Wood.Test.Service +{ + /// + /// 方法命名规范 + /// + public class TestService : ApiService + { + + /// + /// 分页获取用户数据 + /// + /// + /// + public TDataPaged Paged(Pagination param) + { + return new TDataPaged(); + } + + /// + /// 是否存在 + /// + /// + public bool GetExist() + { + return false; + } + + /// + /// 获取树形结构 + /// + /// 树形结构 + public List TreeList() + { + return new List(); + } + /// + /// 获取明细 + /// + /// + public string GetDetail(BaseIdParam param) + { + return "detail"; + } + /// + /// 获取一个最大的排序号码 + /// + /// + public int GetMaxSort() + { + return 10; + } + + /// + /// 新增 + /// + /// + [UnitOfWork] + public void Add() + { + } + /// + /// 更新 + /// + /// + [UnitOfWork] + public void Update() + { + } + + /// + /// 删除 + /// + /// + [UnitOfWork] + public void Delete(BaseIdListParam param) + { + } + + /// + /// 导出 + /// + /// + [UnitOfWork] + public IActionResult Export(IFormCollection fileList) + { + return new NoContentResult(); + } + /// + /// 导入 + /// + /// + [UnitOfWork] + public void Import(IFormCollection fileList) + { + } + } +} diff --git a/API/Wood.Test.Service/Wood.Test.Service.csproj b/API/Wood.Test.Service/Wood.Test.Service.csproj new file mode 100644 index 0000000..63da75c --- /dev/null +++ b/API/Wood.Test.Service/Wood.Test.Service.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + True + + + + + + + + + + + diff --git a/API/Wood.Util/Browser/Browser.cs b/API/Wood.Util/Browser/Browser.cs new file mode 100644 index 0000000..70c7d1b --- /dev/null +++ b/API/Wood.Util/Browser/Browser.cs @@ -0,0 +1,72 @@ +// Copyright (c) 2019 Sarin Na Wangkanai, All Rights Reserved. +// The Apache v2. See License.txt in the project root for license information. + +using System; + +namespace Wood.Util.Browser +{ + public class BaseBrowser + { + public string? Name { get; set; } + public string? Maker { get; set; } + public BrowserType Type { get; set; } = BrowserType.Generic; + public Version? Version { get; set; } + + public BaseBrowser() { } + public BaseBrowser(BrowserType browserType) => Type = browserType; + public BaseBrowser(BrowserType browserType, Version version) : this(browserType) => Version = version; + + public BaseBrowser(string name) + { + //BrowserType type = null; + + ////if (!System.Enum.TryParse(name, true, out type)) + //// throw new BrowserNotFoundException(name, "not found"); + + //Type = type; + } + public Version ToVersion(string version) + { + version = RemoveWhitespace(version); + return Version.TryParse(version, out var parsedVersion) ? parsedVersion : new Version(0, 0); + } + public string RemoveWhitespace(string version) => version.Contains(" ") ? version.Replace(" ", "") : version; + } + + public enum BrowserType + { + IE, + Chrome, + Safari, + Firefox, + Edge, + Opera, + Generic + } + + public class BrowserHelper + { + public static string GetBrwoserInfo(string userAgent) + { + var ie = new InternetExplorer(userAgent); + if (ie.Type == BrowserType.IE) + return string.Format("{0} {1}", ie.Type.ToString(), ie.Version); + var firefox = new Firefox(userAgent); + if (firefox.Type == BrowserType.Firefox) + return string.Format("{0} {1}", firefox.Type.ToString(), firefox.Version); + var edge = new Edge(userAgent); + if (edge.Type == BrowserType.Edge) + return string.Format("{0} {1}", edge.Type.ToString(), edge.Version); + var opera = new Opera(userAgent); + if (opera.Type == BrowserType.Opera) + return string.Format("{0} {1}", opera.Type.ToString(), opera.Version); + var chrome = new Chrome(userAgent); + if (chrome.Type == BrowserType.Chrome) + return string.Format("{0} {1}", chrome.Type.ToString(), chrome.Version); + var safari = new Safari(userAgent); + if (safari.Type == BrowserType.Safari) + return string.Format("{0} {1}", safari.Type.ToString(), safari.Version); + return string.Empty; + } + } +} \ No newline at end of file diff --git a/API/Wood.Util/Browser/Chrome.cs b/API/Wood.Util/Browser/Chrome.cs new file mode 100644 index 0000000..f88c993 --- /dev/null +++ b/API/Wood.Util/Browser/Chrome.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2019 Sarin Na Wangkanai, All Rights Reserved. +// The Apache v2. See License.txt in the project root for license information. + +namespace Wood.Util.Browser +{ + public class Chrome : BaseBrowser + { + private readonly string _agent; + + public Chrome(string agent) + { + _agent = agent.ToLower(); + var chrome = BrowserType.Chrome.ToString().ToLower(); + + if (_agent.Contains(chrome)) + { + var first = _agent.IndexOf(chrome); + var cut = _agent.Substring(first + chrome.Length + 1); + var version = cut.Substring(0, cut.IndexOf(' ')); + Version = ToVersion(version); + Type = BrowserType.Chrome; + } + } + } +} diff --git a/API/Wood.Util/Browser/Edge.cs b/API/Wood.Util/Browser/Edge.cs new file mode 100644 index 0000000..e4abc06 --- /dev/null +++ b/API/Wood.Util/Browser/Edge.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2019 Sarin Na Wangkanai, All Rights Reserved. +// The Apache v2. See License.txt in the project root for license information. + +namespace Wood.Util.Browser +{ + public class Edge : BaseBrowser + { + private readonly string _agent; + + public Edge(string agent) + { + _agent = agent.ToLower(); + var edge = BrowserType.Edge.ToString().ToLower(); + + if (_agent.Contains(edge)) + { + var first = _agent.IndexOf(edge); + var version = _agent.Substring(first + edge.Length + 1); + Version = ToVersion(version); + Type = BrowserType.Edge; + } + } + } +} diff --git a/API/Wood.Util/Browser/Firefox.cs b/API/Wood.Util/Browser/Firefox.cs new file mode 100644 index 0000000..62f1246 --- /dev/null +++ b/API/Wood.Util/Browser/Firefox.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2019 Sarin Na Wangkanai, All Rights Reserved. +// The Apache v2. See License.txt in the project root for license information. + +namespace Wood.Util.Browser +{ + public class Firefox : BaseBrowser + { + private readonly string _agent; + + public Firefox(string agent) + { + _agent = agent.ToLower(); + var firefox = BrowserType.Firefox.ToString().ToLower(); + + if (_agent.Contains(firefox)) + { + var first = _agent.IndexOf(firefox); + var version = _agent.Substring(first + firefox.Length + 1); + Version = ToVersion(version); + Type = BrowserType.Firefox; + } + } + } +} diff --git a/API/Wood.Util/Browser/InternetExplorer.cs b/API/Wood.Util/Browser/InternetExplorer.cs new file mode 100644 index 0000000..17fdd33 --- /dev/null +++ b/API/Wood.Util/Browser/InternetExplorer.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2019 Sarin Na Wangkanai, All Rights Reserved. +// The Apache v2. See License.txt in the project root for license information. + +namespace Wood.Util.Browser +{ + public class InternetExplorer : BaseBrowser + { + private readonly string _agent; + + public InternetExplorer(string agent) + { + _agent = agent.ToLower(); + + var ie10 = "msie"; + var rv = "rv:"; + if (_agent.Contains(ie10)) + { + var first = _agent.IndexOf(ie10); + var cut = _agent.Substring(first + ie10.Length + 1); + var version = cut.Substring(0, cut.IndexOf(';')); + Version = ToVersion(version); + Type = BrowserType.IE; + } + + if (_agent.Contains("ie 11.0")) + { + Type = BrowserType.IE; + Version = new System.Version("11.0"); + } + + if (_agent.Contains(rv) && _agent.Contains("trident")) + { + var first = _agent.IndexOf(rv); + var last = _agent.IndexOf(")", first); + if (first > 0 && last > 0) + { + Type = BrowserType.IE; + var version = _agent.Substring(first + rv.Length, last - first - rv.Length); + Version = new System.Version(version); + } + } + } + } +} diff --git a/API/Wood.Util/Browser/Opera.cs b/API/Wood.Util/Browser/Opera.cs new file mode 100644 index 0000000..91b15e3 --- /dev/null +++ b/API/Wood.Util/Browser/Opera.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2019 Sarin Na Wangkanai, All Rights Reserved. +// The Apache v2. See License.txt in the project root for license information. + +namespace Wood.Util.Browser +{ + public class Opera : BaseBrowser + { + private readonly string _agent; + + public Opera(string agent) + { + _agent = agent.ToLower(); + var opera12 = BrowserType.Opera.ToString().ToLower(); + + if(_agent.Contains(opera12)) + { + var first = _agent.IndexOf("version"); + var version = _agent.Substring(first + "version".Length + 1); + Version = ToVersion(version); + Type = BrowserType.Opera; + } + + var opera15 = "opr"; + if (_agent.Contains(opera15)) + { + var first = _agent.IndexOf(opera15); + var version = _agent.Substring(first + opera15.Length + 1); + Version = ToVersion(version); + Type = BrowserType.Opera; + } + } + } +} diff --git a/API/Wood.Util/Browser/Safari.cs b/API/Wood.Util/Browser/Safari.cs new file mode 100644 index 0000000..7faa861 --- /dev/null +++ b/API/Wood.Util/Browser/Safari.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2019 Sarin Na Wangkanai, All Rights Reserved. +// The Apache v2. See License.txt in the project root for license information. + +namespace Wood.Util.Browser +{ + public class Safari : BaseBrowser + { + private readonly string _agent; + + public Safari(string agent) + { + _agent = agent.ToLower(); + var safari = BrowserType.Safari.ToString().ToLower(); + + if (_agent.Contains(safari)) + { + var first = _agent.IndexOf(safari); + var version = _agent.Substring(first + safari.Length + 1); + Version = ToVersion(version); + Type = BrowserType.Safari; + } + } + } +} diff --git a/API/Wood.Util/CaptchaHelper.cs b/API/Wood.Util/CaptchaHelper.cs new file mode 100644 index 0000000..ec843e8 --- /dev/null +++ b/API/Wood.Util/CaptchaHelper.cs @@ -0,0 +1,150 @@ +using SixLabors.Fonts; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using System; +using System.IO; +using System.Numerics; + +namespace Wood.Util +{ + public class CaptchaHelper + { + #region 得到验证码 + /// + /// Tuple第一个值是表达式,第二个值是表达式结果 + /// + /// + public static Tuple GetCaptchaCode() + { + int value = 0; + char[] operators = { '+', '-', '*' }; + string randomCode = string.Empty; + Random random = new Random(); + + int first = random.Next() % 10; + int second = random.Next() % 10; + char operatorChar = operators[random.Next(0, operators.Length)]; + switch (operatorChar) + { + case '+': value = first + second; break; + case '-': + // 第1个数要大于第二个数 + if (first < second) + { + int temp = first; + first = second; + second = temp; + } + value = first - second; + break; + case '*': value = first * second; break; + } + + char code = (char)('0' + (char)first); + randomCode += code; + randomCode += operatorChar; + code = (char)('0' + (char)second); + randomCode += code; + randomCode += "=?"; + return new Tuple(randomCode, value); + } + #endregion + + #region 生成验证码图片 + /// + /// 生成验证码图片 + /// + /// 验证码字符串 + /// 包含验证码图片的字节数组 + public static byte[] CreateCaptchaImage(string randomCode) + { + const int randAngle = 45; // 随机转动角度 + FontFamily fontFamily = SystemFonts.Collection.Get("Verdana"); + var font = fontFamily.CreateFont(36, FontStyle.Regular | FontStyle.Bold); + + // 计算文本的尺寸 + var textSize = TextMeasurer.MeasureSize(randomCode, new TextOptions(font)); + + int mapWidth = (int)(textSize.Width + 10); + int mapHeight = (int)(textSize.Height + 10); + int singleCodeWidth = mapWidth / randomCode.Length; + int paddingTop = 3; + + var aliceBlue = new Rgba32(240, 248, 255); + + using var image = new Image(mapWidth, mapHeight, aliceBlue); + + var random = new Random(); + + // 绘制干扰曲线 + for (int i = 0; i < 2; i++) + { + PointF p1 = new(0, random.Next(mapHeight)); + PointF p2 = new(random.Next(mapWidth), random.Next(mapHeight)); + PointF p3 = new(random.Next(mapWidth), random.Next(mapHeight)); + PointF p4 = new(mapWidth, random.Next(mapHeight)); + + var path = new PathBuilder(); + path.AddCubicBezier(p1, p2, p3, p4); + + image.Mutate(x => x.Draw(Color.Gray, 1f, path.Build())); + } + + // 定义颜色和字体 + Color[] colors = { + Color.Black, Color.Red, Color.DarkBlue, Color.Green, + Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple + }; + + float x = 3; // 起始位置 + + foreach (char t in randomCode) + { + int cIndex = random.Next(colors.Length); + var color = colors[cIndex]; + // 加减乘运算符不进行旋转 + if (t == '+' || t == '-' || t == '*' || t == '=') + { + // 加减乘运算符不进行旋转 + image.Mutate(ctx => ctx.DrawText(t.ToString(), font, color, new PointF(x, paddingTop))); + } + else + { + float angle = random.Next(-randAngle, randAngle + 1); // 确保包括正负randAngle + + // 创建一个变换矩阵用于旋转文本 + var transform = Matrix3x2.CreateRotation((float)Math.PI * angle / 180, new PointF(x + singleCodeWidth / 2, paddingTop + textSize.Height / 2)); + + // 设置绘图选项并应用变换矩阵 + var drawingOptions = new DrawingOptions + { + Transform = transform, + GraphicsOptions = new GraphicsOptions() + { + Antialias = true, + ColorBlendingMode = PixelColorBlendingMode.Normal + } + }; + + // 绘制变换后的文本 + image.Mutate(ctx => + ctx.DrawText(drawingOptions, t.ToString(), font, color, new PointF(x, paddingTop)) + ); + } + + x += singleCodeWidth; // 移动到下一个字符的位置 + } + + // 将图像保存为 GIF 格式并返回字节数组 + using var ms = new MemoryStream(); + image.Save(ms, new PngEncoder()); + return ms.ToArray(); + } + #endregion + } +} diff --git a/API/Wood.Util/ComputerHelper.cs b/API/Wood.Util/ComputerHelper.cs new file mode 100644 index 0000000..9929a53 --- /dev/null +++ b/API/Wood.Util/ComputerHelper.cs @@ -0,0 +1,160 @@ +using Serilog; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class ComputerHelper + { + public static ComputerInfo GetComputerInfo() + { + ComputerInfo computerInfo = new ComputerInfo(); + try + { + MemoryMetricsClient client = new MemoryMetricsClient(); + MemoryMetrics? memoryMetrics = client.GetMetrics(); + if (memoryMetrics != null) + { + computerInfo.TotalRAM = Math.Ceiling(memoryMetrics.Total / 1024).ToString() + " GB"; + computerInfo.RAMRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + " %"; + } + computerInfo.CPURate = Math.Ceiling(GetCPURate().ToDouble()) + " %"; + computerInfo.RunTime = GetRunTime(); + } + catch (Exception ex) + { + Log.Error(ex, "获取计算机信息失败!"); + } + return computerInfo; + } + + public static bool IsUnix() + { + var isUnix = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + return isUnix; + } + + public static string GetCPURate() + { + string cpuRate = "0"; + if (IsUnix()) + { + string output = ShellHelper.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'"); + cpuRate = output.Trim(); + } + else + { + string? output = ShellHelper.Cmd("wmic", "cpu get LoadPercentage"); + cpuRate = output?.Replace("LoadPercentage", string.Empty).Trim()??"0"; + } + return cpuRate; + } + + public static string GetRunTime() + { + string runTime = string.Empty; + try + { + if (IsUnix()) + { + string output = ShellHelper.Bash("uptime -s"); + output = output.Trim(); + runTime = DateTimeHelper.FormatTime((DateTime.Now - output.ToDateTime())?.TotalMilliseconds.ToString().Split('.')[0].ToLong()??0); + } + else + { + string? output = ShellHelper.Cmd("wmic", "OS get LastBootUpTime/Value"); + string[]? outputArr = output?.Split("=", StringSplitOptions.RemoveEmptyEntries); + if (outputArr!=null&&outputArr.Length == 2) + { + runTime = DateTimeHelper.FormatTime((DateTime.Now - outputArr[1].Split('.')[0].ToDateTime())?.TotalMilliseconds.ToString().Split('.')[0].ToLong()??0); + } + } + } + catch (Exception ex) + { + Log.Error(ex, "获取计算机运行时间失败!"); + } + return runTime; + } + } + + public class MemoryMetrics + { + public double Total { get; set; } + public double Used { get; set; } + public double Free { get; set; } + } + + public class MemoryMetricsClient + { + public MemoryMetrics? GetMetrics() + { + if (ComputerHelper.IsUnix()) + { + return GetUnixMetrics(); + } + return GetWindowsMetrics(); + } + + private MemoryMetrics? GetWindowsMetrics() + { + string? output = ShellHelper.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value"); + + var lines = output?.Trim().Split("\n"); + if (lines != null) + { + var freeMemoryParts = lines[0].Split("=", StringSplitOptions.RemoveEmptyEntries); + var totalMemoryParts = lines[1].Split("=", StringSplitOptions.RemoveEmptyEntries); + + var metrics = new MemoryMetrics(); + metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0); + metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0); + metrics.Used = metrics.Total - metrics.Free; + + return metrics; + } + return null; + } + + private MemoryMetrics GetUnixMetrics() + { + string output = ShellHelper.Bash("free -m"); + + var lines = output.Split("\n"); + var memory = lines[1].Split(" ", StringSplitOptions.RemoveEmptyEntries); + + var metrics = new MemoryMetrics(); + metrics.Total = double.Parse(memory[1]); + metrics.Used = double.Parse(memory[2]); + metrics.Free = double.Parse(memory[3]); + + return metrics; + } + } + + public class ComputerInfo + { + /// + /// CPU使用率 + /// + public string? CPURate { get; set; } + /// + /// 总内存 + /// + public string? TotalRAM { get; set; } + /// + /// 内存使用率 + /// + public string? RAMRate { get; set; } + /// + /// 系统运行时间 + /// + public string? RunTime { get; set; } + } +} diff --git a/API/Wood.Util/ConcurrentList.cs b/API/Wood.Util/ConcurrentList.cs new file mode 100644 index 0000000..73198bd --- /dev/null +++ b/API/Wood.Util/ConcurrentList.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class ConcurrentList : IList + { + protected static object _lock = new object(); + protected List _interalList = new List(); + + public IEnumerator GetEnumerator() + { + return Clone().GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return Clone().GetEnumerator(); + } + + public int Count { get { return _interalList.Count; } } + + public bool IsReadOnly { get { return false; } } + + public T this[int index] + { + get + { + lock (_lock) + { + return _interalList[index]; + } + } + set + { + lock (_lock) + { + _interalList[index] = value; + } + } + } + + public List Clone() + { + List newList = new List(); + lock (_lock) + { + _interalList.ForEach(x => newList.Add(x)); + } + return newList; + } + + public int IndexOf(T item) + { + return _interalList.IndexOf(item); + } + + public void Insert(int index, T item) + { + _interalList.Insert(index, item); + } + + public void RemoveAt(int index) + { + lock (_lock) + { + _interalList.RemoveAt(index); + } + } + + public void Add(T item) + { + lock (_lock) + { + _interalList.Add(item); + } + } + + public void AddRange(IEnumerable list) + { + foreach (T item in list) + { + Add(item); + } + } + + public void Clear() + { + lock (_lock) + { + _interalList.Clear(); + } + } + + public bool Contains(T item) + { + return _interalList.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _interalList.CopyTo(array, arrayIndex); + } + + public bool Remove(T item) + { + if (item == null) + { + return false; + } + lock (_lock) + { + return _interalList.Remove(item); + } + } + + public void RemoveAll(Predicate match) + { + if (match == null) + { + return; + } + Contract.Ensures(Contract.Result() >= 0); + Contract.Ensures(Contract.Result() <= Contract.OldValue(Count)); + Contract.EndContractBlock(); + + foreach (T t in Clone()) + { + if (match(t)) + { + Remove(t); + } + } + } + } +} diff --git a/API/Wood.Util/Config/JwtConfig.cs b/API/Wood.Util/Config/JwtConfig.cs new file mode 100644 index 0000000..cd691e1 --- /dev/null +++ b/API/Wood.Util/Config/JwtConfig.cs @@ -0,0 +1,26 @@ +namespace Wood.Util +{ + public class JwtConfig + { + /// + /// 密钥,string 类型,必须是复杂密钥,长度大于16 + /// + public string? SecretKey { get; set; } + /// + /// 发行方,string 类型 + /// + public string? Issuer { get; set; } + /// + /// 订阅方,string 类型 + /// + public string? Audience { get; set; } + /// + /// 刷新token有效期限 天 + /// + public int RefreshTokenExpire { get; set; } = 30; + /// + /// token有效期限 分钟 + /// + public int TokenExpire { get; set; } = 60; + } +} diff --git a/API/Wood.Util/Config/SystemConfig.cs b/API/Wood.Util/Config/SystemConfig.cs new file mode 100644 index 0000000..51937c9 --- /dev/null +++ b/API/Wood.Util/Config/SystemConfig.cs @@ -0,0 +1,67 @@ +namespace Wood.Util +{ + /// + /// 系统配置 + /// + public class SystemConfig + { + /// + /// 是否开启数据库初始化 + /// + public bool EnableInitDb { get; set; } + + /// + /// Snow Flake Worker Id + /// 雪花id 节点序号 + /// + public int SnowFlakeWorkerId { get; set; } + + /// + /// 允许跨域的站点 + /// + public string AllowCorsSite { get; set; } = ""; + + /// + /// 数据库类型 + /// + public string DBProvider { get; set; } = ""; + /// + /// 数据库字符串 + /// + public string DBConnectionString { get; set; } = ""; + + /// + /// 数据库超时间(秒) + /// + public int DBCommandTimeout { get; set; } + + /// + /// 数据库备份路径 + /// + public string DBBackup { get; set; } = ""; + /// + /// 缓存方式 + /// + public string CacheProvider { get; set; } = ""; + /// + /// redis链接字符串 + /// + public string RedisConnectionString { get; set; } = ""; + /// + /// 是否开启差异化日志 + /// + public bool DBEnableDiffLog { get; set; } + /// + /// 是否执行自动job + /// + public bool RunAutoJob { get; set; } + /// + /// 系统保存的日志天数 + /// + public int LogDays { get; set; } = 90; + + + + public string CustomerDb { get; set; } = ""; + } +} \ No newline at end of file diff --git a/API/Wood.Util/CryptogramHelper.cs b/API/Wood.Util/CryptogramHelper.cs new file mode 100644 index 0000000..50d776f --- /dev/null +++ b/API/Wood.Util/CryptogramHelper.cs @@ -0,0 +1,404 @@ +using Serilog; +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace Wood.Util +{ + public class CryptogramHelper + { + private static readonly string DESKey = "*change*"; // 8位或者16位 + private static readonly string DESIv = "1change1"; // 8位或者16位 + + private static readonly string AESKey = "12345dontusethis"; // 16位或者32位 + private static readonly string AESIv = "youshouldchange!"; // 16位或者32位 + + private static readonly string GMPublickey = "MIIBMzCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEA/////v////////////////////8AAAAA//////////8wRAQg/////v////////////////////8AAAAA//////////wEICjp+p6dn140TVqeS89lCafzl4n1FauPkt28vUFNlA6TBEEEMsSuLB8ZgRlfmQRGajnJlI/jC7/yZgvhcVpFiTNMdMe8Nzai9PZ3nFm9zuNraSFT0KmHfMYqR0AC3zLlITnwoAIhAP////7///////////////9yA99rIcYFK1O79Ak51UEjAgEBA0IABKB1MH2tvhV3AlUIadEiWVQUgILQD3gdRE+ywo44geyAJyxIfbxEsVyhTrTX4eg1QBjgfpWZW4RRBNSeU71lsmo="; + + + private static readonly string GMPrivatekey = "MIICSwIBADCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEA/////v////////////////////8AAAAA//////////8wRAQg/////v////////////////////8AAAAA//////////wEICjp+p6dn140TVqeS89lCafzl4n1FauPkt28vUFNlA6TBEEEMsSuLB8ZgRlfmQRGajnJlI/jC7/yZgvhcVpFiTNMdMe8Nzai9PZ3nFm9zuNraSFT0KmHfMYqR0AC3zLlITnwoAIhAP////7///////////////9yA99rIcYFK1O79Ak51UEjAgEBBIIBVTCCAVECAQEEIOlD9P4tlhSw5V4EjAfuPGdFhTRdMZzkoVSeVGmOiuBMoIHjMIHgAgEBMCwGByqGSM49AQECIQD////+/////////////////////wAAAAD//////////zBEBCD////+/////////////////////wAAAAD//////////AQgKOn6np2fXjRNWp5Lz2UJp/OXifUVq4+S3by9QU2UDpMEQQQyxK4sHxmBGV+ZBEZqOcmUj+MLv/JmC+FxWkWJM0x0x7w3NqL09necWb3O42tpIVPQqYd8xipHQALfMuUhOfCgAiEA/////v///////////////3ID32shxgUrU7v0CTnVQSMCAQGhRANCAASgdTB9rb4VdwJVCGnRIllUFICC0A94HURPssKOOIHsgCcsSH28RLFcoU601+HoNUAY4H6VmVuEUQTUnlO9ZbJq"; + + private static readonly GmCrypto GM = new GmCrypto(GMPublickey, GMPrivatekey); + + /// + /// MD5 哈希 + /// + public static byte[] MD5Hash(string input) + { + using (MD5 md5 = MD5.Create()) + { + byte[] inputBytes = Encoding.UTF8.GetBytes(input); + byte[] hashBytes = md5.ComputeHash(inputBytes); + return hashBytes; + } + } + + /// + /// MD5 哈希 + /// + public static string MD5HashToHex(string input, int bit = 32) + { + byte[] byteArr = MD5Hash(input); + string result = EncodingHelper.ByteArrToHexDefault(byteArr); + if (bit == 16) + { + return result.Substring(8, 16).ToUpper(); + } + else + { + return result.ToUpper(); + } + } + + public static byte[]? AESEncrypt(string input, string key = "", string iv = "") + { + if (string.IsNullOrEmpty(key)) + { + key = AESKey; + } + if (string.IsNullOrEmpty(iv)) + { + iv = AESIv; + } + try + { + var encoding = new ASCIIEncoding(); + var keyByte = encoding.GetBytes(key); + var ivByte = encoding.GetBytes(iv); + using (var aesAlg = Aes.Create()) + { + using (var encryptor = aesAlg.CreateEncryptor(keyByte, ivByte)) + { + using (var msEncrypt = new MemoryStream()) + { + using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) + + using (var swEncrypt = new StreamWriter(csEncrypt)) + { + swEncrypt.Write(input); + } + return msEncrypt.ToArray(); + } + } + } + } + catch (Exception ex) + { + Log.Error(ex, "AESEncrypt加密失败:input({input}),key({key}),iv(iv)", input, key, iv); + } + return null; + } + + public static string AESEncryptToBase64(string input, string key = "", string iv = "") + { + byte[]? byteArr = AESEncrypt(input, key, iv); + if (byteArr != null) + { + return Convert.ToBase64String(byteArr); + } + return string.Empty; + } + + public static string AESEncryptToHex(string input, string key = "", string iv = "") + { + byte[]? byteArr = AESEncrypt(input, key, iv); + if (byteArr != null) + { + return EncodingHelper.ByteArrToHexDefault(byteArr); + } + return string.Empty; + } + + public static string AESDecrypt(byte[] byteArr, string key = "", string iv = "") + { + if (string.IsNullOrEmpty(key)) + { + key = AESKey; + } + if (string.IsNullOrEmpty(iv)) + { + iv = AESIv; + } + try + { + var encoding = new ASCIIEncoding(); + var keyByte = encoding.GetBytes(key); + var ivByte = encoding.GetBytes(iv); + using (var aesAlg = Aes.Create()) + { + using (var decryptor = aesAlg.CreateDecryptor(keyByte, ivByte)) + { + string result; + using (var msDecrypt = new MemoryStream(byteArr)) + { + using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) + { + using (var srDecrypt = new StreamReader(csDecrypt)) + { + result = srDecrypt.ReadToEnd(); + } + } + } + return result; + } + } + } + catch (Exception ex) + { + Log.Error(ex, "AESDecrypt解密失败:byteArr({byteArr}),key({key}),iv(iv)", Convert.ToBase64String(byteArr), key, iv); + } + return string.Empty; + } + + public static string AESDecryptFromBase64(string cipherText, string key = "", string iv = "") + { + var byteArr = Convert.FromBase64String(cipherText); + return AESDecrypt(byteArr, key, iv); + } + + public static string AESDecryptFromHex(string cipherText, string key = "", string iv = "") + { + var byteArr = EncodingHelper.HexToByteArrDefault(cipherText); + return AESDecrypt(byteArr, key, iv); + } + + public static byte[]? DESEncrypt(string input, string key = "", string iv = "") + { + if (string.IsNullOrEmpty(key)) + { + key = DESKey; + } + if (string.IsNullOrEmpty(iv)) + { + iv = DESIv; + } + try + { + using (Aes aesAlg = Aes.Create()) + { + // 设置密钥和初始化向量 + aesAlg.Key = Encoding.UTF8.GetBytes(key); + aesAlg.IV = Encoding.UTF8.GetBytes(iv); + + // 创建加密器 + ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); + + // 加密数据 + using (MemoryStream msEncrypt = new MemoryStream()) + { + using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) + { + using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) + { + // 写入所有数据到流中 + swEncrypt.Write(input); + } + return msEncrypt.ToArray(); + } + } + } + } + catch (Exception ex) + { + Log.Error(ex, "DESEncrypt加密失败:byteArr({input}),key({key}),iv(iv)", input, key, iv); + } + return null; + } + + public static string DESEncryptToBase64(string input, string key = "", string iv = "") + { + byte[]? byteArr = DESEncrypt(input, key, iv); + if (byteArr != null) + { + return Convert.ToBase64String(byteArr); + } + return string.Empty; + } + + public static string DESEncryptToHex(string input, string key = "", string iv = "") + { + byte[]? byteArr = DESEncrypt(input, key, iv); + if (byteArr != null) + { + return EncodingHelper.ByteArrToHexDefault(byteArr); + } + return string.Empty; + } + + public static byte[]? DESDecrypt(byte[] byteArr, string key = "", string iv = "") + { + if (string.IsNullOrEmpty(key)) + { + key = DESKey; + } + if (string.IsNullOrEmpty(iv)) + { + iv = DESIv; + } + try + { + using (Aes aesAlg = Aes.Create()) + { + // 设置密钥和初始化向量 + aesAlg.Key = Encoding.UTF8.GetBytes(key); + aesAlg.IV = Encoding.UTF8.GetBytes(iv); + + // 创建解密器 + ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); + + // 解密数据 + using (MemoryStream msDecrypt = new MemoryStream(byteArr)) + { + using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) + { + using (MemoryStream output = new MemoryStream()) + { + csDecrypt.CopyTo(output); + return output.ToArray(); + } + } + } + } + } + catch (Exception ex) + { + Log.Error(ex, "DESDecrypt解密失败:byteArr({byteArr}),key({key}),iv(iv)", Convert.ToBase64String(byteArr), key, iv); + } + return null; + } + + public static string DESDecryptFromBase64(string cipherText, string key = "", string iv = "") + { + var byteArr = Convert.FromBase64String(cipherText); + var result = DESDecrypt(byteArr, key, iv); + if (result != null) + { + return Encoding.UTF8.GetString(result); + } + return string.Empty; + } + + public static string DESDecryptFromHex(string cipherText, string key = "", string iv = "") + { + var byteArr = EncodingHelper.HexToByteArrDefault(cipherText); + var result = DESDecrypt(byteArr, key, iv); + if (result != null) + { + return Encoding.UTF8.GetString(result); + } + return string.Empty; + } + + /// + /// HMAC 256 哈希 + /// + public static byte[] HMAC_SHA256(string encrypt, string key = "") + { + if (string.IsNullOrEmpty(key)) + { + key = DESKey; + } + var encoding = new ASCIIEncoding(); + byte[] keyByte = encoding.GetBytes(key); + byte[] encryptByte = encoding.GetBytes(encrypt); + using (var hmacsha256 = new HMACSHA256(keyByte)) + { + return hmacsha256.ComputeHash(encryptByte); + } + } + + /// + /// HMAC 256 哈希 + /// + public static string HMAC_SHA256ToHex(string encrypt, string key = "") + { + byte[] hash = HMAC_SHA256(encrypt, key); + return EncodingHelper.ByteArrToHexDefault(hash); + } + + /// + /// 国密 SM2 加密 + /// Key值在CryptogramHelper中设置 + /// Key值GmCrypto中生成 + /// + public static string GMSM2Encrypt(string data) + { + return Convert.ToBase64String(GM.EncryptSm2(data)); + } + + /// + /// 国密 SM2 解密 + /// Key值在 CryptogramHelper 中设置 + /// Key值 GmCrypto 中生成 (需保存) + /// + public static string GMSM2Decrypt(string data) + { + var bytes = Convert.FromBase64String(data); + return GM.DecryptSm2(bytes); + } + + /// + /// 国密 SM3 哈希 + /// + public static string GMSM3Hash(string data) + { + return GM.HashSm3(data); + } + + /// + /// 国密 SM4 加密 + /// 默认Key值在 GmCrypto 中设置 + /// 设置 key iv 后不会使用默认值 + /// + public static string GMSM4Encrypt(string data, string? key = null, string? iv = null) + { + return Convert.ToBase64String(GM.EncryptSM4(data, key, iv)); + } + /// + /// 国密 SM4 解密 + /// 默认Key值在 GmCrypto 中设置 + /// 设置 key iv 后不会使用默认值 + /// + public static string GMSM4Decrypt(string data, string? key = null, string? iv = null) + { + var bytes = Convert.FromBase64String(data); + return Encoding.UTF8.GetString(GM.DecryptSM4(bytes, key, iv)); + } + + /// + /// 生成一个指定长度的随机字符串,包含大小写字母、数字、运算符号、括号和斜杠 + /// + /// 随机字符串的长度 + /// 生成的随机字符串 + public static string GenerateRandomString(int length) + { + // 定义可用字符集 + const string validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*/()[]{}|\\<>?:;.,=!@#$%^&~`_"; + + // 使用 RNGCryptoServiceProvider 提供高随机性的随机数生成器 + using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) + { + // 创建一个字节数组来存储随机字节 + byte[] data = new byte[length]; + rng.GetBytes(data); + + // 使用 StringBuilder 提高性能 + StringBuilder sb = new StringBuilder(length); + + // 循环生成每个字符 + foreach (byte b in data) + { + // 将字节映射到有效字符集中 + char c = validChars[b % validChars.Length]; + sb.Append(c); + } + + // 返回生成的随机字符串 + return sb.ToString(); + } + } + + } +} diff --git a/API/Wood.Util/DataTableHelper.cs b/API/Wood.Util/DataTableHelper.cs new file mode 100644 index 0000000..d158b5a --- /dev/null +++ b/API/Wood.Util/DataTableHelper.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public static class DataTableHelper + { + public static DataTable ListToDataTable(List entitys) + { + //检查实体集合不能为空 + if (entitys == null || entitys.Count < 1) + { + throw new Exception("需转换的集合为空"); + } + //取出第一个实体的所有Propertie + Type entityType = entitys[0]!.GetType(); + PropertyInfo[] entityProperties = entityType.GetProperties(); + + //生成DataTable的structure + //生产代码中,应将生成的DataTable结构Cache起来,此处略 + DataTable dt = new DataTable(); + for (int i = 0; i < entityProperties.Length; i++) + { + dt.Columns.Add(entityProperties[i].Name); + } + //将所有entity添加到DataTable中 + foreach (object? entity in entitys) + { + //检查所有的的实体都为同一类型 + if (entity?.GetType() != entityType) + { + throw new Exception("要转换的集合元素类型不一致"); + } + object[] entityValues = new object[entityProperties.Length]; + for (int i = 0; i < entityProperties.Length; i++) + { + entityValues[i] = entityProperties[i].GetValue(entity, null)!; + } + dt.Rows.Add(entityValues); + } + return dt; + } + } +} diff --git a/API/Wood.Util/DateTimeHelper.cs b/API/Wood.Util/DateTimeHelper.cs new file mode 100644 index 0000000..6627c66 --- /dev/null +++ b/API/Wood.Util/DateTimeHelper.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class DateTimeHelper + { + #region 毫秒转天时分秒 + /// + /// 毫秒转天时分秒 + /// + /// + /// + public static string FormatTime(long ms) + { + int ss = 1000; + int mi = ss * 60; + int hh = mi * 60; + int dd = hh * 24; + + long day = ms / dd; + long hour = (ms - day * dd) / hh; + long minute = (ms - day * dd - hour * hh) / mi; + long second = (ms - day * dd - hour * hh - minute * mi) / ss; + long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss; + + string sDay = day < 10 ? "0" + day : "" + day; //天 + string sHour = hour < 10 ? "0" + hour : "" + hour;//小时 + string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟 + string sSecond = second < 10 ? "0" + second : "" + second;//秒 + string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒 + sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond; + + return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond); + } + #endregion + + #region 获取unix时间戳 + /// + /// 获取unix时间戳 + /// + /// + /// + public static long GetUnixTimeStamp(DateTime dt) + { + long unixTime = ((DateTimeOffset)dt).ToUnixTimeMilliseconds(); + return unixTime; + } + #endregion + + #region 获取日期天的最小时间 + public static DateTime GetDayMinDate(DateTime dt) + { + DateTime min = new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0); + return min; + } + #endregion + + #region 获取日期天的最大时间 + public static DateTime GetDayMaxDate(DateTime dt) + { + DateTime max = new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59); + return max; + } + #endregion + + #region 获取日期天的最大时间 + public static string FormatDateTime(DateTime? dt) + { + if (dt != null) + { + if (dt.Value.Year == DateTime.Now.Year) + { + return dt.Value.ToString("MM-dd HH:mm"); + } + else + { + return dt.Value.ToString("yyyy-MM-dd HH:mm"); + } + } + return string.Empty; + } + #endregion + } +} diff --git a/API/Wood.Util/EncodingHelper.cs b/API/Wood.Util/EncodingHelper.cs new file mode 100644 index 0000000..26ca0c0 --- /dev/null +++ b/API/Wood.Util/EncodingHelper.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Wood.Util +{ + public class EncodingHelper + { + private static string HexStr = "0123456789abcdef"; + private static char[] HexCharArr = HexStr.ToCharArray(); + + public static string ByteArrToHex(byte[] btArr) + { + char[] strArr = new char[btArr.Length * 2]; + int i = 0; + foreach (byte bt in btArr) + { + strArr[i++] = HexCharArr[bt >> 4 & 0xf]; + strArr[i++] = HexCharArr[bt & 0xf]; + } + return new string(strArr); + } + + public static byte[] HexToByteArr(string hexStr) + { + char[] charArr = hexStr.ToCharArray(); + byte[] btArr = new byte[charArr.Length / 2]; + int index = 0; + for (int i = 0; i < charArr.Length; i++) + { + int highBit = HexStr.IndexOf(charArr[i]); + int lowBit = HexStr.IndexOf(charArr[++i]); + btArr[index] = (byte)(highBit << 4 | lowBit); + index++; + } + return btArr; + } + + public static string ByteArrToHexDefault(byte[] btArr) + { + StringBuilder sb = new StringBuilder(); + foreach (byte b in btArr) + { + sb.Append(b.ToString("X2")); + } + return sb.ToString(); + } + + public static byte[] HexToByteArrDefault(string hexStr) + { + byte[] inputArr = new byte[hexStr.Length / 2]; + for (int i = 0; i < hexStr.Length / 2; i++) + { + int v = Convert.ToInt32(hexStr.Substring(i * 2, 2), 16); + inputArr[i] = (byte)v; + } + return inputArr; + } + } +} diff --git a/API/Wood.Util/ExcelHelper.cs b/API/Wood.Util/ExcelHelper.cs new file mode 100644 index 0000000..9df38f3 --- /dev/null +++ b/API/Wood.Util/ExcelHelper.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Wood.Util +{ + /// + /// List导出到Excel文件 + /// + /// + public class ExcelHelper where T : new() + { + } +} + diff --git a/API/Wood.Util/ExceptionHelper.cs b/API/Wood.Util/ExceptionHelper.cs new file mode 100644 index 0000000..98ae148 --- /dev/null +++ b/API/Wood.Util/ExceptionHelper.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class SystemMessageException : Exception + { + // 构造函数:无参构造函数 + public SystemMessageException() + : base() + { + } + + // 构造函数:接受消息字符串 + public SystemMessageException(string message) + : base(message) + { + } + + // 构造函数:接受消息字符串和内部异常对象 + public SystemMessageException(string message, Exception innerException) + : base(message, innerException) + { + } + + // 可选:添加自定义属性或方法 + public string ErrorCode { get; set; } = "-1"; + + public SystemMessageException(string message, string errorCode) + : base(message) + { + ErrorCode = errorCode; + } + + public SystemMessageException(string message, string errorCode, Exception innerException) + : base(message, innerException) + { + ErrorCode = errorCode; + } + } + + public static class Oops + { + + public static SystemMessageException Oh(string message) + { + return new SystemMessageException(message); + } + + public static SystemMessageException Oh(string message, string code) + { + return new SystemMessageException(message, code); + } + } +} diff --git a/API/Wood.Util/Extension/Extension.Convert.cs b/API/Wood.Util/Extension/Extension.Convert.cs new file mode 100644 index 0000000..750c97e --- /dev/null +++ b/API/Wood.Util/Extension/Extension.Convert.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; + +public static class StringExtensions +{ + /// + /// 将string转换为DateTime,若转换失败,则返回默认值。 + /// + /// + public static DateTime? ToDateTime(this string str, DateTime? defaultValue = null) + { + DateTime val; + if (string.IsNullOrWhiteSpace(str)) + { + return defaultValue.GetValueOrDefault(); + } + if (str.Contains("-") || str.Contains("/")) + { + if (DateTime.TryParse(str, out val)) + return val; + + return defaultValue.GetValueOrDefault(); + } + else + { + int length = str.Length; + switch (length) + { + case 4: + if (DateTime.TryParseExact(str, "yyyy", CultureInfo.CurrentCulture, DateTimeStyles.None, out val)) + return val; + return defaultValue.GetValueOrDefault(); + case 6: + if (DateTime.TryParseExact(str, "yyyyMM", CultureInfo.CurrentCulture, DateTimeStyles.None, out val)) + return val; + return defaultValue.GetValueOrDefault(); + case 8: + if (DateTime.TryParseExact(str, "yyyyMMdd", CultureInfo.CurrentCulture, DateTimeStyles.None, out val)) + return val; + return defaultValue.GetValueOrDefault(); + case 10: + if (DateTime.TryParseExact(str, "yyyyMMddHH", CultureInfo.CurrentCulture, DateTimeStyles.None, out val)) + return val; + return defaultValue.GetValueOrDefault(); + case 12: + if (DateTime.TryParseExact(str, "yyyyMMddHHmm", CultureInfo.CurrentCulture, DateTimeStyles.None, out val)) + return val; + return defaultValue.GetValueOrDefault(); + case 14: + if (DateTime.TryParseExact(str, "yyyyMMddHHmmss", CultureInfo.CurrentCulture, DateTimeStyles.None, out val)) + return val; + return defaultValue.GetValueOrDefault(); + default: + if (DateTime.TryParseExact(str, "yyyyMMddHHmmss", CultureInfo.CurrentCulture, DateTimeStyles.None, out val)) + return val; + return defaultValue.GetValueOrDefault(); + } + } + } + /// + /// 强制转换类型 + /// + /// + /// + /// + public static IEnumerable CastSuper(this IEnumerable source) + { + foreach (object item in source) + { + yield return (TResult)Convert.ChangeType(item, typeof(TResult)); + } + } + + // 转换为long + public static long ToLong(this string str, long defaultValue = 0L) => + long.TryParse(str, out var result) ? result : defaultValue; + + // 转换为int + public static int ToInt(this string str, int defaultValue = 0) => + int.TryParse(str, out var result) ? result : defaultValue; + + // 转换为short + public static short ToShort(this string str, short defaultValue = 0) => + short.TryParse(str, out var result) ? result : defaultValue; + + // 转换为decimal + public static decimal ToDecimal(this string str, decimal defaultValue = 0m) => + decimal.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out var result) ? result : defaultValue; + + // 转换为bool + public static bool ToBool(this string str, bool defaultValue = false) => + bool.TryParse(str, out var result) ? result : defaultValue; + + // 转换为float + public static float ToFloat(this string str, float defaultValue = 0f) => + float.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out var result) ? result : defaultValue; + + // 转换为double + public static double ToDouble(this string str, double defaultValue = 0d) => + double.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out var result) ? result : defaultValue; + + // 转换为Guid + public static Guid ToGuid(this string str, Guid defaultValue = default) => + Guid.TryParse(str, out var guid) ? guid : defaultValue; + +} \ No newline at end of file diff --git a/API/Wood.Util/Extension/Extension.Enum.cs b/API/Wood.Util/Extension/Extension.Enum.cs new file mode 100644 index 0000000..da823e6 --- /dev/null +++ b/API/Wood.Util/Extension/Extension.Enum.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; + +namespace Wood.Util +{ + public static partial class Extensions + { + #region 枚举成员转成dictionary类型 + /// + /// 转成dictionary类型 + /// + /// + /// + public static Dictionary EnumToDictionary(this Type enumType) + { + Dictionary dictionary = new Dictionary(); + Type typeDescription = typeof(DescriptionAttribute); + FieldInfo[] fields = enumType.GetFields(); + int sValue = 0; + string sText = string.Empty; + foreach (FieldInfo field in fields) + { + if (field.FieldType.IsEnum) + { + sValue = ((int)enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null)!); + object[] arr = field.GetCustomAttributes(typeDescription, true); + if (arr.Length > 0) + { + DescriptionAttribute da = (DescriptionAttribute)arr[0]; + sText = da.Description; + } + else + { + sText = field.Name; + } + dictionary.Add(sValue, sText); + } + } + return dictionary; + } + #endregion + + #region 获取枚举的描述 + /// + /// 获取枚举值对应的描述 + /// + /// + /// + public static string GetDescription(this System.Enum enumType) + { + FieldInfo EnumInfo = enumType.GetType().GetField(enumType.ToString())!; + if (EnumInfo != null) + { + DescriptionAttribute[] EnumAttributes = (DescriptionAttribute[])EnumInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); + if (EnumAttributes.Length > 0) + { + return EnumAttributes[0].Description; + } + } + return enumType.ToString(); + } + #endregion + + #region 根据值获取枚举的描述 + public static string GetDescriptionByEnum(this object obj) + { + var tEnum = System.Enum.Parse(typeof(T), obj.ToString()??"") as System.Enum; + var description = tEnum!.GetDescription(); + return description; + } + #endregion + } +} diff --git a/API/Wood.Util/Extension/Extension.Exception.cs b/API/Wood.Util/Extension/Extension.Exception.cs new file mode 100644 index 0000000..b5d0dc4 --- /dev/null +++ b/API/Wood.Util/Extension/Extension.Exception.cs @@ -0,0 +1,50 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public static partial class Extensions + { + public static Exception GetOriginalException(this Exception ex) + { + if (ex.InnerException == null) return ex; + + return ex.InnerException.GetOriginalException(); + } + + public static string GetFullExceptionMessage(this Exception ex) { + + StringBuilder sbException = new StringBuilder(); + Exception exception = ex; + sbException.AppendLine(exception.Message); + while (exception.InnerException != null) + { + sbException.AppendLine(exception.InnerException.Message); + exception = exception.InnerException; + } + + return sbException.ToString(); + } + + public static List GetAllErrorMessages(this ModelStateDictionary modelState) + { + var errors = new List(); + + foreach (var state in modelState) + { + foreach (var error in state.Value.Errors) + { + errors.Add(error.ErrorMessage); + } + } + + return errors; + } + + } +} diff --git a/API/Wood.Util/Extension/Extension.Type.cs b/API/Wood.Util/Extension/Extension.Type.cs new file mode 100644 index 0000000..8f22686 --- /dev/null +++ b/API/Wood.Util/Extension/Extension.Type.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public static class TypeExtensions + { + public static object? GetDefaultValue(this TypeInfo typeInfo) + { + if (typeInfo == null) + { + throw new ArgumentNullException("typeInfo"); + } + + if (typeInfo.AsType() == typeof(void)) + { + return null; + } + + switch (Type.GetTypeCode(typeInfo.AsType())) + { + case TypeCode.Object: + case TypeCode.DateTime: + if (typeInfo.IsValueType) + return Activator.CreateInstance(typeInfo.AsType()); + return null; + case TypeCode.Empty: + case TypeCode.String: + return null; + case TypeCode.Boolean: + case TypeCode.Char: + case TypeCode.SByte: + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + return 0; + case TypeCode.Int64: + case TypeCode.UInt64: + return 0; + case TypeCode.Single: + return 0f; + case TypeCode.Double: + return 0.0; + case TypeCode.Decimal: + return 0m; + default: + throw new InvalidOperationException("Code supposed to be unreachable."); + } + } + + public static object GetDefaultValue(this Type type) + { + return type?.GetTypeInfo()?.GetDefaultValue()!; + } + + public static bool IsVisible(this TypeInfo typeInfo) + { + if (typeInfo == null) + { + throw new ArgumentNullException("typeInfo"); + } + + if (typeInfo.IsNested) + { + if (!typeInfo.DeclaringType!.GetTypeInfo().IsVisible()) + { + return false; + } + + if (!typeInfo.IsVisible || !typeInfo.IsNestedPublic) + { + return false; + } + } + else if (!typeInfo.IsVisible || !typeInfo.IsPublic) + { + return false; + } + + if (typeInfo.IsGenericType && !typeInfo.IsGenericTypeDefinition) + { + Type[] genericTypeArguments = typeInfo.GenericTypeArguments; + for (int i = 0; i < genericTypeArguments.Length; i++) + { + if (!genericTypeArguments[i].GetTypeInfo().IsVisible()) + { + return false; + } + } + } + + return true; + } + + public static bool IsTask(this TypeInfo typeInfo) + { + if (typeInfo == null) + { + throw new ArgumentNullException("typeInfo"); + } + + return typeInfo.AsType() == typeof(Task); + } + + public static bool IsValueTask(this TypeInfo typeInfo) + { + if (typeInfo == null) + { + throw new ArgumentNullException("typeInfo"); + } + + return typeInfo.AsType() == typeof(ValueTask); + } + + public static bool IsNullableType(this Type type) + { + if (type.GetTypeInfo().IsGenericType) + { + return type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + return false; + } + + public static bool IsTupleType(this Type type) + { + if ((object)type == null) + { + throw new ArgumentNullException("type"); + } + + if (type.IsGenericType) + { + return typeof(ITuple).IsAssignableFrom(type.GetTypeInfo().GetGenericTypeDefinition()); + } + + return false; + } + } +} diff --git a/API/Wood.Util/Extension/Extension.Validate.cs b/API/Wood.Util/Extension/Extension.Validate.cs new file mode 100644 index 0000000..24d46cf --- /dev/null +++ b/API/Wood.Util/Extension/Extension.Validate.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public static partial class Extensions + { + public static bool IsEmpty(this object value) + { + if (value != null && !string.IsNullOrEmpty(value.ToString())) + { + return false; + } + else + { + return true; + } + } + + public static bool IsNullOrZero(this object value) + { + if (value == null || value.ToString()?.Trim() == "0") + { + return true; + } + else + { + return false; + } + } + + public static bool IsAjaxRequest(this HttpRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + if (request.Headers != null) + return request.Headers["X-Requested-With"] == "XMLHttpRequest"; + return false; + } + } +} diff --git a/API/Wood.Util/FileHelper.cs b/API/Wood.Util/FileHelper.cs new file mode 100644 index 0000000..4ee1d2e --- /dev/null +++ b/API/Wood.Util/FileHelper.cs @@ -0,0 +1,307 @@ +using Serilog; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Wood.Util +{ + public class FileHelper + { + #region 创建文本文件 + /// + /// 创建文件 + /// + /// + /// + public static void CreateFile(string path, string content) + { + if (!Directory.Exists(Path.GetDirectoryName(path))) + { + var folderName = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(folderName)) + Directory.CreateDirectory(folderName); + } + using (StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8)) + { + sw.Write(content); + } + } + #endregion + + #region 上传单个文件 + /// + /// 上传单个文件 + /// + /// + /// + /// + //public async static Task> UploadFile(int fileModule, IFormFileCollection files) + //{ + //string dirModule = string.Empty; + //TData obj = new TData(); + //if (files == null || files.Count == 0) + //{ + // obj.Message = "请先选择文件!"; + // return obj; + //} + //if (files.Count > 1) + //{ + // obj.Message = "一次只能上传一个文件!"; + // return obj; + //} + //TData objCheck = null; + //IFormFile file = files[0]; + //switch (fileModule) + //{ + // case (int)UploadFileType.Portrait: + // objCheck = CheckFileExtension(Path.GetExtension(file.FileName), ".jpg|.jpeg|.gif|.png"); + // if (objCheck.Tag != 1) + // { + // obj.Message = objCheck.Message; + // return obj; + // } + // dirModule = UploadFileType.Portrait.ToString(); + // break; + + // case (int)UploadFileType.News: + // if (file.Length > 5 * 1024 * 1024) // 5MB + // { + // obj.Message = "文件最大限制为 5MB"; + // return obj; + // } + // objCheck = CheckFileExtension(Path.GetExtension(file.FileName), ".jpg|.jpeg|.gif|.png"); + // if (objCheck.Tag != 1) + // { + // obj.Message = objCheck.Message; + // return obj; + // } + // dirModule = UploadFileType.News.ToString(); + // break; + + // case (int)UploadFileType.Import: + // objCheck = CheckFileExtension(Path.GetExtension(file.FileName), ".xls|.xlsx"); + // if (objCheck.Tag != 1) + // { + // obj.Message = objCheck.Message; + // return obj; + // } + // dirModule = UploadFileType.Import.ToString(); + // break; + + // default: + // obj.Message = "请指定上传到的模块"; + // return obj; + //} + //string fileExtension = TextHelper.GetCustomValue(Path.GetExtension(file.FileName), ".png"); + + //string newFileName = SecurityHelper.GetGuid(true) + fileExtension; + //string dir = "Resource" + Path.DirectorySeparatorChar + dirModule + Path.DirectorySeparatorChar + DateTime.Now.ToString("yyyy-MM-dd").Replace('-', Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar; + + //string absoluteDir = Path.Combine(GlobalContext.HostingEnvironment.ContentRootPath, dir); + //string absoluteFileName = string.Empty; + //if (!Directory.Exists(absoluteDir)) + //{ + // Directory.CreateDirectory(absoluteDir); + //} + //absoluteFileName = absoluteDir + newFileName; + //try + //{ + // using (FileStream fs = File.Create(absoluteFileName)) + // { + // await file.CopyToAsync(fs); + // fs.Flush(); + // } + // obj.Data = Path.AltDirectorySeparatorChar + ConvertDirectoryToHttp(dir) + newFileName; + // obj.Message = Path.GetFileNameWithoutExtension(TextHelper.GetCustomValue(file.FileName, newFileName)); + // obj.Description = (file.Length / 1024).ToString(); // KB + // obj.Tag = 1; + //} + //catch (Exception ex) + //{ + // obj.Message = ex.Message; + //} + //return obj; + //} + #endregion + + #region 删除单个文件 + ///// + ///// 删除单个文件 + ///// + ///// + ///// + ///// + //public static TData DeleteFile(int fileModule, string filePath) + //{ + // TData obj = new TData(); + // string dirModule = fileModule.GetDescriptionByEnum(); + + // if (string.IsNullOrEmpty(filePath)) + // { + // obj.Message = "请先选择文件!"; + // return obj; + // } + + // filePath = FilterFilePath(filePath); + // filePath = "Resource" + Path.DirectorySeparatorChar + dirModule + Path.DirectorySeparatorChar + filePath; + // string absoluteDir = Path.Combine(GlobalContext.HostingEnvironment.ContentRootPath, filePath); + // try + // { + // if (File.Exists(absoluteDir)) + // { + // File.Delete(absoluteDir); + // } + // else + // { + // obj.Message = "文件不存在"; + // } + // obj.Tag = 1; + // } + // catch (Exception ex) + // { + // obj.Message = ex.Message; + // } + // return obj; + //} + #endregion + + #region 下载文件 + ///// + ///// 下载文件 + ///// + ///// + ///// + ///// + //public static TData DownloadFile(string filePath, int delete) + //{ + // filePath = FilterFilePath(filePath); + // if (!filePath.StartsWith("wwwroot") && !filePath.StartsWith("Resource")) + // { + // throw new Exception("非法访问"); + // } + // TData obj = new TData(); + // string absoluteFilePath = GlobalContext.HostingEnvironment.ContentRootPath + Path.DirectorySeparatorChar + filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + // byte[] fileBytes = File.ReadAllBytes(absoluteFilePath); + // if (delete == 1) + // { + // File.Delete(absoluteFilePath); + // } + // // md5 值 + // string fileNamePrefix = DateTime.Now.ToString("yyyyMMddHHmmss"); + // string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); + // string title = fileNameWithoutExtension; + // if (fileNameWithoutExtension.Contains("_")) + // { + // title = fileNameWithoutExtension.Split('_')[1].Trim(); + // } + // string fileExtensionName = Path.GetExtension(filePath); + // obj.Data = new FileContentResult(fileBytes, "application/octet-stream") + // { + // FileDownloadName = string.Format("{0}_{1}{2}", fileNamePrefix, title, fileExtensionName) + // }; + // obj.Tag = 1; + // return obj; + //} + #endregion + + #region GetContentType + public static string GetContentType(string path) + { + var types = GetMimeTypes(); + var ext = Path.GetExtension(path).ToLowerInvariant(); + var contentType = types[ext]; + if (string.IsNullOrEmpty(contentType)) + { + contentType = "application/octet-stream"; + } + return contentType; + } + #endregion + + #region GetMimeTypes + public static Dictionary GetMimeTypes() + { + return new Dictionary + { + {".txt", "text/plain"}, + {".pdf", "application/pdf"}, + {".doc", "application/vnd.ms-word"}, + {".docx", "application/vnd.ms-word"}, + {".xls", "application/vnd.ms-excel"}, + {".xlsx", "application/vnd.openxmlformats officedocument.spreadsheetml.sheet"}, + {".png", "image/png"}, + {".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".gif", "image/gif"}, + {".csv", "text/csv"} + }; + } + #endregion + + public static void CreateDirectory(string directory) + { + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + } + + public static void DeleteDirectory(string filePath) + { + try + { + if (Directory.Exists(filePath)) //如果存在这个文件夹删除之 + { + foreach (string d in Directory.GetFileSystemEntries(filePath)) + { + if (File.Exists(d)) + File.Delete(d); //直接删除其中的文件 + else + DeleteDirectory(d); //递归删除子文件夹 + } + Directory.Delete(filePath, true); //删除已空文件夹 + } + } + catch (Exception ex) + { + Log.Error(ex, "文件夹删除失败:filePath({filePath})", filePath); + } + } + + public static string ConvertDirectoryToHttp(string directory) + { + directory = directory.ToString(); + directory = directory.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + return directory; + } + + public static string ConvertHttpToDirectory(string http) + { + http = http.ToString(); + http = http.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + return http; + } + + //public static TData CheckFileExtension(string fileExtension, string allowExtension) + //{ + // TData obj = TData.Success(); + // string[] allowArr = TextHelper.SplitToArray(allowExtension.ToLower(), '|'); + // if (allowArr.Where(p => p.Trim() == fileExtension.ParseToString().ToLower()).Any()) + // return obj; + // else + // { + // obj.Message = "只有文件扩展名是 " + allowExtension + " 的文件才能上传"; + // return obj; + // } + //} + + public static string FilterFilePath(string filePath) + { + filePath = filePath.Replace("../", string.Empty); + filePath = filePath.Replace("..", string.Empty); + filePath = filePath.TrimStart('/'); + return filePath; + } + } +} diff --git a/API/Wood.Util/GM/GmCrypto.cs b/API/Wood.Util/GM/GmCrypto.cs new file mode 100644 index 0000000..710547a --- /dev/null +++ b/API/Wood.Util/GM/GmCrypto.cs @@ -0,0 +1,242 @@ +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Smime; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.EC; +using Org.BouncyCastle.Crypto.Encodings; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.Pqc.Crypto.Lms; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; +using System; +using System.Linq; +using System.Text; + +/// +/// 提供对国密标准(SM2, SM3, SM4)加密算法的支持。 +/// +public class GmCrypto +{ + // SM2 密钥对,用于非对称加密和解密操作 + private AsymmetricCipherKeyPair _sm2KeyPair; + + /// + /// 构造函数,默认生成新的 SM2 密钥对。 + /// + public GmCrypto() + { + _sm2KeyPair = GenerateSm2KeyPair(); + } + /// + /// + /// + /// sm2公匙 + /// sm2私匙 + public GmCrypto(string pubKey, string priKey) + { + _sm2KeyPair = new AsymmetricCipherKeyPair(ReadPublicKeyFromBase64(pubKey), ReadPrivateKeyFromBase64(priKey)); + } + + /// + /// 生成一个新的 SM2 密钥对。 + /// + public AsymmetricCipherKeyPair GenerateSm2KeyPair() + { + // 定义椭圆曲线参数(这里使用的是SM2默认的曲线) + X9ECParameters ecParams = CustomNamedCurves.GetByName("sm2p256v1"); + ECDomainParameters domainParams = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed()); + + // 创建密钥对生成器并初始化 + var keyPairGenerator = GeneratorUtilities.GetKeyPairGenerator("EC"); + var keyGenParam = new ECKeyGenerationParameters(domainParams, new SecureRandom()); + keyPairGenerator.Init(keyGenParam); + return keyPairGenerator.GenerateKeyPair(); + + + } + + public (string pubKey, string priKey) GetSM2Key() + { + // 获取公私钥 + ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters)_sm2KeyPair.Private; + ECPublicKeyParameters publicKey = (ECPublicKeyParameters)_sm2KeyPair.Public; + + // 将公钥转换为Base64编码的字符串 + string publicKeyString = Convert.ToBase64String(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey).GetDerEncoded()); + + // 将私钥转换为PKCS#8格式并Base64编码 + PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey); + string privateKeyString = Convert.ToBase64String(privateKeyInfo.GetDerEncoded()); + + return (publicKeyString, privateKeyString); + } + + + /// + /// 读取公私匙 + /// + /// + /// + public ECPublicKeyParameters ReadPublicKeyFromBase64(string publicKeyBase64) + { + byte[] encodedPublicKey = Convert.FromBase64String(publicKeyBase64); + SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.GetInstance(encodedPublicKey); + return (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyInfo); + } + /// + /// 读取私有钥匙 + /// + /// + /// + public ECPrivateKeyParameters ReadPrivateKeyFromBase64(string privateKeyBase64) + { + byte[] encodedPrivateKey = Convert.FromBase64String(privateKeyBase64); + PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.GetInstance(encodedPrivateKey); + return (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(privateKeyInfo); + } + + /// + /// 使用 SM2 算法加密给定的数据字符串。 + /// + /// 要加密的数据字符串。 + /// 返回加密后的字节数组。 + public byte[] EncryptSm2(string data) + { + return EncryptWithSM2(data, (ECPublicKeyParameters)_sm2KeyPair.Public); + } + + /// + /// 使用 SM2 算法解密给定的加密数据。 + /// + /// 已加密的数据字节数组。 + /// 返回解密后的原始数据字符串。 + public string DecryptSm2(byte[] encryptedData) + { + return DecryptWithSM2(encryptedData, (ECPrivateKeyParameters)_sm2KeyPair.Private); + } + + /// + /// 使用SM2算法进行加密。 + /// + /// 要加密的字符串。 + /// 用于加密的公钥。 + /// 返回加密后的字节数组。 + public static byte[] EncryptWithSM2(string data, ECPublicKeyParameters publicKey) + { + var cipher = new SM2Engine(); + cipher.Init(true, new ParametersWithRandom(publicKey, new SecureRandom())); + return cipher.ProcessBlock(Encoding.UTF8.GetBytes(data), 0, data.Length); + } + + /// + /// 使用SM2算法进行解密。 + /// + /// 要解密的字节数组。 + /// 用于解密的私钥。 + /// 返回解密后的字符串。 + public static string DecryptWithSM2(byte[] encryptedData, ECPrivateKeyParameters privateKey) + { + var cipher = new SM2Engine(); + cipher.Init(false, privateKey); + var output = cipher.ProcessBlock(encryptedData, 0, encryptedData.Length); + return Encoding.UTF8.GetString(output); + } + + /// + /// 使用 SM3 哈希算法计算给定消息的哈希值。 + /// + /// 要计算哈希的消息字符串。 + /// 返回哈希结果的十六进制字符串表示形式。 + public string HashSm3(string message) + { + var sm3Digest = new SM3Digest(); // 创建 SM3 摘要实例 + byte[] messageBytes = Encoding.UTF8.GetBytes(message); // 将消息转换为字节数组 + sm3Digest.BlockUpdate(messageBytes, 0, messageBytes.Length); // 更新摘要对象 + byte[] hash = new byte[sm3Digest.GetDigestSize()]; // 准备存储哈希结果的空间 + sm3Digest.DoFinal(hash, 0); // 完成哈希计算并获取结果 + return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); // 转换为十六进制字符串 + } + + /// + /// 默认的 SM4 对称加密使用的密钥和初始化向量 (IV)。 + /// 注意:在实际应用中应从安全的地方加载这些值。 + /// + private static readonly string DefaultKey = "your-16-byte-key"; // 128 bits + private static readonly string DefaultIV = "your-16-byte-iv-"; // 128 bits + + /// + /// 使用 SM4 算法加密数据 + /// + /// 要加密的明文 + /// 16 字节的密钥 + /// 16 字节的初始化向量(IV) + /// 加密后的字节数组 + public byte[] EncryptSM4(string plainText, string? key=null, string? iv = null) + { + if (string.IsNullOrEmpty(key)) + key = DefaultKey; + if (string.IsNullOrEmpty(iv)) + iv = DefaultIV; + + // 将明文、密钥和 IV 转换为字节数组 + byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(plainText); + byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(key); + byte[] ivBytes = System.Text.Encoding.UTF8.GetBytes(iv); + + // 获取 SM4/CBC/PKCS7Padding 模式的加密引擎 + IBufferedCipher cipher = CipherUtilities.GetCipher("SM4/CBC/PKCS7Padding"); + + // 创建密钥参数 + KeyParameter keyParam = ParameterUtilities.CreateKeyParameter("SM4", keyBytes); + + // 创建包含密钥和 IV 的参数 + ParametersWithIV parameters = new ParametersWithIV(keyParam, ivBytes); + + // 初始化加密模式 + cipher.Init(true, parameters); + + // 执行加密操作并返回加密后的字节数组 + return cipher.DoFinal(inputBytes); + } + + /// + /// 使用 SM4 算法解密数据 + /// + /// 要解密的密文 + /// 16 字节的密钥 + /// 16 字节的初始化向量(IV) + /// 解密后的字节数组 + public byte[] DecryptSM4(byte[] cipherText, string? key=null, string? iv=null) + { + if (string.IsNullOrEmpty(key)) + key = DefaultKey; + if (string.IsNullOrEmpty(iv)) + iv = DefaultIV; + // 将密钥和 IV 转换为字节数组 + byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(key); + byte[] ivBytes = System.Text.Encoding.UTF8.GetBytes(iv); + + // 获取 SM4/CBC/PKCS7Padding 模式的解密引擎 + IBufferedCipher cipher = CipherUtilities.GetCipher("SM4/CBC/PKCS7Padding"); + + // 创建密钥参数 + KeyParameter keyParam = ParameterUtilities.CreateKeyParameter("SM4", keyBytes); + + // 创建包含密钥和 IV 的参数 + ParametersWithIV parameters = new ParametersWithIV(keyParam, ivBytes); + + // 初始化解密模式 + cipher.Init(false, parameters); + + // 执行解密操作并返回解密后的字节数组 + return cipher.DoFinal(cipherText); + } +} \ No newline at end of file diff --git a/API/Wood.Util/GlobalConstant.cs b/API/Wood.Util/GlobalConstant.cs new file mode 100644 index 0000000..fd0a430 --- /dev/null +++ b/API/Wood.Util/GlobalConstant.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class GlobalConstant + { + } +} diff --git a/API/Wood.Util/GlobalContext.cs b/API/Wood.Util/GlobalContext.cs new file mode 100644 index 0000000..9eb089c --- /dev/null +++ b/API/Wood.Util/GlobalContext.cs @@ -0,0 +1,84 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; +using System; +using System.Reflection; +using System.Text; +using Wood.Util.JwtAuthorization; + +namespace Wood.Util +{ + public class GlobalContext + { + /// + /// All registered service and class instance container. Which are used for dependency injection. + /// + public static IServiceCollection? Services { get; set; } + + /// + /// Configured service provider. + /// + public static IServiceProvider? ServiceProvider { get; set; } + /// + /// Configuration + /// + public static IConfiguration? Configuration { get; set; } + /// + /// HostingEnvironment + /// + public static IWebHostEnvironment? HostingEnvironment { get; set; } + + /// + /// 自定义系统配置信息 + /// + public static SystemConfig? SystemConfig { get; set; } + /// + /// JWT权限验证信息 + /// + public static JwtConfig? JwtConfig { get; set; } + + /// + /// 获取配置信息 + /// + /// 配置路径 + /// + public static string? GetConfig(string path) + { + return Configuration![path]?.ToString(); + } + /// + /// 用户信息 + /// + public static JwtUserInfo? UserInfo + { + get + { + var httpContextAccessor = ServiceProvider?.GetRequiredService(); + return httpContextAccessor?.UserInfo(); + } + } + public static string GetVersion() + { + Version version = Assembly.GetEntryAssembly()!.GetName().Version!; + return version.Major + "." + version.Minor; + } + + /// + /// 程序启动时,记录目录 + /// + /// + public static void LogWhenStart(IWebHostEnvironment env) + { + StringBuilder sb = new StringBuilder(); + sb.Append("程序启动"); + sb.Append(" |ContentRootPath:" + env.ContentRootPath); + sb.Append(" |WebRootPath:" + env.WebRootPath); + sb.Append(" |IsDevelopment:" + env.IsDevelopment()); + Log.Debug(sb.ToString()); + } + } +} diff --git a/API/Wood.Util/HttpHelper.cs b/API/Wood.Util/HttpHelper.cs new file mode 100644 index 0000000..c2f61a4 --- /dev/null +++ b/API/Wood.Util/HttpHelper.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +public class HttpHelper +{ + private static readonly HttpClient client = new HttpClient(); + + /// + /// 判断是否为 URL + /// + public static bool IsUrl(string url) + { + if (string.IsNullOrEmpty(url)) + return false; + + url = url.ToLower(); + return url.StartsWith("http://") || url.StartsWith("https://"); + } + + /// + /// 异步 GET 请求 + /// + public static async Task HttpGetAsync(string url, int timeout = 10 * 1000) + { + try + { + // 设置超时时间 + client.Timeout = TimeSpan.FromMilliseconds(timeout); + + HttpResponseMessage response = await client.GetAsync(url); + response.EnsureSuccessStatusCode(); + + string content = await response.Content.ReadAsStringAsync(); + return new HttpResponse(response.StatusCode, content); + } + catch (HttpRequestException ex) + { + Console.WriteLine($"GET Request Error: {ex.Message}"); + return new HttpResponse(HttpStatusCode.BadRequest, $"Error: {ex.Message}"); + } + catch (TaskCanceledException ex) + { + Console.WriteLine($"Request Timeout or Cancelled: {ex.Message}"); + return new HttpResponse(HttpStatusCode.RequestTimeout, "Request timed out."); + } + catch (Exception ex) + { + Console.WriteLine($"Unexpected Error: {ex.Message}"); + return new HttpResponse(HttpStatusCode.InternalServerError, $"Unexpected error: {ex.Message}"); + } + } + + /// + /// 异步 POST 请求 + /// + public static async Task HttpPostAsync(string postUrl, T postData, string contentType = "application/json", int timeout = 10 * 1000) + { + try + { + // 设置超时时间 + client.Timeout = TimeSpan.FromMilliseconds(timeout); + + string jsonContent = JsonConvert.SerializeObject(postData); + var content = new StringContent(jsonContent, Encoding.UTF8, contentType); + + HttpResponseMessage response = await client.PostAsync(postUrl, content); + response.EnsureSuccessStatusCode(); + + string responseBody = await response.Content.ReadAsStringAsync(); + return new HttpResponse(response.StatusCode, responseBody); + } + catch (HttpRequestException ex) + { + Console.WriteLine($"POST Request Error: {ex.Message}"); + return new HttpResponse(HttpStatusCode.BadRequest, $"Error: {ex.Message}"); + } + catch (TaskCanceledException ex) + { + Console.WriteLine($"Request Timeout or Cancelled: {ex.Message}"); + return new HttpResponse(HttpStatusCode.RequestTimeout, "Request timed out."); + } + catch (Exception ex) + { + Console.WriteLine($"Unexpected Error: {ex.Message}"); + return new HttpResponse(HttpStatusCode.InternalServerError, $"Unexpected error: {ex.Message}"); + } + } + + /// + /// 根据传入的数据,得到相应页面数据(适用于复杂的 HTTP 请求) + /// + public static async Task GetHttpRequestDataAsync(HttpItem httpItem) + { + using (var requestMessage = new HttpRequestMessage()) + { + try + { + // 设置请求方法 + requestMessage.Method = new HttpMethod(httpItem.Method); + requestMessage.RequestUri = new Uri(GetUrl(httpItem.URL)); + + // 设置请求头 + foreach (var header in httpItem.Headers ?? Array.Empty>()) + { + requestMessage.Headers.Add(header.Key, header.Value); + } + + // 设置内容类型 + if (!string.IsNullOrEmpty(httpItem.ContentType)) + { + requestMessage.Content = new StringContent(httpItem.Postdata!, Encoding.UTF8, httpItem.ContentType); + } + + // 设置 Cookie + if (!string.IsNullOrEmpty(httpItem.Cookie)) + { + requestMessage.Headers.Add("Cookie", httpItem.Cookie); + } + + // 发送请求并获取响应 + HttpResponseMessage response = await client.SendAsync(requestMessage); + response.EnsureSuccessStatusCode(); + + string content = await response.Content.ReadAsStringAsync(); + return new HttpResponse(response.StatusCode, content); + } + catch (Exception ex) + { + Console.WriteLine($"Request Error: {ex.Message}"); + return new HttpResponse(HttpStatusCode.InternalServerError, $"Error: {ex.Message}"); + } + } + } + + /// + /// 确保 URL 包含协议前缀 + /// + private static string GetUrl(string url) + { + if (!(url.Contains("http://") || url.Contains("https://"))) + { + url = "http://" + url; + } + return url; + } +} + +/// +/// HTTP 响应结果类 +/// +public class HttpResponse +{ + public HttpStatusCode StatusCode { get; set; } + public string Content { get; set; } + + public HttpResponse(HttpStatusCode statusCode, string content) + { + StatusCode = statusCode; + Content = content; + } +} + +/// +/// HTTP 请求项类 +/// +public class HttpItem +{ + public string URL { get; set; } = ""; + public string Method { get; set; } = "GET"; + public int Timeout { get; set; } = 10000; + public string ContentType { get; set; } = "application/json"; + public string? Postdata { get; set; } + public string? Cookie { get; set; } + public KeyValuePair[] Headers { get; set; }=new KeyValuePair[0]; +} \ No newline at end of file diff --git a/API/Wood.Util/IdGeneratorHelper.cs b/API/Wood.Util/IdGeneratorHelper.cs new file mode 100644 index 0000000..e5d9dc7 --- /dev/null +++ b/API/Wood.Util/IdGeneratorHelper.cs @@ -0,0 +1,68 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Util; + +namespace Wood.Util +{ + /// + /// 生成数据库主键Id + /// + public class IdGeneratorHelper + { + //private int SnowFlakeWorkerId = GlobalContext.SystemConfig!.SnowFlakeWorkerId; + + //private Snowflake snowflake; + + private static readonly IdGeneratorHelper instance = new IdGeneratorHelper(); + + private IdGeneratorHelper() + { + //snowflake = new Snowflake(SnowFlakeWorkerId, 0, 0); + } + + public static IdGeneratorHelper Instance + { + get + { + return instance; + } + } + /// + /// 雪花id + /// + /// + public long GetId() + { + return SnowFlakeSingle.Instance.NextId(); + } + /// + /// Guid + /// format + /// N - 32 个数字,没有分隔符 + /// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + /// D - 使用连字符 (hyphen) 分隔的 32 个数字 + /// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + /// B - 使用大括号包围的 D 格式 + /// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + /// P - 使用圆括号包围的 D 格式 + /// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) + /// X - 使用大括号包围的 X 格式,与 B 类似但每个十六进制值都用大写表示,并且在每组之间添加空格 + /// {0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX} + /// Y - 使用大括号包围的 D 格式,但在第三组前添加 "4-" 和 "8-" 前缀以指示版本和变体信息 + /// {xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx} + /// + /// + public string GetGuid(string format="") + { + if(string.IsNullOrEmpty(format)) + { + return Guid.NewGuid().ToString().ToUpper(); + } + return Guid.NewGuid().ToString(format).ToUpper(); + } + } +} diff --git a/API/Wood.Util/JsonConvert/DateOnlyConverter.cs b/API/Wood.Util/JsonConvert/DateOnlyConverter.cs new file mode 100644 index 0000000..9cc9559 --- /dev/null +++ b/API/Wood.Util/JsonConvert/DateOnlyConverter.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class DateOnlyConverter:JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(DateTime) || objectType == typeof(DateTime?); + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + if ((reader.Value == null || reader.Value.ToString() == "") && objectType.IsNullableType()) + return null; + return Convert.ToDateTime(reader.Value).Date; + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value == null) + { + writer.WriteNull(); + return; + } + DateTime? dt = value as DateTime?; + if (dt == null) + { + writer.WriteNull(); + return; + } + writer.WriteValue(dt.Value.ToString("yyyy-MM-dd")); + } + } +} diff --git a/API/Wood.Util/JsonConvert/LongToStringJsonConverter.cs b/API/Wood.Util/JsonConvert/LongToStringJsonConverter.cs new file mode 100644 index 0000000..b0015ac --- /dev/null +++ b/API/Wood.Util/JsonConvert/LongToStringJsonConverter.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class LongToStringJsonConverter : JsonConverter + { + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + /// + public override long ReadJson(JsonReader reader, Type objectType, long existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var jt = JValue.ReadFrom(reader); + return jt?.ToString()?.ToLong()??0; + } + + /// + /// 序列化 + /// + /// + /// + /// + public override void WriteJson(JsonWriter writer, long value, JsonSerializer serializer) + { + serializer.Serialize(writer, value.ToString()); + } + } +} diff --git a/API/Wood.Util/JsonConvert/NullableIntConverter.cs b/API/Wood.Util/JsonConvert/NullableIntConverter.cs new file mode 100644 index 0000000..29a2296 --- /dev/null +++ b/API/Wood.Util/JsonConvert/NullableIntConverter.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class NullableIntConverter: JsonConverter + { + public override int? ReadJson(JsonReader reader, Type objectType, int? existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if ((reader.Value == null || reader.Value.ToString() == "")) + return 0; + + return Convert.ToInt32(reader.Value); + } + + public override void WriteJson(JsonWriter writer, int? value, JsonSerializer serializer) + { + writer.WriteValue(value); + } + } +} diff --git a/API/Wood.Util/JsonConvert/NullableLongToStringJsonConverter.cs b/API/Wood.Util/JsonConvert/NullableLongToStringJsonConverter.cs new file mode 100644 index 0000000..289d7e7 --- /dev/null +++ b/API/Wood.Util/JsonConvert/NullableLongToStringJsonConverter.cs @@ -0,0 +1,44 @@ +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util +{ + public class NullableLongToStringJsonConverter : JsonConverter + { + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + /// + public override long? ReadJson(JsonReader reader, Type objectType, long? existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var jt = JValue.ReadFrom(reader); + if (jt.IsEmpty()) + return null; + return jt.Value(); + } + + /// + /// 序列化 + /// + /// + /// + /// + public override void WriteJson(JsonWriter writer, long? value, JsonSerializer serializer) + { + if(value==0) + serializer.Serialize(writer, null); + else + serializer.Serialize(writer, value?.ToString()); + } + } +} diff --git a/API/Wood.Util/JsonHelper.cs b/API/Wood.Util/JsonHelper.cs new file mode 100644 index 0000000..c2e721d --- /dev/null +++ b/API/Wood.Util/JsonHelper.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; + +namespace Wood.Util +{ + #region JsonHelper + public static class JsonHelper + { + public static T? ToObject(this string Json) + { + Json = Json.Replace(" ", ""); + return Json == null ? default(T) : Newtonsoft.Json.JsonConvert.DeserializeObject(Json); + } + + public static JObject ToJObject(this string Json) + { + return Json == null ? JObject.Parse("{}") : JObject.Parse(Json.Replace(" ", "")); + } + + public static JArray ToJArray(this string Json) + { + return Json == null ? JArray.Parse("[]") : JArray.Parse(Json.Replace(" ", "")); + } + + public static string ToJson(this object obj) + { + return obj == null ? string.Empty: Newtonsoft.Json.JsonConvert.SerializeObject(obj); + } + } + #endregion +} diff --git a/API/Wood.Util/JwtAuthorization/HttpContextExtension.cs b/API/Wood.Util/JwtAuthorization/HttpContextExtension.cs new file mode 100644 index 0000000..16ef97d --- /dev/null +++ b/API/Wood.Util/JwtAuthorization/HttpContextExtension.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util.JwtAuthorization +{ + public static class HttpContextExtension + { + public static JwtUserInfo? UserInfo(this IHttpContextAccessor httpContextAccessor) + { + if (httpContextAccessor?.HttpContext?.User != null) + { + return httpContextAccessor.HttpContext.UserInfo(); + } + return null; + } + + + public static JwtUserInfo? UserInfo(this HttpContext httpContext) + { + if (httpContext?.User != null) + { + if (httpContext.User.Claims.Any()) + { + var claims = httpContext.User.Claims; + JwtUserInfo info = new JwtUserInfo(); + info.RealName = claims.First(it => it.Type == nameof(info.RealName)).Value; + info.UserName = claims.First(it => it.Type == nameof(info.UserName)).Value; + info.UserId = claims.First(it => it.Type == nameof(info.UserId)).Value.ToLong(); + info.AccountType = claims.First(it => it.Type == nameof(info.AccountType)).Value.ToInt(); + info.NickName = claims.First(it => it.Type == nameof(info.NickName)).Value; + info.OrgId = claims.First(it => it.Type == nameof(info.OrgId)).Value.ToLong(); + info.TenantId = claims.First(it => it.Type == nameof(info.TenantId)).Value.ToLong(); + return info; + } + } + return null; + } + + public static JwtUserInfo? UserInfo(this ControllerBase controllerBase) + { + if (controllerBase?.HttpContext != null) + { + return controllerBase?.HttpContext.UserInfo(); + } + return null; + } + } +} diff --git a/API/Wood.Util/JwtAuthorization/JwtHelper.cs b/API/Wood.Util/JwtAuthorization/JwtHelper.cs new file mode 100644 index 0000000..3683fe5 --- /dev/null +++ b/API/Wood.Util/JwtAuthorization/JwtHelper.cs @@ -0,0 +1,80 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; + +namespace Wood.Util.JwtAuthorization +{ + public class JwtHelper + { + /// + /// 创建jwtToken + /// + /// + /// + public JwtToken CreateToken(JwtUserInfo info) + { + // 1. 定义需要使用到的Claims + var claims = new[] + { + new Claim(nameof(info.RealName), info.RealName!), //HttpContext.User.Identity.Name + new Claim(nameof(info.NickName), info.NickName!), + new Claim(nameof(info.UserName), info.UserName!), + new Claim(nameof(info.OrgId), info.OrgId.ToString()), + new Claim(nameof(info.UserId), info.UserId.ToString()), + new Claim(nameof(info.AccountType), ((int)info.AccountType).ToString()), + new Claim(nameof(info.TenantId), info.TenantId.ToString()) + }; + + // 2. 从 appsettings.json 中读取SecretKey + var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(GlobalContext.JwtConfig!.SecretKey!)); + + // 3. 选择加密算法 + var algorithm = SecurityAlgorithms.HmacSha256; + + // 4. 生成Credentials + var signingCredentials = new SigningCredentials(secretKey, algorithm); + + // 5. 根据以上,生成token + var tokenExpiresTime = DateTime.Now.AddMinutes(GlobalContext.JwtConfig!.TokenExpire); + var jwtSecurityToken = new JwtSecurityToken( + GlobalContext.JwtConfig!.Issuer!, //Issuer + GlobalContext.JwtConfig!.Audience!, //Audience + claims, //Claims, + DateTime.Now, //notBefore + tokenExpiresTime, //expires + signingCredentials //Credentials + ); + + // 6. 将token变为string + var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken); + var refreshToken = GenerateRefreshToken(); + return new JwtToken() + { + Token = token, + RefreshToken = refreshToken, + TokenExpiresTime= tokenExpiresTime, + IssuedAt=DateTime.Now, + RefreshTokenExpiresTime = DateTime.Now.AddDays(GlobalContext.JwtConfig.RefreshTokenExpire), + Issuer= GlobalContext.JwtConfig!.Issuer!, + Audience= GlobalContext.JwtConfig!.Audience! + }; + } + + /// + /// 生成 refreshToken + /// + /// + private string GenerateRefreshToken() + { + var randomNumber = new byte[32]; + using (var rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(randomNumber); + return Convert.ToBase64String(randomNumber); + } + } + } +} diff --git a/API/Wood.Util/JwtAuthorization/JwtToken.cs b/API/Wood.Util/JwtAuthorization/JwtToken.cs new file mode 100644 index 0000000..c02598b --- /dev/null +++ b/API/Wood.Util/JwtAuthorization/JwtToken.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util.JwtAuthorization +{ + public class JwtToken + { + public string? Token { get; set; } + public string? RefreshToken { get; set; } + /// + /// Token 过期时间 + /// + public DateTime TokenExpiresTime { get; internal set; } + /// + /// RefreshToken过期时间 + /// + public DateTime RefreshTokenExpiresTime { get; internal set; } + /// + /// 签发时间 + /// + public DateTime IssuedAt { get; set; } + /// + /// 发行者 + /// + public string? Issuer { get; internal set; } + /// + /// 订阅者 + /// + public string? Audience { get; internal set; } + } +} diff --git a/API/Wood.Util/JwtAuthorization/JwtUserInfo.cs b/API/Wood.Util/JwtAuthorization/JwtUserInfo.cs new file mode 100644 index 0000000..ca017dd --- /dev/null +++ b/API/Wood.Util/JwtAuthorization/JwtUserInfo.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util.JwtAuthorization +{ + /// + /// jwt信息 + /// + public class JwtUserInfo + { + /// + /// 用户id + /// + public long UserId { get; set; } = 0; + /// + /// 租户 + /// + public long TenantId { get; set; } = 0; + /// + /// 账号 + /// + public string? UserName { get; set; } + /// + /// 姓名 + /// + public string? RealName { get; set; } + /// + /// 姓名 + /// + public string? NickName { get; set; } + + /// + /// 机构id + /// + public long OrgId { get; set; } + + /// + /// 用户类型 + /// 9999 超级管理员 + /// 991 租管 + /// 9 管理员 + /// 0 用户 + /// AccountTypeEnum 对应的 int值 + /// + public int AccountType { get; set; } + + /// + /// 是否管理员 + /// + public bool IsAdmin + { + get + { + return AccountType == 9|| IsTenantAdmin|| IsSuperAdmin; + } + } + + /// + /// 是否租户管理员 + /// + public bool IsTenantAdmin + { + get + { + return AccountType == 991|| IsSuperAdmin; + } + } + + /// + /// 是否超级管理员 + /// + public bool IsSuperAdmin + { + get + { + return AccountType == 9999; + } + } + + public string CacheKey + { + get + { + return UserId + "-" + TenantId; + } + } + } +} diff --git a/API/Wood.Util/NetHelper.cs b/API/Wood.Util/NetHelper.cs new file mode 100644 index 0000000..946c49d --- /dev/null +++ b/API/Wood.Util/NetHelper.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using Wood.Util.Browser; + +namespace Wood.Util +{ + public class NetHelper + { + private static HttpContext HttpContext + { + get { return GlobalContext.ServiceProvider?.GetService()!.HttpContext!; } + } + + public static string Ip + { + get + { + string result = string.Empty; + if (HttpContext != null) + { + result = GetWebClientIp(); + } + if (string.IsNullOrEmpty(result)) + { + result = GetLanIp(); + } + return result; + } + } + + private static string GetWebClientIp() + { + try + { + string ip = GetWebRemoteIp(); + foreach (var hostAddress in Dns.GetHostAddresses(ip)) + { + if (hostAddress.AddressFamily == AddressFamily.InterNetwork) + { + return hostAddress.ToString(); + } + } + } + catch (Exception ex) + { + Log.Error(ex,"获取IP失败!"); + } + return string.Empty; + } + + public static string GetLanIp() + { + try + { + foreach (var hostAddress in Dns.GetHostAddresses(Dns.GetHostName())) + { + if (hostAddress.AddressFamily == AddressFamily.InterNetwork) + { + return hostAddress.ToString(); + } + } + } + catch (Exception ex) + { + Log.Error(ex, "获取LanIP失败!"); + } + return string.Empty; + } + + + + private static string GetWebRemoteIp() + { + try + { + string? ip = HttpContext?.Connection?.RemoteIpAddress?.ToString(); + if (HttpContext != null && HttpContext.Request != null) + { + if (HttpContext.Request.Headers.ContainsKey("X-Real-IP")) + { + ip = HttpContext.Request.Headers["X-Real-IP"].ToString(); + } + + if (HttpContext.Request.Headers.ContainsKey("X-Forwarded-For")) + { + ip = HttpContext.Request.Headers["X-Forwarded-For"].ToString(); + } + } + return ip??""; + } + catch (Exception ex) + { + Log.Error(ex, "获取客户端远程IP失败!"); + } + return string.Empty; + } + + public static string Browser + { + get + { + try + { + var browser = HttpContext.Request.Headers["User-Agent"]; + var agent = UserAgent.ToString(); + return BrowserHelper.GetBrwoserInfo(agent); + } + catch (Exception ex) + { + Log.Error(ex, "获取端远程浏览器信息失败!"); + } + return string.Empty; + } + } + + public static string UserAgent + { + get + { + string? userAgent = string.Empty; + try + { + userAgent = HttpContext?.Request?.Headers["User-Agent"]; + } + catch (Exception ex) + { + Log.Error(ex, "获取端远程浏览器【User-Agent】失败!"); + } + return userAgent??string.Empty; + } + } + + #region 判断是否是外网IP + public static bool IsInnerIP(string ipAddress) + { + bool isInnerIp = false; + long ipNum = GetIpNum(ipAddress); + /** + 私有IP:A类 10.0.0.0-10.255.255.255 + B类 172.16.0.0-172.31.255.255 + C类 192.168.0.0-192.168.255.255 + 当然,还有127这个网段是环回地址 + **/ + long aBegin = GetIpNum("10.0.0.0"); + long aEnd = GetIpNum("10.255.255.255"); + long bBegin = GetIpNum("172.16.0.0"); + long bEnd = GetIpNum("172.31.255.255"); + long cBegin = GetIpNum("192.168.0.0"); + long cEnd = GetIpNum("192.168.255.255"); + isInnerIp = IsInner(ipNum, aBegin, aEnd) || IsInner(ipNum, bBegin, bEnd) || IsInner(ipNum, cBegin, cEnd) || ipAddress.Equals("127.0.0.1"); + return isInnerIp; + } + + /// + /// 把IP地址转换为Long型数字 + /// + /// IP地址字符串 + /// + private static long GetIpNum(string ipAddress) + { + string[] ip = ipAddress.Split('.'); + long a = int.Parse(ip[0]); + long b = int.Parse(ip[1]); + long c = int.Parse(ip[2]); + long d = int.Parse(ip[3]); + + long ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d; + return ipNum; + } + + private static bool IsInner(long userIp, long begin, long end) + { + return (userIp >= begin) && (userIp <= end); + } + #endregion + + public static string GetOSVersion() + { + var osVersion = string.Empty; + try + { + var userAgent = UserAgent; + if (userAgent.Contains("NT 10")) + { + osVersion = "Windows 10"; + } + else if (userAgent.Contains("NT 6.3")) + { + osVersion = "Windows 8"; + } + else if (userAgent.Contains("NT 6.1")) + { + osVersion = "Windows 7"; + } + else if (userAgent.Contains("NT 6.0")) + { + osVersion = "Windows Vista/Server 2008"; + } + else if (userAgent.Contains("NT 5.2")) + { + osVersion = "Windows Server 2003"; + } + else if (userAgent.Contains("NT 5.1")) + { + osVersion = "Windows XP"; + } + else if (userAgent.Contains("NT 5")) + { + osVersion = "Windows 2000"; + } + else if (userAgent.Contains("NT 4")) + { + osVersion = "Windows NT4"; + } + else if (userAgent.Contains("Android")) + { + osVersion = "Android"; + } + else if (userAgent.Contains("Me")) + { + osVersion = "Windows Me"; + } + else if (userAgent.Contains("98")) + { + osVersion = "Windows 98"; + } + else if (userAgent.Contains("95")) + { + osVersion = "Windows 95"; + } + else if (userAgent.Contains("Mac")) + { + osVersion = "Mac"; + } + else if (userAgent.Contains("Unix")) + { + osVersion = "UNIX"; + } + else if (userAgent.Contains("Linux")) + { + osVersion = "Linux"; + } + else if (userAgent.Contains("SunOS")) + { + osVersion = "SunOS"; + } + } + catch (Exception ex) + { + Log.Error(ex, "获取OS版本信息失败!"); + } + return osVersion; + } + } +} diff --git a/API/Wood.Util/ReflectionHelper.cs b/API/Wood.Util/ReflectionHelper.cs new file mode 100644 index 0000000..ddac90d --- /dev/null +++ b/API/Wood.Util/ReflectionHelper.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; + +namespace Wood.Util +{ + public class ReflectionHelper + { + private static ConcurrentDictionary dictCache = new ConcurrentDictionary(); + + #region 得到类里面的属性集合 + /// + /// 得到类里面的属性集合 + /// + /// + /// + /// + public static PropertyInfo[]? GetProperties(Type type, string[]? columns = null) + { + if(string.IsNullOrEmpty(type.FullName)) + return null; + PropertyInfo[]? properties = null; + if (dictCache.ContainsKey(type.FullName)) + { + properties = dictCache[type.FullName] as PropertyInfo[]; + } + else + { + properties = type.GetProperties(); + dictCache.TryAdd(type.FullName, properties); + } + + if (columns != null && columns.Length > 0) + { + // 按columns顺序返回属性 + var columnPropertyList = new List(); + foreach (var column in columns) + { + var columnProperty = properties?.Where(p => p.Name == column).FirstOrDefault(); + if (columnProperty != null) + { + columnPropertyList.Add(columnProperty); + } + } + return columnPropertyList.ToArray(); + } + else + { + return properties; + } + } + #endregion + } +} diff --git a/API/Wood.Util/ShellHelper.cs b/API/Wood.Util/ShellHelper.cs new file mode 100644 index 0000000..429def4 --- /dev/null +++ b/API/Wood.Util/ShellHelper.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Wood.Util +{ + public class ShellHelper + { + public static string Bash(string command) + { + var escapedArgs = command.Replace("\"", "\\\""); + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{escapedArgs}\"", + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + process.Start(); + string result = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + process.Dispose(); + return result; + } + + public static string? Cmd(string fileName, string args) + { + string? output = string.Empty; + + var info = new ProcessStartInfo(); + info.FileName = fileName; + info.Arguments = args; + info.RedirectStandardOutput = true; + + using (var process = Process.Start(info)) + { + output = process?.StandardOutput.ReadToEnd(); + } + return output; + } + } +} diff --git a/API/Wood.Util/Snowflake.cs b/API/Wood.Util/Snowflake.cs new file mode 100644 index 0000000..e1ee404 --- /dev/null +++ b/API/Wood.Util/Snowflake.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Wood.Util; + +namespace Wood.Util +{ + /// + /// 雪花id + /// + public class Snowflake + { + private const long TwEpoch = 1546272000000L;//2019-01-01 00:00:00 + + private const int WorkerIdBits = 5; + private const int DatacenterIdBits = 5; + private const int SequenceBits = 12; + private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits); + private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits); + + private const int WorkerIdShift = SequenceBits; + private const int DatacenterIdShift = SequenceBits + WorkerIdBits; + private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits; + private const long SequenceMask = -1L ^ (-1L << SequenceBits); + + private long _sequence = 0L; + private long _lastTimestamp = -1L; + /// + ///10位的数据机器位中的高位 + /// + public long WorkerId { get; protected set; } + /// + /// 10位的数据机器位中的低位 + /// + public long DatacenterId { get; protected set; } + + private readonly object _lock = new object(); + /// + /// 基于Twitter的snowflake算法 + /// + /// 10位的数据机器位中的高位,默认不应该超过5位(5byte) + /// 10位的数据机器位中的低位,默认不应该超过5位(5byte) + /// 初始序列 + public Snowflake(long workerId, long datacenterId, long sequence = 0L) + { + WorkerId = workerId; + DatacenterId = datacenterId; + _sequence = sequence; + + if (workerId > MaxWorkerId || workerId < 0) + { + throw new ArgumentException($"worker Id can't be greater than {MaxWorkerId} or less than 0"); + } + + if (datacenterId > MaxDatacenterId || datacenterId < 0) + { + throw new ArgumentException($"datacenter Id can't be greater than {MaxDatacenterId} or less than 0"); + } + } + + public long CurrentId { get; private set; } + + /// + /// 获取下一个Id,该方法线程安全 + /// + /// + public long NextId() + { + lock (_lock) + { + var timestamp = DateTimeHelper.GetUnixTimeStamp(DateTime.Now); + if (timestamp < _lastTimestamp) + { + //TODO 是否可以考虑直接等待? + throw new Exception( + $"Clock moved backwards or wrapped around. Refusing to generate id for {_lastTimestamp - timestamp} ticks"); + } + + if (_lastTimestamp == timestamp) + { + _sequence = (_sequence + 1) & SequenceMask; + if (_sequence == 0) + { + timestamp = TilNextMillis(_lastTimestamp); + } + } + else + { + _sequence = 0; + } + _lastTimestamp = timestamp; + CurrentId = ((timestamp - TwEpoch) << TimestampLeftShift) | + (DatacenterId << DatacenterIdShift) | + (WorkerId << WorkerIdShift) | _sequence; + + return CurrentId; + } + } + + private long TilNextMillis(long lastTimestamp) + { + var timestamp = DateTimeHelper.GetUnixTimeStamp(DateTime.Now); + while (timestamp <= lastTimestamp) + { + timestamp = DateTimeHelper.GetUnixTimeStamp(DateTime.Now); + } + return timestamp; + } + } +} diff --git a/API/Wood.Util/TextHelper.cs b/API/Wood.Util/TextHelper.cs new file mode 100644 index 0000000..88b0dfc --- /dev/null +++ b/API/Wood.Util/TextHelper.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Wood.Util +{ + public class TextHelper + { + /// + /// 获取默认值 + /// + /// + /// + /// + public static string GetCustomValue(string value, string defaultValue) + { + if (string.IsNullOrEmpty(value)) + { + return defaultValue; + } + else + { + return value; + } + } + + /// + /// 截取指定长度的字符串 + /// + /// + /// + /// + public static string GetSubString(string value, int length, bool ellipsis = false) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + if (value.Length > length) + { + value = value.Substring(0, length); + if (ellipsis) + { + value += "..."; + } + } + return value; + } + + /// + /// 字符串转指定类型数组 + /// + /// + /// + /// + public static T[] SplitToArray(string value, char split) + { + T[] arr = value.Split(new string[] { split.ToString() }, StringSplitOptions.RemoveEmptyEntries).CastSuper().ToArray(); + return arr; + } + } +} diff --git a/API/Wood.Util/Validations/ChineseOnlyAttribute.cs b/API/Wood.Util/Validations/ChineseOnlyAttribute.cs new file mode 100644 index 0000000..67fd00c --- /dev/null +++ b/API/Wood.Util/Validations/ChineseOnlyAttribute.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wood.Util.Validations +{ + /// + /// 中文验证 + /// + public class ChineseOnlyAttribute : ValidationAttribute + { + public override bool IsValid(object? value) + { + if (value == null) + return false; + + var str = value.ToString(); + + return ValidatorHelper.IsOnlyChinese(str!); + } + } +} diff --git a/API/Wood.Util/Validations/UniqueValueAttribute.cs b/API/Wood.Util/Validations/UniqueValueAttribute.cs new file mode 100644 index 0000000..142ba5c --- /dev/null +++ b/API/Wood.Util/Validations/UniqueValueAttribute.cs @@ -0,0 +1,127 @@ +using Microsoft.Extensions.DependencyInjection; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Wood.Util; + +namespace WoodWood.Util.Validations +{ + /// + /// 数据库中 唯一值验证 + /// null 和 "" 不会进行验证 + /// + public class UniqueValueAttribute : ValidationAttribute + { + /// + /// 字段名称,留空取当前 + /// + public string? PropertyName { get; set; } + /// + /// 实体,留空取当前 + /// + public Type? EntityType { get; set; } + + /// + /// + /// + /// + /// + /// + protected override ValidationResult IsValid(object? value, ValidationContext validationContext) + { + if (value == null|| string.IsNullOrEmpty(value.ToString())) + return ValidationResult.Success!; + + var serviceProvider = validationContext.GetService(typeof(IServiceProvider)) as IServiceProvider; + if (serviceProvider == null) + return new ValidationResult($"[{validationContext.MemberName}]无法获取服务提供者!"); + + // 获取 ISqlSugarClient 实例 + var sqlClient = serviceProvider!.GetRequiredService(); + if (sqlClient == null) + return new ValidationResult($"[{validationContext.MemberName}]无法获取 ISqlSugarClient!"); + + string sqlTable = ""; + bool hasTenantFilter = false; + bool hasDeletedFilter = false; + string sqlProperty = ""; + Type sqlPropertyType; + //字段名 + if (string.IsNullOrEmpty(PropertyName)) + // 获取成员名称(属性名) + sqlProperty = validationContext.MemberName ?? ""; + else + sqlProperty = PropertyName; + Type sqlType; + //表明 + if (EntityType == null) + sqlType = validationContext.ObjectType; + else + sqlType = EntityType; + + // 获取类上的所有自定义特性,包括继承的特性 + var classAttributes = sqlType.GetCustomAttributes(true); + // 如果你知道具体要查找的特性类型,可以直接获取它 + var sugarTable = Attribute.GetCustomAttribute(sqlType, typeof(SugarTable)) as SugarTable; + if (sugarTable == null) + return new ValidationResult($"[{validationContext.MemberName}]无法识别SugarTable表信息!"); + sqlTable = sugarTable.TableName; + + // 假设我们要检查 实体是否有 租户过滤特性 + hasTenantFilter = sqlType.GetInterfaces().Any(it => it.Name == "ITenantIdFilter"); + + // 假设我们要检查 实体是否有 软删除过滤特性 + hasDeletedFilter = sqlType.GetInterfaces().Any(it => it.Name == "IDeletedFilter"); + + //字段类型 + sqlPropertyType = sqlType.GetProperty(sqlProperty)!.PropertyType; + + // 获取当前对象实例及其主键值 + var propertyInfo = validationContext.ObjectType.GetProperty("Id"); + var primaryKeyValue = propertyInfo?.GetValue(validationContext.ObjectInstance); + long idVal = 0; + if (primaryKeyValue == null) + return new ValidationResult($"[{validationContext.MemberName}]无法识别主键信息!"); + else + idVal = primaryKeyValue.ToString()!.ToLong(); + + string sql = $"select count(id) from {sqlTable} where "; + + if (sqlPropertyType == typeof(string)) + sql += $"{sqlProperty}='{value.ToString()}'"; + else if (sqlPropertyType == typeof(int)) + sql += $"{sqlProperty}={value}"; + else if (sqlPropertyType == typeof(long)) + sql += $"{sqlProperty}={value}"; + else + return new ValidationResult($"[{validationContext.MemberName}]不支持的字段类型,只支持【string,int,long】!"); + + if (idVal > 0) + sql += $" and Id != {idVal}"; + + var userInfo = GlobalContext.UserInfo; + if (hasTenantFilter) + if (userInfo == null) + return new ValidationResult($"[{validationContext.MemberName}]没有找到租户信息!"); + else + if(!userInfo.IsSuperAdmin) + sql += $" and Tenantid={userInfo.TenantId}"; + + + if (hasDeletedFilter) + sql += $" and IsDelete=0"; + + var res = sqlClient.Ado.SqlQuerySingle(sql); + if (res > 0) + return new ValidationResult(!string.IsNullOrEmpty(ErrorMessage) ? ErrorMessage : $"该{validationContext.MemberName}已存在,请输入其他值。"); + + // 执行同步验证逻辑 + return ValidationResult.Success!; + } + } +} diff --git a/API/Wood.Util/Validations/ValidatorHelper.cs b/API/Wood.Util/Validations/ValidatorHelper.cs new file mode 100644 index 0000000..faf54ea --- /dev/null +++ b/API/Wood.Util/Validations/ValidatorHelper.cs @@ -0,0 +1,350 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Wood.Util.Validations +{ + public static class ValidatorHelper + { + #region 验证输入字符串为数字(带小数) + /// + /// 验证输入字符串为带小数点正数 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsNumber(this string str) + { + return Regex.IsMatch(str, "^([0]|([1-9]+\\d{0,}?))(.[\\d]+)?$"); + } + /// + /// 验证输入字符串为带小数点正负数 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsNumberic(this string str) + { + return Regex.IsMatch(str, "^-?\\d+$|^(-?\\d+)(\\.\\d+)?$"); + } + #endregion + + #region 验证中国电话格式是否有效,格式010-85849685 + /// + /// 验证中国电话格式是否有效,格式010-85849685 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsTel(this string str) + { + return Regex.IsMatch(str, @"^(0[0-9]{2,3}\-)?([2-9][0-9]{6,7})+(\-[0-9]{1,4})?$", RegexOptions.IgnoreCase); + } + #endregion + + #region 验证输入字符串为电话号码 + /// + /// 验证输入字符串为电话号码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsPhone(this string str) + { + return Regex.IsMatch(str, @"(^(\d{2,4}[-_-—]?)?\d{3,8}([-_-—]?\d{3,8})?([-_-—]?\d{1,7})?$)|(^0?1[35]\d{9}$)"); + //弱一点的验证: @"\d{3,4}-\d{7,8}" + } + #endregion + + #region 验证是否是有效传真号码 + /// + /// 验证是否是有效传真号码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsFax(this string str) + { + return Regex.IsMatch(str, @"^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$"); + } + #endregion + + #region 验证手机号是否合法 + /// + /// 验证手机号是否合法 号段为13,14,15,16,17,18,19 0,86开头将自动识别 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsMobile(this string str) + { + if (!str.StartsWith("1")) + { + str = str.TrimStart(new char[] { '8', '6', }).TrimStart('0'); + } + return Regex.IsMatch(str, @"^(13|14|15|16|17|18|19)\d{9}$"); + } + #endregion + + #region 验证身份证是否有效 + /// + /// 验证身份证是否有效 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsIDCard(this string str) + { + switch (str.Length) + { + case 18: + { + return str.IsIDCard18(); + } + case 15: + { + return str.IsIDCard15(); + } + default: + return false; + } + } + + /// + /// 验证输入字符串为18位的身份证号码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsIDCard18(this string str) + { + long n = 0; + if (long.TryParse(str.Remove(17), out n) == false || n < Math.Pow(10, 16) || long.TryParse(str.Replace('x', '0').Replace('X', '0'), out n) == false) + { + return false;//数字验证 + } + const string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91"; + if (address.IndexOf(str.Remove(2), StringComparison.Ordinal) == -1) + { + return false;//省份验证 + } + string birth = str.Substring(6, 8).Insert(6, "-").Insert(4, "-"); + DateTime time; + if (DateTime.TryParse(birth, out time) == false) + { + return false;//生日验证 + } + string[] arrVarifyCode = "1,0,x,9,8,7,6,5,4,3,2".Split(','); + string[] wi = "7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2".Split(','); + char[] ai = str.Remove(17).ToCharArray(); + int sum = 0; + for (int i = 0; i < 17; i++) + { + sum += int.Parse(wi[i]) * int.Parse(ai[i].ToString()); + } + int y = -1; + Math.DivRem(sum, 11, out y); + return arrVarifyCode[y] == str.Substring(17, 1).ToLower(); + } + /// + /// 验证输入字符串为15位的身份证号码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsIDCard15(this string str) + { + long n = 0; + if (long.TryParse(str, out n) == false || n < Math.Pow(10, 14)) + { + return false;//数字验证 + } + const string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91"; + if (address.IndexOf(str.Remove(2), StringComparison.Ordinal) == -1) + { + return false;//省份验证 + } + string birth = str.Substring(6, 6).Insert(4, "-").Insert(2, "-"); + DateTime time; + return DateTime.TryParse(birth, out time) != false; + } + #endregion + + #region 验证是否是有效邮箱地址 + /// + /// 验证是否是有效邮箱地址 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsEmail(this string str) + { + return Regex.IsMatch(str, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"); + } + #endregion + + #region 验证是否只含有汉字 + /// + /// 验证是否只含有汉字 + /// + /// 输入字符 + /// + public static bool IsOnlyChinese(this string strln) + { + return Regex.IsMatch(strln, @"^[\u4e00-\u9fa5]+$"); + } + #endregion + + #region 是否有多余的字符 防止SQL注入 + /// + /// 是否有多余的字符 防止SQL注入 + /// + /// 输入字符 + /// + public static bool IsBadString(this string str) + { + if (string.IsNullOrEmpty(str)) + return false; + //列举一些特殊字符串 + const string badChars = "@,*,#,$,!,+,',=,--,%,^,&,?,(,), <,>,[,],{,},/,\\,;,:,\",\"\",delete,update,drop,alert,select"; + var arraryBadChar = badChars.Split(','); + return arraryBadChar.Any(t => !str.Contains(t)); + } + #endregion + + #region 是否由数字、26个英文字母或者下划线組成的字串 + /// + /// 是否由数字、26个英文字母或者下划线組成的字串 + /// + /// 输入字符 + /// + public static bool IsNzx(this string str) + { + return Regex.Match(str, "^[0-9a-zA-Z_]+$").Success; + } + #endregion + + #region 由数字、26个英文字母、汉字組成的字串 + /// + /// 由数字、26个英文字母、汉字組成的字串 + /// + /// 输入字符 + /// + public static bool IsSzzmChinese(this string str) + { + return Regex.Match(str, @"^[0-9a-zA-Z\u4e00-\u9fa5]+$").Success; + } + #endregion + + #region 由数字、26个英文字母組成的字串 + /// + /// 是否由数字、26个英文字母組成的字串 + /// + /// 输入字符 + /// + public static bool IsSzzm(this string str) + { + return Regex.Match(str, @"^[0-9a-zA-Z]+$").Success; + } + #endregion + + #region 验证输入字符串为邮政编码 + /// + /// 验证输入字符串为邮政编码 + /// + /// 输入字符 + /// 返回一个bool类型的值 + public static bool IsPostCode(this string str) + { + return Regex.IsMatch(str, @"\d{6}"); + } + #endregion + + #region 检查对象的输入长度 + /// + /// 检查对象的输入长度 + /// + /// 输入字符 + /// 指定的长度 + /// false 太长,true -太短 + public static bool CheckLength(this string str, int length) + { + if (str.Length > length) + { + return false;//长度太长 + } + return str.Length >= length; + } + + #endregion + + #region 判断用户输入是否为日期 + /// + /// 判断用户输入是否为日期 + /// + /// 输入字符 + /// 返回一个bool类型的值 + /// + /// 可判断格式如下(其中-可替换为/,不影响验证) + /// YYYY | YYYY-MM | YYYY-MM-DD | YYYY-MM-DD HH:MM:SS | YYYY-MM-DD HH:MM:SS.FFF + /// + public static bool IsDateTime(this string str) + { + if (null == str) + { + return false; + } + const string regexDate = @"[1-2]{1}[0-9]{3}((-|\/|\.){1}(([0]?[1-9]{1})|(1[0-2]{1}))((-|\/|\.){1}((([0]?[1-9]{1})|([1-2]{1}[0-9]{1})|(3[0-1]{1})))( (([0-1]{1}[0-9]{1})|2[0-3]{1}):([0-5]{1}[0-9]{1}):([0-5]{1}[0-9]{1})(\.[0-9]{3})?)?)?)?$"; + if (Regex.IsMatch(str, regexDate)) + { + //以下各月份日期验证,保证验证的完整性 + int indexY = -1; + int indexM = -1; + int indexD = -1; + if (-1 != (indexY = str.IndexOf("-", StringComparison.Ordinal))) + { + indexM = str.IndexOf("-", indexY + 1, StringComparison.Ordinal); + indexD = str.IndexOf(":", StringComparison.Ordinal); + } + else + { + indexY = str.IndexOf("/", StringComparison.Ordinal); + indexM = str.IndexOf("/", indexY + 1, StringComparison.Ordinal); + indexD = str.IndexOf(":", StringComparison.Ordinal); + } + //不包含日期部分,直接返回true + if (-1 == indexM) + return true; + if (-1 == indexD) + { + indexD = str.Length + 3; + } + int iYear = Convert.ToInt32(str.Substring(0, indexY)); + int iMonth = Convert.ToInt32(str.Substring(indexY + 1, indexM - indexY - 1)); + int iDate = Convert.ToInt32(str.Substring(indexM + 1, indexD - indexM - 4)); + //判断月份日期 + if (iMonth < 8 && 1 == iMonth % 2 || iMonth > 8 && 0 == iMonth % 2) + { + if (iDate < 32) + return true; + } + else + { + if (iMonth != 2) + { + if (iDate < 31) + return true; + } + else + { + //闰年 + if (0 == iYear % 400 || 0 == iYear % 4 && 0 < iYear % 100) + { + if (iDate < 30) + return true; + } + else + { + if (iDate < 29) + return true; + } + } + } + } + return false; + } + #endregion + } +} diff --git a/API/Wood.Util/Wood.Util.csproj b/API/Wood.Util/Wood.Util.csproj new file mode 100644 index 0000000..59dcc6c --- /dev/null +++ b/API/Wood.Util/Wood.Util.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + + + + + + + + + + + + + + + + diff --git a/API/WoodAdmin.sln b/API/WoodAdmin.sln new file mode 100644 index 0000000..7405930 --- /dev/null +++ b/API/WoodAdmin.sln @@ -0,0 +1,263 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01 Framework 基础设施层", "01 Framework 基础设施层", "{0D0F3140-E7C9-494A-8CE4-EB7899A51CDB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02 DataAccess数据库核心层", "02 DataAccess数据库核心层", "{8D2E75B2-DBAD-43EC-81A2-7B50DB400E93}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "04 Business 业务逻辑层", "04 Business 业务逻辑层", "{283948F1-48FF-4328-A3DD-07344C7AFF43}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cache 数据缓存接口", "Cache 数据缓存接口", "{DE45D774-2013-4CA1-BD7C-CDDD73582A12}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wood.Cache.Interface", "Wood.Cache\Wood.Cache.Interface\Wood.Cache.Interface.csproj", "{98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wood.Util", "Wood.Util\Wood.Util.csproj", "{B0CEE5E9-956D-426E-A01F-9367CC23CF00}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03 Entity实体层", "03 Entity实体层", "{A2015F70-2929-40EC-A2E1-88108CA90316}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "05 WebHost", "05 WebHost", "{733D2669-1EC3-4570-A2AA-655C5250E103}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "06 插件", "06 插件", "{E3C7D56C-B89F-4360-8DD8-DCFF34443263}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wood.Admin.WebApi", "Wood.Admin.WebApi\Wood.Admin.WebApi.csproj", "{984AE6BE-0519-4BAA-A133-7DCB4050DF15}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wood.MemoryCache", "Wood.Cache\Wood.MemoryCache\Wood.MemoryCache.csproj", "{AB91197D-76F9-4C48-86EA-D0D065AB2C97}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07 测试", "07 测试", "{A89606FB-495E-4E40-96B1-D346C5741C3E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wood.RedisCache", "Wood.Cache\Wood.RedisCache\Wood.RedisCache.csproj", "{11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wood.Data.Repository", "Wood.Data.Repository\Wood.Data.Repository.csproj", "{872D1F69-CEFE-4A97-984F-9B3629A64485}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wood.EventBus", "Wood.EventBus\Wood.EventBus.csproj", "{DB189457-088C-40CC-9346-7B134410A547}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wood.Entity", "Wood.Entity\Wood.Entity.csproj", "{39D5F339-9655-47A9-ACD4-85E7B59E7316}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wood.AutoJob", "Wood.AutoJob\Wood.AutoJob.csproj", "{AB793379-833D-4EB1-B1B4-DF2AE3725C8F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wood.Service", "Wood.Service\Wood.Service.csproj", "{ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wood.Test.Service", "Wood.Test.Service\Wood.Test.Service.csproj", "{C99418C4-436C-4192-8BAD-59EB15A8920E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataBaseMigration", "CherryTaskManager\DataBaseMigration.csproj", "{61536DAA-FD5D-7C12-B49D-9E39B3EE212F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskManager.Contracts", "TaskManager.Contracts\TaskManager.Contracts.csproj", "{F1EC14A6-0E61-699A-F4F8-22694BFAC40B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskManager.Entity", "TaskManager.Entity\TaskManager.Entity.csproj", "{455FF25B-01EE-9E01-FA1B-D48D38DBFE07}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskManager.EntityFramework", "TaskManager.EntityFramework\TaskManager.EntityFramework.csproj", "{AB11CC45-3E23-194F-0054-FAED19F972D3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|iPhone = Debug|iPhone + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Release|Any CPU = Release|Any CPU + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Debug|iPhone.Build.0 = Debug|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Release|Any CPU.Build.0 = Release|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Release|iPhone.ActiveCfg = Release|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Release|iPhone.Build.0 = Release|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Debug|iPhone.Build.0 = Debug|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Release|Any CPU.Build.0 = Release|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Release|iPhone.ActiveCfg = Release|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Release|iPhone.Build.0 = Release|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B0CEE5E9-956D-426E-A01F-9367CC23CF00}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Debug|Any CPU.Build.0 = Debug|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Debug|iPhone.Build.0 = Debug|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Release|Any CPU.ActiveCfg = Release|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Release|Any CPU.Build.0 = Release|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Release|iPhone.ActiveCfg = Release|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Release|iPhone.Build.0 = Release|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {984AE6BE-0519-4BAA-A133-7DCB4050DF15}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Debug|iPhone.Build.0 = Debug|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Release|Any CPU.Build.0 = Release|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Release|iPhone.ActiveCfg = Release|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Release|iPhone.Build.0 = Release|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {AB91197D-76F9-4C48-86EA-D0D065AB2C97}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Debug|iPhone.Build.0 = Debug|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Release|Any CPU.Build.0 = Release|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Release|iPhone.ActiveCfg = Release|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Release|iPhone.Build.0 = Release|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Debug|Any CPU.Build.0 = Debug|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Debug|iPhone.Build.0 = Debug|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Release|Any CPU.ActiveCfg = Release|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Release|Any CPU.Build.0 = Release|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Release|iPhone.ActiveCfg = Release|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Release|iPhone.Build.0 = Release|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {872D1F69-CEFE-4A97-984F-9B3629A64485}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Debug|iPhone.Build.0 = Debug|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Release|Any CPU.Build.0 = Release|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Release|iPhone.ActiveCfg = Release|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Release|iPhone.Build.0 = Release|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DB189457-088C-40CC-9346-7B134410A547}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Debug|iPhone.Build.0 = Debug|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Release|Any CPU.Build.0 = Release|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Release|iPhone.ActiveCfg = Release|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Release|iPhone.Build.0 = Release|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {39D5F339-9655-47A9-ACD4-85E7B59E7316}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Debug|iPhone.Build.0 = Debug|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Release|Any CPU.Build.0 = Release|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Release|iPhone.ActiveCfg = Release|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Release|iPhone.Build.0 = Release|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Debug|iPhone.Build.0 = Debug|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Release|Any CPU.Build.0 = Release|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Release|iPhone.ActiveCfg = Release|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Release|iPhone.Build.0 = Release|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Debug|iPhone.Build.0 = Debug|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Release|Any CPU.Build.0 = Release|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Release|iPhone.ActiveCfg = Release|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Release|iPhone.Build.0 = Release|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C99418C4-436C-4192-8BAD-59EB15A8920E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Debug|iPhone.Build.0 = Debug|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Release|Any CPU.Build.0 = Release|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Release|iPhone.ActiveCfg = Release|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Release|iPhone.Build.0 = Release|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {61536DAA-FD5D-7C12-B49D-9E39B3EE212F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Debug|iPhone.Build.0 = Debug|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Release|Any CPU.Build.0 = Release|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Release|iPhone.ActiveCfg = Release|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Release|iPhone.Build.0 = Release|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F1EC14A6-0E61-699A-F4F8-22694BFAC40B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Debug|Any CPU.Build.0 = Debug|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Debug|iPhone.Build.0 = Debug|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Release|Any CPU.ActiveCfg = Release|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Release|Any CPU.Build.0 = Release|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Release|iPhone.ActiveCfg = Release|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Release|iPhone.Build.0 = Release|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {455FF25B-01EE-9E01-FA1B-D48D38DBFE07}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Debug|iPhone.Build.0 = Debug|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Release|Any CPU.Build.0 = Release|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Release|iPhone.ActiveCfg = Release|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Release|iPhone.Build.0 = Release|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {AB11CC45-3E23-194F-0054-FAED19F972D3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DE45D774-2013-4CA1-BD7C-CDDD73582A12} = {0D0F3140-E7C9-494A-8CE4-EB7899A51CDB} + {98E2F89F-4DDB-4C83-B6BD-DA9CB31803AD} = {DE45D774-2013-4CA1-BD7C-CDDD73582A12} + {B0CEE5E9-956D-426E-A01F-9367CC23CF00} = {0D0F3140-E7C9-494A-8CE4-EB7899A51CDB} + {984AE6BE-0519-4BAA-A133-7DCB4050DF15} = {733D2669-1EC3-4570-A2AA-655C5250E103} + {AB91197D-76F9-4C48-86EA-D0D065AB2C97} = {DE45D774-2013-4CA1-BD7C-CDDD73582A12} + {11BE0DFB-FE4F-4AB5-BFEB-1218945E9901} = {DE45D774-2013-4CA1-BD7C-CDDD73582A12} + {872D1F69-CEFE-4A97-984F-9B3629A64485} = {8D2E75B2-DBAD-43EC-81A2-7B50DB400E93} + {DB189457-088C-40CC-9346-7B134410A547} = {0D0F3140-E7C9-494A-8CE4-EB7899A51CDB} + {39D5F339-9655-47A9-ACD4-85E7B59E7316} = {A2015F70-2929-40EC-A2E1-88108CA90316} + {AB793379-833D-4EB1-B1B4-DF2AE3725C8F} = {283948F1-48FF-4328-A3DD-07344C7AFF43} + {ECD9FCA8-7F51-4AD1-8185-A7CC203437E0} = {283948F1-48FF-4328-A3DD-07344C7AFF43} + {C99418C4-436C-4192-8BAD-59EB15A8920E} = {283948F1-48FF-4328-A3DD-07344C7AFF43} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4873C9CF-80BE-4949-BB7D-A1CA9E3BC77D} + EndGlobalSection +EndGlobal diff --git a/Doc/autojob.md b/Doc/autojob.md new file mode 100644 index 0000000..7f8a059 --- /dev/null +++ b/Doc/autojob.md @@ -0,0 +1,81 @@ +# 定时任务Job +用来执行一些定时任务,依赖Quartz,如果job同步执行请加 [DisallowConcurrentExecution] 特性 +### AutoJobTask +定时任务父类 +```csharp +[JobDetail(JobId = "job_DatabasesBackup", GroupName = "system", Description = "数据库备份")] +[PeriodSeconds(60, RunOnStart = true, TriggerId = "trigger_DatabasesBackup")] +[DisallowConcurrentExecution] +public class DatabasesBackupJob : AutoJobTask +{ + + public override async Task Run(IJobExecutionContext context,IServiceProvider serviceProvider) + { + ... + } +} +``` +## 定时任务特性 +### JobDetailAttribute +用于描述定时任务的作用 + +- JobId:任务ID +- GroupName:分组名称 +- Description:描述 + +### CronAttribute +定时任务触发器,Cron表达式 + +- TriggerId:触发器ID +- Args:触发器参数 +- Description:描述 +- StartTime:开始时间 +- EndTime:结束时间 +- MaxNumberOfRuns:最大执行次数 +- MaxNumberOfErrors:最大错误次数 +- NumRetries:重试次数 +- RetryTimeout:重试超时时间 +- RunOnStart:是否在启动时执行 + +### PeriodSecondsAttribute +每隔x秒执行任务 + +- TriggerId:触发器ID +- Args:触发器参数 +- Description:描述 +- StartTime:开始时间 +- EndTime:结束时间 +- MaxNumberOfRuns:最大执行次数 +- MaxNumberOfErrors:最大错误次数 +- NumRetries:重试次数 +- RetryTimeout:重试超时时间 +- RunOnStart:是否在启动时执行 + +### PeriodMinutesAttribute +每隔x分钟执行任务 + +- TriggerId:触发器ID +- Args:触发器参数 +- Description:描述 +- StartTime:开始时间 +- EndTime:结束时间 +- MaxNumberOfRuns:最大执行次数 +- MaxNumberOfErrors:最大错误次数 +- NumRetries:重试次数 +- RetryTimeout:重试超时时间 +- RunOnStart:是否在启动时执行 + +### DailyAtAttribute +每天x点执行任务 + +- TriggerId:触发器ID +- Args:触发器参数 +- Description:描述 +- StartTime:开始时间 +- EndTime:结束时间 +- MaxNumberOfRuns:最大执行次数 +- MaxNumberOfErrors:最大错误次数 +- NumRetries:重试次数 +- RetryTimeout:重试超时时间 +- RunOnStart:是否在启动时执行 + diff --git a/Doc/eventbus.md b/Doc/eventbus.md new file mode 100644 index 0000000..1a9c705 --- /dev/null +++ b/Doc/eventbus.md @@ -0,0 +1,33 @@ +# 事件总线 +在这里主要用来发布项目事件用的,更好的解耦代码。目前只有内存事件的实现。 + +### IntegrationEvent +事件父类,所有自定以事件必须要继承这个父类。 +```csharp +//操作日志记录事件 +public class LogOperationEvent : IntegrationEvent +{ +} +``` +### IEventLog +标记事件需要记录执行日志,错误日志所有事件都会记录 + +### IntegrationEventHandler +事件处理器 +继承这个类之后实现Run 方法即可 +```csharp +///系统操作日志事件处理器 单例注入,记录事件日志 +public class LogOperationEventHandler : IntegrationEventHandler, ISingleton, IEventLog +{ + /// + /// 保存日志 + /// + /// + /// + /// + public override async Task Run(LogOperationEvent @event, IServiceScope scope) + { + await scope.ServiceProvider.GetRequiredService>().InsertAsync(@event.GetPayload()!); + } +} +``` diff --git a/Doc/home.md b/Doc/home.md new file mode 100644 index 0000000..c9de1b4 --- /dev/null +++ b/Doc/home.md @@ -0,0 +1,106 @@ +# 项目结构 + +### WoodAdmin 解决方案 +- 01 Framework 基础设施层 + - Cache 数据缓存接口 + - Wood.Cache.Interface 缓存抽象接口 + - Wood.MemoryCache 内存缓存 + - Wood.RedisCache Redis缓存 + - Wood.EventBus 事件总线 + - Wood.Util 工具类 +- 02 DataAccess数据库核心层 + - Wood.Data.Repository 数据库 +- 03 Entity实体层 + - Wood.Entity 实体 +- 04 Business 业务逻辑层 + - Wood.AutoJob 定时任务 + - Wood.Service 核心服务 + - Wood.Test.Service 示例 +- 05 WebHost + - Wood.Admin.WebApi WebApi + +# 快速开始 + +1. 在【03 Entity实体层】添加需要映射的实体 +```csharp +/// +/// 测试信息 +/// +[SugarTable("SysTest", "测试信息")] +public class TestEntity : EntityBaseExtra +{ + /// + /// 名称 + /// + [SugarColumn(ColumnDescription = "名称",Length =64)] + [Required(ErrorMessage = "必须填写名称!")] + public string Name { get; set; } = ""; + + /// + /// 编码 + /// + [SugarColumn(ColumnDescription = "编码", Length = 32)] + [Required] + [UniqueValue(ErrorMessage ="编码不能重复!")] + public string FormCode { get; set; } = ""; + /// + /// 排序 + /// + [SugarColumn(ColumnDescription = "排序")] + public int Sort { get; set; } = 0; +} +``` +2. 在【04 Business 业务逻辑层】新建项目(名称以Service为结尾),添加对【Wood.Service】引用。 +3. 在【04 Business 业务逻辑层】新建Service,继承【ApiService】。 +```csharp +/// +/// 测试服务 +/// +public class TestService : ApiService +{ + /// + /// 分页获取用户数据 + /// + /// + /// + public TDataPaged Paged(Pagination param) + { + return new TDataPaged(); + } + + /// + /// 是否存在 + /// + /// + public bool GetExist() + { + return false; + } + + /// + /// 获取树形结构 + /// + /// 树形结构 + public List TreeList() + { + return new List(); + } + /// + /// 获取明细 + /// + /// + public TestEntity GetDetail(BaseIdParam param) + { + return new TestEntity(); + } +} +``` +4. 在WebApi项目引用新建项目 +5. 运行即可看到api列表,Get开头自动注册get请求,否则为post请求,特殊需要可以进行[HttpGet][HttpPost]标记。 + +### 项目约定: +- 实体 放在【Wood.Entity】 +- Service类放在以Service为后缀的项目中 +- AutoJob放在【Wood.AutoJob】 +- 工具放在【Wood.Util】 +- 自定义事件放在【Wood.EventBus】 diff --git a/Doc/service.md b/Doc/service.md new file mode 100644 index 0000000..6219d97 --- /dev/null +++ b/Doc/service.md @@ -0,0 +1,74 @@ +# 业务逻辑层 + +在这里主要实现项目业务逻辑,原则上不能在【Wood.Service】中直接写需要的业务逻辑,这里是系统自带的一些业务的实现,可以新建一个Service,对其进行引用。这里有两种Service父类,一个Manager父类,Service实现里边的方法会被注册为接口,Manager实现则会被自动依赖注入。 +### ApiCRUDService +这个父类提供了简单增删改查实现,继承了之后,自动提供简单增删改查接口,如有需要可以在子类中重写,实现自己的功能。 +- T:实体 +- TDTO:实体Detail查询的dto +- TAddParam:新增参数 +- TUpdateParam:更新参数 +- 提供方法: + - GetDetail 获取单个明细 + - Add 新增 + - Update 修改 + - Delete 删除 接受数组参数,支持批量删除 +```csharp +/// +/// 职位管理 +/// +public class PositionService : ApiCRUDService +{ + public PositionService(SqlSugarRepository repository) : base(repository) + { + } + + /// + /// 分页查询职位 + /// + /// + /// + public async Task> Paged(PositionPagedParam param) + { + return await _repository.AsQueryable() + .WhereIF(!string.IsNullOrEmpty(param.Name), it => it.PositionName.Contains(param.Name!) || it.FormCode.Contains(param.Name!)) + .ToPagedListAsync(param); + } +} +``` +### ApiService +这个父类标记目标类为需要注册为api,这个父类里边没有任何实现,当然你也可以自定义实现。 +```csharp +/// +/// 用户管理 +/// +public class UserService : ApiService +{ + ...... +} +``` +### ApiManager +Manager用于封装一些在service中反复需要使用的功能。对实体进行Manager封装后,只用注入Manager即可,不需要再注入Repository。 +- T:entity实体 +- 封装Manager后必须要标注,注入类型,当然所有标注这些注入类型的类都会被自动扫描注入。 + - IScoped 注册为Scoped + - ITransient 注册为Transient + - ISingleton 注册为Singleton + - ApiManager中的方法 + - AsQueryable() 获取 ISugarQueryable + - AsRepository() 获取 SqlSugarRepository +```csharp +// 用户管理 ,瞬时生命周期注入 +public class UserManager : ApiManager, ITransient +{ + ...... +} +``` +### 一些接口说明 +继承这些接口会实现相应的功能 +- IScoped 注册为Scoped +- ITransient 注册为Transient +- ISingleton 注册为Singleton +- IDiff 标记,记录差异日志,用于实体 +- IntegrationEvent 事件总线,事件类型 +- IntegrationEventHandler 事件处理器,T:(IntegrationEvent实现类) +- IEventLog 标记,记录事件日志,用于开启记录目标事件的事件日志 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..64df0ff --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 一念 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..34dacb6 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# WoodAdmin + +### :tw-1f6a9: 框架介绍 + + WoodAdmin 是基于 .net 8 实现的通用权限开发框架,前端采用 Vue3+Element-plus+Vite,后端集成多租户、缓存、数据校验、鉴权、事件总线、动态API、任务调度、等众多功能。代码结构简单清晰,注释详尽,易于上手与二次开发,。 + +### :tw-2764: 说明 + +1. 支持各种数据库,后台配置文件自行修改(自动生成数据库及种子数据) +2. 前端运行步骤:1、安装依赖npm install 2、运行npm run dev 3、打包npm run build +3. 后端直接在vs2022运行 +4. 测试用户:superadmin/123456 + +### :tw-23f0: 开发流程 +1. 新解决方案中,建立独立的类库项目(名称以Service结尾),引用Wood.Service层 +2. 打开类库项目xml注释生成,swagger 会自动添加注释 +3. WebApi层引用新建的类库项目即可 + +### :tw-1f534: 详细说明,参考doc文件夹 \ No newline at end of file diff --git a/Web/.env b/Web/.env new file mode 100644 index 0000000..86fec3b --- /dev/null +++ b/Web/.env @@ -0,0 +1 @@ +VITE_TEST=123 \ No newline at end of file diff --git a/Web/.env.development b/Web/.env.development new file mode 100644 index 0000000..2635439 --- /dev/null +++ b/Web/.env.development @@ -0,0 +1,5 @@ +# just a flag +ENV = 'development' + +# base api +VITE_API_BASE_URL = 'http://127.0.0.1:7001' diff --git a/Web/.env.production b/Web/.env.production new file mode 100644 index 0000000..b763518 --- /dev/null +++ b/Web/.env.production @@ -0,0 +1,6 @@ +# just a flag +ENV = 'production' + +# base api +VITE_API_BASE_URL = 'http://127.0.0.1:5001' + diff --git a/Web/.eslintrc.cjs b/Web/.eslintrc.cjs new file mode 100644 index 0000000..b64731a --- /dev/null +++ b/Web/.eslintrc.cjs @@ -0,0 +1,14 @@ +/* eslint-env node */ +require('@rushstack/eslint-patch/modern-module-resolution') + +module.exports = { + root: true, + 'extends': [ + 'plugin:vue/vue3-essential', + 'eslint:recommended', + '@vue/eslint-config-prettier/skip-formatting' + ], + parserOptions: { + ecmaVersion: 'latest' + } +} diff --git a/Web/.prettierrc.json b/Web/.prettierrc.json new file mode 100644 index 0000000..e463e0a --- /dev/null +++ b/Web/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "tabWidth": 2, + "singleQuote": true, + "printWidth": 100, + "trailingComma": "none", + "htmlWhitespaceSensitivity": "ignore" +} \ No newline at end of file diff --git a/Web/index.html b/Web/index.html new file mode 100644 index 0000000..e631329 --- /dev/null +++ b/Web/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/Web/jsconfig.json b/Web/jsconfig.json new file mode 100644 index 0000000..5a1f2d2 --- /dev/null +++ b/Web/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + }, + "exclude": ["node_modules", "dist"] +} diff --git a/Web/package-lock.json b/Web/package-lock.json new file mode 100644 index 0000000..e5f1efe --- /dev/null +++ b/Web/package-lock.json @@ -0,0 +1,5680 @@ +{ + "name": "vue3-element-admin", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vue3-element-admin", + "version": "0.0.0", + "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^5.1.12", + "@wangeditor/plugin-upload-attachment": "^1.1.0", + "axios": "^1.6.7", + "element-plus": "^2.6.1", + "js-cookie": "^3.0.5", + "normalize.css": "^8.0.1", + "nprogress": "^0.2.0", + "path-browserify": "^1.0.1", + "path-to-regexp": "^6.2.1", + "pinia": "^2.1.7", + "sass": "^1.71.1", + "screenfull": "^6.0.2", + "vue": "^3.4.21", + "vue-router": "^4.3.0", + "xlsx": "^0.18.5" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.3.3", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/eslint-config-prettier": "^8.0.0", + "eslint": "^8.49.0", + "eslint-plugin-vue": "^9.17.0", + "prettier": "^3.0.3", + "vite": "^5.1.5", + "vite-plugin-vue-devtools": "^7.0.16" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.26.5.tgz", + "integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.26.5.tgz", + "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.5", + "@babel/types": "^7.26.5", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", + "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.26.5.tgz", + "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", + "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-decorators": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", + "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.5.tgz", + "integrity": "sha512-GJhPO0y8SD5EYVCy2Zr+9dSZcEgaSmq5BLR0Oc25TOEhC+ba49vUAGZFjy8v79z9E1mdldq4x9d1xgh4L1d5dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", + "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.26.5.tgz", + "integrity": "sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.5", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.5", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.5", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.26.5.tgz", + "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.0.tgz", + "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.0", + "@parcel/watcher-darwin-arm64": "2.5.0", + "@parcel/watcher-darwin-x64": "2.5.0", + "@parcel/watcher-freebsd-x64": "2.5.0", + "@parcel/watcher-linux-arm-glibc": "2.5.0", + "@parcel/watcher-linux-arm-musl": "2.5.0", + "@parcel/watcher-linux-arm64-glibc": "2.5.0", + "@parcel/watcher-linux-arm64-musl": "2.5.0", + "@parcel/watcher-linux-x64-glibc": "2.5.0", + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", + "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.4", + "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.10.5", + "resolved": "https://registry.npmmirror.com/@rushstack/eslint-patch/-/eslint-patch-1.10.5.tgz", + "integrity": "sha512-kkKUDVlII2DQiKy7UstOR1ErJP8kUKAQ4oa+SQtM0K+lPdmmjj0YnnxBgtTVYH7mUKtbsxeFC9y0AmK7Yb78/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@transloadit/prettier-bytes": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz", + "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@types/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==", + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.14", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@uppy/companion-client": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.2.2.tgz", + "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==", + "license": "MIT", + "dependencies": { + "@uppy/utils": "^4.1.2", + "namespace-emitter": "^2.0.1" + } + }, + "node_modules/@uppy/core": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz", + "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==", + "license": "MIT", + "dependencies": { + "@transloadit/prettier-bytes": "0.0.7", + "@uppy/store-default": "^2.1.1", + "@uppy/utils": "^4.1.3", + "lodash.throttle": "^4.1.1", + "mime-match": "^1.0.2", + "namespace-emitter": "^2.0.1", + "nanoid": "^3.1.25", + "preact": "^10.5.13" + } + }, + "node_modules/@uppy/store-default": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.1.1.tgz", + "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==", + "license": "MIT" + }, + "node_modules/@uppy/utils": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.1.3.tgz", + "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==", + "license": "MIT", + "dependencies": { + "lodash.throttle": "^4.1.1" + } + }, + "node_modules/@uppy/xhr-upload": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz", + "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==", + "license": "MIT", + "dependencies": { + "@uppy/companion-client": "^2.2.2", + "@uppy/utils": "^4.1.2", + "nanoid": "^3.1.25" + }, + "peerDependencies": { + "@uppy/core": "^2.3.3" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", + "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.5.tgz", + "integrity": "sha512-lOz4t39ZdmU4DJAa2hwPYmKc8EsuGa2U0L9KaZaOJUt0UwQNjNA3AZTq6uEivhOKhhG1Wvy96SvYBoFmCg3uuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.5.tgz", + "integrity": "sha512-zTrNmOd4939H9KsRIGmmzn3q2zvv1mjxkYZHgqHZgDrXz5B1Q3WyGEjO2f+JrmKghvl1JIRcvo63LgM1kH5zFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.6", + "@babel/types": "^7.25.6", + "@vue/babel-helper-vue-transform-on": "1.2.5", + "@vue/babel-plugin-resolve-type": "1.2.5", + "html-tags": "^3.3.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.5.tgz", + "integrity": "sha512-U/ibkQrf5sx0XXRnUZD1mo5F7PkpKyTbfXM3a3rC4YnUz6crHEz9Jg09jzzL6QYlXNto/9CePdOg/c87O4Nlfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/parser": "^7.25.6", + "@vue/compiler-sfc": "^3.5.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/devtools-core": { + "version": "7.7.0", + "resolved": "https://registry.npmmirror.com/@vue/devtools-core/-/devtools-core-7.7.0.tgz", + "integrity": "sha512-tSO3pghV5RZGSonZ87S2fOGru3X93epmar5IjZOWjHxH6XSwnK5UbR2aW5puZV+LgLoVYrcNou3krSo5k1F31g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.0", + "@vue/devtools-shared": "^7.7.0", + "mitt": "^3.0.1", + "nanoid": "^5.0.9", + "pathe": "^1.1.2", + "vite-hot-client": "^0.2.4" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vue/devtools-core/node_modules/nanoid": { + "version": "5.0.9", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-5.0.9.tgz", + "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.0", + "resolved": "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-7.7.0.tgz", + "integrity": "sha512-5cvZ+6SA88zKC8XiuxUfqpdTwVjJbvYnQZY5NReh7qlSGPvVDjjzyEtW+gdzLXNSd8tStgOjAdMCpvDQamUXtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.0", + "birpc": "^0.2.19", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.1" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.0", + "resolved": "https://registry.npmmirror.com/@vue/devtools-shared/-/devtools-shared-7.7.0.tgz", + "integrity": "sha512-jtlQY26R5thQxW9YQTpXbI0HoK0Wf9Rd4ekidOkRvSy7ChfK0kIU6vvcBtjj87/EcpeOSK49fZAicaFNJcoTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/eslint-config-prettier": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/@vue/eslint-config-prettier/-/eslint-config-prettier-8.0.0.tgz", + "integrity": "sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^5.0.0" + }, + "peerDependencies": { + "eslint": ">= 8.0.0", + "prettier": ">= 3.0.0" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "vue": "3.5.13" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "license": "MIT", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@wangeditor/basic-modules": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz", + "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==", + "license": "MIT", + "dependencies": { + "is-url": "^1.2.4" + }, + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.throttle": "^4.1.1", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/code-highlight": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz", + "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.23.0" + }, + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/core": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.19.tgz", + "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==", + "license": "MIT", + "dependencies": { + "@types/event-emitter": "^0.3.3", + "event-emitter": "^0.3.5", + "html-void-elements": "^2.0.0", + "i18next": "^20.4.0", + "scroll-into-view-if-needed": "^2.2.28", + "slate-history": "^0.66.0" + }, + "peerDependencies": { + "@uppy/core": "^2.1.1", + "@uppy/xhr-upload": "^2.0.3", + "dom7": "^3.0.0", + "is-hotkey": "^0.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.foreach": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "lodash.toarray": "^4.4.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/editor": { + "version": "5.1.23", + "resolved": "https://registry.npmjs.org/@wangeditor/editor/-/editor-5.1.23.tgz", + "integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==", + "license": "MIT", + "dependencies": { + "@uppy/core": "^2.1.1", + "@uppy/xhr-upload": "^2.0.3", + "@wangeditor/basic-modules": "^1.1.7", + "@wangeditor/code-highlight": "^1.0.3", + "@wangeditor/core": "^1.1.19", + "@wangeditor/list-module": "^1.0.5", + "@wangeditor/table-module": "^1.1.4", + "@wangeditor/upload-image-module": "^1.0.2", + "@wangeditor/video-module": "^1.1.4", + "dom7": "^3.0.0", + "is-hotkey": "^0.2.0", + "lodash.camelcase": "^4.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.foreach": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "lodash.toarray": "^4.4.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/editor-for-vue": { + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz", + "integrity": "sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==", + "license": "MIT", + "peerDependencies": { + "@wangeditor/editor": ">=5.1.0", + "vue": "^3.0.5" + } + }, + "node_modules/@wangeditor/list-module": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.5.tgz", + "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==", + "license": "MIT", + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/plugin-upload-attachment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wangeditor/plugin-upload-attachment/-/plugin-upload-attachment-1.1.0.tgz", + "integrity": "sha512-K6SsV3Cv1g+Ob1xjRRQ13Sh3lcj3yAa/aXMaKKbaPI76rNZiOpyAGH/iVv5i9enmwbZql01IXpvhK+HtrikVyQ==", + "license": "MIT", + "dependencies": { + "dom7": "^4.0.4" + }, + "peerDependencies": { + "@uppy/core": "^2.1.5", + "@wangeditor/editor": ">=5.1.16", + "snabbdom": "^3.3.1" + } + }, + "node_modules/@wangeditor/plugin-upload-attachment/node_modules/dom7": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-4.0.6.tgz", + "integrity": "sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==", + "license": "MIT", + "dependencies": { + "ssr-window": "^4.0.0" + } + }, + "node_modules/@wangeditor/plugin-upload-attachment/node_modules/ssr-window": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz", + "integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==", + "license": "MIT" + }, + "node_modules/@wangeditor/table-module": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.4.tgz", + "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==", + "license": "MIT", + "peerDependencies": { + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.isequal": "^4.5.0", + "lodash.throttle": "^4.1.1", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/upload-image-module": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz", + "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==", + "license": "MIT", + "peerDependencies": { + "@uppy/core": "^2.0.3", + "@uppy/xhr-upload": "^2.0.3", + "@wangeditor/basic-modules": "1.x", + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "lodash.foreach": "^4.5.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/@wangeditor/video-module": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.4.tgz", + "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==", + "license": "MIT", + "peerDependencies": { + "@uppy/core": "^2.1.4", + "@uppy/xhr-upload": "^2.0.7", + "@wangeditor/core": "1.x", + "dom7": "^3.0.0", + "nanoid": "^3.2.0", + "slate": "^0.72.0", + "snabbdom": "^3.1.0" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/birpc": { + "version": "0.2.19", + "resolved": "https://registry.npmmirror.com/birpc/-/birpc-0.2.19.tgz", + "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "optional": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001692", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz", + "integrity": "sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom7": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz", + "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==", + "license": "MIT", + "dependencies": { + "ssr-window": "^3.0.0-alpha.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.82", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.82.tgz", + "integrity": "sha512-Zq16uk1hfQhyGx5GpwPAYDwddJuSGhtRhgOA2mCxANYaDT79nAeGnaXogMGng4KqLaJUVnOnuL0+TDop9nLOiA==", + "dev": true, + "license": "ISC" + }, + "node_modules/element-plus": { + "version": "2.9.3", + "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.3.tgz", + "integrity": "sha512-6tSLp5XytDS4TMZ0P3aGZnr7MXTagfNycepNfIDitd9IgwM9y01+Ssu6mglNi8RiXYhek6LBWNOd/cvpIO12+w==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-stack-parser-es": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-0.1.5.tgz", + "integrity": "sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.2", + "resolved": "https://registry.npmmirror.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.2.tgz", + "integrity": "sha512-1yI3/hf35wmlq66C8yOyrujQnel+v5l1Vop5Cl2I6ylyNTT1JbuUUnV3/41PzwTzcyDp/oF0jWE3HXvcH5AQOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.32.0", + "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.32.0.tgz", + "integrity": "sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "vue-eslint-parser": "^9.4.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/execa": { + "version": "9.5.2", + "resolved": "https://registry.npmmirror.com/execa/-/execa-9.5.2.tgz", + "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.3", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.0", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", + "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/human-signals": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/human-signals/-/human-signals-8.0.0.tgz", + "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/i18next": { + "version": "20.6.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.6.1.tgz", + "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "5.0.3", + "resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.0.3.tgz", + "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hotkey": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz", + "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==", + "license": "MIT" + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmmirror.com/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmmirror.com/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "optional": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz", + "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==", + "license": "ISC", + "dependencies": { + "wildcard": "^1.1.0" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/namespace-emitter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", + "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "license": "ISC" + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, + "node_modules/normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==", + "license": "MIT" + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmmirror.com/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.3.0.tgz", + "integrity": "sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.5.1", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.1.tgz", + "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/preact": { + "version": "10.25.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.25.4.tgz", + "integrity": "sha512-jLdZDb+Q+odkHJ+MpW/9U5cODzqnB+fy2EiHSZES7ldV5LK7yjlVzTp7R8Xy6W6y75kfK8iWYtFVH7lvjwrCMA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-ms": { + "version": "9.2.0", + "resolved": "https://registry.npmmirror.com/pretty-ms/-/pretty-ms-9.2.0.tgz", + "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.1.tgz", + "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.30.1", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sass": { + "version": "1.83.4", + "resolved": "https://registry.npmmirror.com/sass/-/sass-1.83.4.tgz", + "integrity": "sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/screenfull": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-6.0.2.tgz", + "integrity": "sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw==", + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "2.2.31", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz", + "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^1.0.20" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/sirv/-/sirv-3.0.0.tgz", + "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/slate": { + "version": "0.72.8", + "resolved": "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz", + "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==", + "license": "MIT", + "dependencies": { + "immer": "^9.0.6", + "is-plain-object": "^5.0.0", + "tiny-warning": "^1.0.3" + } + }, + "node_modules/slate-history": { + "version": "0.66.0", + "resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.66.0.tgz", + "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^5.0.0" + }, + "peerDependencies": { + "slate": ">=0.65.3" + } + }, + "node_modules/snabbdom": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.2.tgz", + "integrity": "sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q==", + "license": "MIT", + "engines": { + "node": ">=12.17.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmmirror.com/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ssr-window": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz", + "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==", + "license": "MIT" + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superjson": { + "version": "2.2.2", + "resolved": "https://registry.npmmirror.com/superjson/-/superjson-2.2.2.tgz", + "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/synckit": { + "version": "0.9.2", + "resolved": "https://registry.npmmirror.com/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "license": "ISC" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", + "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", + "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-hot-client": { + "version": "0.2.4", + "resolved": "https://registry.npmmirror.com/vite-hot-client/-/vite-hot-client-0.2.4.tgz", + "integrity": "sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0" + } + }, + "node_modules/vite-plugin-inspect": { + "version": "0.8.9", + "resolved": "https://registry.npmmirror.com/vite-plugin-inspect/-/vite-plugin-inspect-0.8.9.tgz", + "integrity": "sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/utils": "^0.7.10", + "@rollup/pluginutils": "^5.1.3", + "debug": "^4.3.7", + "error-stack-parser-es": "^0.1.5", + "fs-extra": "^11.2.0", + "open": "^10.1.0", + "perfect-debounce": "^1.0.0", + "picocolors": "^1.1.1", + "sirv": "^3.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.1" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/vite-plugin-vue-devtools": { + "version": "7.7.0", + "resolved": "https://registry.npmmirror.com/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-7.7.0.tgz", + "integrity": "sha512-1dWiREwIl4JELwXGHXih80hIgjcViMcZGr3j0edo6NQ9kNzAOxMIUgFqc/TO1ary4ZroJUxoB0YDI6jnDf13iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-core": "^7.7.0", + "@vue/devtools-kit": "^7.7.0", + "@vue/devtools-shared": "^7.7.0", + "execa": "^9.5.1", + "sirv": "^3.0.0", + "vite-plugin-inspect": "0.8.9", + "vite-plugin-vue-inspector": "^5.3.1" + }, + "engines": { + "node": ">=v14.21.3" + }, + "peerDependencies": { + "vite": "^3.1.0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0" + } + }, + "node_modules/vite-plugin-vue-inspector": { + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-5.3.1.tgz", + "integrity": "sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/plugin-proposal-decorators": "^7.23.0", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.22.15", + "@vue/babel-plugin-jsx": "^1.1.5", + "@vue/compiler-dom": "^3.3.4", + "kolorist": "^1.8.0", + "magic-string": "^0.30.4" + }, + "peerDependencies": { + "vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0" + } + }, + "node_modules/vue": { + "version": "3.5.13", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.0.tgz", + "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", + "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==", + "license": "MIT" + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/yoctocolors/-/yoctocolors-2.1.1.tgz", + "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/Web/package.json b/Web/package.json new file mode 100644 index 0000000..ba89040 --- /dev/null +++ b/Web/package.json @@ -0,0 +1,42 @@ +{ + "name": "vue3-element-admin", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^5.1.12", + "@wangeditor/plugin-upload-attachment": "^1.1.0", + "axios": "^1.6.7", + "element-plus": "^2.6.1", + "js-cookie": "^3.0.5", + "normalize.css": "^8.0.1", + "nprogress": "^0.2.0", + "path-browserify": "^1.0.1", + "path-to-regexp": "^6.2.1", + "pinia": "^2.1.7", + "sass": "^1.71.1", + "screenfull": "^6.0.2", + "vue": "^3.4.21", + "vue-router": "^4.3.0", + "xlsx": "^0.18.5" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.3.3", + "@vitejs/plugin-vue": "^5.0.4", + "@vue/eslint-config-prettier": "^8.0.0", + "eslint": "^8.49.0", + "eslint-plugin-vue": "^9.17.0", + "prettier": "^3.0.3", + "vite": "^5.1.5", + "vite-plugin-vue-devtools": "^7.0.16" + } +} diff --git a/Web/public/favicon.ico b/Web/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/Web/src/App.vue b/Web/src/App.vue new file mode 100644 index 0000000..b958da8 --- /dev/null +++ b/Web/src/App.vue @@ -0,0 +1,4 @@ + + diff --git a/Web/src/api/system/autoJobApi.js b/Web/src/api/system/autoJobApi.js new file mode 100644 index 0000000..e05614a --- /dev/null +++ b/Web/src/api/system/autoJobApi.js @@ -0,0 +1,50 @@ +import request from '@/utils/request' + +/** + * @param {Object} data + * @param {string} data.description job描述 + */ +export function getPaged(data) { + return request({ + url: '/api/autoJob/paged', + method: 'post', + data + }) +} + +/*** + * 开始job + * @param {string} id triggerId + */ +export function startJob(id) { + return request({ + url: '/api/autoJob/start', + method: 'get', + params: { id } + }) +} +/*** + * 暂停job + * @param {string} id triggerId + */ +export function stopJob(id) { + return request({ + url: '/api/autoJob/stop', + method: 'get', + params: { id } + }) +} + +/*** + * 延期job + * @param {Object} data + * @param {string} data.id triggerId + * @param {string} data.endTime 延期结束时间 + */ +export function deferredJob(data) { + return request({ + url: '/api/autoJob/deferred', + method: 'post', + data + }) + } diff --git a/Web/src/api/system/dataDictApi.js b/Web/src/api/system/dataDictApi.js new file mode 100644 index 0000000..447812e --- /dev/null +++ b/Web/src/api/system/dataDictApi.js @@ -0,0 +1,68 @@ +import request from '@/utils/request' + +/** + * @param {Object} data + * @param {string} data.name 字典名称 + */ +export function getPaged(data) { + return request({ + url: '/api/dataDict/paged', + method: 'post', + data + }) +} + +/** + * 获取一个最大的数字 + */ +export function getMaxSort() { + return request({ + url: '/api/dataDict/maxSort', + method: 'get' + }) +} +/** + * 删除字典 + * @param {string[]} data.ids 字典id列表 + */ +export function deleteDataDict(data) { + return request({ + url: '/api/dataDict/delete', + method: 'post', + data + }) +} + +/** + * 新增字典 + */ +export function addDataDict(data) { + return request({ + url: '/api/dataDict/add', + method: 'post', + data + }) +} + +/** + * 更新字典 + */ +export function updateDataDict(data) { + return request({ + url: '/api/dataDict/update', + method: 'post', + data + }) +} + +/** + * 获取字典明细 + * @param {string} id 字典id + */ +export function getDataDict(id) { + return request({ + url: '/api/dataDict/detail', + method: 'get', + params: { id } + }) +} diff --git a/Web/src/api/system/dataDictDetailApi.js b/Web/src/api/system/dataDictDetailApi.js new file mode 100644 index 0000000..a5a50b5 --- /dev/null +++ b/Web/src/api/system/dataDictDetailApi.js @@ -0,0 +1,80 @@ +import request from '@/utils/request' + +/** + * @param {Object} data + * @param {string} data.name 字典名称 + */ +export function getPaged(data) { + return request({ + url: '/api/dataDictDetail/paged', + method: 'post', + data + }) +} + +/** + * 获取一个最大的数字 + */ +export function getMaxSort() { + return request({ + url: '/api/dataDictDetail/maxSort', + method: 'get' + }) +} +/** + * 删除字典 + * @param {string[]} data.ids 字典id列表 + */ +export function deleteDataDictDetail(data) { + return request({ + url: '/api/dataDictDetail/delete', + method: 'post', + data + }) +} + +/** + * 新增字典 + */ +export function addDataDictDetail(data) { + return request({ + url: '/api/dataDictDetail/add', + method: 'post', + data + }) +} + +/** + * 更新字典 + */ +export function updateDataDictDetail(data) { + return request({ + url: '/api/dataDictDetail/update', + method: 'post', + data + }) +} + +/** + * 获取字典明细 + * @param {string} id 字典id + */ +export function getDataDictDetail(id) { + return request({ + url: '/api/dataDictDetail/detail', + method: 'get', + params: { id } + }) +} + +/** + * 获取字典明细 + * @param {string} code 字典类型code + */ +export function getSelectList(code) { + return request({ + url: '/api/dataDictDetail/selectList', + method: 'get', + params: { code } + }) +} diff --git a/Web/src/api/system/fileApi.js b/Web/src/api/system/fileApi.js new file mode 100644 index 0000000..658b32d --- /dev/null +++ b/Web/src/api/system/fileApi.js @@ -0,0 +1,38 @@ +import request from '@/utils/request' + +/** + * 获取上传路径 + * @returns {Object} return 路径信息 + * @returns {String} return.local 本地仓储上传路径 + */ +export function getFileUploadPath() { + return { + local: import.meta.env.VITE_API_BASE_URL + '/api/file/upload' + } +} + +/** + * 获取图片 + * @param {String} code 文件编码批号 + */ +export function getFiles(code) { + return request({ + url: '/api/file/filesByCode', + method: 'get', + params: { code } + }) +} + +/** + * 上传文件 + * @param {FormData} data + * @returns + */ + +export function uploadFile(data) { + return request({ + url: '/api/file/upload', + method: 'post', + data + }) +} \ No newline at end of file diff --git a/Web/src/api/system/logApi.js b/Web/src/api/system/logApi.js new file mode 100644 index 0000000..3824007 --- /dev/null +++ b/Web/src/api/system/logApi.js @@ -0,0 +1,111 @@ +import request from '@/utils/request' + +/** + * 登录日志 + * @param {Object} data + * @param {String} data.userName 用户名 + * @param {String} data.startTime 开始时间 + * @param {String} data.endTime 结束时间 + */ +export function getFiles(data) { + return request({ + url: '/api/log/pagedLogin', + method: 'post', + data + }) +} + +/** + * 登录日志 + * @param {Object} data + * @param {String} data.userName 用户名 + * @param {String} data.startTime 开始时间 + * @param {String} data.endTime 结束时间 + */ +export function getLogLogin(data) { + return request({ + url: '/api/log/pagedLogin', + method: 'post', + data + }) +} + +/** + * job日志 + * @param {Object} data + * @param {String} data.jobId jobId + * @param {String} data.startTime 开始时间 + * @param {String} data.endTime 结束时间 + */ +export function getLogJob(data) { + return request({ + url: '/api/log/pagedJob', + method: 'post', + data + }) +} + +/** + * 事件日志 + * @param {Object} data + * @param {String} data.eventName 事件名称 + * @param {String} data.startTime 开始时间 + * @param {String} data.endTime 结束时间 + */ +export function getLogEvent(data) { + return request({ + url: '/api/log/pagedEvent', + method: 'post', + data + }) +} + +/** + * 登录日志 + * @param {Object} data + * @param {String} data.requestUrl 请求路径 + * @param {String} data.source 来源 + * @param {String} data.controllerName 控制器名称 + * @param {String} data.actionName 方法名称 + * @param {String} data.startTime 开始时间 + * @param {String} data.endTime 结束时间 + */ +export function getLogException(data) { + return request({ + url: '/api/log/pagedException', + method: 'post', + data + }) +} + +/** + * 操作日志 + * @param {Object} data + * @param {String} data.requestUrl 请求路径 + * @param {String} data.controllerName 控制器名称 + * @param {String} data.actionName 方法名称 + * @param {String} data.startTime 开始时间 + * @param {String} data.endTime 结束时间 + */ +export function getLogOperation(data) { + return request({ + url: '/api/log/pagedOperation', + method: 'post', + data + }) +} + +/** + * 差异日志 + * @param {Object} data + * @param {String} data.tableName 表名 + * @param {String} data.startTime 开始时间 + * @param {String} data.endTime 结束时间 + */ +export function getLogDiff(data) { + return request({ + url: '/api/log/pagedDiff', + method: 'post', + data + }) +} diff --git a/Web/src/api/system/menuApi.js b/Web/src/api/system/menuApi.js new file mode 100644 index 0000000..9b2acfb --- /dev/null +++ b/Web/src/api/system/menuApi.js @@ -0,0 +1,83 @@ +import request from '@/utils/request' + +/** + * @param {Object} data + * @param {string} data.name 菜单名称 + * @param {Number} data.treeType 菜单类型 1: 目录,2: 目录-菜单,其他: 目录-菜单-按钮 + */ +export function getTreeList(data) { + return request({ + url: '/api/menu/treeList', + method: 'post', + data + }) +} + +/** + * @param {Object} data + * @param {string} data.name 菜单名称 + * @param {Number} data.treeType 菜单类型 1: 目录,2: 目录-菜单,其他: 目录-菜单-按钮 + */ +export function getElTreeList(data) { + return request({ + url: '/api/menu/elTreeList', + method: 'post', + data + }) +} + +/** + * 获取一个最大的数字 + */ +export function getMaxSort() { + return request({ + url: '/api/menu/maxSort', + method: 'get', + }) +} + +/** + * 新增菜单 + */ +export function addMenu(data) { + return request({ + url: '/api/menu/add', + method: 'post', + data + }) +} + +/** + * 更新菜单 + */ +export function updateMenu(data) { + return request({ + url: '/api/menu/update', + method: 'post', + data + }) +} + +/** + * 删除菜单 + * @param {string[]} data.ids 菜单id + */ +export function deleteMenu(data) { + return request({ + url: '/api/menu/delete', + method: 'post', + data + }) +} + +/** + * 获取菜单明细 + * @param {string} id 菜单id + */ +export function getMenu(id) { + return request({ + url: '/api/menu/detail', + method: 'get', + params: { id } + }) +} \ No newline at end of file diff --git a/Web/src/api/system/messageApi.js b/Web/src/api/system/messageApi.js new file mode 100644 index 0000000..71eb805 --- /dev/null +++ b/Web/src/api/system/messageApi.js @@ -0,0 +1,135 @@ +import request from '@/utils/request' + +/** + * 新增 + * @param {Object} data + */ +export function addMessage(data) { + return request({ + url: '/api/message/add', + method: 'post', + data + }) +} + +/** + * 更新 + * @param {Object} data + */ +export function updateMessage(data) { + return request({ + url: '/api/message/update', + method: 'post', + data + }) +} + +/** + * 发布信息 + * @param {Object} data + * @param {String} data.id 消息id + * @param {String[]} data.userIds 私信的用户列表 + */ +export function publishMessage(data) { + return request({ + url: '/api/message/publish', + method: 'post', + data + }) +} + +/** + * 设置已读 + * @param {String} id 消息id + */ +export function setRead(id) { + return request({ + url: '/api/message/setRead', + method: 'get', + params: { id } + }) +} + +/** + * 全部已读 + */ +export function setAllRead() { + return request({ + url: '/api/message/setAllRead', + method: 'get' + }) +} + +/** + * 获取未读消息的数量 + */ +export function messageCount() { + return request({ + url: '/api/message/messageCount', + method: 'get' + }) +} + +/** + * 查询所有接受的消息 + * @param {Object} data + * @param {string} data.title 标题 + * @param {Number} data.type 标题 0系统通知 1公告 2私信 + */ +export function pagedReceived(data) { + return request({ + url: '/api/message/pagedReceived', + method: 'post', + data + }) +} +/** + * 查询所有自己发布的消息 + * @param {Object} data + * @param {string} data.title 标题 + * @param {Number} data.type 标题 0系统通知 1公告 2私信 + */ +export function pagedPublish(data) { + return request({ + url: '/api/message/pagedPublish', + method: 'post', + data + }) +} + +/** + * 获取消息详情 + * @param {string} id + * @returns + */ +export function getMessage(id) { + return request({ + url: '/api/message/detail', + method: 'get', + params: { id } + }) +} + +/** + * 删除消息 + * @param {string[]} data.ids 消息id列表 + */ +export function deleteMessage(data) { + return request({ + url: '/api/message/delete', + method: 'post', + data + }) +} + +/** + * 撤回消息 + * @param {string[]} data.ids 消息id列表 + */ +export function recalledMessage(data) { + return request({ + url: '/api/message/recalled', + method: 'post', + data + }) +} diff --git a/Web/src/api/system/orgApi.js b/Web/src/api/system/orgApi.js new file mode 100644 index 0000000..136bfd7 --- /dev/null +++ b/Web/src/api/system/orgApi.js @@ -0,0 +1,79 @@ +import request from '@/utils/request' +/** + * @param {Object} data + * @param {string} data.name 机构名称 + */ +export function getTreeList(data) { + return request({ + url: '/api/org/treeList', + method: 'post', + data + }) +} + +/** + * @param {Object} data + * @param {string} data.name 机构名称 + */ +export function getElTreeList(data) { + return request({ + url: '/api/org/elTreeList', + method: 'post', + data + }) +} + +/** + * 获取一个最大的数字 + */ +export function getMaxSort() { + return request({ + url: '/api/org/maxSort', + method: 'get' + }) +} +/** + * 删除机构 + * @param {string[]} data.ids 机构id + */ +export function deleteOrg(data) { + return request({ + url: '/api/org/delete', + method: 'post', + data + }) +} + +/** + * 新增机构 + */ +export function addOrg(data) { + return request({ + url: '/api/org/add', + method: 'post', + data + }) +} + +/** + * 更新机构 + */ +export function updateOrg(data) { + return request({ + url: '/api/org/update', + method: 'post', + data + }) +} + +/** + * 获取机构明细 + * @param {string} id 机构id + */ +export function getOrg(id) { + return request({ + url: '/api/org/detail', + method: 'get', + params: { id } + }) +} diff --git a/Web/src/api/system/positionApi.js b/Web/src/api/system/positionApi.js new file mode 100644 index 0000000..785ff6a --- /dev/null +++ b/Web/src/api/system/positionApi.js @@ -0,0 +1,77 @@ +import request from '@/utils/request' + +/** + * @param {Object} data + * @param {string} data.name 职位名称 + */ +export function getPaged(data) { + return request({ + url: '/api/position/paged', + method: 'post', + data + }) +} + +/** + * 获取一个最大的数字 + */ +export function getMaxSort() { + return request({ + url: '/api/position/maxSort', + method: 'get' + }) +} +/** + * 删除职位 + * @param {string[]} data.ids 职位id列表 + */ +export function deletePosition(data) { + return request({ + url: '/api/position/delete', + method: 'post', + data + }) +} + +/** + * 新增职位 + */ +export function addPosition(data) { + return request({ + url: '/api/position/add', + method: 'post', + data + }) +} + +/** + * 更新职位 + */ +export function updatePosition(data) { + return request({ + url: '/api/position/update', + method: 'post', + data + }) +} + +/** + * 获取职位详情 + */ +export function getPosition(id) { + return request({ + url: '/api/position/detail', + method: 'get', + params: { id } + }) +} + +/** + * 获取职位select列表 + */ +export function getSelectList() { + return request({ + url: '/api/position/selectList', + method: 'post' + }) +} diff --git a/Web/src/api/system/roleApi.js b/Web/src/api/system/roleApi.js new file mode 100644 index 0000000..6e6ab66 --- /dev/null +++ b/Web/src/api/system/roleApi.js @@ -0,0 +1,90 @@ +import request from '@/utils/request' + +/** + * @param {Object} data + * @param {string} data.name 角色名称 + */ +export function getPaged(data) { + return request({ + url: '/api/role/paged', + method: 'post', + data + }) +} + +/** + * 获取一个最大的数字 + */ +export function getMaxSort() { + return request({ + url: '/api/role/maxSort', + method: 'get' + }) +} +/** + * 删除角色 + * @param {string[]} data.ids 角色id列表 + */ +export function deleteRole(data) { + return request({ + url: '/api/role/delete', + method: 'post', + data + }) +} + +/** + * 新增角色 + */ +export function addRole(data) { + return request({ + url: '/api/role/add', + method: 'post', + data + }) +} + +/** + * 更新角色 + */ +export function updateRole(data) { + return request({ + url: '/api/role/update', + method: 'post', + data + }) +} + +/** + * 更新角色数据权限范围 + */ +export function updateRoleDataType(data) { + return request({ + url: '/api/role/updateRoleDataType', + method: 'post', + data + }) +} + +/** + * 获取角色明细 + * @param {string} id 角色id + */ +export function getRole(id) { + return request({ + url: '/api/role/detail', + method: 'get', + params: { id } + }) +} + + +/** + * 获取角色select列表 + */ +export function getSelectList() { + return request({ + url: '/api/role/selectList', + method: 'post' + }) +} \ No newline at end of file diff --git a/Web/src/api/system/sysApi.js b/Web/src/api/system/sysApi.js new file mode 100644 index 0000000..8dc1eca --- /dev/null +++ b/Web/src/api/system/sysApi.js @@ -0,0 +1,13 @@ +import request from '@/utils/request' + +/** + * 获取枚举选项 + * @param {string} name 名称 + */ +export function getEnumOptions(name) { + return request({ + url: '/api/system/enumOptions', + method: 'get', + params: { name } + }) + } \ No newline at end of file diff --git a/Web/src/api/system/tenantApi.js b/Web/src/api/system/tenantApi.js new file mode 100644 index 0000000..9c17845 --- /dev/null +++ b/Web/src/api/system/tenantApi.js @@ -0,0 +1,78 @@ +import request from '@/utils/request' + +/** + * @param {Object} data + * @param {string} data.name 租户名称 + */ +export function getPaged(data) { + return request({ + url: '/api/tenant/paged', + method: 'post', + data + }) +} + +/** + * 删除租户 + * @param {string} data.id 租户id列表 + */ +export function deleteTenant(data) { + return request({ + url: '/api/tenant/delete', + method: 'post', + data + }) +} + +/** + * 新增租户 + */ +export function addTenant(data) { + return request({ + url: '/api/tenant/add', + method: 'post', + data + }) +} + +/** + * 获取租户详情 + */ +export function getTenant(id) { + return request({ + url: '/api/tenant/detail', + method: 'get', + params: { id } + }) +} + +/** + * 启用租户 + */ +export function openTenant(id) { + return request({ + url: '/api/tenant/open', + method: 'get', + params: { id } + }) +} + +/** + * 禁用租户 + */ +export function closeTenant(id) { + return request({ + url: '/api/tenant/close', + method: 'get', + params: { id } + }) +} +/** + * 获取一个最大的数字 + */ +export function getMaxSort() { + return request({ + url: '/api/tenant/maxSort', + method: 'get' + }) +} \ No newline at end of file diff --git a/Web/src/api/system/userApi.js b/Web/src/api/system/userApi.js new file mode 100644 index 0000000..462db35 --- /dev/null +++ b/Web/src/api/system/userApi.js @@ -0,0 +1,172 @@ +import request from '@/utils/request' + +/** + * @param {Object} data 登录信息 + * @param {string} data.username 用户名 + * @param {string} data.password 密码 + * @param {string} data.captchaCode 验证码code + * @param {string} data.captcha 验证码Id + */ +export function login(data) { + return request({ + url: '/api/user/login', + method: 'post', + data + }) +} + +/** + * @param {Object} data 登录信息 + * @param {string} data.username 用户名 + * @param {string} data.password 密码 + * @param {string} data.tenantId 租户id + * @param {string} data.captcha 验证码Id + */ +export function tenantLogin(data) { + return request({ + url: '/api/user/tenantLogin', + method: 'post', + data + }) +} + +/** + * @param {{refreshToken:string}} token 刷新令牌 + */ +export function refreshLogin(data) { + return request({ + url: '/api/user/refreshLogin', + method: 'post', + data + }) +} + +/*** + * 获取当前用户的信息 + */ +export function getCurrentInfo() { + return request({ + url: '/api/user/currentUserInfo', + method: 'get', + }) +} + +/*** + * 获取当前用户的菜单 + */ +export function getCurrentMenu() { + return request({ + url: '/api/user/currentRoleAuthorizeInfo', + method: 'get', + }) +} + +/** + * @returns 验证码 和 验证码code + */ +export function getCaptcha() { + return request({ + url: '/api/user/captcha', + method: 'get' + }) +} + +/** + * 分页获取用户信息 + */ +export function getPaged(data) { + return request({ + url: '/api/user/Paged', + method: 'post', + data + }) +} + +/** + * 分页获取用户信息 + */ +export function exportUser(data) { + return request({ + url: '/api/user/export', + method: 'post', + responseType:'blob', + data + }) +} + +/** + * @param {Object} data 登录信息 + * @param {string} data.name 用户名|姓名 + * @param {list} data.ids id列表 + * 获取用户信息 + */ +export function getSelectList(data) { + return request({ + url: '/api/user/selectList', + method: 'post', + data + }) +} + + +/** + * 获取用户信息 + * @param {string[]} data.ids 用户id列表 + */ +export function deleteUser(data) { + return request({ + url: '/api/user/delete', + method: 'post', + data + }) +} + +/** + * 新增用户信息 + */ +export function addUser(data) { + return request({ + url: '/api/user/add', + method: 'post', + data + }) +} + +/** + * 更新用户信息 + */ +export function updateUser(data) { + return request({ + url: '/api/user/update', + method: 'post', + data + }) +} + +/** + * 获取用户明细 + * @param {string} id 用户id + */ +export function getUser(id) { + return request({ + url: '/api/user/detail', + method: 'get', + params: { id } + }) +} + +/** + * 修改密码 + * @param {Object} data + * @param {String} data.id 用户id + * @param {String} data.password 旧密码 + * @param {String} data.newPassword 新密码 + * @param {String} data.confirmPassword 确认密码 + */ +export function resetPassword(data) { + return request({ + url: '/api/user/resetPassword', + method: 'post', + data + }) +} diff --git a/Web/src/assets/401_images/401.gif b/Web/src/assets/401_images/401.gif new file mode 100644 index 0000000000000000000000000000000000000000..cd6e0d9433421b3f29d0ec0c40f755e354728000 GIT binary patch literal 164227 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⋘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 GY5fOuZZib{ literal 0 HcmV?d00001 diff --git a/Web/src/assets/404.png b/Web/src/assets/404.png new file mode 100644 index 0000000000000000000000000000000000000000..3d8e2305cc973ad2121403aee4bf08728f76c461 GIT binary patch literal 98071 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 literal 0 HcmV?d00001 diff --git a/Web/src/assets/404_cloud.png b/Web/src/assets/404_cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..c6281d09013e0a2c5f8e699a0a6038d9480291e5 GIT binary patch literal 4766 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 literal 0 HcmV?d00001 diff --git a/Web/src/assets/404_images/404.png b/Web/src/assets/404_images/404.png new file mode 100644 index 0000000000000000000000000000000000000000..3d8e2305cc973ad2121403aee4bf08728f76c461 GIT binary patch literal 98071 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 literal 0 HcmV?d00001 diff --git a/Web/src/assets/404_images/404_cloud.png b/Web/src/assets/404_images/404_cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..c6281d09013e0a2c5f8e699a0a6038d9480291e5 GIT binary patch literal 4766 zcmV;P5@GF$P)z1^@s6R@{TJ00001b5ch_0Itp) z=>Px{SV=@dRCodHoqLcR#eK)SXLk2aLP!ExlChA4#6y+=^RN{OKVlN7GET+i$PP9^ zR9s2L*v|8hkf(_)D$dKqRm8-V1lyIWxJbn=$|g=hDpjdKsES{RV8G%C=q$?uPKVI@ zbbI@l>3n{tyVKlhc5i35XJ>Y|yXtp4kM3Xp`rF^@?)i03k5(>Zihwa@T{TcUOb~82 zTJOM^>y%N4l~$ulnNg#?eZCwAYG0|Oex$WNovFbIGuH{@yXYMt0GXDQ>*{(`>`vI92rNTSOTED2gOaUqjet*R?SA(5hWGK`(H+RF7z@Pt5R z2=#Q)*B8@$Zdg#H7dU@sR^4YNfGhwY_oonNO(js<8Hhuq>4Eq*uAQH?;acfeeP53j z{pr?fc@ulS&Apq2h)v?8a?25H0jvfVtHZ6#j=_%ddbH1m`1z)`# zL%bG^`4;g$2+4vL<6DU~@B}Lxvrz`(N{0->r(37%A=!`>bS)}@7*)EzCriG51HW6^ zRQ&*YKHg^9wvr7T!647_N~nI>nDA{T&^IS{6SReM`-!wZ%$R*I1NSRYvbudmb18R2 zvU}#vQa%_sf=yP!Z$PS@f-69W#;9=y$glJCcZy3jxr_|s>|CimwI&SBO3u3;ux+H^ z=_7Q5+sNE@i+U&eztoLF4HUs9Yvy-V82)tm+1apsi2oY`s*6Svv6JV*-3u?Wso= zt(|z+WqRk73RTrG3daYwgnKJ^Kv={5HRRhEYdr9DgFh$~^kqa^=w?W0QOnWgpXDZO z{7%a$+KAY=&}}HoYZ5AVb-8MurfXc6iH(e-0D7Ffk3qIc?a?(WJo-j0p&P8sbc0#A zJ&s`0yC9kP%2Ek^PcX>kP1VeQ@XLTcKY>cE4;7~871w8M)dBLq0ei;Mu%lHUN*Z~0 zMdwsC+?_XaNx|`BJxxcNHMzu;jmW=)Q8P!a#A_?`bqhwz^e68eMvAtDyo|K zdKRl07OU)nuV11$eZyk$GP?f}^1a(;-hD~1at&XXnO@Lm6RVDOG49$^@KW_}b!;OF zw%SlKtE2A-Hd!&Z^7#MTvjxo0uO7pJYPIt6Q?|yI^cBHaL3)MO<|~bho6Q}@U4}vZ zadJN|8w;|_wQmT!r$ z%Go4VPwVv}DX3!>2wTL}?n8bcpo@~m(mY#3APgTNQLN2CX z_IsW_Sn}0`@2e7|yNH4HZ3hjdj(3%+M~n!AvTmy+Ouv$5%b1|qloqe!J-9<9<%0ZMLke& zs|WO+wP5-dtzAG%_Y&_Aj?uzZi=JA_IB7j`t*mT7_Y)BLr=xZZ@^N1iEUsc{?ff7x zmj{8mJbIr+fJX|R_v3;Wo@6?QLvJ<2+f4kHmqXKH?q`jc>^1oGX~irztr<65vbYMWQt)=pJ} zwP%u^8QZNszmV4@IBk^BUXq^ogV}?kV@>X#H3mXQuozI>C3^@sg4x5;X^KI>5iAB2 zcgY?Cj$rn%beduia0H71#a*(8fFqbaES;tp1RTL)KyjDsA>asR4@;*h1_4K~7*O0L zdk8p!*~8Llib23lZ^VEy;Fo@ZN&Z(_z~Bku+#&1hn#FYlYlhBX-djSkMHUOU5ka;W z{dlv8u8VAjj=Q%Q0(a8d-P0_RBUm$Z+`U#1_%tN@WTS|VV2zM**OMUdw~*{ZaS0s3 z;!ttdk|H2HlFj~ZT$s=iY#}1V5!3Elskes4y1}ePZJD3%MHHoJ;lCUr&C4ADQ_Er zo?CDTsbn$SFCo8yT)+B^E3aOyt7pqKbF@+mR)&gCwq&t4YunY(zX{pIuQvk3x)e)4 zf&40R;UZR-D>XAxu7@Y8b;I|v^_xlWFOsIC+ic$y`kw0P9-$)u;uF_%O)y9y6?O|E zt=0RGw(Mnx))Rc3^aZ|tTV_MKi;U7&pt~(y*bo~W!D3;_C&8$EX`y}v`E_J-tmz$G ztW8ozxL57QuWGjEa^GbfvYDF;*)t9>kU^>BZ2fmm%C} zr55UHAcQs-C)MEy7K>Q+1cOwvi}S6>Zz4Nl&Fu0;_S@gb1H(Z+uvOrA3pOtL31mmG z*hMR3o%-hiKuJhN0TZp86{nn&k+#5RvKg?h_1R z-AvZf4Za^q^~r9!i1z=~_?pPx$+|fV;Z~SXT?ygNa|DY8x;q4eRLjZ!qlge|OROoq zdvUT-SC5qn>gRYYwfbb*yO7LTo-V;4)>ULBq`CuHHkWPx9K1wPKv}^sJ zvzLKsVEbzw6AWU#8|BhkeGn-&$f(yZOE>r|B3)tE{Bu1F+G%XR54pE(f0JR6X4v_~H7n&nb<@P@ypJiL8*CcA&1S?mAuQBEFVHAZZ`2in; z;-jDH3UrEptJi}7^*v-O;=Vz&cx}oaVP8dd!-oUW=xq^fs&3vF2H~SoMRJUCnL&PL z=JR**ZrsL&adLhhV&8X>OOSpYM^ZGa;TveXo4Ox~)0&uIbd5`=s%9_F#Y^H8&R&}# z+p|J8zM*|788wYRn=ZrO@00gxWK)JV^itOUiLrk~J!Bw zmTereZNdQS%W+yMIC1tOGIn@ti}43Nn&2f};loLQXqjM;%43DWcUX%2Q%N#dEG`D` zogv#LT_W2)Y!bJFyxQ)<;t1>~%4d)VsVf~ z5yNDOw9Rl3Wv?LHk(SGC(|{h+bqISui#$NRoc)w}!a}qJG_BVWvpGs&-u*qt0pEBxqQpwq(QUD5uiu!d5 zv(}>8epdCb6z)^tCa#B6Lqme$^LjfzukX@|<$hVS@9URKzE1omP^!r0Q~7^k)*nMG zah7%^#1c$Mh0p6rd|tAOAlCt~CWec;A6LuT#QjN>39)2)r>i0MvAtZUTkHXH2~tJB zeIHF%k@g8Yr)uu;V&>y-VDlpz>9wha$T5vL(?-*yzgH@{uE-pnqD@Y zYo2Zd@OkaP=k-6dVqWJe)71c=Cvi(GPdAs`YByN+FUX&O!)R`;j2KpcR0UQ_JkSf| z61#Cr3`Oi8q{IKFuy;YMrc0Fb28cIRS9d|KtMg`9oISWDjxhH)Xao~q)(0TgjlD)L zsY8z~{%+)Tpd)b=nx|`kYleJ1NR!yIvf&fR)s+2Pd8&&fw&=0rHMT6()l$Lx-;y6r z`r2bPLjIm4Sut^p?(u>oh3nC{;%4|f@;Qi=E0;q%c%C6xBqfCksmy2akRQX(bQxsZ z5V@VnAvRSQ*!O$aC?5BJL}UPOeO*>26-TD$5Nx3#xCBOq3i?pd_tvv648nCk6boJ% zJC<}m=dR`W2s!;e#CpDKId&an~t)uFZJMQeF~>)zphMu z3IOHF@bT1v%qW9I1dH0pRL$6uqQ~-Oa{(lHOImJ@p`vH#s{74p|6{Pc8~JC*CBCh` z4Q&%FiiqcXM`_t!;H8YEkl`xvtwry*d(7JV6Qx35O=uqji$6#1hgg+%ap|RWRtOd? zFi)WqMc<5+iqKB8L2jGh459);#(p%8QSCi@EGrwnh{)8AkZfRrb%I5agC5nAr=Mq8 zO`UPuR>;=!G9aF0Cvi(Gjq2;cW9k0Bj>ujP`+Ly-j!jOLU{UL&MS?IRxEm&E+2mV6 z4cBrJcZzt!(eyodEK@tbM_HciLEEjF+%3Jf*gJwHLsX`A#habKtBzpv>tx`kcILy;`I#fwSqz`x zP}XJ*^wiE-IP4rbf+_U^Q2qhLa#K5YI5khpAU{QpgTyD1s~oxJal-1!Ahuv`YR4*t znky@?8hL{0nL*egaCU0v)3jJ)&0%qOZ6V;TUE!|<@Lk9wNZVg@uw_t6dLBjZHI(mT zh$B}@AjhelH>-T|q*+xC!w(xB?qb6E9V`l*cRx;n?Q6@1J=W`38ydQ)9orR@P+vm= z9V?rSl}dQKQsM15hptMfx9#Yb2qsfIpF;Znt(~@k?oz^r1dHZBK4IRf>h)cr(zm7k zrgw(~b5lFfip#-qO9Y#>Q@YH<6YAZe32x^Lqqnlu+4?4MZ4%5)?aWqE&VCaSENVMs zD~_KEZee}kF39$NS~e?h03{^Y?9`6z0so_@eeO6P2((SGsQIt)O(SzM*vZFlcA@ZQ z$k+A@8wm&|Q#-OY>-$k#+;P4TutKnCkq(_QYg8D1WcuO2s2$OJtsJ*NFgLZ+3XnO8 zW1V2pa*ZE1n{j#Y6pGu!s5eLNH9BrWFqzufjeMC_tKKNRyPhuuQYBclsE1FR>+7}p z?aUn9#>~OG=)LH148i34kDo_mLpJx;P86&jIPMz3X0c#=<{g@-zefieXRi7XWLr6V zPkti=b5lD}VBB$X1R&ec_{sXtvE%iJ#!l4BvYqFtsesGo5#-9`8eIy9Km!Dh7_4{t6|!cF8-ZvX%Q07*qoM6N<$g4q%^5&!@I literal 0 HcmV?d00001 diff --git a/Web/src/components/Breadcrumb/index.vue b/Web/src/components/Breadcrumb/index.vue new file mode 100644 index 0000000..76aac32 --- /dev/null +++ b/Web/src/components/Breadcrumb/index.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/Web/src/components/Hamburger/index.vue b/Web/src/components/Hamburger/index.vue new file mode 100644 index 0000000..7bae870 --- /dev/null +++ b/Web/src/components/Hamburger/index.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/Web/src/components/RightPanel/index.vue b/Web/src/components/RightPanel/index.vue new file mode 100644 index 0000000..0dd468a --- /dev/null +++ b/Web/src/components/RightPanel/index.vue @@ -0,0 +1,148 @@ + + + + + + + diff --git a/Web/src/components/Screenfull/index.vue b/Web/src/components/Screenfull/index.vue new file mode 100644 index 0000000..97dbecb --- /dev/null +++ b/Web/src/components/Screenfull/index.vue @@ -0,0 +1,55 @@ + + + + diff --git a/Web/src/components/SizeSelect/index.vue b/Web/src/components/SizeSelect/index.vue new file mode 100644 index 0000000..b35b06c --- /dev/null +++ b/Web/src/components/SizeSelect/index.vue @@ -0,0 +1,71 @@ + + + + diff --git a/Web/src/components/SvgIcon/elIcon.vue b/Web/src/components/SvgIcon/elIcon.vue new file mode 100644 index 0000000..3a90470 --- /dev/null +++ b/Web/src/components/SvgIcon/elIcon.vue @@ -0,0 +1,9 @@ + + + diff --git a/Web/src/components/SvgIcon/icon.vue b/Web/src/components/SvgIcon/icon.vue new file mode 100644 index 0000000..a69569e --- /dev/null +++ b/Web/src/components/SvgIcon/icon.vue @@ -0,0 +1,38 @@ + + + diff --git a/Web/src/components/SwitchDark/index.vue b/Web/src/components/SwitchDark/index.vue new file mode 100644 index 0000000..6d8929a --- /dev/null +++ b/Web/src/components/SwitchDark/index.vue @@ -0,0 +1,23 @@ + + + diff --git a/Web/src/components/Uploads/importErrorDialog.vue b/Web/src/components/Uploads/importErrorDialog.vue new file mode 100644 index 0000000..1bb58b3 --- /dev/null +++ b/Web/src/components/Uploads/importErrorDialog.vue @@ -0,0 +1,88 @@ + + + diff --git a/Web/src/components/Uploads/multipleImgUpload.vue b/Web/src/components/Uploads/multipleImgUpload.vue new file mode 100644 index 0000000..b3d8384 --- /dev/null +++ b/Web/src/components/Uploads/multipleImgUpload.vue @@ -0,0 +1,115 @@ + + + + diff --git a/Web/src/components/Uploads/singleImgUpload.vue b/Web/src/components/Uploads/singleImgUpload.vue new file mode 100644 index 0000000..0e741ba --- /dev/null +++ b/Web/src/components/Uploads/singleImgUpload.vue @@ -0,0 +1,102 @@ + + + diff --git a/Web/src/components/Uploads/uploadButton.vue b/Web/src/components/Uploads/uploadButton.vue new file mode 100644 index 0000000..1a1e799 --- /dev/null +++ b/Web/src/components/Uploads/uploadButton.vue @@ -0,0 +1,123 @@ + + + diff --git a/Web/src/directive/authDirective.js b/Web/src/directive/authDirective.js new file mode 100644 index 0000000..8c41c77 --- /dev/null +++ b/Web/src/directive/authDirective.js @@ -0,0 +1,60 @@ +import store from '@/stores' + +/** + * 用户权限指令 + * @directive 单个权限验证(v-auth="xxx") + * @directive 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]") + * @directive 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]") + */ +export function authDirective(app) { + // 单个权限验证(v-auth="xxx") + app.directive('auth', { + mounted(el, binding) { + const stores = store.permissionStore() + if (!stores.hasPermission(binding.value)) el.parentNode.removeChild(el) + } + }) + // 多个权限验证,满足一个则显示(v-auths="[xxx,xxx]") + app.directive('auths', { + mounted(el, binding) { + let flag = false + const stores = store.permissionStore() + for (let i of binding.value) { + if (stores.hasPermission(i)) { + flag = true + break + } + } + if (!flag) el.parentNode.removeChild(el) + } + }) + // 多个权限验证,全部满足则显示(v-auth-all="[xxx,xxx]") + app.directive('auth-all', { + mounted(el, binding) { + const stores = store.permissionStore() + let flag = true + for (let i of binding.value) { + if (!stores.hasPermission(i)) { + flag = false + break + } + } + if (!flag) el.parentNode.removeChild(el) + } + }) + + // 多个权限验证,满足其中一个则显示(v-auth-any="[xxx,xxx]") + app.directive('auth-any', { + mounted(el, binding) { + const stores = store.permissionStore() + let flag = false + for (let i of binding.value) { + if (stores.hasPermission(i)) { + flag = true + break + } + } + if (!flag) el.parentNode.removeChild(el) + } + }) +} diff --git a/Web/src/directive/index.js b/Web/src/directive/index.js new file mode 100644 index 0000000..6b8c5c2 --- /dev/null +++ b/Web/src/directive/index.js @@ -0,0 +1,10 @@ +import { authDirective } from '@/directive/authDirective'; + +/** + * 导出指令方法:v-xxx + * @methods authDirective 用户权限指令,用法:v-auth + */ +export function directive(app) { + // 用户权限指令 + authDirective(app); +} \ No newline at end of file diff --git a/Web/src/layout/components/AppMain.vue b/Web/src/layout/components/AppMain.vue new file mode 100644 index 0000000..212842d --- /dev/null +++ b/Web/src/layout/components/AppMain.vue @@ -0,0 +1,73 @@ + + + + + + + diff --git a/Web/src/layout/components/Footer/index.vue b/Web/src/layout/components/Footer/index.vue new file mode 100644 index 0000000..ed5d22d --- /dev/null +++ b/Web/src/layout/components/Footer/index.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/Web/src/layout/components/Navbar.vue b/Web/src/layout/components/Navbar.vue new file mode 100644 index 0000000..df86a26 --- /dev/null +++ b/Web/src/layout/components/Navbar.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/Web/src/layout/components/Settings/index.vue b/Web/src/layout/components/Settings/index.vue new file mode 100644 index 0000000..43ccb17 --- /dev/null +++ b/Web/src/layout/components/Settings/index.vue @@ -0,0 +1,198 @@ + + + + + diff --git a/Web/src/layout/components/Sidebar/FixiOSBug.js b/Web/src/layout/components/Sidebar/FixiOSBug.js new file mode 100644 index 0000000..5f8d006 --- /dev/null +++ b/Web/src/layout/components/Sidebar/FixiOSBug.js @@ -0,0 +1,18 @@ +export default { + mounted() { + // In order to fix the click on menu on the ios device will trigger the mouseleave bug + // https://github.com/PanJiaChen/vue-element-admin/issues/1135 + this.fixBugIniOS() + }, + methods: { + fixBugIniOS() { + const $subMenu = this.$refs.subMenu + if ($subMenu) { + const handleMouseleave = $subMenu.handleMouseleave + $subMenu.handleMouseleave = (e) => { + handleMouseleave(e) + } + } + } + } +} diff --git a/Web/src/layout/components/Sidebar/Logo.vue b/Web/src/layout/components/Sidebar/Logo.vue new file mode 100644 index 0000000..a2d3755 --- /dev/null +++ b/Web/src/layout/components/Sidebar/Logo.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/Web/src/layout/components/Sidebar/SidebarItem.vue b/Web/src/layout/components/Sidebar/SidebarItem.vue new file mode 100644 index 0000000..898d524 --- /dev/null +++ b/Web/src/layout/components/Sidebar/SidebarItem.vue @@ -0,0 +1,99 @@ + + + diff --git a/Web/src/layout/components/Sidebar/index.vue b/Web/src/layout/components/Sidebar/index.vue new file mode 100644 index 0000000..552d3be --- /dev/null +++ b/Web/src/layout/components/Sidebar/index.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/Web/src/layout/components/SidebarColumn/index.vue b/Web/src/layout/components/SidebarColumn/index.vue new file mode 100644 index 0000000..067c559 --- /dev/null +++ b/Web/src/layout/components/SidebarColumn/index.vue @@ -0,0 +1,143 @@ + + + diff --git a/Web/src/layout/components/TagsView/ScrollPane.vue b/Web/src/layout/components/TagsView/ScrollPane.vue new file mode 100644 index 0000000..8f534f8 --- /dev/null +++ b/Web/src/layout/components/TagsView/ScrollPane.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/Web/src/layout/components/TagsView/index.vue b/Web/src/layout/components/TagsView/index.vue new file mode 100644 index 0000000..1bccf4b --- /dev/null +++ b/Web/src/layout/components/TagsView/index.vue @@ -0,0 +1,338 @@ + + + + + + + diff --git a/Web/src/layout/components/index.js b/Web/src/layout/components/index.js new file mode 100644 index 0000000..6e03296 --- /dev/null +++ b/Web/src/layout/components/index.js @@ -0,0 +1,6 @@ +export { default as Navbar } from './Navbar.vue' +export { default as Sidebar } from './Sidebar/index.vue' +export { default as SidebarColumn } from './SidebarColumn/index.vue' +export { default as AppMain } from './AppMain.vue' +export { default as TagsView } from './TagsView/index.vue' +export { default as Settings } from './Settings/index.vue' diff --git a/Web/src/layout/index.vue b/Web/src/layout/index.vue new file mode 100644 index 0000000..48347e7 --- /dev/null +++ b/Web/src/layout/index.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/Web/src/main.js b/Web/src/main.js new file mode 100644 index 0000000..67b3850 --- /dev/null +++ b/Web/src/main.js @@ -0,0 +1,47 @@ +import 'normalize.css/normalize.css' // A modern alternative to CSS resets + +import { createApp } from 'vue' +import { createPinia } from 'pinia' + + +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import 'element-plus/theme-chalk/dark/css-vars.css'; //暗黑模式 +//element中文 +import zhCn from 'element-plus/dist/locale/zh-cn.mjs' + +import '@/styles/index.scss' // global css + +import App from './App.vue' +import { router } from './router' + +//elementui 图标 +import * as ElementPlusIconsVue from '@element-plus/icons-vue' + +import '@/permission' // permission control +//自定义指令 +import { directive } from '@/directive/index' + +// 上传附件注册 +import { Boot } from '@wangeditor/editor' +import attachmentModule from '@wangeditor/plugin-upload-attachment' +// 注册。要在创建编辑器之前注册,且只能注册一次,不可重复注册。 +Boot.registerModule(attachmentModule) + +const app = createApp(App) + +//挂载自定义指令 +directive(app); + +app.use(createPinia()) + +app.use(router) +app.use(ElementPlus, { + locale: zhCn +}) + +for (const [key, component] of Object.entries(ElementPlusIconsVue)) { + app.component(key, component) +} + +app.mount('#app') diff --git a/Web/src/permission.js b/Web/src/permission.js new file mode 100644 index 0000000..994592a --- /dev/null +++ b/Web/src/permission.js @@ -0,0 +1,110 @@ +import { router, addDynamicRoutes } from './router' +import store from './stores' +import { ElMessage } from 'element-plus' +import NProgress from 'nprogress' // progress bar +import 'nprogress/nprogress.css' // progress bar style +import { getToken,getRefreshToken } from '@/utils/auth' // get token from cookie +import getPageTitle from '@/utils/get-page-title' + +NProgress.configure({ showSpinner: false }) // NProgress Configuration + +const whiteList = ['/login'] // no redirect whitelist + +const getUserStore = () => store.userStore() +const getPermissionStore = () => store.permissionStore() + +router.beforeEach(async (to, from, next) => { + // start progress bar + NProgress.start() + // set page title + document.title = getPageTitle(to.meta.title) + + // determine whether the user has logged in + const hasToken = getToken() + if (hasToken) { + if (to.path === '/login') { + // if is logged in, redirect to the home page + next({ path: '/' }) + NProgress.done() + } + else if(to.name==='500'){ + next() + NProgress.done() + } + else { + const userStore = getUserStore() + const hasGetUserInfo = userStore.state.userName && userStore.state.id && userStore.state.userName != '' && userStore.state.id != '' + if (hasGetUserInfo) { + next() + } else { + try { + //获取用户菜单 + let accessRoutes = await userStore.getMenu() + //获取用户信息 + await userStore.getInfo() + + //初始化用户菜单 + let menus= accessRoutes.filter(it=>it.menuType!=3) + // dynamically add accessible routes + addDynamicRoutes(menus) + + //按钮权限 + let btns= accessRoutes.filter(it=>it.menuType==3).map(it=>it.permission) + //设置权限 + getPermissionStore().setPermission(btns) + + if (accessRoutes.length < 1) { + //用户没有动态菜单直接到首页 + next('/') + } else if (to.name == 'allto404') { + //如果导航之前没有获取到动态菜单,则会被allto404捕获 则需要在获取动态菜单后重新定向到正确路径 + next(to.path) + } else { + //正确导航 + next({ ...to, replace: true }) + } + } catch (error) { + ElMessage.error('Has Error') + NProgress.done() + // remove token and go to login page to re-login + //await userStore.resetAllToken() + // other pages that do not have permission to access are redirected to the login page. + window.location.href="/500" + } + } + } + } else { + /* has no token*/ + const refresToken=getRefreshToken() + if(refresToken){ + //重新用刷新token登录 + let uStore = getUserStore() + await uStore.reLogin() + .catch(async ()=>{ + //刷新失败 + await uStore.resetAllToken() + // other pages that do not have permission to access are redirected to the login page. + window.location.href="/login?redirect="+to.path + NProgress.done() + return + }) + //刷新成功 + next() + } + else if (whiteList.indexOf(to.path) !== -1) { + // in the free login whitelist, go directly + next() + } else { + // other pages that do not have permission to access are redirected to the login page. + // next(`/login?redirect=${to.path}`) + NProgress.done() + //store.userStore().resetAllToken() + window.location.href="/login?redirect="+to.path + } + } +}) + +router.afterEach(() => { + // finish progress bar + NProgress.done() +}) diff --git a/Web/src/router/index.js b/Web/src/router/index.js new file mode 100644 index 0000000..f28673a --- /dev/null +++ b/Web/src/router/index.js @@ -0,0 +1,159 @@ +import { createRouter, createWebHistory } from 'vue-router' +/* Layout */ +import Layout from '@/layout/index.vue' + +/** + * Note: sub-menu only appear when route children.length >= 1 + * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html + * + * hidden: true if set true, item will not show in the sidebar(default is false) + * alwaysShow: true if set true, will always show the root menu + * if not set alwaysShow, when item has more than one children route, + * it will becomes nested mode, otherwise not show the root menu + * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb + * name:'router-name' the name is used by (must set!!!) + * meta : { + roles: ['admin','editor'] control the page roles (you can set multiple roles) + title: 'title' the name show in sidebar and breadcrumb (recommend set) + icon: 'svg-name'/'el-icon-x' the icon show in the sidebar + breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) + activeMenu: '/example/list' if set path, the sidebar will highlight the path you set + } + */ + +const modules = import.meta.glob('../views/**/*.vue') +/** + * 返回指定路径的模块 + * @param {string} path 组件路径/views/xx/xx.vue + * @param {string} rename 组件重命名的名字 默认 null + * @returns + */ +function findModules(path,rename=null) { + let findPath = '../views' + path + if(rename){ + return () => + modules[findPath]().then((result) => { + result.default.__name = rename + return result + }) + }else{ + return modules[findPath] + } +} + +/** + * constantRoutes + * a base page that does not have permission requirements + * all roles can be accessed + */ +export const constantRoutes = [ + { + path: '/redirect', + component: Layout, + hidden: true, + name: 'Redirect', + children: [ + { + path: '/redirect/:path(.*)', + component: () => import('@/views/system/redirect/index.vue') + } + ] + }, + { + path: '/login', + component: () => import('@/views/system/login/index.vue'), + name: 'login', + hidden: true + }, + { + path: '/404', + component: () => import('@/views/404.vue'), + name: '404', + hidden: true + }, + { + path: '/500', + component: () => import('@/views/500.vue'), + name: '500', + hidden: true + }, + { path: '/:catchAll(.*)',component: () => import('@/views/404.vue'),name: 'allto404', hidden: true } +] + +/** + * asyncRoutes + * the routes that need to be dynamically loaded based on user roles + */ +export const asyncRoutes = [] + +// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465 +export function resetRouter() { + for (let i in asyncRoutes) { + let rname = asyncRoutes[i].name + if (rname != 'allto404') { + router.removeRoute(rname) + } + } + asyncRoutes.length = 0 +} + +export function addDynamicRoutes(routes) { + //0 代表为根目录 、菜单 + let roots= routes.filter(it=>it.parentId==0) + asyncRoutes.length = 0 + + for (let i in roots) { + asyncRoutes.push(_addRoutes(roots[i],routes)) + } + // 404 page must be placed at the end !!! + //asyncRoutes.push({ path: '/:catchAll(.*)', redirect: '/404', name: 'allto404', hidden: true }) + for (let i in asyncRoutes) { + router.addRoute(asyncRoutes[i]) + } +} + +function _addRoutes(routeInfo,routes) { + let route = { name: routeInfo.routeName?routeInfo.routeName:routeInfo.id, path: routeInfo.routePath, meta: { title: routeInfo.menuName } } + if (routeInfo.componentPath) { + if (routeInfo.componentPath == 'Layout') { + route.component = Layout + } else { + // 动态加载组件,组件名称与路由名称保持一致,方便tagsView 的缓存和销毁 + // keepalive 根据 tagsViewStore.cachedViews 缓存组件 + // vue3.3 以后使用 defineOptions({name: 'xxx'}) + route.component = findModules(routeInfo.componentPath) + } + } + if (routeInfo.redirectPath) { + route.redirect = routeInfo.redirectPath + } + if (routeInfo.menuIcon) { + route.meta.icon = routeInfo.menuIcon + } + if (routeInfo.isAffix) { + route.meta.affix = routeInfo.isAffix + } + if(routeInfo.isCache){ + route.meta.isCache = routeInfo.isCache + } + if(routeInfo.outLink){ + route.meta.outLink = routeInfo.outLink + } + //目录 + if(routeInfo.menuType===1){ + let children= routes.filter(it=>it.parentId===routeInfo.id) + if (children.length > 0) { + route.children = [] + for (let i in children) { + route.children.push(_addRoutes(children[i],routes)) + } + } + } + //菜单 + return route +} + +export const router = createRouter({ + history: createWebHistory(), + routes: constantRoutes +}) diff --git a/Web/src/settings.js b/Web/src/settings.js new file mode 100644 index 0000000..c4b6000 --- /dev/null +++ b/Web/src/settings.js @@ -0,0 +1,39 @@ +export default { + title: 'Vue Admin Template', + + /** + * @type {boolean} true | false + * @description Whether show the settings right-panel + */ + showSettings: true, + + /** + * @type {boolean} true | false + * @description Whether show the logo in sidebar + */ + sidebarLogo: false, + + /*** + * 是否显示页脚 + */ + showFooter: true, + + /** + * @type {string | array} 'production' | ['production', 'development'] + * @description Need show err logs component. + * The default is only used in the production env + * If you want to also use it in dev, you can pass ['production', 'development'] + */ + errorLog: 'production', + + /** + * 布局类型 + * column: 侧边多栏布局 + * sidebar: 抽屉式侧边栏布局 + */ + layoutType:'sidebar', + /** + * 主题颜色 + */ + theme:'#409EFF' +} diff --git a/Web/src/stores/index.js b/Web/src/stores/index.js new file mode 100644 index 0000000..1f9faad --- /dev/null +++ b/Web/src/stores/index.js @@ -0,0 +1,15 @@ +import { useAppStore } from './modules/app' +import { useSettingsStore } from './modules/settings' +import { useUserStore } from './modules/user' +import { usePermissionStore } from './modules/permission' +import { useTagsViewStore } from './modules/tagsView' + +const store = { + appStore: () => useAppStore(), + settingsStore: () => useSettingsStore(), + userStore: () => useUserStore(), + permissionStore: () => usePermissionStore(), + tagsViewStore: () => useTagsViewStore(), +} + +export default store diff --git a/Web/src/stores/modules/app.js b/Web/src/stores/modules/app.js new file mode 100644 index 0000000..a998f13 --- /dev/null +++ b/Web/src/stores/modules/app.js @@ -0,0 +1,34 @@ +import Cookies from 'js-cookie' +import { defineStore } from 'pinia' +import { ref } from 'vue' + +export const useAppStore = defineStore('appStore', () => { + const size = ref(Cookies.get('size') || 'default') + const sidebar = ref({ + opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, + withoutAnimation: false + }) + + function toggleSideBar() { + sidebar.value.opened = !sidebar.value.opened + sidebar.value.withoutAnimation = false + if (sidebar.value.opened) { + Cookies.set('sidebarStatus', 1) + } else { + Cookies.set('sidebarStatus', 0) + } + } + + function closeSideBar(withoutAnimation) { + Cookies.set('sidebarStatus', 0) + sidebar.value.opened = false + sidebar.value.withoutAnimation = withoutAnimation + } + + function setSize(s) { + size.value = s + Cookies.set('size', s) + } + + return { size, sidebar, toggleSideBar, closeSideBar, setSize } +}) diff --git a/Web/src/stores/modules/permission.js b/Web/src/stores/modules/permission.js new file mode 100644 index 0000000..2609e9d --- /dev/null +++ b/Web/src/stores/modules/permission.js @@ -0,0 +1,66 @@ +import { asyncRoutes, constantRoutes } from '@/router' +import { defineStore } from 'pinia' +import { ref } from 'vue' + +/** + * Use meta.role to determine if the current user has permission + * @param roles + * @param route + */ +// function hasPermission(roles, route) { +// if (route.meta && route.meta.roles) { +// return roles.some((role) => route.meta.roles.includes(role)) +// } else { +// return true +// } +// } + +/** + * Filter asynchronous routing tables by recursion + * @param routes asyncRoutes + * @param roles + */ +// export function filterAsyncRoutes(routes, roles) { +// const res = [] + +// routes.forEach((route) => { +// const tmp = { ...route } +// if (hasPermission(roles, tmp)) { +// if (tmp.children) { +// tmp.children = filterAsyncRoutes(tmp.children, roles) +// } +// res.push(tmp) +// } +// }) + +// return res +// } + +export const usePermissionStore = defineStore('permissionStore',()=> { + + const roles= ref([]) + const routes= ref([]) + + function setPermission(r){ + routes.value= [...constantRoutes, ...asyncRoutes] + roles.value=r; + } + + function clearPermission(){ + roles.value=[]; + } + + function hasPermission(r) { + if(this.roles.length===1&&this.roles[0]==='*'){ + return true; + } + return this.roles.includes(r); + } + return { + roles, + routes, + setPermission, + clearPermission, + hasPermission + } +}) diff --git a/Web/src/stores/modules/settings.js b/Web/src/stores/modules/settings.js new file mode 100644 index 0000000..07f3471 --- /dev/null +++ b/Web/src/stores/modules/settings.js @@ -0,0 +1,67 @@ +import defaultSettings from '@/settings' +import { defineStore } from 'pinia' +import { ref } from 'vue' + +const config = initSettings() + +function initSettings() { + let localSettings = localStorage.getItem('settings') + if (localSettings) { + var settings = JSON.parse(localSettings) + setTheme(settings.theme) + return settings + } else { + setTheme(defaultSettings.theme) + return defaultSettings + } +} + +function setTheme(theme) { + // document.documentElement 是全局变量时 + const el = document.documentElement + // const el = document.getElementById('xxx') + + // 获取 css 变量 + getComputedStyle(el).getPropertyValue(`--el-color-primary`) + + // 设置 css 变量 + el.style.setProperty('--el-color-primary', theme) +} + +export const useSettingsStore = defineStore('settingsStore', () => { + const showSettings = ref(config.showSettings) + const sidebarLogo = ref(config.sidebarLogo) + const showFooter = ref(config.showFooter) + const theme = ref(config.theme) + const layoutType = ref(config.layoutType) + + function changeSetting({ key, value }) { + switch (key) { + case 'showSettings': + showSettings.value = value + break + case 'sidebarLogo': + sidebarLogo.value = value + break + case 'showFooter': + showFooter.value = value + break + case 'layoutType': + layoutType.value = value + break + case 'theme': + theme.value = value + break + } + + localStorage.setItem('settings', JSON.stringify(this)) + } + return { + showSettings, + sidebarLogo, + showFooter, + layoutType, + theme, + changeSetting + } +}) diff --git a/Web/src/stores/modules/tagsView.js b/Web/src/stores/modules/tagsView.js new file mode 100644 index 0000000..4216015 --- /dev/null +++ b/Web/src/stores/modules/tagsView.js @@ -0,0 +1,158 @@ +import { defineStore } from 'pinia' +import { ref } from 'vue' + +export const useTagsViewStore = defineStore('tagsViewStore', () => { + const visitedViews = ref([]) + const cachedViews = ref([]) + + function addView(view) { + addVisitedView(view) + addCachedView(view) + } + function delView(view) { + return new Promise((resolve) => { + _delVisitedView(view) + _delCachedView(view) + resolve({ + visitedViews: [...visitedViews.value], + cachedViews: [...cachedViews.value] + }) + }) + } + function delVisitedView(view) { + return new Promise((resolve) => { + _delVisitedView(view) + resolve([...visitedViews.value]) + }) + } + function delCachedView(view) { + return new Promise((resolve) => { + _delCachedView(view) + resolve([...cachedViews.value]) + }) + } + function delOthersViews(view) { + return new Promise((resolve) => { + _delOthersVisitedViews(view) + _delOthersCachedViews(view) + resolve({ + visitedViews: [...visitedViews.value], + cachedViews: [...cachedViews.value] + }) + }) + } + + function delOthersVisitedViews(view) { + return new Promise((resolve) => { + _delOthersVisitedViews(view) + resolve([...visitedViews.value]) + }) + } + + function delOthersCachedViews(view) { + return new Promise((resolve) => { + _delOthersCachedViews(view) + resolve([...cachedViews.value]) + }) + } + + function delAllViews(view) { + return new Promise((resolve) => { + _delAllVisitedViews(view) + cachedViews.value = [] + resolve({ + visitedViews: [...visitedViews.value], + cachedViews: [...cachedViews.value] + }) + }) + } + + function delAllVisitedViews() { + return new Promise((resolve) => { + _delAllVisitedViews() + resolve([...visitedViews.value]) + }) + } + + function delAllCachedViews() { + return new Promise((resolve) => { + cachedViews.value = [] + resolve([...cachedViews.value]) + }) + } + + function updateVisitedView(view) { + for (let v of visitedViews.value) { + if (v.path === view.path) { + v = Object.assign(v, view) + break + } + } + } + + function addCachedView(view) { + if (cachedViews.value.includes(view.name)) return + if (view.meta.isCache) { + cachedViews.value.push(view.name) + } + } + + function _delVisitedView(view) { + for (const [i, v] of visitedViews.value.entries()) { + if (v.path === view.path) { + visitedViews.value.splice(i, 1) + break + } + } + } + + function _delCachedView(view) { + const index = cachedViews.value.indexOf(view.name) + index > -1 && cachedViews.value.splice(index, 1) + } + + function _delOthersVisitedViews(view) { + visitedViews.value = visitedViews.value.filter((v) => { + return v.meta.affix || v.path === view.path + }) + } + function _delOthersCachedViews(view) { + const index = cachedViews.value.indexOf(view.name) + if (index > -1) { + cachedViews.value = cachedViews.value.slice(index, index + 1) + } else { + // if index = -1, there is no cached tags + cachedViews.value = [] + } + } + function _delAllVisitedViews() { + // keep affix tags + const affixTags = visitedViews.value.filter((tag) => tag.meta.affix) + visitedViews.value = affixTags + } + function addVisitedView(view) { + if (visitedViews.value.some((v) => v.path === view.path)) return + visitedViews.value.push( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) + } + return{ + visitedViews, + cachedViews, + addView, + addCachedView, + addVisitedView, + updateVisitedView, + delView, + delVisitedView, + delCachedView, + delOthersViews, + delOthersVisitedViews, + delOthersCachedViews, + delAllViews, + delAllVisitedViews, + delAllCachedViews, + } +}) diff --git a/Web/src/stores/modules/user.js b/Web/src/stores/modules/user.js new file mode 100644 index 0000000..6f19e95 --- /dev/null +++ b/Web/src/stores/modules/user.js @@ -0,0 +1,152 @@ +import { tenantLogin, getCurrentInfo, getCurrentMenu, refreshLogin } from '@/api/system/userApi' +import { getToken, saveToken, removeToken, getRefreshToken, saveRefreshToken,removeRefreshToken } from '@/utils/auth' + +import { resetRouter } from '@/router' +import { defineStore } from 'pinia' +import { parseTime, diffInDays } from '@/utils/formatTime' +import { reactive } from 'vue' + +export const useUserStore = defineStore('userStore', () => { + const state = reactive(getDefaultState()) + function resetState() { + Object.assign(state, getDefaultState()) + } + + function login(userInfo) { + return new Promise((resolve, reject) => { + tenantLogin(userInfo) + .then((response) => { + const { data } = response + + let refreshTokenExpiresTime = parseTime(data.refreshTokenExpiresTime) + + let expiresDays = diffInDays(new Date(), refreshTokenExpiresTime) + + state.token = data.token + state.refreshToken = data.refreshToken + + saveToken(data.token) + saveRefreshToken(data.refreshToken, expiresDays) + + resolve({ code: 1 }) + }) + .catch((error) => { + reject(error) + }) + }) + } + + function reLogin() { + return new Promise((resolve, reject) => { + let refreshToken = getRefreshToken() + let postInfo = { + refreshToken: refreshToken + } + refreshLogin(postInfo) + .then((response) => { + const { data } = response + let refreshTokenExpiresTime = parseTime(data.refreshTokenExpiresTime) + + let expiresDays = diffInDays(new Date(), refreshTokenExpiresTime) + + state.token = data.token + state.refreshToken = data.refreshToken + + saveToken(data.token) + saveRefreshToken(data.refreshToken, expiresDays) + resolve() + }) + .catch((error) => { + reject(error) + }) + }) + } + + function getInfo() { + return new Promise((resolve, reject) => { + getCurrentInfo() + .then((response) => { + let { data } = response + + state.realName = data.realName + state.nickName = data.nickName + state.accountType = data.accountType + state.roleName = data.roleName + state.orgName = data.orgName + state.tenantId = data.tenantId + state.orgId = data.orgId + state.position = data.position + state.id = data.id + state.userName = data.userName + state.avatar = data.avatar + + resolve(data) + }) + .catch((error) => { + reject(error) + }) + }) + } + + function getMenu() { + return new Promise((resolve, reject) => { + getCurrentMenu(this.token) + .then((response) => { + resolve(response.data) + }) + .catch((error) => { + reject(error) + }) + }) + } + + function logout() { + return new Promise((resolve) => { + removeToken() // must remove token first + removeRefreshToken() + resetRouter() + resetState() + resolve() + }) + } + /** + * 重置所有token 包括 RefreshToken + */ + function resetAllToken() { + return new Promise((resolve) => { + removeToken() // must remove token first + removeRefreshToken() + resetState() + resolve() + }) + } + + return { + state, + resetState, + login, + reLogin, + logout, + getInfo, + getMenu, + resetAllToken + } +}) + +const getDefaultState = () => { + return { + token: getToken(), + refreshToken: getRefreshToken(), + realName: '', + nickName: '', + accountType: '', + roleName: '', + position: '', + orgName: '', + tenantId: '', + orgId: '', + userName: '', + avatar: '', + id: '' + } +} diff --git a/Web/src/styles/element-ui.scss b/Web/src/styles/element-ui.scss new file mode 100644 index 0000000..28faa8c --- /dev/null +++ b/Web/src/styles/element-ui.scss @@ -0,0 +1,100 @@ +// cover some element-ui styles + +.el-breadcrumb__inner, +.el-breadcrumb__inner a { + font-weight: 400 !important; +} + +.el-upload { + input[type='file'] { + display: none !important; + } +} + +.el-upload__input { + display: none; +} + +.dark .el-dialog { + transform: none; + left: 0; + position: relative; + padding: 0; + margin: var(--el-dialog-margin-top,15vh) auto 0px; + header { + background: #3C3C3C; + color: #fff; + padding: 10px; + + button { + i.el-icon { + color: #fff !important; + } + } + } + + .el-dialog__body { + padding: 10px; + } +} + +.el-dialog { + transform: none; + left: 0; + position: relative; + padding: 0; + + margin: var(--el-dialog-margin-top,15vh) auto 0px; + header { + background: var(--el-color-primary); + color: #fff; + padding: 10px; + + button { + i.el-icon { + color: #fff !important; + } + } + } + + .el-dialog__body { + padding: 10px; + } +} + +// refine element ui upload +.upload-container { + .el-upload { + width: 100%; + + .el-upload-dragger { + width: 100%; + height: 200px; + } + } +} + + +// to fix el-date-picker css style +.el-range-separator { + box-sizing: content-box; +} + +//表格头部改造 +.el-table thead{ + color: var(--el-text-color-primary); + tr{ + th{ + background: var(--el-fill-color-light) !important; + } + } +} + + +.el-custom-dialog-footer{ + padding: 10px; +} + +.el-custom-dialog-icon{ + margin-right: 3px; display: inline; vertical-align: middle +} \ No newline at end of file diff --git a/Web/src/styles/font-awesome/font-awesome.scss b/Web/src/styles/font-awesome/font-awesome.scss new file mode 100644 index 0000000..d811791 --- /dev/null +++ b/Web/src/styles/font-awesome/font-awesome.scss @@ -0,0 +1,2332 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +@font-face { + font-family: 'FontAwesome'; + src: url('@/styles/font-awesome/fontawesome-webfont.eot?v=4.7.0') format('embedded-opentype'), url('@/styles/font-awesome/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), + url('@/styles/font-awesome/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('@/styles/font-awesome/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), + url('@/styles/font-awesome/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: 0.2em 0.25em 0.15em; + border: solid 0.08em #eee; + border-radius: 0.1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: 0.3em; +} +.fa.fa-pull-right { + margin-left: 0.3em; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: 0.3em; +} +.fa.pull-right { + margin-left: 0.3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=1)'; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2)'; + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=3)'; + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)'; + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)'; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #fff; +} +.fa-glass:before { + content: '\f000'; +} +.fa-music:before { + content: '\f001'; +} +.fa-search:before { + content: '\f002'; +} +.fa-envelope-o:before { + content: '\f003'; +} +.fa-heart:before { + content: '\f004'; +} +.fa-star:before { + content: '\f005'; +} +.fa-star-o:before { + content: '\f006'; +} +.fa-user:before { + content: '\f007'; +} +.fa-film:before { + content: '\f008'; +} +.fa-th-large:before { + content: '\f009'; +} +.fa-th:before { + content: '\f00a'; +} +.fa-th-list:before { + content: '\f00b'; +} +.fa-check:before { + content: '\f00c'; +} +.fa-remove:before, +.fa-close:before, +.fa-times:before { + content: '\f00d'; +} +.fa-search-plus:before { + content: '\f00e'; +} +.fa-search-minus:before { + content: '\f010'; +} +.fa-power-off:before { + content: '\f011'; +} +.fa-signal:before { + content: '\f012'; +} +.fa-gear:before, +.fa-cog:before { + content: '\f013'; +} +.fa-trash-o:before { + content: '\f014'; +} +.fa-home:before { + content: '\f015'; +} +.fa-file-o:before { + content: '\f016'; +} +.fa-clock-o:before { + content: '\f017'; +} +.fa-road:before { + content: '\f018'; +} +.fa-download:before { + content: '\f019'; +} +.fa-arrow-circle-o-down:before { + content: '\f01a'; +} +.fa-arrow-circle-o-up:before { + content: '\f01b'; +} +.fa-inbox:before { + content: '\f01c'; +} +.fa-play-circle-o:before { + content: '\f01d'; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: '\f01e'; +} +.fa-refresh:before { + content: '\f021'; +} +.fa-list-alt:before { + content: '\f022'; +} +.fa-lock:before { + content: '\f023'; +} +.fa-flag:before { + content: '\f024'; +} +.fa-headphones:before { + content: '\f025'; +} +.fa-volume-off:before { + content: '\f026'; +} +.fa-volume-down:before { + content: '\f027'; +} +.fa-volume-up:before { + content: '\f028'; +} +.fa-qrcode:before { + content: '\f029'; +} +.fa-barcode:before { + content: '\f02a'; +} +.fa-tag:before { + content: '\f02b'; +} +.fa-tags:before { + content: '\f02c'; +} +.fa-book:before { + content: '\f02d'; +} +.fa-bookmark:before { + content: '\f02e'; +} +.fa-print:before { + content: '\f02f'; +} +.fa-camera:before { + content: '\f030'; +} +.fa-font:before { + content: '\f031'; +} +.fa-bold:before { + content: '\f032'; +} +.fa-italic:before { + content: '\f033'; +} +.fa-text-height:before { + content: '\f034'; +} +.fa-text-width:before { + content: '\f035'; +} +.fa-align-left:before { + content: '\f036'; +} +.fa-align-center:before { + content: '\f037'; +} +.fa-align-right:before { + content: '\f038'; +} +.fa-align-justify:before { + content: '\f039'; +} +.fa-list:before { + content: '\f03a'; +} +.fa-dedent:before, +.fa-outdent:before { + content: '\f03b'; +} +.fa-indent:before { + content: '\f03c'; +} +.fa-video-camera:before { + content: '\f03d'; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: '\f03e'; +} +.fa-pencil:before { + content: '\f040'; +} +.fa-map-marker:before { + content: '\f041'; +} +.fa-adjust:before { + content: '\f042'; +} +.fa-tint:before { + content: '\f043'; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: '\f044'; +} +.fa-share-square-o:before { + content: '\f045'; +} +.fa-check-square-o:before { + content: '\f046'; +} +.fa-arrows:before { + content: '\f047'; +} +.fa-step-backward:before { + content: '\f048'; +} +.fa-fast-backward:before { + content: '\f049'; +} +.fa-backward:before { + content: '\f04a'; +} +.fa-play:before { + content: '\f04b'; +} +.fa-pause:before { + content: '\f04c'; +} +.fa-stop:before { + content: '\f04d'; +} +.fa-forward:before { + content: '\f04e'; +} +.fa-fast-forward:before { + content: '\f050'; +} +.fa-step-forward:before { + content: '\f051'; +} +.fa-eject:before { + content: '\f052'; +} +.fa-chevron-left:before { + content: '\f053'; +} +.fa-chevron-right:before { + content: '\f054'; +} +.fa-plus-circle:before { + content: '\f055'; +} +.fa-minus-circle:before { + content: '\f056'; +} +.fa-times-circle:before { + content: '\f057'; +} +.fa-check-circle:before { + content: '\f058'; +} +.fa-question-circle:before { + content: '\f059'; +} +.fa-info-circle:before { + content: '\f05a'; +} +.fa-crosshairs:before { + content: '\f05b'; +} +.fa-times-circle-o:before { + content: '\f05c'; +} +.fa-check-circle-o:before { + content: '\f05d'; +} +.fa-ban:before { + content: '\f05e'; +} +.fa-arrow-left:before { + content: '\f060'; +} +.fa-arrow-right:before { + content: '\f061'; +} +.fa-arrow-up:before { + content: '\f062'; +} +.fa-arrow-down:before { + content: '\f063'; +} +.fa-mail-forward:before, +.fa-share:before { + content: '\f064'; +} +.fa-expand:before { + content: '\f065'; +} +.fa-compress:before { + content: '\f066'; +} +.fa-plus:before { + content: '\f067'; +} +.fa-minus:before { + content: '\f068'; +} +.fa-asterisk:before { + content: '\f069'; +} +.fa-exclamation-circle:before { + content: '\f06a'; +} +.fa-gift:before { + content: '\f06b'; +} +.fa-leaf:before { + content: '\f06c'; +} +.fa-fire:before { + content: '\f06d'; +} +.fa-eye:before { + content: '\f06e'; +} +.fa-eye-slash:before { + content: '\f070'; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: '\f071'; +} +.fa-plane:before { + content: '\f072'; +} +.fa-calendar:before { + content: '\f073'; +} +.fa-random:before { + content: '\f074'; +} +.fa-comment:before { + content: '\f075'; +} +.fa-magnet:before { + content: '\f076'; +} +.fa-chevron-up:before { + content: '\f077'; +} +.fa-chevron-down:before { + content: '\f078'; +} +.fa-retweet:before { + content: '\f079'; +} +.fa-shopping-cart:before { + content: '\f07a'; +} +.fa-folder:before { + content: '\f07b'; +} +.fa-folder-open:before { + content: '\f07c'; +} +.fa-arrows-v:before { + content: '\f07d'; +} +.fa-arrows-h:before { + content: '\f07e'; +} +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: '\f080'; +} +.fa-twitter-square:before { + content: '\f081'; +} +.fa-facebook-square:before { + content: '\f082'; +} +.fa-camera-retro:before { + content: '\f083'; +} +.fa-key:before { + content: '\f084'; +} +.fa-gears:before, +.fa-cogs:before { + content: '\f085'; +} +.fa-comments:before { + content: '\f086'; +} +.fa-thumbs-o-up:before { + content: '\f087'; +} +.fa-thumbs-o-down:before { + content: '\f088'; +} +.fa-star-half:before { + content: '\f089'; +} +.fa-heart-o:before { + content: '\f08a'; +} +.fa-sign-out:before { + content: '\f08b'; +} +.fa-linkedin-square:before { + content: '\f08c'; +} +.fa-thumb-tack:before { + content: '\f08d'; +} +.fa-external-link:before { + content: '\f08e'; +} +.fa-sign-in:before { + content: '\f090'; +} +.fa-trophy:before { + content: '\f091'; +} +.fa-github-square:before { + content: '\f092'; +} +.fa-upload:before { + content: '\f093'; +} +.fa-lemon-o:before { + content: '\f094'; +} +.fa-phone:before { + content: '\f095'; +} +.fa-square-o:before { + content: '\f096'; +} +.fa-bookmark-o:before { + content: '\f097'; +} +.fa-phone-square:before { + content: '\f098'; +} +.fa-twitter:before { + content: '\f099'; +} +.fa-facebook-f:before, +.fa-facebook:before { + content: '\f09a'; +} +.fa-github:before { + content: '\f09b'; +} +.fa-unlock:before { + content: '\f09c'; +} +.fa-credit-card:before { + content: '\f09d'; +} +.fa-feed:before, +.fa-rss:before { + content: '\f09e'; +} +.fa-hdd-o:before { + content: '\f0a0'; +} +.fa-bullhorn:before { + content: '\f0a1'; +} +.fa-bell:before { + content: '\f0f3'; +} +.fa-certificate:before { + content: '\f0a3'; +} +.fa-hand-o-right:before { + content: '\f0a4'; +} +.fa-hand-o-left:before { + content: '\f0a5'; +} +.fa-hand-o-up:before { + content: '\f0a6'; +} +.fa-hand-o-down:before { + content: '\f0a7'; +} +.fa-arrow-circle-left:before { + content: '\f0a8'; +} +.fa-arrow-circle-right:before { + content: '\f0a9'; +} +.fa-arrow-circle-up:before { + content: '\f0aa'; +} +.fa-arrow-circle-down:before { + content: '\f0ab'; +} +.fa-globe:before { + content: '\f0ac'; +} +.fa-wrench:before { + content: '\f0ad'; +} +.fa-tasks:before { + content: '\f0ae'; +} +.fa-filter:before { + content: '\f0b0'; +} +.fa-briefcase:before { + content: '\f0b1'; +} +.fa-arrows-alt:before { + content: '\f0b2'; +} +.fa-group:before, +.fa-users:before { + content: '\f0c0'; +} +.fa-chain:before, +.fa-link:before { + content: '\f0c1'; +} +.fa-cloud:before { + content: '\f0c2'; +} +.fa-flask:before { + content: '\f0c3'; +} +.fa-cut:before, +.fa-scissors:before { + content: '\f0c4'; +} +.fa-copy:before, +.fa-files-o:before { + content: '\f0c5'; +} +.fa-paperclip:before { + content: '\f0c6'; +} +.fa-save:before, +.fa-floppy-o:before { + content: '\f0c7'; +} +.fa-square:before { + content: '\f0c8'; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: '\f0c9'; +} +.fa-list-ul:before { + content: '\f0ca'; +} +.fa-list-ol:before { + content: '\f0cb'; +} +.fa-strikethrough:before { + content: '\f0cc'; +} +.fa-underline:before { + content: '\f0cd'; +} +.fa-table:before { + content: '\f0ce'; +} +.fa-magic:before { + content: '\f0d0'; +} +.fa-truck:before { + content: '\f0d1'; +} +.fa-pinterest:before { + content: '\f0d2'; +} +.fa-pinterest-square:before { + content: '\f0d3'; +} +.fa-google-plus-square:before { + content: '\f0d4'; +} +.fa-google-plus:before { + content: '\f0d5'; +} +.fa-money:before { + content: '\f0d6'; +} +.fa-caret-down:before { + content: '\f0d7'; +} +.fa-caret-up:before { + content: '\f0d8'; +} +.fa-caret-left:before { + content: '\f0d9'; +} +.fa-caret-right:before { + content: '\f0da'; +} +.fa-columns:before { + content: '\f0db'; +} +.fa-unsorted:before, +.fa-sort:before { + content: '\f0dc'; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: '\f0dd'; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: '\f0de'; +} +.fa-envelope:before { + content: '\f0e0'; +} +.fa-linkedin:before { + content: '\f0e1'; +} +.fa-rotate-left:before, +.fa-undo:before { + content: '\f0e2'; +} +.fa-legal:before, +.fa-gavel:before { + content: '\f0e3'; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: '\f0e4'; +} +.fa-comment-o:before { + content: '\f0e5'; +} +.fa-comments-o:before { + content: '\f0e6'; +} +.fa-flash:before, +.fa-bolt:before { + content: '\f0e7'; +} +.fa-sitemap:before { + content: '\f0e8'; +} +.fa-umbrella:before { + content: '\f0e9'; +} +.fa-paste:before, +.fa-clipboard:before { + content: '\f0ea'; +} +.fa-lightbulb-o:before { + content: '\f0eb'; +} +.fa-exchange:before { + content: '\f0ec'; +} +.fa-cloud-download:before { + content: '\f0ed'; +} +.fa-cloud-upload:before { + content: '\f0ee'; +} +.fa-user-md:before { + content: '\f0f0'; +} +.fa-stethoscope:before { + content: '\f0f1'; +} +.fa-suitcase:before { + content: '\f0f2'; +} +.fa-bell-o:before { + content: '\f0a2'; +} +.fa-coffee:before { + content: '\f0f4'; +} +.fa-cutlery:before { + content: '\f0f5'; +} +.fa-file-text-o:before { + content: '\f0f6'; +} +.fa-building-o:before { + content: '\f0f7'; +} +.fa-hospital-o:before { + content: '\f0f8'; +} +.fa-ambulance:before { + content: '\f0f9'; +} +.fa-medkit:before { + content: '\f0fa'; +} +.fa-fighter-jet:before { + content: '\f0fb'; +} +.fa-beer:before { + content: '\f0fc'; +} +.fa-h-square:before { + content: '\f0fd'; +} +.fa-plus-square:before { + content: '\f0fe'; +} +.fa-angle-double-left:before { + content: '\f100'; +} +.fa-angle-double-right:before { + content: '\f101'; +} +.fa-angle-double-up:before { + content: '\f102'; +} +.fa-angle-double-down:before { + content: '\f103'; +} +.fa-angle-left:before { + content: '\f104'; +} +.fa-angle-right:before { + content: '\f105'; +} +.fa-angle-up:before { + content: '\f106'; +} +.fa-angle-down:before { + content: '\f107'; +} +.fa-desktop:before { + content: '\f108'; +} +.fa-laptop:before { + content: '\f109'; +} +.fa-tablet:before { + content: '\f10a'; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: '\f10b'; +} +.fa-circle-o:before { + content: '\f10c'; +} +.fa-quote-left:before { + content: '\f10d'; +} +.fa-quote-right:before { + content: '\f10e'; +} +.fa-spinner:before { + content: '\f110'; +} +.fa-circle:before { + content: '\f111'; +} +.fa-mail-reply:before, +.fa-reply:before { + content: '\f112'; +} +.fa-github-alt:before { + content: '\f113'; +} +.fa-folder-o:before { + content: '\f114'; +} +.fa-folder-open-o:before { + content: '\f115'; +} +.fa-smile-o:before { + content: '\f118'; +} +.fa-frown-o:before { + content: '\f119'; +} +.fa-meh-o:before { + content: '\f11a'; +} +.fa-gamepad:before { + content: '\f11b'; +} +.fa-keyboard-o:before { + content: '\f11c'; +} +.fa-flag-o:before { + content: '\f11d'; +} +.fa-flag-checkered:before { + content: '\f11e'; +} +.fa-terminal:before { + content: '\f120'; +} +.fa-code:before { + content: '\f121'; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: '\f122'; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: '\f123'; +} +.fa-location-arrow:before { + content: '\f124'; +} +.fa-crop:before { + content: '\f125'; +} +.fa-code-fork:before { + content: '\f126'; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: '\f127'; +} +.fa-question:before { + content: '\f128'; +} +.fa-info:before { + content: '\f129'; +} +.fa-exclamation:before { + content: '\f12a'; +} +.fa-superscript:before { + content: '\f12b'; +} +.fa-subscript:before { + content: '\f12c'; +} +.fa-eraser:before { + content: '\f12d'; +} +.fa-puzzle-piece:before { + content: '\f12e'; +} +.fa-microphone:before { + content: '\f130'; +} +.fa-microphone-slash:before { + content: '\f131'; +} +.fa-shield:before { + content: '\f132'; +} +.fa-calendar-o:before { + content: '\f133'; +} +.fa-fire-extinguisher:before { + content: '\f134'; +} +.fa-rocket:before { + content: '\f135'; +} +.fa-maxcdn:before { + content: '\f136'; +} +.fa-chevron-circle-left:before { + content: '\f137'; +} +.fa-chevron-circle-right:before { + content: '\f138'; +} +.fa-chevron-circle-up:before { + content: '\f139'; +} +.fa-chevron-circle-down:before { + content: '\f13a'; +} +.fa-html5:before { + content: '\f13b'; +} +.fa-css3:before { + content: '\f13c'; +} +.fa-anchor:before { + content: '\f13d'; +} +.fa-unlock-alt:before { + content: '\f13e'; +} +.fa-bullseye:before { + content: '\f140'; +} +.fa-ellipsis-h:before { + content: '\f141'; +} +.fa-ellipsis-v:before { + content: '\f142'; +} +.fa-rss-square:before { + content: '\f143'; +} +.fa-play-circle:before { + content: '\f144'; +} +.fa-ticket:before { + content: '\f145'; +} +.fa-minus-square:before { + content: '\f146'; +} +.fa-minus-square-o:before { + content: '\f147'; +} +.fa-level-up:before { + content: '\f148'; +} +.fa-level-down:before { + content: '\f149'; +} +.fa-check-square:before { + content: '\f14a'; +} +.fa-pencil-square:before { + content: '\f14b'; +} +.fa-external-link-square:before { + content: '\f14c'; +} +.fa-share-square:before { + content: '\f14d'; +} +.fa-compass:before { + content: '\f14e'; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: '\f150'; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: '\f151'; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: '\f152'; +} +.fa-euro:before, +.fa-eur:before { + content: '\f153'; +} +.fa-gbp:before { + content: '\f154'; +} +.fa-dollar:before, +.fa-usd:before { + content: '\f155'; +} +.fa-rupee:before, +.fa-inr:before { + content: '\f156'; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: '\f157'; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: '\f158'; +} +.fa-won:before, +.fa-krw:before { + content: '\f159'; +} +.fa-bitcoin:before, +.fa-btc:before { + content: '\f15a'; +} +.fa-file:before { + content: '\f15b'; +} +.fa-file-text:before { + content: '\f15c'; +} +.fa-sort-alpha-asc:before { + content: '\f15d'; +} +.fa-sort-alpha-desc:before { + content: '\f15e'; +} +.fa-sort-amount-asc:before { + content: '\f160'; +} +.fa-sort-amount-desc:before { + content: '\f161'; +} +.fa-sort-numeric-asc:before { + content: '\f162'; +} +.fa-sort-numeric-desc:before { + content: '\f163'; +} +.fa-thumbs-up:before { + content: '\f164'; +} +.fa-thumbs-down:before { + content: '\f165'; +} +.fa-youtube-square:before { + content: '\f166'; +} +.fa-youtube:before { + content: '\f167'; +} +.fa-xing:before { + content: '\f168'; +} +.fa-xing-square:before { + content: '\f169'; +} +.fa-youtube-play:before { + content: '\f16a'; +} +.fa-dropbox:before { + content: '\f16b'; +} +.fa-stack-overflow:before { + content: '\f16c'; +} +.fa-instagram:before { + content: '\f16d'; +} +.fa-flickr:before { + content: '\f16e'; +} +.fa-adn:before { + content: '\f170'; +} +.fa-bitbucket:before { + content: '\f171'; +} +.fa-bitbucket-square:before { + content: '\f172'; +} +.fa-tumblr:before { + content: '\f173'; +} +.fa-tumblr-square:before { + content: '\f174'; +} +.fa-long-arrow-down:before { + content: '\f175'; +} +.fa-long-arrow-up:before { + content: '\f176'; +} +.fa-long-arrow-left:before { + content: '\f177'; +} +.fa-long-arrow-right:before { + content: '\f178'; +} +.fa-apple:before { + content: '\f179'; +} +.fa-windows:before { + content: '\f17a'; +} +.fa-android:before { + content: '\f17b'; +} +.fa-linux:before { + content: '\f17c'; +} +.fa-dribbble:before { + content: '\f17d'; +} +.fa-skype:before { + content: '\f17e'; +} +.fa-foursquare:before { + content: '\f180'; +} +.fa-trello:before { + content: '\f181'; +} +.fa-female:before { + content: '\f182'; +} +.fa-male:before { + content: '\f183'; +} +.fa-gittip:before, +.fa-gratipay:before { + content: '\f184'; +} +.fa-sun-o:before { + content: '\f185'; +} +.fa-moon-o:before { + content: '\f186'; +} +.fa-archive:before { + content: '\f187'; +} +.fa-bug:before { + content: '\f188'; +} +.fa-vk:before { + content: '\f189'; +} +.fa-weibo:before { + content: '\f18a'; +} +.fa-renren:before { + content: '\f18b'; +} +.fa-pagelines:before { + content: '\f18c'; +} +.fa-stack-exchange:before { + content: '\f18d'; +} +.fa-arrow-circle-o-right:before { + content: '\f18e'; +} +.fa-arrow-circle-o-left:before { + content: '\f190'; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: '\f191'; +} +.fa-dot-circle-o:before { + content: '\f192'; +} +.fa-wheelchair:before { + content: '\f193'; +} +.fa-vimeo-square:before { + content: '\f194'; +} +.fa-turkish-lira:before, +.fa-try:before { + content: '\f195'; +} +.fa-plus-square-o:before { + content: '\f196'; +} +.fa-space-shuttle:before { + content: '\f197'; +} +.fa-slack:before { + content: '\f198'; +} +.fa-envelope-square:before { + content: '\f199'; +} +.fa-wordpress:before { + content: '\f19a'; +} +.fa-openid:before { + content: '\f19b'; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: '\f19c'; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: '\f19d'; +} +.fa-yahoo:before { + content: '\f19e'; +} +.fa-google:before { + content: '\f1a0'; +} +.fa-reddit:before { + content: '\f1a1'; +} +.fa-reddit-square:before { + content: '\f1a2'; +} +.fa-stumbleupon-circle:before { + content: '\f1a3'; +} +.fa-stumbleupon:before { + content: '\f1a4'; +} +.fa-delicious:before { + content: '\f1a5'; +} +.fa-digg:before { + content: '\f1a6'; +} +.fa-pied-piper-pp:before { + content: '\f1a7'; +} +.fa-pied-piper-alt:before { + content: '\f1a8'; +} +.fa-drupal:before { + content: '\f1a9'; +} +.fa-joomla:before { + content: '\f1aa'; +} +.fa-language:before { + content: '\f1ab'; +} +.fa-fax:before { + content: '\f1ac'; +} +.fa-building:before { + content: '\f1ad'; +} +.fa-child:before { + content: '\f1ae'; +} +.fa-paw:before { + content: '\f1b0'; +} +.fa-spoon:before { + content: '\f1b1'; +} +.fa-cube:before { + content: '\f1b2'; +} +.fa-cubes:before { + content: '\f1b3'; +} +.fa-behance:before { + content: '\f1b4'; +} +.fa-behance-square:before { + content: '\f1b5'; +} +.fa-steam:before { + content: '\f1b6'; +} +.fa-steam-square:before { + content: '\f1b7'; +} +.fa-recycle:before { + content: '\f1b8'; +} +.fa-automobile:before, +.fa-car:before { + content: '\f1b9'; +} +.fa-cab:before, +.fa-taxi:before { + content: '\f1ba'; +} +.fa-tree:before { + content: '\f1bb'; +} +.fa-spotify:before { + content: '\f1bc'; +} +.fa-deviantart:before { + content: '\f1bd'; +} +.fa-soundcloud:before { + content: '\f1be'; +} +.fa-database:before { + content: '\f1c0'; +} +.fa-file-pdf-o:before { + content: '\f1c1'; +} +.fa-file-word-o:before { + content: '\f1c2'; +} +.fa-file-excel-o:before { + content: '\f1c3'; +} +.fa-file-powerpoint-o:before { + content: '\f1c4'; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: '\f1c5'; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: '\f1c6'; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: '\f1c7'; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: '\f1c8'; +} +.fa-file-code-o:before { + content: '\f1c9'; +} +.fa-vine:before { + content: '\f1ca'; +} +.fa-codepen:before { + content: '\f1cb'; +} +.fa-jsfiddle:before { + content: '\f1cc'; +} +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: '\f1cd'; +} +.fa-circle-o-notch:before { + content: '\f1ce'; +} +.fa-ra:before, +.fa-resistance:before, +.fa-rebel:before { + content: '\f1d0'; +} +.fa-ge:before, +.fa-empire:before { + content: '\f1d1'; +} +.fa-git-square:before { + content: '\f1d2'; +} +.fa-git:before { + content: '\f1d3'; +} +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: '\f1d4'; +} +.fa-tencent-weibo:before { + content: '\f1d5'; +} +.fa-qq:before { + content: '\f1d6'; +} +.fa-wechat:before, +.fa-weixin:before { + content: '\f1d7'; +} +.fa-send:before, +.fa-paper-plane:before { + content: '\f1d8'; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: '\f1d9'; +} +.fa-history:before { + content: '\f1da'; +} +.fa-circle-thin:before { + content: '\f1db'; +} +.fa-header:before { + content: '\f1dc'; +} +.fa-paragraph:before { + content: '\f1dd'; +} +.fa-sliders:before { + content: '\f1de'; +} +.fa-share-alt:before { + content: '\f1e0'; +} +.fa-share-alt-square:before { + content: '\f1e1'; +} +.fa-bomb:before { + content: '\f1e2'; +} +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: '\f1e3'; +} +.fa-tty:before { + content: '\f1e4'; +} +.fa-binoculars:before { + content: '\f1e5'; +} +.fa-plug:before { + content: '\f1e6'; +} +.fa-slideshare:before { + content: '\f1e7'; +} +.fa-twitch:before { + content: '\f1e8'; +} +.fa-yelp:before { + content: '\f1e9'; +} +.fa-newspaper-o:before { + content: '\f1ea'; +} +.fa-wifi:before { + content: '\f1eb'; +} +.fa-calculator:before { + content: '\f1ec'; +} +.fa-paypal:before { + content: '\f1ed'; +} +.fa-google-wallet:before { + content: '\f1ee'; +} +.fa-cc-visa:before { + content: '\f1f0'; +} +.fa-cc-mastercard:before { + content: '\f1f1'; +} +.fa-cc-discover:before { + content: '\f1f2'; +} +.fa-cc-amex:before { + content: '\f1f3'; +} +.fa-cc-paypal:before { + content: '\f1f4'; +} +.fa-cc-stripe:before { + content: '\f1f5'; +} +.fa-bell-slash:before { + content: '\f1f6'; +} +.fa-bell-slash-o:before { + content: '\f1f7'; +} +.fa-trash:before { + content: '\f1f8'; +} +.fa-copyright:before { + content: '\f1f9'; +} +.fa-at:before { + content: '\f1fa'; +} +.fa-eyedropper:before { + content: '\f1fb'; +} +.fa-paint-brush:before { + content: '\f1fc'; +} +.fa-birthday-cake:before { + content: '\f1fd'; +} +.fa-area-chart:before { + content: '\f1fe'; +} +.fa-pie-chart:before { + content: '\f200'; +} +.fa-line-chart:before { + content: '\f201'; +} +.fa-lastfm:before { + content: '\f202'; +} +.fa-lastfm-square:before { + content: '\f203'; +} +.fa-toggle-off:before { + content: '\f204'; +} +.fa-toggle-on:before { + content: '\f205'; +} +.fa-bicycle:before { + content: '\f206'; +} +.fa-bus:before { + content: '\f207'; +} +.fa-ioxhost:before { + content: '\f208'; +} +.fa-angellist:before { + content: '\f209'; +} +.fa-cc:before { + content: '\f20a'; +} +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: '\f20b'; +} +.fa-meanpath:before { + content: '\f20c'; +} +.fa-buysellads:before { + content: '\f20d'; +} +.fa-connectdevelop:before { + content: '\f20e'; +} +.fa-dashcube:before { + content: '\f210'; +} +.fa-forumbee:before { + content: '\f211'; +} +.fa-leanpub:before { + content: '\f212'; +} +.fa-sellsy:before { + content: '\f213'; +} +.fa-shirtsinbulk:before { + content: '\f214'; +} +.fa-simplybuilt:before { + content: '\f215'; +} +.fa-skyatlas:before { + content: '\f216'; +} +.fa-cart-plus:before { + content: '\f217'; +} +.fa-cart-arrow-down:before { + content: '\f218'; +} +.fa-diamond:before { + content: '\f219'; +} +.fa-ship:before { + content: '\f21a'; +} +.fa-user-secret:before { + content: '\f21b'; +} +.fa-motorcycle:before { + content: '\f21c'; +} +.fa-street-view:before { + content: '\f21d'; +} +.fa-heartbeat:before { + content: '\f21e'; +} +.fa-venus:before { + content: '\f221'; +} +.fa-mars:before { + content: '\f222'; +} +.fa-mercury:before { + content: '\f223'; +} +.fa-intersex:before, +.fa-transgender:before { + content: '\f224'; +} +.fa-transgender-alt:before { + content: '\f225'; +} +.fa-venus-double:before { + content: '\f226'; +} +.fa-mars-double:before { + content: '\f227'; +} +.fa-venus-mars:before { + content: '\f228'; +} +.fa-mars-stroke:before { + content: '\f229'; +} +.fa-mars-stroke-v:before { + content: '\f22a'; +} +.fa-mars-stroke-h:before { + content: '\f22b'; +} +.fa-neuter:before { + content: '\f22c'; +} +.fa-genderless:before { + content: '\f22d'; +} +.fa-facebook-official:before { + content: '\f230'; +} +.fa-pinterest-p:before { + content: '\f231'; +} +.fa-whatsapp:before { + content: '\f232'; +} +.fa-server:before { + content: '\f233'; +} +.fa-user-plus:before { + content: '\f234'; +} +.fa-user-times:before { + content: '\f235'; +} +.fa-hotel:before, +.fa-bed:before { + content: '\f236'; +} +.fa-viacoin:before { + content: '\f237'; +} +.fa-train:before { + content: '\f238'; +} +.fa-subway:before { + content: '\f239'; +} +.fa-medium:before { + content: '\f23a'; +} +.fa-yc:before, +.fa-y-combinator:before { + content: '\f23b'; +} +.fa-optin-monster:before { + content: '\f23c'; +} +.fa-opencart:before { + content: '\f23d'; +} +.fa-expeditedssl:before { + content: '\f23e'; +} +.fa-battery-4:before, +.fa-battery:before, +.fa-battery-full:before { + content: '\f240'; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: '\f241'; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: '\f242'; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: '\f243'; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: '\f244'; +} +.fa-mouse-pointer:before { + content: '\f245'; +} +.fa-i-cursor:before { + content: '\f246'; +} +.fa-object-group:before { + content: '\f247'; +} +.fa-object-ungroup:before { + content: '\f248'; +} +.fa-sticky-note:before { + content: '\f249'; +} +.fa-sticky-note-o:before { + content: '\f24a'; +} +.fa-cc-jcb:before { + content: '\f24b'; +} +.fa-cc-diners-club:before { + content: '\f24c'; +} +.fa-clone:before { + content: '\f24d'; +} +.fa-balance-scale:before { + content: '\f24e'; +} +.fa-hourglass-o:before { + content: '\f250'; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: '\f251'; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: '\f252'; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: '\f253'; +} +.fa-hourglass:before { + content: '\f254'; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: '\f255'; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: '\f256'; +} +.fa-hand-scissors-o:before { + content: '\f257'; +} +.fa-hand-lizard-o:before { + content: '\f258'; +} +.fa-hand-spock-o:before { + content: '\f259'; +} +.fa-hand-pointer-o:before { + content: '\f25a'; +} +.fa-hand-peace-o:before { + content: '\f25b'; +} +.fa-trademark:before { + content: '\f25c'; +} +.fa-registered:before { + content: '\f25d'; +} +.fa-creative-commons:before { + content: '\f25e'; +} +.fa-gg:before { + content: '\f260'; +} +.fa-gg-circle:before { + content: '\f261'; +} +.fa-tripadvisor:before { + content: '\f262'; +} +.fa-odnoklassniki:before { + content: '\f263'; +} +.fa-odnoklassniki-square:before { + content: '\f264'; +} +.fa-get-pocket:before { + content: '\f265'; +} +.fa-wikipedia-w:before { + content: '\f266'; +} +.fa-safari:before { + content: '\f267'; +} +.fa-chrome:before { + content: '\f268'; +} +.fa-firefox:before { + content: '\f269'; +} +.fa-opera:before { + content: '\f26a'; +} +.fa-internet-explorer:before { + content: '\f26b'; +} +.fa-tv:before, +.fa-television:before { + content: '\f26c'; +} +.fa-contao:before { + content: '\f26d'; +} +.fa-500px:before { + content: '\f26e'; +} +.fa-amazon:before { + content: '\f270'; +} +.fa-calendar-plus-o:before { + content: '\f271'; +} +.fa-calendar-minus-o:before { + content: '\f272'; +} +.fa-calendar-times-o:before { + content: '\f273'; +} +.fa-calendar-check-o:before { + content: '\f274'; +} +.fa-industry:before { + content: '\f275'; +} +.fa-map-pin:before { + content: '\f276'; +} +.fa-map-signs:before { + content: '\f277'; +} +.fa-map-o:before { + content: '\f278'; +} +.fa-map:before { + content: '\f279'; +} +.fa-commenting:before { + content: '\f27a'; +} +.fa-commenting-o:before { + content: '\f27b'; +} +.fa-houzz:before { + content: '\f27c'; +} +.fa-vimeo:before { + content: '\f27d'; +} +.fa-black-tie:before { + content: '\f27e'; +} +.fa-fonticons:before { + content: '\f280'; +} +.fa-reddit-alien:before { + content: '\f281'; +} +.fa-edge:before { + content: '\f282'; +} +.fa-credit-card-alt:before { + content: '\f283'; +} +.fa-codiepie:before { + content: '\f284'; +} +.fa-modx:before { + content: '\f285'; +} +.fa-fort-awesome:before { + content: '\f286'; +} +.fa-usb:before { + content: '\f287'; +} +.fa-product-hunt:before { + content: '\f288'; +} +.fa-mixcloud:before { + content: '\f289'; +} +.fa-scribd:before { + content: '\f28a'; +} +.fa-pause-circle:before { + content: '\f28b'; +} +.fa-pause-circle-o:before { + content: '\f28c'; +} +.fa-stop-circle:before { + content: '\f28d'; +} +.fa-stop-circle-o:before { + content: '\f28e'; +} +.fa-shopping-bag:before { + content: '\f290'; +} +.fa-shopping-basket:before { + content: '\f291'; +} +.fa-hashtag:before { + content: '\f292'; +} +.fa-bluetooth:before { + content: '\f293'; +} +.fa-bluetooth-b:before { + content: '\f294'; +} +.fa-percent:before { + content: '\f295'; +} +.fa-gitlab:before { + content: '\f296'; +} +.fa-wpbeginner:before { + content: '\f297'; +} +.fa-wpforms:before { + content: '\f298'; +} +.fa-envira:before { + content: '\f299'; +} +.fa-universal-access:before { + content: '\f29a'; +} +.fa-wheelchair-alt:before { + content: '\f29b'; +} +.fa-question-circle-o:before { + content: '\f29c'; +} +.fa-blind:before { + content: '\f29d'; +} +.fa-audio-description:before { + content: '\f29e'; +} +.fa-volume-control-phone:before { + content: '\f2a0'; +} +.fa-braille:before { + content: '\f2a1'; +} +.fa-assistive-listening-systems:before { + content: '\f2a2'; +} +.fa-asl-interpreting:before, +.fa-american-sign-language-interpreting:before { + content: '\f2a3'; +} +.fa-deafness:before, +.fa-hard-of-hearing:before, +.fa-deaf:before { + content: '\f2a4'; +} +.fa-glide:before { + content: '\f2a5'; +} +.fa-glide-g:before { + content: '\f2a6'; +} +.fa-signing:before, +.fa-sign-language:before { + content: '\f2a7'; +} +.fa-low-vision:before { + content: '\f2a8'; +} +.fa-viadeo:before { + content: '\f2a9'; +} +.fa-viadeo-square:before { + content: '\f2aa'; +} +.fa-snapchat:before { + content: '\f2ab'; +} +.fa-snapchat-ghost:before { + content: '\f2ac'; +} +.fa-snapchat-square:before { + content: '\f2ad'; +} +.fa-pied-piper:before { + content: '\f2ae'; +} +.fa-first-order:before { + content: '\f2b0'; +} +.fa-yoast:before { + content: '\f2b1'; +} +.fa-themeisle:before { + content: '\f2b2'; +} +.fa-google-plus-circle:before, +.fa-google-plus-official:before { + content: '\f2b3'; +} +.fa-fa:before, +.fa-font-awesome:before { + content: '\f2b4'; +} +.fa-handshake-o:before { + content: '\f2b5'; +} +.fa-envelope-open:before { + content: '\f2b6'; +} +.fa-envelope-open-o:before { + content: '\f2b7'; +} +.fa-linode:before { + content: '\f2b8'; +} +.fa-address-book:before { + content: '\f2b9'; +} +.fa-address-book-o:before { + content: '\f2ba'; +} +.fa-vcard:before, +.fa-address-card:before { + content: '\f2bb'; +} +.fa-vcard-o:before, +.fa-address-card-o:before { + content: '\f2bc'; +} +.fa-user-circle:before { + content: '\f2bd'; +} +.fa-user-circle-o:before { + content: '\f2be'; +} +.fa-user-o:before { + content: '\f2c0'; +} +.fa-id-badge:before { + content: '\f2c1'; +} +.fa-drivers-license:before, +.fa-id-card:before { + content: '\f2c2'; +} +.fa-drivers-license-o:before, +.fa-id-card-o:before { + content: '\f2c3'; +} +.fa-quora:before { + content: '\f2c4'; +} +.fa-free-code-camp:before { + content: '\f2c5'; +} +.fa-telegram:before { + content: '\f2c6'; +} +.fa-thermometer-4:before, +.fa-thermometer:before, +.fa-thermometer-full:before { + content: '\f2c7'; +} +.fa-thermometer-3:before, +.fa-thermometer-three-quarters:before { + content: '\f2c8'; +} +.fa-thermometer-2:before, +.fa-thermometer-half:before { + content: '\f2c9'; +} +.fa-thermometer-1:before, +.fa-thermometer-quarter:before { + content: '\f2ca'; +} +.fa-thermometer-0:before, +.fa-thermometer-empty:before { + content: '\f2cb'; +} +.fa-shower:before { + content: '\f2cc'; +} +.fa-bathtub:before, +.fa-s15:before, +.fa-bath:before { + content: '\f2cd'; +} +.fa-podcast:before { + content: '\f2ce'; +} +.fa-window-maximize:before { + content: '\f2d0'; +} +.fa-window-minimize:before { + content: '\f2d1'; +} +.fa-window-restore:before { + content: '\f2d2'; +} +.fa-times-rectangle:before, +.fa-window-close:before { + content: '\f2d3'; +} +.fa-times-rectangle-o:before, +.fa-window-close-o:before { + content: '\f2d4'; +} +.fa-bandcamp:before { + content: '\f2d5'; +} +.fa-grav:before { + content: '\f2d6'; +} +.fa-etsy:before { + content: '\f2d7'; +} +.fa-imdb:before { + content: '\f2d8'; +} +.fa-ravelry:before { + content: '\f2d9'; +} +.fa-eercast:before { + content: '\f2da'; +} +.fa-microchip:before { + content: '\f2db'; +} +.fa-snowflake-o:before { + content: '\f2dc'; +} +.fa-superpowers:before { + content: '\f2dd'; +} +.fa-wpexplorer:before { + content: '\f2de'; +} +.fa-meetup:before { + content: '\f2e0'; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} diff --git a/Web/src/styles/font-awesome/fontawesome-webfont.eot b/Web/src/styles/font-awesome/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..e9f60ca953f93e35eab4108bd414bc02ddcf3928 GIT binary patch literal 165742 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 G*yFsbY~cLNXLP73aA74Mq6M9f^&YV`isWW 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

5q!RY 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 + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Web/src/styles/font-awesome/fontawesome-webfont.ttf b/Web/src/styles/font-awesome/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..35acda2fa1196aad98c2adf4378a7611dd713aa3 GIT binary patch literal 165548 zcmd4434D~*)jxjkv&@#+*JQHIB(r2Agk&ZO5W=u;0Z~v85Ce*$fTDsRbs2>!AXP+E zv})s8XszXKwXa&S)7IKescosX*7l99R$G?_w7v?NC%^Bx&rC7|(E7f=|L^lpa-Zk9 z`?>d?d+s^so_oVMW6Z|VOlEVZPMtq{)pOIHX3~v25n48F@|3AkA5-983xDXec_W** zHg8HX#uvihecqa7Yb`$*a~)&Wy^KjmE?joS+JOO-B;B|Y@umw`Uvs>da>d0W;5qQ!4Qz zJxL+bkEIe8*8}j>Q>BETG1+ht-^o+}utRA<*p2#Ix&jHe=hB??wf3sZuV5(_`d1DH zgI+ncCI1s*Tuw6@6DFOB@-mE3%l-{_4z<*f9!g8!dcoz@f1eyoO9;V5yN|*Pk0}XYPFk z!g(%@Qka**;2iW8;b{R|Dg0FbU_E9^hd3H%a#EV5;HVvgVS_k;c*=`1YN*`2lhZm3 zqOTF2Pfz8N%lA<(eJUSDWevumUJ;MocT>zZ5W08%2JkP2szU{CP(((>LmzOmB>ZOpelu zIw>A5mu@gGU}>QA1RKFi-$*aQL_KL1GNuOxs0@)VEz%g?77_AY_{e55-&2X`IC z!*9krPH>;hA+4QUe(ZB_4Z@L!DgUN;`X-m}3;G6(Mf9flyest6ciunvokm)?oZmzF z@?{e2C{v;^ys6AQy_IN=B99>#C*fPn3ra`%a_!FN6aIXi^rn1ymrrZ@gw3bA$$zqb zqOxiHDSsYDDkGmZpD$nT@HfSi%fmt6l*S0Iupll)-&7{*yFioy4w3x%GVEpx@jWf@QO?itTs?#7)d3a-Ug&FLt_)FMnmOp5gGJy@z7B*(^RVW^e1dkQ zkMHw*dK%Ayu_({yrG6RifN!GjP=|nt${60CMrjDAK)0HZCYpnJB&8QF&0_TaoF9-S zu?&_mPAU0&@X=Qpc>I^~UdvKIk0usk``F{`3HAbeHC$CyQPtgN@2lwR?3>fKwC|F> zYx{2LyT9-8zVGxM?E7=y2YuRM`{9bijfXoA&pEvG@Fj<@J$%dI`wu^U__@Oe5C8e_ z2ZyyI_9GQXI*-gbvh>I$N3K0`%aQw!JbvW4BL|QC`N#+Vf_#9QLu~J`8d;ySFWi^v zo7>mjx3(|cx3jOOZ+~B=@8!PUzP`iku=8-}aMR(`;kk#q53fC(KD_gA&*A-tGlyS3 z+m)8@1~El#u3as^j;LR~)}{9CG~D_9MNw(aQga zKO~TeK}MY%7{tgG{veXj;r|am2GwFztR{2O|5v~?px`g+cB0=PQ}aFOx^-}vA95F5 zA7=4<%*Y5_FJ|j%P>qdnh_@iTs0Qv3Shg)-OV0=S+zU1vekc4cfZ>81?nWLD;PJf5 zm^TgA&zNr~$ZdkLfD=nH@)f_xSjk$*;M3uDgT;zqnj*X$`6@snD%LSpiMm2N;QAN~ z_kcBPVyrp@Qi?Q@UdCdRu{^&CvWYrt=QCD^e09&FD^N$nM_`>%e`5*`?~&bbh->n~ zJ(9*nTC4`EGNEOm%t%U8(?hP3%1b;hjQAV0Nc?8hxeG3 zaPKiTHp5uQTE@n~b#}l3uJMQ)kGfOHpF%kkn&43O#D#F5Fg6KwPr4VR9c4{M`YDK; z3jZ{uoAx?m(^2k>9gNLvXKdDEjCCQ+Y~-2K00%hd9AfOW{fx~8OmhL>=?SSyfsZaC!Gt-z(=`WU+-&Dfn0#_n3e*q()q-CYLpelpxsjC~b#-P^<1eJJmK#NGc1 zV_&XPb2-)pD^|e^5@<6_cHeE7RC;w7<*1(><1_>^E_ievcm0P?8kubdDQj%vyA=3 z3HKCZFYIRQXH9UujQt#S{T$`}0_FTN4TrE7KVs}9q&bK>55B|Lul6(cGRpdO1Kd`| zeq(~e`?pp&g#Y$EXw}*o`yJwccQ0eFbi*Ov?^iSS>U6j#82bal{s6dMn-2#V{#Xo$ zI$lq~{fx0cA?=^g&OdKq?7tBAUym`?3z*+P_+QpC_SX>Hn~c4gX6!Ab|67K!w~_Ac z_ZWKz;eUUXv46n53-{h3#@>IKu@7En?4O7`qA>R1M~r=hy#Got_OTNVaQ-*)f3gq` zWqlf9>?rCwhC2Ie;GSYEYlZ8Edx9~|1c$Hz6P6|~v_elnBK`=R&nMuzUuN8VKI0ZA z+#be@iW#>ma1S$XYhc_CQta5uxC`H|9>(1-GVW=IdlO`OC*!^vIHdJ2gzINKkYT)d z3*#jl84q5~c0(mMGIK+jJFO2k6NLvlqs#h}}L0klN#8)z2^A6*6 zU5q!Nj7Gdit%LiB@#bE}TbkhZGoIMXcoN~QNYfU9dezGK=;@4)al-X6K6WSL9b4dD zWqdqfOo0cRfI27sjPXfulka7G3er!7o3@tm>3GioJTpUZZ!$jX5aV4vjL$A+d`^n- zxp1e$e?~9k^CmMsKg9T%fbFbqIHX;GIu<72kYZMzEPZ`#55myqXbyss&PdzkU-kng%ZaGx-qUd{ORDE9`W-<*I${1)W@@_xo| z#P?RjZA0Ge?Tp_{4)ER51-F;+Tjw*r6ZPHZW&C#J-;MVj3S2+qccSdOkoNAY8NUbR z-HUYhnc!Y!{C@9;sxqIIma{CrC z{*4;OzZrsik@3eKWBglt8Gju9$G0;6ZPfp5`1hya;Q!vUjQ{6qsNQ=S2c6;1ApV)% zjDJ4@_b}tnn&43HfiA|MBZsgbpsdVv#(xMHfA~D(KUU!0Wc>La#(y%O@fT{~-ede{ zR>pr0_Y2hXOT@kS3F8L=^RH0;%c~jx_4$nd=5@w@I~NXdzuUt2E2!)DYvKACfAu5A zUwe%4KcdXn;r@iOKr8s4QQm)bG5$uH@xLJ7o5hU3g}A?UF#a~+dV4S9??m7ZG5+_} zjQ<05{sZ6d0><|ea8JQ~#Q6It>z^jLhZ*lv;9g|>Fxqwm@O+4TAHKu*zfkVS4R9I8 z{~NIVcQ50g0KQKVb`<_&>lp7xn*Q?{2i@S=9gJ(JgXqP;%S_@4CSmVFk{g($tYngU z2omdDCYcd#!MC-SNwz*FIf|L&M40PMCV4uTQXRtTUT0GMZYDM0-H5Up z-(yk}+^8)~YEHrRGpXe%CMDJ}DT(-2W~^` zjDf-D4fq2U%2=tnQ*LW*>*Q@NeQ=U48Xk01IuzADy1ym0rit^WHK~^SwU449k4??k zJX|$cO-EBU&+R{a*)XQ6t~;?kuP)y%}DA(=%g4sNM$ z8a1k^e#^m%NS4_=9;HTdn_VW0>ap!zx91UcR50pxM}wo(NA}d;)_n~5mQGZt41J8L zZE5Hkn1U{CRFZ(Oxk3tb${0}UQ~92RJG;|T-PJKt>+QV$(z%hy+)Jz~xmNJS#48TFsM{-?LHd-bxvg|X{pRq&u74~nC4i>i16LEAiprfpGA zYjeP(qECX_9cOW$*W=U1YvVDXKItrNcS$?{_zh2o=MDaGyL^>DsNJtwjW%Do^}YA3 z3HS=f@249Yh{jnme5ZRV>tcdeh+=o(;eXg_-64c@tJ&As=oIrFZ& z*Gx&Lr>wdAF8POg_#5blBAP!&nm-O!$wspA>@;>RyOdqWZe?F%--gC9nTXZ%DnmK< z`p0sh@aOosD-jbIoje0ec`&&fWsK?xPdf*L)Qp(MwKKIOtB+EDn(3w-9Ns9O~i z7MwnG8-?RZlv&XIJZUK*;)r!1@Bh4bnRO*JmgwqANa8v4EvHWvBQYYGT?tN4>BRz1 zf1&5N7@@!g89ym5LO{@=9>;Y8=^ExA9{+#aKfFGPwby8wn)db@o}%Z_x0EjQWsmb6 zA9uX(vr-n8$U~x9dhk~VKeI!h^3Z2NXu;>n6BHB%6e2u2VJ!ZykHWv-t19}tU-Yz$ zHXl2#_m7V&O!q(RtK+(Yads868*Wm*!~EzJtW!oq)kw}`iSZl@lNpanZn&u|+px84 zZrN7t&ayK4;4x_@`Q;;XMO4{VelhvW%CtX7w;>J6y=346)vfGe)zJBQ9o$eAhcOPy zjwRa6$CvN-8qHjFi;}h1wAb{Kcnn{;+ITEi`fCUk^_(hJ&q1Z=yo*jRs<94E#yX67 zRj)s)V&gd0VVZGcLALQ|_Lp<4{XEBIF-*yma#;%V*m^xSuqeG?H-7=M0Cq%%W9`2Oe>Ov)OMv8yKrI^mZ$ql{A!!3mw_27Y zE=V#cA@HopguAWPAMhKDb__-Z_(TN7;*A`XxrMefxoz4{Seu)$%$=sPf{vT@Pf_T`RlrC#CPDl$#FnvU|VBC$0(E>+3EG z&3xsml}L_UE3bNGX6T~2dV6S%_M9{`E9kgHPa+9mas{tj$S<&{z?nRzH2b4~4m^Wc zVF+o4`w9BO_!IohZO_=<;=$8j?7KUk(S5llK6wfy9m$GsiN5*e{q(ZS6vU4l6&{s5 zXrJJ@giK>(m%yKhRT;egW||O~pGJ&`7b8-QIchNCms)}88aL8Jh{cIp1uu`FMo!ZP z1fne;+5#%k3SM7Kqe|`%w1JI=6hJJrog4j?5Iq!j=b=0AJS5%ev_9?eR!_H>OLzLM z_U#QLoi=0npY1+gHmde37Kgp)+PKl=nC>pM|EJCAEPBRXQZvb74&LUs*^WCT5Q%L-{O+y zQKgd4Cek)Gjy~OLwb&xJT2>V%wrprI+4aOtWs*;<9pGE>o8u|RvPtYh;P$XlhlqF_ z77X`$AlrH?NJj1CJdEBA8;q*JG-T8nm>hL#38U9ZYO3UTNWdO3rg-pEe5d= zw3Xi@nV)1`P%F?Y4s9yVPgPYT9d#3SLD{*L0U{ z;TtVh?Wb0Lp4MH{o@L6GvhJE=Y2u>{DI_hMtZgl~^3m3#ZUrkn?-5E3A!m!Z>183- zpkovvg1$mQawcNKoQ*tW=gtZqYGqCd)D#K;$p113iB1uE#USvWT}QQ7kM7!al-C^P zmmk!=rY+UJcJLry#vkO%BuM>pb)46x!{DkRYY7wGNK$v=np_sv7nfHZO_=eyqLSK zA6ebf$Bo&P&CR_C*7^|cA>zl^hJ7z0?xu#wFzN=D8 zxm(>@s?z1E;|!Py8HuyHM}_W5*Ff>m5U0Jhy?txDx{jjLGNXs}(CVxgu9Q4tPgE+Hm z*9ll7bz80456xzta(cX+@W!t7xTWR-OgnG_>YM~t&_#5vzC`Mp5aKlXsbO7O0HKAC z2iQF2_|0d6y4$Pu5P-bfZMRzac(Yl{IQgfa0V>u;BJRL(o0$1wD7WOWjKwP)2-6y$ zlPcRhIyDY>{PFLvIr0!VoCe;c_}dp>U-X z`pii$Ju=g+Wy~f|R7yuZZjYAv4AYJT}Ct-OfF$ZUBa> zOiKl0HSvn=+j1=4%5yD}dAq5^vgI~n>UcXZJGkl671v`D74kC?HVsgEVUZNBihyAm zQUE~mz%na<71JU=u_51}DT92@IPPX)0eiDweVeDWmD&fpw12L;-h=5Gq?za0HtmUJ zH@-8qs1E38^OR8g5Q^sI0)J}rOyKu$&o1s=bpx{TURBaQ(!P7i1=oA@B4P>8wu#ek zxZHJqz$1GoJ3_W^(*tZqZsoJlG*66B5j&D6kx@x^m6KxfD?_tCIgCRc?kD~(zmgCm zLGhpE_YBio<-2T9r;^qM0TO{u_N5@cU&P7is8f9-5vh4~t?zMqUEV!d@P{Y)%APE6 zC@k9|i%k6)6t2uJRQQTHt`P5Lgg%h*Fr*Hst8>_$J{ZI{mNBjN$^2t?KP8*6_xXu5xx8ufMp5R?P(R-t`{n6c{!t+*z zh;|Ek#vYp1VLf;GZf>~uUhU}a<>y*ErioacK@F{%7aq0y(Ytu@OPe;mq`jlJD+HtQ zUhr^&Zeh93@tZASEHr)@YqdxFu69(=VFRCysjBoGqZ!U;W1gn5D$myEAmK|$NsF>Z zoV+w>31}eE0iAN9QAY2O+;g%zc>2t#7Dq5vTvb&}E*5lHrkrj!I1b0=@+&c(qJcmok6 zSZAuQ496j<&@a6?K6ox1vRks+RqYD< zT9On_zdVf}IStW^#13*WV8wHQWz$L;0cm)|JDbh|f~*LV8N$;2oL|R99**#AT1smo zob=4dB_WB-D3}~I!ATFHzdW%WacH{qwv5Go2WzQzwRrv)ZajWMp{13T_u;Rz^V-VF z@#62k@#FD#t@v9ye*A%@ODWm-@oM_$_3Cy1BS+(+ujzNF@8a7?`$B^{iX2A-2_nA? zfi2=05XV^;D_2G}Up$eFW|Ofb^zuE)bWHkXR4Jm!Sz0O?)x6QD^kOufR`*v0=|sS?#*ZCvvr^VkV!zhLF3}FHf%+=#@ae1Qq<4~Y1EGYK$Ib1 zg!s~&&u27X&4Ks^(L3%}Npx!_-A)We=0v#yzv03fzxKZ8iV6KIX5U&?>^E?%iIUZ4 z2sD^vRg%kOU!B5@iV{&gBNc9vB)i{Wa@joIa2#4=oAl|-xqj_~$h33%zgk*UWGUV# zf3>{T#2buK?AZH?)h>10N)#VHvOV}%c|wR%HF|pgm8k`*=1l5P8ttZ1Ly@=C5?d9s z)R>B@43V`}=0??4tp?Y}Ox0$SH)yg(!|@V7H^}C-GyAXHFva04omv@`|LCuFRM2`U zxCM>41^p9U3cR>W>`h`{m^VWSL0SNz27{ske7TN1dTpM|P6Hn!^*}+fr>rJ*+GQN{ ziKp9Zda}CgnbNv#9^^&{MChK=E|Wr}tk?tP#Q?iZ%$2k;Eo9~}^tmv?g~PW^C$`N)|awe=5m{Xqd!M=ST?2~(mWjdOsXK#yVMN(qP6`q#tg+rQexf|*BeIU)a z^WuJyPR4WVsATp2E{*y77*kZ9 zEB{*SRHSVGm8ThtES`9!v{E``H)^3d+TG_?{b|eytE1cy^QbPxY3KFTWh&NZi`C?O z;777FMti@+U+IRl7B{=SCc93nKp`>jeW38muw(9T3AqySM#x@9G|p?N;IiNy(KN7? zMz3hIS5SaXrGqD(NIR0ZMnJT%%^~}|cG(Ez!3#)*o{{QjPUIVFOQ%dccgC0*WnAJW zL*1k^HZ5-%bN;%C&2vpW`=;dB5iu4SR48yF$;K8{SY`7mu6c z@q{10W=zwHuav3wid&;5tHCUlUgeVf&>wKuUfEVuUsS%XZ2RPvr>;HI=<(RACmN-M zR8(DJD^lePC9|rUrFgR?>hO#VkFo8}zA@jt{ERalZl$!LP4-GTT`1w}QNUcvuEFRv z`)NyzRG!e-04~~Y1DK>70lGq9rD4J}>V(1*UxcCtBUmyi-Y8Q$NOTQ&VfJIlBRI;7 z5Dr6QNIl|8NTfO>Jf|kZVh7n>hL^)`@3r1BaPIKjxrLrjf8A>RDaI{wYlKG)6-7R~ zsZQ}Kk{T~BDVLo#Zm@cc<&x{X<~boVS5(zfvp1s3RbASf6EKpp>+IFV9s`#Yx#+I& zMz5zL9IUgaqrnG*_=_qm|JBcwfl`bw=c=uU^R>Nm%k4_TeDjy|&K2eKwx!u8 z9&lbdJ?yJ@)>!NgE_vN8+*}$8+Uxk4EBNje>!s2_nOCtE+ie>zl!9&!!I)?QPMD&P zm$5sb#Le|%L<#tZbz%~WWv&yUZH6NLl>OK#CBOp{e~$&fuqQd03DJfLrcWa}IvMu* zy;z7L)WxyINd`m}Fh=l&6EWmHUGLkeP{6Vc;Xq->+AS`1T*b9>SJ#<2Cf!N<)o7Ms z!Gj)CiteiY$f@_OT4C*IODVyil4|R)+8nCf&tw%_BEv!z3RSN|pG(k%hYGrU_Ec^& zNRpzS-nJ*v_QHeHPu}Iub>F_}G1*vdGR~ZSdaG(JEwXM{Df;~AK)j(<_O<)u)`qw* zQduoY)s+$7NdtxaGEAo-cGn7Z5yN#ApXWD1&-5uowpb7bR54QcA7kWG@gybdQQa&cxCKxup2Av3_#{04Z^J#@M&a}P$M<((Zx{A8 z!Ue=%xTpWEzWzKIhsO_xc?e$$ai{S63-$76>gtB?9usV&`qp=Kn*GE5C&Tx`^uyza zw{^ImGi-hkYkP`^0r5vgoSL$EjuxaoKBh2L;dk#~x%`TgefEDi7^(~cmE)UEw*l#i+5f-;!v^P%ZowUbhH*3Av)CifOJX7KS6#d|_83fqJ#8VL=h2KMI zGYTbGm=Q=0lfc{$IDTn;IxIgLZ(Z?)#!mln$0r3A(um zzBIGw6?zmj=H#CkvRoT+C{T=_kfQQ!%8T;loQ5;tH?lZ%M{aG+z75&bhJE`sNSO`$ z`0eget1V7SqB@uA;kQ4UkJ-235xxryG*uzwDPikrWOi1;8WASslh$U4RY{JHgggsL zMaZ|PI2Ise8dMEpuPnW`XYJY^W$n>4PxVOPCO#DnHKfqe+Y7BA6(=QJn}un5MkM7S zkL?&Gvnj|DI!4xt6BV*t)Zv0YV-+(%$}7QcBMZ01jlLEiPk>A3;M^g%K=cNDF6d!7 z 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 d0mRO}xo^G_%I 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 SdSQM28?+M|D(2r_;{O0|uQ74} literal 0 HcmV?d00001 diff --git a/Web/src/styles/font-awesome/fontawesome-webfont.woff2 b/Web/src/styles/font-awesome/fontawesome-webfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..4d13fc60404b91e398a37200c4a77b645cfd9586 GIT binary patch literal 77160 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 literal 0 HcmV?d00001 diff --git a/Web/src/styles/index.scss b/Web/src/styles/index.scss new file mode 100644 index 0000000..e08baa2 --- /dev/null +++ b/Web/src/styles/index.scss @@ -0,0 +1,169 @@ +@use './mixin.scss'; +@use './transition.scss'; +@use './element-ui.scss'; +@use './font-awesome/font-awesome.scss'; + +body { + height: 100%; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + font-family: + Helvetica Neue, + Helvetica, + PingFang SC, + Hiragino Sans GB, + Microsoft YaHei, + SimSun, + sans-serif; + font-weight: 400; +} + +label { + font-weight: 700; +} + +html { + height: 100%; + box-sizing: border-box; +} + +#app { + height: 100%; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +a:focus, +a:active { + outline: none; +} + +a, +a:focus, +a:hover { + cursor: pointer; + color: inherit; + text-decoration: none; +} + +div:focus { + outline: none; +} + +.clearfix { + &:after { + visibility: hidden; + display: block; + font-size: 0; + content: ' '; + clear: both; + height: 0; + } +} + +//设置 弹出框的默认最小高度 +.el-dialog { + .app-container { + min-height: 40vh; + } +} + +// 表格布局 +.app-container { + width: 100%; + flex-grow: 1; + display: flex; + flex-direction: column; + + .search-container { + .el-form { + .el-form-item { + margin-bottom: 0px; + } + //全局input输入框长度不设置时clearable会导致宽度自动变更 + .el-input { + width: 200px !important; + } + } + } + //表格不带分页样式 + .full-table-container { + margin-top: 10px; + flex: 1; + .el-card__body { + height: 100%; + + .el-table { + height: 100%; + } + } + } + + //表格带分页样式 + .paged-table-container { + margin-top: 10px; + flex: 1; + .el-card__body { + height: 100%; + .el-table { + height: calc(100% - 45px); + } + } + } +} + +//边侧 主页面布局 适合左边树形结构 右边表格 +.app-container-main-aside { + width: 100%; + flex-grow: 1; + display: flex; + + .app-container-aside { + width: 300px; //必须有一个宽度 如果需要自定以请重写 + height: 100%; + flex-grow: 0; + flex-shrink: 0; + .el-card { + height: 100%; + } + } + + .app-container-main { + height: 100%; + width: calc(100% - 300px); //必须有一个宽度 如果需要自定以请重写 + display: flex; + flex-direction: column; + margin-left: 10px; + + .search-container { + .el-form { + .el-form-item { + margin-bottom: 0px; + } + //全局input输入框长度不设置时clearable会导致宽度自动变更 + .el-input { + width: 200px !important; + } + } + } + //设置表格自适应高度 + .paged-table-container { + flex: 1; + .el-card__body { + height: 100%; + .el-table { + height: calc(100% - 45px); + } + } + } + } +} + +#nprogress .bar { + background: var(--el-color-primary) !important; //自定义颜色 +} diff --git a/Web/src/styles/mixin.scss b/Web/src/styles/mixin.scss new file mode 100644 index 0000000..3ca7168 --- /dev/null +++ b/Web/src/styles/mixin.scss @@ -0,0 +1,28 @@ +@mixin clearfix { + &:after { + content: ''; + display: table; + clear: both; + } +} + +@mixin scrollBar { + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } +} + +@mixin relative { + position: relative; + width: 100%; + height: 100%; +} diff --git a/Web/src/styles/transition.scss b/Web/src/styles/transition.scss new file mode 100644 index 0000000..4b7e0e1 --- /dev/null +++ b/Web/src/styles/transition.scss @@ -0,0 +1,48 @@ +// global transition css + +/* fade */ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.28s; +} + +.fade-enter, +.fade-leave-active { + opacity: 0; +} + +/* fade-transform */ +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all .5s; +} + +.fade-transform-enter-from { + opacity: 0; + transform: translateX(-30px); +} + +.fade-transform-leave-to { + opacity: 0; + transform: translateX(30px); +} + +/* breadcrumb transition */ +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all .5s; +} + +.breadcrumb-enter-from, +.breadcrumb-leave-to { + opacity: 0; + transform: translateX(40px); +} + +.breadcrumb-move { + transition: all .5s; +} + +.breadcrumb-leave-active { + position: absolute; +} diff --git a/Web/src/styles/variables.module.scss b/Web/src/styles/variables.module.scss new file mode 100644 index 0000000..7faa471 --- /dev/null +++ b/Web/src/styles/variables.module.scss @@ -0,0 +1,37 @@ +// sidebar +$menuText: #bfcbd9; +$menuActiveText: #409eff; +$subMenuActiveText: #f4f4f5; //https://github.com/ElemeFE/element/issues/12951 + +$menuBg: #304156; +$menuHover: #263445; + +$subMenuBg: #1f2d3d; +$subMenuHover: #001528; + +$menuBg_dark: #252526; +$menuHover_dark: #1e1e1e; + +$subMenuBg_dark: #3c3c3c; +$subMenuHover_dark: #1e1e1e; + +$sideBarWidth: 210px; + +// the :export directive is the magic sauce for webpack +// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass +:export { + menuText: $menuText; + menuActiveText: $menuActiveText; + subMenuActiveText: $subMenuActiveText; + menuBg: $menuBg; + menuHover: $menuHover; + subMenuBg: $subMenuBg; + subMenuHover: $subMenuHover; + sideBarWidth: $sideBarWidth; + + menuBg_dark: $menuBg_dark; + menuHover_dark: $menuHover_dark; + + subMenuBg_dark: $subMenuBg_dark; + subMenuHover_dark: $subMenuHover_dark; +} diff --git a/Web/src/utils/auth.js b/Web/src/utils/auth.js new file mode 100644 index 0000000..9c4ca46 --- /dev/null +++ b/Web/src/utils/auth.js @@ -0,0 +1,33 @@ +import Cookies from 'js-cookie' + +const TokenKey = 'vue_admin_template_token' +const RefreshTokenKey = 'vue_admin_template_refresh_token' + +export function getToken() { + return Cookies.get(TokenKey) +} + +export function saveToken(token) { + return Cookies.set(TokenKey, token) +} + +export function removeToken() { + return Cookies.remove(TokenKey) +} + +export function getRefreshToken() { + return Cookies.get(RefreshTokenKey) +} + +/** + * @param {string} token + * @param {Number} expires 几天后过期 + * 设置refreshToken + */ +export function saveRefreshToken(refreshToken,expires) { + return Cookies.set(RefreshTokenKey, refreshToken,{expires:expires}) +} + +export function removeRefreshToken() { + return Cookies.remove(RefreshTokenKey) +} diff --git a/Web/src/utils/base64Conver.js b/Web/src/utils/base64Conver.js new file mode 100644 index 0000000..67d1b09 --- /dev/null +++ b/Web/src/utils/base64Conver.js @@ -0,0 +1,84 @@ +/** + * @description: base64 to blob + */ +export function dataURLtoBlob(base64Buf) { + const arr = base64Buf.split(','); + const typeItem = arr[0]; + const mime = typeItem.match(/:(.*?);/)[1]; + const bstr = window.atob(arr[1]); + let n = bstr.length; + const u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], { type: mime }); +} + +/** + * img url to base64 + * @param url + */ +export function urlToBase64(url, mineType) { + return new Promise((resolve, reject) => { + let canvas = document.createElement('CANVAS') ; + const ctx = canvas.getContext('2d'); + + const img = new Image(); + img.crossOrigin = ''; + img.onload = function () { + if (!canvas || !ctx) { + return reject(); + } + canvas.height = img.height; + canvas.width = img.width; + ctx.drawImage(img, 0, 0); + const dataURL = canvas.toDataURL(mineType || 'image/png'); + canvas = null; + resolve(dataURL); + }; + img.src = url; + }); +} + +/** + * File转Base64 + * @param file + */ +export function fileToBase64(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result); + reader.onerror = (error) => reject(error); + }); +} + +/** + * Base64转File + * @param dataURL {String} base64 + * @param fileName {String} 文件名 + * @param mimeType {String} [可选]文件类型,默认为base64中的类型 + * @returns {File} + */ +export function base64ToFile(dataURL, fileName, mimeType = null) { + var arr = dataURL.split(','); + var defaultMimeType = arr[0].match(/:(.*?);/)[1]; + var bStr = atob(arr[1]); + let n = bStr.length; + var u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bStr.charCodeAt(n); + } + return new File([u8arr], fileName, { type: mimeType || defaultMimeType }); +} + +/** + * Blob转File + * @param blob {Blob} blob + * @param fileName {String} 文件名 + * @param mimeType {String} 文件类型 + * @return {File} + */ +export function blobToFile(blob, fileName, mimeType) { + return new File([blob], fileName, { type: mimeType }); +} diff --git a/Web/src/utils/download.js b/Web/src/utils/download.js new file mode 100644 index 0000000..4b68056 --- /dev/null +++ b/Web/src/utils/download.js @@ -0,0 +1,113 @@ +import { dataURLtoBlob, urlToBase64 } from './base64Conver'; + +/** + * Download online pictures + * @param url + * @param filename + * @param mime + * @param bom + */ +export function downloadByOnlineUrl(url, filename, mime, bom) { + urlToBase64(url).then((base64) => { + downloadByBase64(base64, filename, mime, bom); + }); +} + +/** + * Download pictures based on base64 + * @param buf + * @param filename + * @param mime + * @param bom + */ +export function downloadByBase64(buf, filename, mime, bom) { + const base64Buf = dataURLtoBlob(buf); + downloadByData(base64Buf, filename, mime, bom); +} + +/** + * Download according to the background interface file stream + * @param {*} data + * @param {*} filename + * @param {*} mime + * @param {*} bom + */ +export function downloadByData(data, filename, mime, bom) { + const blobData = typeof bom !== 'undefined' ? [bom, data] : [data]; + const blob = new Blob(blobData, { type: mime || 'application/octet-stream' }); + + const blobURL = window.URL.createObjectURL(blob); + const tempLink = document.createElement('a'); + tempLink.style.display = 'none'; + tempLink.href = blobURL; + tempLink.setAttribute('download', filename); + if (typeof tempLink.download === 'undefined') { + tempLink.setAttribute('target', '_blank'); + } + document.body.appendChild(tempLink); + tempLink.click(); + document.body.removeChild(tempLink); + window.URL.revokeObjectURL(blobURL); +} + +/** + * Download file according to file address + * @param {*} sUrl + */ +export function downloadByUrl({ url, target = '_blank', fileName }) { + const isChrome = window.navigator.userAgent.toLowerCase().indexOf('chrome') > -1; + const isSafari = window.navigator.userAgent.toLowerCase().indexOf('safari') > -1; + + if (/(iP)/g.test(window.navigator.userAgent)) { + console.error('Your browser does not support download!'); + return false; + } + if (isChrome || isSafari) { + const link = document.createElement('a'); + link.href = url; + link.target = target; + + if (link.download !== undefined) { + link.download = fileName || url.substring(url.lastIndexOf('/') + 1, url.length); + } + + if (document.createEvent) { + const e = document.createEvent('MouseEvents'); + e.initEvent('click', true, true); + link.dispatchEvent(e); + return true; + } + } + if (url.indexOf('?') === -1) { + url += '?download'; + } + + openWindow(url, { target }); + return true; +} +/** + * + * @param {string} url + * @param { target?: TargetContext | string; noopener?: boolean; noreferrer?: boolean } opt + */ +export function openWindow(url, opt ) { + const { target = '__blank', noopener = true, noreferrer = true } = opt || {}; + const feature = []; + + noopener && feature.push('noopener=yes'); + noreferrer && feature.push('noreferrer=yes'); + + window.open(url, target, feature.join(',')); +} +/** + * @param {RawAxiosResponseHeaders | AxiosResponseHeaders} headers + */ +export function getFileName(headers ) { + var fileName = headers['content-disposition'].split(';')[1].split('filename=')[1]; + var fileNameUnicode = headers['content-disposition'].split('filename*=')[1]; + if (fileNameUnicode) { + //当存在 filename* 时,取filename* 并进行解码(为了解决中文乱码问题) + fileName = decodeURIComponent(fileNameUnicode.split("''")[1]); + } + return fileName; +} diff --git a/Web/src/utils/formatTime.js b/Web/src/utils/formatTime.js new file mode 100644 index 0000000..d6a8a26 --- /dev/null +++ b/Web/src/utils/formatTime.js @@ -0,0 +1,260 @@ +/** + * 时间日期转换 + * @param {Date} date 当前时间,new Date() 格式 + * @param {string} format 需要转换的时间格式字符串 + * @description format 字符串随意,如 `YYYY-mm、YYYY-mm-dd` + * @description format 季度:"YYYY-mm-dd HH:MM:SS QQQQ" + * @description format 星期:"YYYY-mm-dd HH:MM:SS WWW" + * @description format 几周:"YYYY-mm-dd HH:MM:SS ZZZ" + * @description format 季度 + 星期 + 几周:"YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ" + * @returns {string} 返回拼接后的时间字符串 + */ +export function formatDate(date, format) { + if (!(date instanceof Date) || isNaN(date.getTime())) { + throw new Error('Invalid date'); + } + if (typeof format !== 'string') { + throw new Error('Invalid format string'); + } + + const we = date.getDay(); // 星期 + const z = getWeek(date); // 周 + const qut = Math.floor((date.getMonth() + 3) / 3).toString(); // 季度 + + const opt = { + 'Y+': date.getFullYear().toString(), // 年 + 'm+': (date.getMonth() + 1).toString(), // 月(月份从0开始,要+1) + 'd+': date.getDate().toString(), // 日 + 'H+': date.getHours().toString(), // 时 + 'M+': date.getMinutes().toString(), // 分 + 'S+': date.getSeconds().toString(), // 秒 + 'q+': qut, // 季度 + }; + + const week = ['日', '一', '二', '三', '四', '五', '六']; + const quarter = ['一', '二', '三', '四']; + + const replaceFormat = (pattern, replacement) => { + const regex = new RegExp(`(${pattern})`, 'g'); + format = format.replace(regex, match => { + if (match.length > 1) { + return replacement.length > 1 ? replacement : replacement.slice(-1); + } + return replacement; + }); + }; + + if (/(W+)/.test(format)) { + replaceFormat('W+', week[we]); + } + if (/(Q+)/.test(format)) { + replaceFormat('Q+', quarter[qut - 1]); + } + if (/(Z+)/.test(format)) { + replaceFormat('Z+', z.toString()); + } + + for (let k in opt) { + replaceFormat(k, opt[k].padStart(k.length, '0')); + } + + return format; +} + +/** + * 获取当前日期是第几周 + * @param {Date} dateTime 当前传入的日期值 + * @returns {number} 返回第几周数字值 + */ +export function getWeek(dateTime) { + if (!(dateTime instanceof Date) || isNaN(dateTime.getTime())) { + throw new Error('Invalid date'); + } + + let temptTime = new Date(dateTime.getTime()); + let weekday = temptTime.getDay() || 7; + temptTime.setDate(temptTime.getDate() - weekday + 1 + 5); + let firstDay = new Date(temptTime.getFullYear(), 0, 1); + let dayOfWeek = firstDay.getDay(); + let spendDay = dayOfWeek === 0 ? 1 : 7 - dayOfWeek + 1; + firstDay = new Date(temptTime.getFullYear(), 0, 1 + spendDay); + let d = Math.ceil((temptTime.valueOf() - firstDay.valueOf()) / 86400000); + return Math.ceil(d / 7); +} + +/** + * 时间问候语 + * @param {Date} param 当前时间,new Date() 格式 + * @returns {string} 返回拼接后的时间字符串 + */ +export function formatAxis(param) { + if (!(param instanceof Date) || isNaN(param.getTime())) { + throw new Error('Invalid date'); + } + + const hour = param.getHours(); + if (hour < 6) return '凌晨好'; + if (hour < 9) return '早上好'; + if (hour < 12) return '上午好'; + if (hour < 14) return '中午好'; + if (hour < 17) return '下午好'; + if (hour < 19) return '傍晚好'; + if (hour < 22) return '晚上好'; + return '夜里好'; +} + +/** + * Parse the time to string + * @param {(Object|string|number)} time + * @param {string} cFormat + * @returns {string | null} + */ +export function parseTime(time, cFormat = '{y}-{m}-{d} {h}:{i}:{s}') { + if (!time) { + return null; + } + + let date; + if (typeof time === 'object') { + date = time; + } else if (typeof time === 'string') { + if (/^[0-9]+$/.test(time)) { + time = parseInt(time); + } else { + time = time.replace(/-/g, '/'); + } + date = new Date(time); + } else if (typeof time === 'number') { + if (time.toString().length === 10) { + time *= 1000; + } + date = new Date(time); + } else { + throw new Error('Invalid time input'); + } + + if (isNaN(date.getTime())) { + throw new Error('Invalid date'); + } + + const formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: ['日', '一', '二', '三', '四', '五', '六'][date.getDay()] + }; + + return cFormat.replace(/{([ymdhisa])+}/g, (result, key) => { + const value = formatObj[key]; + return key === 'a' ? value : value.toString().padStart(2, '0'); + }); +} + + /** + * @param {(Object|string|number)} time 时间戳,yyyy-MM-dd HH:mm:ss,new Date() + * @param {string} option + * @returns {string} + */ +export function formatTime(time, option) { + if (!time) { + return ''; + } + + let parsedTime; + if (typeof time === 'string' || typeof time === 'number') { + parsedTime = parseTime(time, option || 'YYYY-mm-dd HH:MM:SS'); + } else { + throw new Error('Invalid time input'); + } + + const d = new Date(parsedTime); + const now = Date.now(); + const diff = (now - d) / 1000; + + if (diff < 30) { + return '刚刚'; + } else if (diff < 3600) { + return `${Math.ceil(diff / 60)}分钟前`; + } else if (diff < 86400) { + return `${Math.ceil(diff / 3600)}小时前`; + } else if (diff < 259200) { + return '1天前'; + } else { + return parsedTime; + } +} + +/** + * + * @param {Date} startDate + * @param {Date} endDate + * @returns + */ +export function diffInYears(startDate, endDate) { + let startYear = startDate.getFullYear(); + let endYear = endDate.getFullYear(); + + // 计算年份差 + return endYear - startYear; +} +/** + * + * @param {Date} startDate + * @param {Date} endDate + * @returns + */ +export function diffInMonths(startDate, endDate) { + let yearDifference = diffInYears(startDate, endDate); + let monthDifference = endDate.getMonth() - startDate.getMonth(); + + // 如果结束月份小于开始月份,则需要调整年份和月份差 + if (monthDifference < 0) { + yearDifference--; + monthDifference += 12; + } + + return yearDifference * 12 + monthDifference; +} +/** + * + * @param {Date} startDate + * @param {Date} endDate + * @returns + */ +export function diffInDays(startDate, endDate) { + const millisecondsPerDay = 1000 * 60 * 60 * 24; + return Math.floor((endDate - startDate) / millisecondsPerDay); +} +/** + * + * @param {Date} startDate + * @param {Date} endDate + * @returns + */ +export function diffInHours(startDate, endDate) { + const millisecondsPerHour = 1000 * 60 * 60; + return Math.floor((endDate - startDate) / millisecondsPerHour); +} +/** + * + * @param {Date} startDate + * @param {Date} endDate + * @returns + */ +export function diffInMinutes(startDate, endDate) { + const millisecondsPerMinute = 1000 * 60; + return Math.floor((endDate - startDate) / millisecondsPerMinute); +} +/** + * + * @param {Date} startDate + * @param {Date} endDate + * @returns + */ +export function diffInSeconds(startDate, endDate) { + const millisecondsPerSecond = 1000; + return Math.floor((endDate - startDate) / millisecondsPerSecond); +} diff --git a/Web/src/utils/get-page-title.js b/Web/src/utils/get-page-title.js new file mode 100644 index 0000000..a6de99d --- /dev/null +++ b/Web/src/utils/get-page-title.js @@ -0,0 +1,10 @@ +import defaultSettings from '@/settings' + +const title = defaultSettings.title || 'Vue Admin Template' + +export default function getPageTitle(pageTitle) { + if (pageTitle) { + return `${pageTitle} - ${title}` + } + return `${title}` +} diff --git a/Web/src/utils/index.js b/Web/src/utils/index.js new file mode 100644 index 0000000..324cc4a --- /dev/null +++ b/Web/src/utils/index.js @@ -0,0 +1,73 @@ +/** + * Created by PanJiaChen on 16/11/18. + */ + +/** + * @param {string} url + * @returns {Object} + */ +export function param2Obj(url) { + const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') + if (!search) { + return {} + } + const obj = {} + const searchArr = search.split('&') + searchArr.forEach((v) => { + const index = v.indexOf('=') + if (index !== -1) { + const name = v.substring(0, index) + const val = v.substring(index + 1, v.length) + obj[name] = val + } + }) + return obj +} + +/** + * Check if an element has a class + * @param {HTMLElement} elm + * @param {string} cls + * @returns {boolean} + */ +export function hasClass(ele, cls) { + return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) +} + +/** + * Add class to element + * @param {HTMLElement} elm + * @param {string} cls + */ +export function addClass(ele, cls) { + if (!hasClass(ele, cls)) ele.className += ' ' + cls +} + +/** + * Remove class from element + * @param {HTMLElement} elm + * @param {string} cls + */ +export function removeClass(ele, cls) { + if (hasClass(ele, cls)) { + const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') + ele.className = ele.className.replace(reg, ' ') + } +} + +/** + * 等待标记完成 + * @param {Boolen} ref(Boolen) flag + */ +export async function waiting(flag){ + if (!flag.value) { + await new Promise((resolve) => { + const check = setInterval(() => { + if (flag.value) { + clearInterval(check) + resolve() + } + }, 100) // 每100毫秒检查一次 + }) + } +} \ No newline at end of file diff --git a/Web/src/utils/request.js b/Web/src/utils/request.js new file mode 100644 index 0000000..44fa9df --- /dev/null +++ b/Web/src/utils/request.js @@ -0,0 +1,120 @@ +import axios from 'axios' +import { ElMessage } from 'element-plus' +import store from '@/stores' + +const app_base_api = import.meta.env.VITE_API_BASE_URL +// create an axios instance +const service = axios.create({ + baseURL: app_base_api, // url = base url + request url + // withCredentials: true, // send cookies when cross-domain requests + timeout: 120 * 1000 // request timeout +}) + +// request interceptor +service.interceptors.request.use( + (config) => { + // do something before request is sent + let userStore=store.userStore(); + if (userStore.state.token) { + // let each request carry token + // ['X-Token'] is a custom headers key + // please modify it according to the actual situation + config.headers['Authorization'] ="Bearer "+ userStore.state.token + config.headers['X-Authorization'] ="Bearer "+ userStore.state.refreshToken + } + return config + }, + (error) => { + // do something with request error + console.log(error) // for debug + return Promise.reject(error) + } +) + +// 是否在刷新Token标记 +let isRefreshingToken=false +// 刷新时后续的请求队列 +let requestList = [] + +// response interceptor +service.interceptors.response.use( + /** + * If you want to get http information such as headers or status + * Please return response => response + */ + + /** + * Determine the request status by custom code + * Here is just an example + * You can also judge the status by HTTP Status Code + */ + async (response) => { + if (response.status === 200) { + const res = response.data + //下载文件 + if(res instanceof Blob){ + return response + } + // 1 是正确 . + if (res.code != 1) { + //报错 + ElMessage({ + message: res.message || 'Error', + type: 'error', + duration: 5 * 1000 + }) + return Promise.reject(new Error(res.message || 'Error')) + } else { + return res + } + } else { + return Promise.reject(new Error(response.statusText || 'Error')) + } + }, + async (error) => { + if(error.status===401){ + if(!isRefreshingToken){ + // 修改isRefreshing状态 + isRefreshingToken = true + await store.userStore().reLogin() + .catch(async err=>{ + debugger + //重新到登录页 + store.userStore().resetAllToken() + window.location.href="/login" + return Promise.reject(err) + }) + // 重置状态 + isRefreshingToken = false + // token 刷新后将数组里的请求队列方法重新执行 + requestList.forEach((it) => it()) + // 重新请求完清空 + requestList = [] + // 继续未完成的请求 + const resp = await service.request(error.config) + // 返回请求结果 + return Promise.resolve(resp) + + }else{ + // 后面的请求走这里排队 + // 返回未执行 resolve 的 Promise + return new Promise(resolve => { + // 用函数形式将 resolve 存入,等待获取新token后再执行 + requestList.push(() => { + resolve(service(error.config)) + }) + }) + } + }else{ + console.log('err' + error) // for debug + ElMessage({ + message: error.message, + type: 'error', + duration: 5 * 1000 + }) + return Promise.reject(error) + } + } +) + +export default service diff --git a/Web/src/utils/validate.js b/Web/src/utils/validate.js new file mode 100644 index 0000000..4cfc329 --- /dev/null +++ b/Web/src/utils/validate.js @@ -0,0 +1,382 @@ +/** + * Created by PanJiaChen on 16/11/18. + */ + +/** + * @param {string} path + * @returns {Boolean} + */ +export function isExternal(path) { + return /^(https?:|mailto:|tel:)/.test(path) +} + +/** + * 2020.11.29 lyt 整理 + * 工具类集合,适用于平时开发 + * 新增多行注释信息,鼠标放到方法名即可查看 + */ + +/** + * 验证百分比(不可以小数) + * @param {string} val 当前值字符串 + * @returns {string} 返回处理后的字符串 + */ + export function verifyNumberPercentage(val) { + // 匹配空格 + let v = val.replace(/(^\s*)|(\s*$)/g, ''); + // 只能是数字和小数点,不能是其他输入 + v = v.replace(/[^\d]/g, ''); + // 不能以0开始 + v = v.replace(/^0/g, ''); + // 数字超过100,赋值成最大值100 + v = v.replace(/^[1-9]\d\d{1,3}$/, '100'); + // 返回结果 + return v; +} + +/** + * 验证百分比(可以小数) + * @param {string} val 当前值字符串 + * @returns {string} 返回处理后的字符串 + */ +export function verifyNumberPercentageFloat(val ) { + let v = verifyNumberIntegerAndFloat(val); + // 数字超过100,赋值成最大值100 + v = v.replace(/^[1-9]\d\d{1,3}$/, '100'); + // 超过100之后不给再输入值 + v = v.replace(/^100\.$/, '100'); + // 返回结果 + return v; +} + +/** + * 小数或整数(不可以负数) + * @param {string} val 当前值字符串 + * @returns {string} 返回处理后的字符串 + */ +export function verifyNumberIntegerAndFloat(val) { + // 匹配空格 + let v = val.replace(/(^\s*)|(\s*$)/g, ''); + // 只能是数字和小数点,不能是其他输入 + v = v.replace(/[^\d.]/g, ''); + // 以0开始只能输入一个 + v = v.replace(/^0{2}$/g, '0'); + // 保证第一位只能是数字,不能是点 + v = v.replace(/^\./g, ''); + // 小数只能出现1位 + v = v.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.'); + // 小数点后面保留2位 + v = v.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3'); + // 返回结果 + return v; +} + +/** + * 正整数验证 + * @param {string} val 当前值字符串 + * @returns {string} 返回处理后的字符串 + */ +export function verifiyNumberInteger(val) { + // 匹配空格 + let v = val.replace(/(^\s*)|(\s*$)/g, ''); + // 去掉 '.' , 防止贴贴的时候出现问题 如 0.1.12.12 + v = v.replace(/[\.]*/g, ''); + // 去掉以 0 开始后面的数, 防止贴贴的时候出现问题 如 00121323 + v = v.replace(/(^0[\d]*)$/g, '0'); + // 首位是0,只能出现一次 + v = v.replace(/^0\d$/g, '0'); + // 只匹配数字 + v = v.replace(/[^\d]/g, ''); + // 返回结果 + return v; +} + +/** + * 去掉中文及空格 + * @param {string} val 当前值字符串 + * @returns {string} 返回处理后的字符串 + */ +export function verifyCnAndSpace(val) { + // 匹配中文与空格 + let v = val.replace(/[\u4e00-\u9fa5\s]+/g, ''); + // 匹配空格 + v = v.replace(/(^\s*)|(\s*$)/g, ''); + // 返回结果 + return v; +} + +/** + * 去掉英文及空格 + * @param {string} val 当前值字符串 + * @returns {string} 返回处理后的字符串 + */ +export function verifyEnAndSpace(val) { + // 匹配英文与空格 + let v = val.replace(/[a-zA-Z]+/g, ''); + // 匹配空格 + v = v.replace(/(^\s*)|(\s*$)/g, ''); + // 返回结果 + return v; +} + +/** + * 禁止输入空格 + * @param {string} val 当前值字符串 + * @returns {string} 返回处理后的字符串 + */ +export function verifyAndSpace(val) { + // 匹配空格 + let v = val.replace(/(^\s*)|(\s*$)/g, ''); + // 返回结果 + return v; +} + +/** + * 金额用 `,` 区分开 + * @param {string} val 当前值字符串 + * @returns {string} 返回处理后的字符串 + */ +export function verifyNumberComma(val) { + // 调用小数或整数(不可以负数)方法 + let v = verifyNumberIntegerAndFloat(val); + // 字符串转成数组 + v = v.toString().split('.'); + // \B 匹配非单词边界,两边都是单词字符或者两边都是非单词字符 + v[0] = v[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); + // 数组转字符串 + v = v.join('.'); + // 返回结果 + return v; +} + +/** + * 匹配文字变色(搜索时) + * @param {string} val 当前值字符串 + * @param {string} text 要处理的字符串值 + * @param {string} color 搜索到时字体高亮颜色 + * @returns {string} 返回处理后的字符串 + */ +export function verifyTextColor(val, text = '', color = 'red') { + // 返回内容,添加颜色 + let v = text.replace(new RegExp(val, 'gi'), `${val}`); + // 返回结果 + return v; +} + +/** + * 数字转中文大写 + * @param {string} val 当前值字符串 + * @param {string} unit 默认:仟佰拾亿仟佰拾万仟佰拾元角分 + * @returns {string} 返回处理后的字符串 + */ +export function verifyNumberCnUppercase(val, unit = '仟佰拾亿仟佰拾万仟佰拾元角分', v = '') { + // 当前内容字符串添加 2个0,为什么?? + val += '00'; + // 返回某个指定的字符串值在字符串中首次出现的位置,没有出现,则该方法返回 -1 + let lookup = val.indexOf('.'); + // substring:不包含结束下标内容,substr:包含结束下标内容 + if (lookup >= 0) val = val.substring(0, lookup) + val.substring(lookup + 1, 2); + // 根据内容 val 的长度,截取返回对应大写 + unit = unit.substring(unit.length - val.length); + // 循环截取拼接大写 + for (let i = 0; i < val.length; i++) { + v += '零壹贰叁肆伍陆柒捌玖'.substring(val.substring(i, 1), 1) + unit.substring(i, 1); + } + // 正则处理 + v = v + .replace(/零角零分$/, '整') + .replace(/零[仟佰拾]/g, '零') + .replace(/零{2,}/g, '零') + .replace(/零([亿|万])/g, '$1') + .replace(/零+元/, '元') + .replace(/亿零{0,3}万/, '亿') + .replace(/^元/, '零元'); + // 返回结果 + return v; +} + +/** + * 手机号码 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 手机号码正确 + */ +export function verifyPhone(val) { + // false: 手机号码不正确 + if (!/^((12[0-9])|(13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0|1,5-9]))\d{8}$/.test(val)) return false; + // true: 手机号码正确 + else return true; +} + +/** + * 国内电话号码 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 国内电话号码正确 + */ +export function verifyTelPhone(val) { + // false: 国内电话号码不正确 + if (!/\d{3}-\d{8}|\d{4}-\d{7}/.test(val)) return false; + // true: 国内电话号码正确 + else return true; +} + +/** + * 登录账号 (字母开头,允许5-16字节,允许字母数字下划线) + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 登录账号正确 + */ +export function verifyAccount(val) { + // false: 登录账号不正确 + if (!/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/.test(val)) return false; + // true: 登录账号正确 + else return true; +} + +/** + * 密码 (以字母开头,长度在6~16之间,只能包含字母、数字和下划线) + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 密码正确 + */ +export function verifyPassword(val) { + // false: 密码不正确 + if (!/^[a-zA-Z]\w{5,15}$/.test(val)) return false; + // true: 密码正确 + else return true; +} + +/** + * 强密码 (字母+数字+特殊字符,长度在6-16之间) + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 强密码正确 + */ +export function verifyPasswordPowerful(val) { + // false: 强密码不正确 + if (!/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(val)) + return false; + // true: 强密码正确 + else return true; +} + +/** + * 密码强度 + * @param {string} val 当前值字符串 + * @description 弱:纯数字,纯字母,纯特殊字符 + * @description 中:字母+数字,字母+特殊字符,数字+特殊字符 + * @description 强:字母+数字+特殊字符 + * @returns {string} 返回处理后的字符串:弱、中、强 + */ +export function verifyPasswordStrength(val) { + let v = ''; + // 弱:纯数字,纯字母,纯特殊字符 + if (/^(?:\d+|[a-zA-Z]+|[!@#$%^&\.*]+){6,16}$/.test(val)) v = '弱'; + // 中:字母+数字,字母+特殊字符,数字+特殊字符 + if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(val)) v = '中'; + // 强:字母+数字+特殊字符 + if (/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&\.*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&\.*]+$)(?![\d!@#$%^&\.*]+$)[a-zA-Z\d!@#$%^&\.*]{6,16}$/.test(val)) + v = '强'; + // 返回结果 + return v; +} + +/** + * IP地址 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: IP地址正确 + */ +export function verifyIPAddress(val) { + // false: IP地址不正确 + if ( + !/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/.test( + val + ) + ) + return false; + // true: IP地址正确 + else return true; +} + +/** + * 邮箱 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 邮箱正确 + */ +export function verifyEmail(val) { + // false: 邮箱不正确 + if ( + !/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( + val + ) + ) + return false; + // true: 邮箱正确 + else return true; +} + +/** + * 身份证 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 身份证正确 + */ +export function verifyIdCard(val) { + // false: 身份证不正确 + if (!/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(val)) return false; + // true: 身份证正确 + else return true; +} + +/** + * 姓名 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 姓名正确 + */ +export function verifyFullName(val) { + // false: 姓名不正确 + if (!/^[\u4e00-\u9fa5]{1,6}(·[\u4e00-\u9fa5]{1,6}){0,2}$/.test(val)) return false; + // true: 姓名正确 + else return true; +} + +/** + * 邮政编码 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: 邮政编码正确 + */ +export function verifyPostalCode(val) { + // false: 邮政编码不正确 + if (!/^[1-9][0-9]{5}$/.test(val)) return false; + // true: 邮政编码正确 + else return true; +} + +/** + * url 处理 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true: url 正确 + */ +export function verifyUrl(val) { + // false: url不正确 + if ( + !/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( + val + ) + ) + return false; + // true: url正确 + else return true; +} + +/** + * 车牌号 + * @param {string} val 当前值字符串 + * @returns {boolean} 返回 true:车牌号正确 + */ +export function verifyCarNum(val) { + // false: 车牌号不正确 + if ( + !/^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$/.test( + val + ) + ) + return false; + // true:车牌号正确 + else return true; +} diff --git a/Web/src/utils/waitUtils/countWait.js b/Web/src/utils/waitUtils/countWait.js new file mode 100644 index 0000000..387ad93 --- /dev/null +++ b/Web/src/utils/waitUtils/countWait.js @@ -0,0 +1,69 @@ +/** + * CountWaitManager 类用于管理等待状态 + */ +class CountWaitManager { + countFlag = 0; + key = ""; + oriWaitCount = 0; + constructor(key, waitCount) { + this.key = key; + this.oriWaitCount = waitCount; + } + + /** + * 重置等待标记 + */ + reset() { + this.countFlag = this.oriWaitCount; + } + + /** + * 获取等待id + * @returns string + */ + getKey() { + return this.key; + } + + /** + * 设置等待状态-1 + */ + set() { + this.countFlag--; + } + + /** + * 等待指定的所有组件挂载完成,或在超时后拒绝 + * @param timeout 超时时间(毫秒),默认5秒 + * @returns Promise,当所有组件挂载完成时resolve,超时则reject + */ + wait(timeout = 5000) { + if(this.countFlag < 1){ + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + const deadline = Date.now() + timeout; + + const check = () => { + if (Date.now() >= deadline) { + reject(new Error("组件挂载超时")); + return; + } + + // 检查所有指定的keys是否都已挂载 + const allMounted = this.countFlag < 1; + + if (allMounted) { + resolve(); + } else { + setTimeout(check, 100); + } + }; + + check(); + }); + } +} + +export default CountWaitManager; diff --git a/Web/src/utils/waitUtils/simpleWait.js b/Web/src/utils/waitUtils/simpleWait.js new file mode 100644 index 0000000..32503bf --- /dev/null +++ b/Web/src/utils/waitUtils/simpleWait.js @@ -0,0 +1,63 @@ +/** + * SimpleWaitManager 类用于管理等待状态 + */ +class SimpleWaitManager { + waitFlag = false; + key = ""; + constructor(key) { + this.key = key; + } + /** + * 重置等待标记 + */ + reset() { + this.waitFlag = false; + } + + /** + * 设置等待标志为完成 + */ + set() { + this.waitFlag = true; + } + /** + * 获取等待id + * @returns string + */ + getKey() { + return this.key; + } + + /** + * 等待 + * @param timeout 超时时间(毫秒),默认5秒 + * @returns Promise,等待完成时resolve,超时则reject + */ + wait(timeout = 5000) { + if (this.waitFlag === true) { + return Promise.resolve(); + } + return new Promise((resolve, reject) => { + const deadline = Date.now() + timeout; + + const check = () => { + if (Date.now() >= deadline) { + reject(new Error("等待超时")); + return; + } + + const allMounted = this.waitFlag === true; + + if (allMounted) { + resolve(); + } else { + setTimeout(check, 100); + } + }; + + check(); + }); + } +} + +export default SimpleWaitManager; diff --git a/Web/src/utils/waitUtils/waitable.js b/Web/src/utils/waitUtils/waitable.js new file mode 100644 index 0000000..0c358e6 --- /dev/null +++ b/Web/src/utils/waitUtils/waitable.js @@ -0,0 +1,46 @@ +import SimpleWaitManager from "./simpleWait"; +import CountWaitManager from "./countWait"; + + +/** + * 等待waitObjs中的所有等待任务完成 + * @param {(SimpleWaitManager|CountWaitManager)[]} waitObjs + * */ +export function waitAll(waitObjs) { + return new Promise((resolve, reject) => { + Promise.all(waitObjs.map((obj) => obj.wait())) + .then(() => { + resolve(); + }) + .catch((err) => { + console.error(err); + reject(err); + }); + }); +} + +/** + * 获取新的计数等待实例。 + * @param {number} waitCount 等待次数 + * @returns CountWaitManager + */ +export function getCountWait(waitCount) { + let key = generateSimpleUniqueId(); + const waitObj = new CountWaitManager(key, waitCount); + waitObj.reset(); + return waitObj; +} + +/** + * 获取新的简单等待实例。 + * @returns SimpleWaitManager 实例 + */ +export function getSimpleWait() { + let key = generateSimpleUniqueId(); + const waitObj = new SimpleWaitManager(key); + return waitObj; +} + +function generateSimpleUniqueId() { + return Date.now().toString(36) + Math.random().toString(36).substring(2); +} diff --git a/Web/src/views/404.vue b/Web/src/views/404.vue new file mode 100644 index 0000000..cf99829 --- /dev/null +++ b/Web/src/views/404.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/Web/src/views/500.vue b/Web/src/views/500.vue new file mode 100644 index 0000000..4df6736 --- /dev/null +++ b/Web/src/views/500.vue @@ -0,0 +1,716 @@ + + + + + \ No newline at end of file diff --git a/Web/src/views/dashboard/index.vue b/Web/src/views/dashboard/index.vue new file mode 100644 index 0000000..bf7d3a7 --- /dev/null +++ b/Web/src/views/dashboard/index.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/Web/src/views/system/autoJob/components/deferredJobDialog.vue b/Web/src/views/system/autoJob/components/deferredJobDialog.vue new file mode 100644 index 0000000..478b870 --- /dev/null +++ b/Web/src/views/system/autoJob/components/deferredJobDialog.vue @@ -0,0 +1,74 @@ + + \ No newline at end of file diff --git a/Web/src/views/system/autoJob/index.vue b/Web/src/views/system/autoJob/index.vue new file mode 100644 index 0000000..4c1cb1a --- /dev/null +++ b/Web/src/views/system/autoJob/index.vue @@ -0,0 +1,137 @@ + + + + + \ No newline at end of file diff --git a/Web/src/views/system/components/dictSelect.vue b/Web/src/views/system/components/dictSelect.vue new file mode 100644 index 0000000..5b61326 --- /dev/null +++ b/Web/src/views/system/components/dictSelect.vue @@ -0,0 +1,29 @@ + + diff --git a/Web/src/views/system/components/enumSelect.vue b/Web/src/views/system/components/enumSelect.vue new file mode 100644 index 0000000..ac7550e --- /dev/null +++ b/Web/src/views/system/components/enumSelect.vue @@ -0,0 +1,29 @@ + + diff --git a/Web/src/views/system/components/orgCascader.vue b/Web/src/views/system/components/orgCascader.vue new file mode 100644 index 0000000..2ddd3d6 --- /dev/null +++ b/Web/src/views/system/components/orgCascader.vue @@ -0,0 +1,89 @@ + + diff --git a/Web/src/views/system/components/orgTree.vue b/Web/src/views/system/components/orgTree.vue new file mode 100644 index 0000000..f217c78 --- /dev/null +++ b/Web/src/views/system/components/orgTree.vue @@ -0,0 +1,68 @@ + + diff --git a/Web/src/views/system/components/positionSelect.vue b/Web/src/views/system/components/positionSelect.vue new file mode 100644 index 0000000..e25d091 --- /dev/null +++ b/Web/src/views/system/components/positionSelect.vue @@ -0,0 +1,26 @@ + + diff --git a/Web/src/views/system/components/userSelect.vue b/Web/src/views/system/components/userSelect.vue new file mode 100644 index 0000000..e7b734e --- /dev/null +++ b/Web/src/views/system/components/userSelect.vue @@ -0,0 +1,65 @@ + + diff --git a/Web/src/views/system/components/userSelectDialog.vue b/Web/src/views/system/components/userSelectDialog.vue new file mode 100644 index 0000000..ea3f298 --- /dev/null +++ b/Web/src/views/system/components/userSelectDialog.vue @@ -0,0 +1,129 @@ + + diff --git a/Web/src/views/system/dataDict/components/dictDetailDialog.vue b/Web/src/views/system/dataDict/components/dictDetailDialog.vue new file mode 100644 index 0000000..10642b4 --- /dev/null +++ b/Web/src/views/system/dataDict/components/dictDetailDialog.vue @@ -0,0 +1,135 @@ + + diff --git a/Web/src/views/system/dataDict/components/editDialog.vue b/Web/src/views/system/dataDict/components/editDialog.vue new file mode 100644 index 0000000..ccc4e4d --- /dev/null +++ b/Web/src/views/system/dataDict/components/editDialog.vue @@ -0,0 +1,141 @@ + + diff --git a/Web/src/views/system/dataDict/components/editDictDetailDialog.vue b/Web/src/views/system/dataDict/components/editDictDetailDialog.vue new file mode 100644 index 0000000..3998052 --- /dev/null +++ b/Web/src/views/system/dataDict/components/editDictDetailDialog.vue @@ -0,0 +1,151 @@ + + diff --git a/Web/src/views/system/dataDict/index.vue b/Web/src/views/system/dataDict/index.vue new file mode 100644 index 0000000..13a371c --- /dev/null +++ b/Web/src/views/system/dataDict/index.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/Web/src/views/system/log/logDiffIndex.vue b/Web/src/views/system/log/logDiffIndex.vue new file mode 100644 index 0000000..ff3905d --- /dev/null +++ b/Web/src/views/system/log/logDiffIndex.vue @@ -0,0 +1,88 @@ + + \ No newline at end of file diff --git a/Web/src/views/system/log/logEventIndex.vue b/Web/src/views/system/log/logEventIndex.vue new file mode 100644 index 0000000..9e4440f --- /dev/null +++ b/Web/src/views/system/log/logEventIndex.vue @@ -0,0 +1,89 @@ + + \ No newline at end of file diff --git a/Web/src/views/system/log/logExceptionIndex.vue b/Web/src/views/system/log/logExceptionIndex.vue new file mode 100644 index 0000000..5fb9786 --- /dev/null +++ b/Web/src/views/system/log/logExceptionIndex.vue @@ -0,0 +1,106 @@ + + \ No newline at end of file diff --git a/Web/src/views/system/log/logJobIndex.vue b/Web/src/views/system/log/logJobIndex.vue new file mode 100644 index 0000000..3011d8c --- /dev/null +++ b/Web/src/views/system/log/logJobIndex.vue @@ -0,0 +1,89 @@ + + \ No newline at end of file diff --git a/Web/src/views/system/log/logLoginIndex.vue b/Web/src/views/system/log/logLoginIndex.vue new file mode 100644 index 0000000..3f89cf5 --- /dev/null +++ b/Web/src/views/system/log/logLoginIndex.vue @@ -0,0 +1,89 @@ + + \ No newline at end of file diff --git a/Web/src/views/system/log/logOperateIndex.vue b/Web/src/views/system/log/logOperateIndex.vue new file mode 100644 index 0000000..798a78d --- /dev/null +++ b/Web/src/views/system/log/logOperateIndex.vue @@ -0,0 +1,103 @@ + + \ No newline at end of file diff --git a/Web/src/views/system/login/components/tenantDialog.vue b/Web/src/views/system/login/components/tenantDialog.vue new file mode 100644 index 0000000..b943b80 --- /dev/null +++ b/Web/src/views/system/login/components/tenantDialog.vue @@ -0,0 +1,93 @@ + + + diff --git a/Web/src/views/system/login/index.vue b/Web/src/views/system/login/index.vue new file mode 100644 index 0000000..068cc0f --- /dev/null +++ b/Web/src/views/system/login/index.vue @@ -0,0 +1,308 @@ + + + + + + + diff --git a/Web/src/views/system/menu/components/editDialog.vue b/Web/src/views/system/menu/components/editDialog.vue new file mode 100644 index 0000000..1f73b58 --- /dev/null +++ b/Web/src/views/system/menu/components/editDialog.vue @@ -0,0 +1,350 @@ + + + + + diff --git a/Web/src/views/system/menu/components/elIconList.vue b/Web/src/views/system/menu/components/elIconList.vue new file mode 100644 index 0000000..1087c3b --- /dev/null +++ b/Web/src/views/system/menu/components/elIconList.vue @@ -0,0 +1,40 @@ + + + diff --git a/Web/src/views/system/menu/components/faIconList.vue b/Web/src/views/system/menu/components/faIconList.vue new file mode 100644 index 0000000..8b364bd --- /dev/null +++ b/Web/src/views/system/menu/components/faIconList.vue @@ -0,0 +1,825 @@ + + + + + \ No newline at end of file diff --git a/Web/src/views/system/menu/index.vue b/Web/src/views/system/menu/index.vue new file mode 100644 index 0000000..ce73329 --- /dev/null +++ b/Web/src/views/system/menu/index.vue @@ -0,0 +1,107 @@ + + + diff --git a/Web/src/views/system/message/components/editDialog.vue b/Web/src/views/system/message/components/editDialog.vue new file mode 100644 index 0000000..cfc8db5 --- /dev/null +++ b/Web/src/views/system/message/components/editDialog.vue @@ -0,0 +1,240 @@ + + diff --git a/Web/src/views/system/message/components/publishDialog.vue b/Web/src/views/system/message/components/publishDialog.vue new file mode 100644 index 0000000..841bfca --- /dev/null +++ b/Web/src/views/system/message/components/publishDialog.vue @@ -0,0 +1,196 @@ + + diff --git a/Web/src/views/system/message/components/viewDialog.vue b/Web/src/views/system/message/components/viewDialog.vue new file mode 100644 index 0000000..54c0daa --- /dev/null +++ b/Web/src/views/system/message/components/viewDialog.vue @@ -0,0 +1,82 @@ + + diff --git a/Web/src/views/system/message/publishIndex.vue b/Web/src/views/system/message/publishIndex.vue new file mode 100644 index 0000000..9bac363 --- /dev/null +++ b/Web/src/views/system/message/publishIndex.vue @@ -0,0 +1,180 @@ + + diff --git a/Web/src/views/system/message/receiveIndex.vue b/Web/src/views/system/message/receiveIndex.vue new file mode 100644 index 0000000..04cace2 --- /dev/null +++ b/Web/src/views/system/message/receiveIndex.vue @@ -0,0 +1,114 @@ + + diff --git a/Web/src/views/system/org/components/editDialog.vue b/Web/src/views/system/org/components/editDialog.vue new file mode 100644 index 0000000..7906c8c --- /dev/null +++ b/Web/src/views/system/org/components/editDialog.vue @@ -0,0 +1,193 @@ + + diff --git a/Web/src/views/system/org/index.vue b/Web/src/views/system/org/index.vue new file mode 100644 index 0000000..34a500e --- /dev/null +++ b/Web/src/views/system/org/index.vue @@ -0,0 +1,92 @@ + + + + \ No newline at end of file diff --git a/Web/src/views/system/personalCenter/index.vue b/Web/src/views/system/personalCenter/index.vue new file mode 100644 index 0000000..f6bbd96 --- /dev/null +++ b/Web/src/views/system/personalCenter/index.vue @@ -0,0 +1,263 @@ + + diff --git a/Web/src/views/system/position/components/editDialog.vue b/Web/src/views/system/position/components/editDialog.vue new file mode 100644 index 0000000..1594807 --- /dev/null +++ b/Web/src/views/system/position/components/editDialog.vue @@ -0,0 +1,141 @@ + + + diff --git a/Web/src/views/system/position/index.vue b/Web/src/views/system/position/index.vue new file mode 100644 index 0000000..9095ab5 --- /dev/null +++ b/Web/src/views/system/position/index.vue @@ -0,0 +1,117 @@ + + diff --git a/Web/src/views/system/redirect/index.vue b/Web/src/views/system/redirect/index.vue new file mode 100644 index 0000000..ee92551 --- /dev/null +++ b/Web/src/views/system/redirect/index.vue @@ -0,0 +1,14 @@ + diff --git a/Web/src/views/system/role/components/editDataTypeDialog.vue b/Web/src/views/system/role/components/editDataTypeDialog.vue new file mode 100644 index 0000000..8bd86eb --- /dev/null +++ b/Web/src/views/system/role/components/editDataTypeDialog.vue @@ -0,0 +1,113 @@ + + diff --git a/Web/src/views/system/role/components/editDialog.vue b/Web/src/views/system/role/components/editDialog.vue new file mode 100644 index 0000000..c94e7ff --- /dev/null +++ b/Web/src/views/system/role/components/editDialog.vue @@ -0,0 +1,207 @@ + + + + diff --git a/Web/src/views/system/role/index.vue b/Web/src/views/system/role/index.vue new file mode 100644 index 0000000..e847d06 --- /dev/null +++ b/Web/src/views/system/role/index.vue @@ -0,0 +1,134 @@ + + diff --git a/Web/src/views/system/tenant/components/editDialog.vue b/Web/src/views/system/tenant/components/editDialog.vue new file mode 100644 index 0000000..fabcc92 --- /dev/null +++ b/Web/src/views/system/tenant/components/editDialog.vue @@ -0,0 +1,140 @@ + + diff --git a/Web/src/views/system/tenant/index.vue b/Web/src/views/system/tenant/index.vue new file mode 100644 index 0000000..23eed5b --- /dev/null +++ b/Web/src/views/system/tenant/index.vue @@ -0,0 +1,166 @@ + + diff --git a/Web/src/views/system/user/components/editDialog.vue b/Web/src/views/system/user/components/editDialog.vue new file mode 100644 index 0000000..4db78bb --- /dev/null +++ b/Web/src/views/system/user/components/editDialog.vue @@ -0,0 +1,232 @@ + + diff --git a/Web/src/views/system/user/index.vue b/Web/src/views/system/user/index.vue new file mode 100644 index 0000000..8fbee33 --- /dev/null +++ b/Web/src/views/system/user/index.vue @@ -0,0 +1,218 @@ + + + diff --git a/Web/vite.config.js b/Web/vite.config.js new file mode 100644 index 0000000..905875e --- /dev/null +++ b/Web/vite.config.js @@ -0,0 +1,49 @@ +'use strict' +import { defineConfig, loadEnv } from 'vite' +import vue from '@vitejs/plugin-vue' +import VueDevTools from 'vite-plugin-vue-devtools' +import path from 'path' + +const pathResolve = (dir) => { + // eslint-disable-next-line no-undef + return path.resolve(__dirname, dir) +} + +export default ({ mode }) => { + // const env = loadEnv(mode, process.cwd()) // 获取.env文件里定义的环境变量 + // console.log(env); //变量在命令行里打印出来 + return defineConfig({ + plugins: [vue(), VueDevTools()], + server: { + host: '127.0.0.1', + port: 7005, + hmr: true, + proxy: { + // 跨域设置,在后端已经设置 + // '/api': { + // target: env.VITE_API_BASE_URL, + // changeOrigin: true, + // rewrite: (path) => { + // console.log(path) + // return path + // }, + // } + } + }, + resolve: { + alias: { + '@': pathResolve('src') + } + }, + css: { + preprocessorOptions: { + scss: { + api: 'modern-compiler', // 或 "modern","legacy" + importers: [ + // ... + ], + }, + }, + }, + }) +}