From e5e181488d6c55b9af5456de5d0a60f5a47b8e57 Mon Sep 17 00:00:00 2001 From: faker <1784913417@qq.com> Date: Mon, 8 May 2023 16:02:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 25 + .gitattributes | 63 + .gitignore | 316 +++ Dockerfile | 30 + LICENSE | 21 + Znyc.Cloudcar.Admin.AspNetCore/AspNetCore.xml | 804 ++++++ .../Common/CorsMiddleware.cs | 49 + .../Common/ErrCode.cs | 115 + .../Common/Initialization.cs | 25 + .../Common/MyApiException.cs | 93 + .../Common/Permission.cs | 64 + .../Common/SessionObject.cs | 20 + .../Mvc/ApiController.cs | 253 ++ .../Mvc/AreaApiController.cs | 373 +++ .../Mvc/Filter/ActionFilter.cs | 149 ++ .../Mvc/Filter/ExceptionHandlingAttribute.cs | 102 + .../Mvc/Filter/FunctionAuthorizationFilter.cs | 74 + .../Mvc/Filter/FunctionAuthorizeAttribute.cs | 26 + .../Mvc/Filter/HiddenApiAttribute.cs | 49 + .../Filter/NoPermissionRequiredAttribute.cs | 18 + .../Mvc/Filter/SwaggerFileUploadFilter.cs | 55 + .../Mvc/TokenProvider.cs | 220 ++ .../PublishProfiles/FolderProfile.pubxml | 16 + .../ViewModel/DBConnResult.cs | 24 + .../ViewModel/DbConnInfo.cs | 48 + .../ViewModel/SearchModel.cs | 34 + .../ViewModel/UpdateEnableViewModel.cs | 22 + .../ViewModel/VueCascaderModel.cs | 27 + .../ViewModel/VuexMenusTree.cs | 90 + .../Znyc.Cloudcar.Admin.AspNetCore.csproj | 73 + .../AppDbContextFactoryAttribute.cs | 23 + .../Attributes/ShardingTableAttribute.cs | 39 + .../Attributes/UnitOfWorkAttribute.cs | 12 + .../Cache/CacheHelper.cs | 406 +++ .../Cache/CacheProvider.cs | 23 + .../Cache/ICacheService.cs | 305 +++ .../Cache/MemoryCacheService.cs | 594 +++++ .../Cache/RedisCacheService.cs | 634 +++++ Znyc.Cloudcar.Admin.Commons/Commons.csproj | 235 ++ Znyc.Cloudcar.Admin.Commons/Config/Configs.cs | 49 + .../Const/CommonConst.cs | 79 + .../Const/CurrencyConst.cs | 90 + .../Const/ReturnConst.cs | 115 + Znyc.Cloudcar.Admin.Commons/Core/App/App.cs | 289 +++ .../Core/App/HostingStartup.cs | 32 + .../Core/App/HttpContextLocal.cs | 69 + .../Core/Application/BaseApp.cs | 461 ++++ .../Core/Dapper/DapperDbContext.cs | 128 + .../Core/DataManager/AppDBContextAttribute.cs | 24 + .../Core/DataManager/DBServerProvider.cs | 230 ++ .../Core/DataManager/DbConnectionOptions.cs | 42 + .../Core/DataManager/WriteAndReadEnum.cs | 23 + .../Core/DataManager/YuebonDbOptions.cs | 18 + .../Core/DataManager/YuebonDbOptionsSetup.cs | 64 + .../Core/DbContextCore/BaseDbContext.cs | 796 ++++++ .../Core/DbContextCore/DbContextFactory.cs | 101 + .../Core/DbContextCore/DefaultModelBuilder.cs | 17 + .../Core/DbContextCore/MySqlDbContext.cs | 124 + .../Core/DbContextCore/OracleDbContext.cs | 69 + .../Core/DbContextCore/PostgreSQLDbContext.cs | 80 + .../Core/DbContextCore/SQLiteDbContext.cs | 62 + .../Core/DbContextCore/SqlServerDbContext.cs | 225 ++ .../Core/Dtos/DeletesInputDto.cs | 16 + .../Core/Dtos/IInputDto.cs | 14 + .../Core/Dtos/IOutputDto.cs | 9 + .../Core/Dtos/InputDtoValidateExtensions.cs | 80 + .../Core/Dtos/SearchInputDto.cs | 39 + .../Core/IDbContext/IDbContextCore.cs | 491 ++++ .../Core/IDbContext/IDbContextFactory.cs | 24 + .../Core/IDbContext/IMySqlDbContext.cs | 6 + .../Core/IDbContext/IOracleDbContext.cs | 6 + .../Core/IDbContext/IPostgreSQLDbContext.cs | 6 + .../Core/IDbContext/ISQLiteDbContext.cs | 6 + .../Core/IDbContext/ISqlServerDbContext.cs | 6 + .../Core/IRepositories/IReadOnlyRepository.cs | 14 + .../Core/IRepositories/IRepository.cs | 833 ++++++ .../Core/IServices/IService.cs | 629 +++++ .../Core/Models/BaseEntity.cs | 55 + .../Core/Models/BaseViewModel.cs | 12 + .../Core/Models/Entity.cs | 9 + .../Core/Models/IBaseEntity.cs | 14 + .../Core/Models/ICreationAudited.cs | 20 + .../Core/Models/IDataAuthEnabled.cs | 18 + .../Core/Models/IDeleteAudited.cs | 13 + .../Core/Models/IEntity.cs | 9 + .../Core/Models/IEntityHash.cs | 10 + .../Core/Models/IExpirable.cs | 20 + .../Core/Models/IModificationAudited.cs | 20 + .../Core/Models/IMustHaveTenant.cs | 13 + .../Core/Module/AutoMapperService.cs | 22 + .../Core/Module/MoudleService.cs | 88 + .../Core/Repositories/BaseRepository.cs | 2255 +++++++++++++++++ .../Core/Services/BaseService.cs | 1006 ++++++++ Znyc.Cloudcar.Admin.Commons/Cos/CosOptions.cs | 22 + Znyc.Cloudcar.Admin.Commons/Data/Check.cs | 251 ++ .../Data/MicroDataTable.cs | 95 + .../Data/MicroDataTableHelper.cs | 52 + .../DependencyInjection/IPrivateDependency.cs | 9 + .../DependencyInjection/IScopedDependency.cs | 9 + .../ISingletonDependency.cs | 9 + .../ITransientDependency.cs | 9 + .../Encrypt/Base64Util.cs | 318 +++ .../Encrypt/Cryptography.cs | 59 + .../Encrypt/DEncrypt.cs | 164 ++ .../Encrypt/EncodeHelper.cs | 650 +++++ .../Encrypt/EncryptHelper.cs | 91 + .../Encrypt/MD5Util.cs | 184 ++ .../Encrypt/QQEncryptUtil.cs | 51 + .../Encrypt/RSASecurityHelper.cs | 273 ++ .../Encrypt/RSAUtils.cs | 66 + .../Enums/ActivityStatusEnum.cs | 26 + .../Enums/BannerTypeEnum.cs | 25 + .../Enums/CallFeedbackStatusEnum.cs | 30 + .../Enums/CommonStatus.cs | 30 + .../Enums/CurrencyEnum.cs | 168 ++ .../Enums/DatabaseType.cs | 43 + .../Enums/DictionaryCodeEnum.cs | 17 + .../Enums/EquipmentState.cs | 47 + .../Enums/HandleStatusEnum.cs | 24 + .../Enums/JobAction.cs | 19 + .../Enums/JobRunResult.cs | 17 + .../Enums/LinqExpressionType.cs | 15 + Znyc.Cloudcar.Admin.Commons/Enums/MsgType.cs | 23 + .../Enums/PlatformTypeEnum.cs | 25 + .../Enums/ProductStatusEnum.cs | 41 + .../Enums/ProductTypeEnum.cs | 20 + .../Enums/QueryOrderBy.cs | 8 + .../Enums/UserCertificationEnum.cs | 30 + Znyc.Cloudcar.Admin.Commons/Enums/UserType.cs | 23 + Znyc.Cloudcar.Admin.Commons/Extend/ExtDate.cs | 281 ++ .../Extend/ExtIEnumerable.cs | 45 + Znyc.Cloudcar.Admin.Commons/Extend/ExtInt.cs | 33 + .../Extend/ExtQueryable.cs | 46 + .../Extend/ExtString.cs | 566 +++++ Znyc.Cloudcar.Admin.Commons/Extend/Extlong.cs | 38 + Znyc.Cloudcar.Admin.Commons/Extend/Reflect.cs | 76 + .../Extensions/ApiDescriptionExtension.cs | 32 + .../AppServiceCollectionExtensions.cs | 605 +++++ .../Extensions/CollectionExtensions.cs | 78 + .../Extensions/DateTimeExtensions.cs | 308 +++ .../EntityFrameworkCoreExtensions.cs | 246 ++ .../Extensions/EnumExtensions.cs | 120 + .../Extensions/ExpressionExtensions.cs | 293 +++ .../Extensions/HttpContextExtentions.cs | 20 + .../Extensions/ObjectExtension.cs | 1508 +++++++++++ .../Extensions/ParameterCheckExtensions.cs | 216 ++ .../Extensions/SessionExtensions.cs | 43 + .../Extensions/SqlMapperExtensions.Async.cs | 789 ++++++ .../Extensions/SqlMapperExtensions.cs | 1266 +++++++++ .../Extensions/TypeExtensions.cs | 424 ++++ .../Extensions/YuebonClaimTypes.cs | 59 + .../Helpers/AppVersionHelper.cs | 28 + .../Helpers/BooleanJsonConverter.cs | 37 + .../Helpers/ByteConvertHelper.cs | 45 + .../Helpers/ConvertHelper.cs | 868 +++++++ .../Helpers/CookiesHelper.cs | 129 + .../Helpers/DatetimeJsonConverter.cs | 74 + .../Helpers/DecimalJsonConverter.cs | 38 + .../Helpers/EmojiFilterHelper.cs | 76 + .../Helpers/EntityMapper.cs | 194 ++ .../Helpers/FileHelper.cs | 250 ++ .../Helpers/FileQuartz.cs | 133 + .../Helpers/GuidUtils.cs | 99 + .../Helpers/HttpContextHelper.cs | 27 + .../Helpers/HttpRequestHelper.cs | 220 ++ .../Helpers/ImgHelper.cs | 158 ++ .../Helpers/IntJsonConverter.cs | 38 + .../Helpers/NPOIHelper.cs | 628 +++++ .../Helpers/ObjectReplaceHtmlHelper.cs | 61 + .../Helpers/RuntimeHelper.cs | 137 + .../Helpers/SessionHelper.cs | 46 + .../Helpers/SignHelper.cs | 193 ++ .../Helpers/StringHelper.cs | 166 ++ .../Helpers/UpperFirstCaseNamingPolicy.cs | 20 + .../Helpers/XmlConverter.cs | 59 + .../IoC/IoCContainer.cs | 23 + .../Json/JsonHelper.cs | 136 + .../Linq/EnumerableExtentions.cs | 65 + Znyc.Cloudcar.Admin.Commons/Log/DbLogType.cs | 65 + .../Log/Log4netHelper.cs | 209 ++ .../Mapping/MapperExtensions.cs | 93 + .../Net/IIPAddressParser.cs | 19 + .../Net/IPAddressRange.cs | 143 ++ .../Net/IpAddressUtil.cs | 164 ++ .../Net/RemoteIpParser.cs | 34 + .../Net/ReversProxyIpParser.cs | 27 + Znyc.Cloudcar.Admin.Commons/Net/TencentIp.cs | 97 + .../Options/AllowCacheApp.cs | 53 + .../Options/AppSetting.cs | 316 +++ .../Options/AssembleTypeConsts.cs | 23 + .../Options/CodeGenerateOption.cs | 58 + .../Options/DbContextOption.cs | 30 + .../Options/JwtOption.cs | 33 + .../Options/UIConstants.cs | 74 + Znyc.Cloudcar.Admin.Commons/Page/PageIfno.cs | 99 + .../Page/PageResult.cs | 68 + .../Page/PagerHelper.cs | 390 +++ .../PublishProfiles/FolderProfile.pubxml | 14 + .../Properties/Resources.Designer.cs | 378 +++ .../Properties/Resources.resx | 226 ++ .../Result/ResultOutPut.cs | 134 + .../Result/TokenResult.cs | 31 + Znyc.Cloudcar.Admin.Commons/Tree/JsTree.cs | 39 + .../Tree/JsTreeModel.cs | 37 + .../Tree/TreeSelect.cs | 56 + .../Tree/TreeSelectModel.cs | 27 + Znyc.Cloudcar.Admin.Commons/Tree/TreeView.cs | 60 + .../Tree/TreeViewModel.cs | 114 + .../Tree/VueRouterModel.cs | 95 + .../Znyc.Cloudcar.Admin.Commons.csproj | 174 ++ .../HangfireDispose.cs | 43 + .../TaskJobs/AutoActivityJob.cs | 24 + .../TaskJobs/AutoBannerJob.cs | 24 + .../TaskJobs/AutoStatisticalJob.cs | 24 + .../Znyc.Cloudcar.Admin.Hangfire.csproj | 19 + .../Collection/GpsRealTime.cs | 66 + .../IRepositorys/IGpsRealTimeRepository.cs | 15 + Znyc.Cloudcar.Admin.MongoDb/MongoContext.cs | 22 + .../Repositorys/GpsRealTimeRepository.cs | 35 + .../Znyc.Cloudcar.Admin.MongoDb.Core.csproj | 10 + .../Application/AreaApp.cs | 279 ++ .../Application/MenuApp.cs | 441 ++++ .../Application/UploadFileApp.cs | 217 ++ .../Application/UserApp.cs | 127 + .../Dtos/Activity/ActivityAddInput.cs | 45 + .../Dtos/Activity/ActivityOutputDto.cs | 57 + .../Dtos/Activity/ActivityUpdateInput.cs | 15 + .../Dtos/Activity/SearchActivityModel.cs | 26 + .../Dtos/AdminCurrentUser.cs | 158 ++ .../Dtos/AdminUser/AdminUserInputDto.cs | 70 + .../Dtos/AdminUser/AdminUserOutputDto.cs | 83 + .../Dtos/Api/ApiInputDto.cs | 16 + .../Dtos/Api/ApiOutputDto.cs | 16 + .../Dtos/App/AppInputDto.cs | 60 + .../Dtos/App/AppOutputDto.cs | 120 + .../Dtos/ApplyJob/ApplyJobInputDto.cs | 136 + .../Dtos/ApplyJob/ApplyJobOutputDto.cs | 188 ++ .../Dtos/Area/AreaInputDto.cs | 70 + .../Dtos/Area/AreaOutputDto.cs | 112 + .../Dtos/Area/AreaPickerOutputDto.cs | 26 + .../Dtos/Area/AreaSelect2OutDto.cs | 21 + .../Dtos/Audit/AuditInputDto.cs | 39 + .../Dtos/Audit/AuditOutputDto.cs | 42 + .../Dtos/Banner/BannerInput.cs | 75 + .../Dtos/Banner/BannerOutputDto.cs | 58 + .../Dtos/Banner/BannerUpdateInput.cs | 13 + .../Dtos/Banner/SearchBannerModel.cs | 13 + .../Dtos/CallFeedback/CallFeedbackInput.cs | 23 + .../CallFeedback/CallFeedbackOutputDto.cs | 49 + .../CallFeedback/SearchCallFeedbackModel.cs | 18 + .../Dtos/Certification/CertificationOutput.cs | 41 + .../Dtos/Currency/CurrencyInput.cs | 22 + .../Dtos/Currency/CurrencyOutputDto.cs | 22 + .../CurrencyRecord/CurrencyRecordInput.cs | 22 + .../CurrencyRecord/CurrencyRecordOutputDto.cs | 73 + .../SearchCurrencyRecordModel.cs | 34 + .../Dtos/DashboardOutModel.cs | 146 ++ .../Dtos/Dictionary/DictionaryInputDto.cs | 55 + .../Dtos/Dictionary/DictionaryListOutput.cs | 29 + .../Dtos/Dictionary/DictionaryOutputDto.cs | 57 + .../Dtos/Document/ImageOutput.cs | 24 + .../Dtos/Equipment/EquipmentAddInput.cs | 120 + .../Dtos/Equipment/EquipmentOutputDto.cs | 212 ++ .../Dtos/Equipment/EquipmentUpdateInput.cs | 120 + .../Dtos/Equipment/SearchEquipmentModel.cs | 26 + .../ExceptionsLogs/ExceptionsLogsInPutDto.cs | 60 + .../ExceptionsLogs/ExceptionsLogsOutputDto.cs | 56 + .../Dtos/Feedback/FeedbackInput.cs | 10 + .../Dtos/Feedback/FeedbackOutputDto.cs | 50 + .../Dtos/Feedback/FeedbackPicOutput.cs | 23 + .../Dtos/Feedback/SearchFeedbackModel.cs | 23 + .../Function/FunctionTreeTableOutputDto.cs | 159 ++ .../Dtos/Function/ModuleFunctionOutputDto.cs | 42 + .../Dtos/IndustryJobs/IndustryJobsInputDto.cs | 36 + .../IndustryJobs/IndustryJobsOutputDto.cs | 60 + .../IndustryJobs/IndustryJobsTreeTableDto.cs | 39 + .../Dtos/LoginLogs/LoginLogsInPutDto.cs | 114 + .../Dtos/LoginLogs/LoginLogsOutputDto.cs | 56 + .../Dtos/LoginLogs/SearchLoginLogsModel.cs | 26 + .../Dtos/Menu/MenuInputDto.cs | 131 + .../Dtos/Menu/MenuOutputDto.cs | 176 ++ .../Dtos/Menu/MenuTreeTableOutputDto.cs | 171 ++ .../Dtos/Message/MessageInputDto.cs | 48 + .../Dtos/Message/MessageLogsInputDto.cs | 32 + .../Dtos/Message/MessageLogsOutputDto.cs | 26 + .../Dtos/Message/MessageOutputDto.cs | 46 + .../OperationLogs/OperationLogsInPutDto.cs | 70 + .../OperationLogs/OperationLogsOutputDto.cs | 114 + .../OperationLogs/SearchOperationLogsModel.cs | 21 + .../Dtos/Order/OrderOutput.cs | 107 + .../Dtos/OrderDetail/OrderDetailOutput.cs | 35 + .../Dtos/Organize/OrganizeInputDto.cs | 65 + .../Dtos/Organize/OrganizeOutputDto.cs | 82 + .../Dtos/PaymentRecord/PaymentRecordInput.cs | 25 + .../PaymentRecord/PaymentRecordOutputDto.cs | 57 + .../PaymentRecord/SearchPaymentRecordModel.cs | 28 + .../Dtos/Recharge/RechargeAddInput.cs | 17 + .../Dtos/Recharge/RechargeOutputDto.cs | 32 + .../Dtos/Recharge/RechargeUpdateInput.cs | 10 + .../Dtos/Recharge/SearchRechargeModel.cs | 26 + .../RechargeIntro/RechargeIntroAddInput.cs | 25 + .../RechargeIntro/RechargeIntroOutputDto.cs | 30 + .../Dtos/Recruitment/RecruitmentInputDto.cs | 114 + .../Dtos/Recruitment/RecruitmentOutputDto.cs | 185 ++ .../Recruitment/SearchRecruitmentModel.cs | 41 + .../Dtos/Region/RegionOutputDto.cs | 29 + .../Dtos/Role/RoleAuthorizeDataInputDto.cs | 31 + .../Dtos/Role/RoleAuthorizeInputDto.cs | 45 + .../Dtos/Role/RoleAuthorizeOutputDto.cs | 59 + .../Dtos/Role/RoleDataInputDto.cs | 40 + .../Dtos/Role/RoleDataOutputDto.cs | 40 + .../Dtos/Role/RoleInputDto.cs | 70 + .../Dtos/Role/RoleOutputDto.cs | 116 + .../Dtos/SecurityProfile.cs | 151 ++ .../Dtos/Statistical/StatisticalInputDto.cs | 61 + .../Statistical/StatisticalListOutputDto.cs | 61 + .../Dtos/Statistical/StatisticalOutputDto.cs | 88 + .../Dtos/SysSetting/SysSettingOutputDto.cs | 321 +++ .../Dtos/SystemType/SystemTypeInputDto.cs | 60 + .../Dtos/SystemType/SystemTypeOutputDto.cs | 100 + .../Dtos/UploadFile/UploadFileInputDto.cs | 80 + .../Dtos/UploadFile/UploadFileOutputDto.cs | 91 + .../UploadFile/UploadFileResultOuputDto.cs | 46 + .../Dtos/User/SearchUserModel.cs | 36 + .../Dtos/User/UserAllListFocusOutPutDto.cs | 227 ++ .../Dtos/User/UserExtendInputDto.cs | 104 + .../Dtos/User/UserExtendOutPutDto.cs | 171 ++ .../Dtos/User/UserFocusExtendOutPutDto.cs | 68 + .../Dtos/User/UserInPutDto.cs | 41 + .../Dtos/User/UserLogOnInputDto.cs | 109 + .../Dtos/User/UserLogOnOutputDto.cs | 120 + .../Dtos/User/UserOpenIdsInputDto.cs | 24 + .../Dtos/User/UserOpenIdsOutputDto.cs | 30 + .../Dtos/User/UserOutputDto.cs | 123 + .../Dtos/User/UserThemeInputDto.cs | 36 + .../Dtos/User/UserWithAccessedCtrls.cs | 33 + .../Dtos/WxUnifyUser/WxUnifyUserAddInput.cs | 53 + .../Dtos/WxUnifyUser/WxUnifyUserOutputDto.cs | 55 + .../WxUserRelation/WxUserRelationOutputDto.cs | 12 + .../Entitys/APPEntity.cs | 45 + .../Entitys/ActivityEntity.cs | 73 + .../Entitys/AdminUserEntity.cs | 64 + .../Entitys/AdminUserLogOnEntity.cs | 59 + .../Entitys/ApiEntity.cs | 17 + .../Entitys/ApplyJobEntity.cs | 121 + .../Entitys/AreaEntity.cs | 67 + .../Entitys/AuditEntity.cs | 50 + .../Entitys/BannerEntity.cs | 69 + .../Entitys/CallFeedbackEntity.cs | 37 + .../Entitys/CertificationEntity.cs | 56 + .../Entitys/CurrencyEntity.cs | 32 + .../Entitys/CurrencyRecordEntity.cs | 37 + .../Entitys/DbLogsEntity.cs | 41 + .../Entitys/DictionaryEntity.cs | 49 + .../Entitys/EquipmentEntity.cs | 134 + .../Entitys/EquipmentPictureEntity.cs | 28 + .../Entitys/ExceptionsLogsEntity.cs | 65 + .../Entitys/FeedbackEntity.cs | 37 + .../Entitys/FeedbackPicEntity.cs | 35 + .../Entitys/IndustryJobsEntity.cs | 34 + .../Entitys/LogEntity.cs | 85 + .../Entitys/LoginLogsEntity.cs | 73 + .../Entitys/MenuEntity.cs | 110 + .../Entitys/MessageEntity.cs | 50 + .../Entitys/MessageLogsEntity.cs | 29 + .../Entitys/OperationLogsEntity.cs | 76 + .../Entitys/OrderDetailEntity.cs | 41 + .../Entitys/OrderEntity.cs | 116 + .../Entitys/OrganizeEntity.cs | 56 + .../Entitys/PaymentRecordEntity.cs | 54 + .../Entitys/RechargeEntity.cs | 22 + .../Entitys/RechargeIntroEntity.cs | 47 + .../Entitys/RecruitmentEntity.cs | 114 + .../Entitys/RegionEntity.cs | 32 + .../Entitys/RoleAuthorizeEntity.cs | 43 + .../Entitys/RoleDataEntity.cs | 27 + .../Entitys/RoleEntityEntity.cs | 47 + .../Entitys/StatisticalEntity.cs | 70 + .../Entitys/SysSettingEntity.cs | 13 + .../Entitys/SystemTypeEntity.cs | 44 + .../Entitys/UploadFileEntity.cs | 86 + .../Entitys/UserEntity.cs | 56 + .../Entitys/UserExtendEntity.cs | 126 + .../Entitys/UserFocusEntity.cs | 31 + .../Entitys/UserNameCardViewEntity.cs | 174 ++ .../Entitys/UserOpenIdsEntity.cs | 31 + .../Entitys/WxUnifyUserEntity.cs | 59 + .../Entitys/WxUserRelationEntity.cs | 35 + .../Recruitment/IAPPRepository.cs | 32 + .../Recruitment/IActivityRepository.cs | 12 + .../Recruitment/IAdminUserLogOnRepository.cs | 15 + .../Recruitment/IAdminUserRepository.cs | 108 + .../Recruitment/IApiRepository.cs | 9 + .../Recruitment/IApplyJobRepository.cs | 18 + .../Recruitment/IAreaRepository.cs | 9 + .../Recruitment/IAuditRepository.cs | 12 + .../Recruitment/IBannerRepository.cs | 12 + .../Recruitment/ICallFeedbackRepository.cs | 18 + .../Recruitment/ICertificationRepository.cs | 15 + .../Recruitment/ICurrencyRecordRepository.cs | 12 + .../Recruitment/ICurrencyRepository.cs | 12 + .../Recruitment/IDictionaryRepository.cs | 24 + .../IEquipmentPictureRepository.cs | 12 + .../Recruitment/IEquipmentRepository.cs | 12 + .../Recruitment/IExceptionsLogsRepository.cs | 9 + .../Recruitment/IFeedbackPicRepository.cs | 11 + .../Recruitment/IFeedbackRepository.cs | 11 + .../Recruitment/IIndustryJobsRepository.cs | 9 + .../Recruitment/ILoginLogsRepository.cs | 22 + .../Recruitment/IMenuRepository.cs | 25 + .../Recruitment/IMessageLogsRepository.cs | 11 + .../Recruitment/IMessageRepository.cs | 11 + .../Recruitment/IOperationLogsRepository.cs | 9 + .../Recruitment/IOrderDetailRepository.cs | 11 + .../Recruitment/IOrderRepository.cs | 11 + .../Recruitment/IOrganizeRepository.cs | 19 + .../Recruitment/IPaymentRecordRepository.cs | 12 + .../Recruitment/IRechargeIntroRepository.cs | 12 + .../Recruitment/IRechargeRepository.cs | 12 + .../Recruitment/IRecruitmentRepository.cs | 18 + .../Recruitment/IRegionRepository.cs | 23 + .../Recruitment/IRoleAuthorizeRepository.cs | 23 + .../Recruitment/IRoleDataRepository.cs | 16 + .../Recruitment/IRoleRepository.cs | 9 + .../Recruitment/IStatisticalRepository.cs | 13 + .../Recruitment/ISystemTypeRepository.cs | 15 + .../Recruitment/IUploadFileRepository.cs | 20 + .../Recruitment/IUserRepository.cs | 18 + .../Recruitment/IWxUnifyUserRepository.cs | 12 + .../Recruitment/IWxUserRelationRepository.cs | 12 + .../IServices/IAPPService.cs | 45 + .../IServices/IActivityService.cs | 43 + .../IServices/IAdminUserLogOnService.cs | 25 + .../IServices/IAdminUserService.cs | 109 + .../IServices/IApiService.cs | 12 + .../IServices/IApplyJobService.cs | 46 + .../IServices/IAreaService.cs | 28 + .../IServices/IAuditService.cs | 29 + .../IServices/IBannerService.cs | 43 + .../IServices/ICallFeedbackService.cs | 29 + .../IServices/ICertificationService.cs | 17 + .../IServices/ICurrencyRecordService.cs | 25 + .../IServices/ICurrencyService.cs | 41 + .../IServices/IDictionaryService.cs | 54 + .../IServices/IEquipmentService.cs | 35 + .../IServices/IExceptionsLogsService.cs | 40 + .../IServices/IFeedbackService.cs | 28 + .../IServices/IIndustryJobsService.cs | 36 + .../IServices/ILoginLogsService.cs | 42 + .../IServices/IMenuService.cs | 69 + .../IServices/IMessageLogsService.cs | 14 + .../IServices/IMessageService.cs | 12 + .../IServices/IOperationLogsService.cs | 42 + .../IServices/IOrderDetailService.cs | 12 + .../IServices/IOrderService.cs | 12 + .../IServices/IOrganizeService.cs | 46 + .../IServices/IPaymentRecordService.cs | 25 + .../IServices/IRechargeService.cs | 41 + .../IServices/IRecruitmentService.cs | 51 + .../IServices/IRegionService.cs | 17 + .../IServices/IRoleAuthorizeService.cs | 40 + .../IServices/IRoleDataService.cs | 17 + .../IServices/IRoleService.cs | 32 + .../IServices/IStatisticalService.cs | 24 + .../IServices/ISystemTypeService.cs | 27 + .../IServices/IUploadFileService.cs | 21 + .../IServices/IUserService.cs | 38 + .../IServices/IWxUserRelationService.cs | 21 + .../Repositories/Recruitment/APPRepository.cs | 59 + .../Recruitment/ActivityRepository.cs | 21 + .../Recruitment/AdminUserLogOnRepository.cs | 30 + .../Recruitment/AdminUserRepository.cs | 189 ++ .../Repositories/Recruitment/ApiRepository.cs | 18 + .../Recruitment/ApplyJobRepository.cs | 34 + .../Recruitment/AreaRepository.cs | 18 + .../Recruitment/AuditRepository.cs | 36 + .../Recruitment/BannerRepository.cs | 21 + .../Recruitment/CallFeedbackRepository.cs | 36 + .../Recruitment/CertificationRepository.cs | 32 + .../Recruitment/CurrencyRecordRepository.cs | 21 + .../Recruitment/CurrencyRepository.cs | 21 + .../Recruitment/DictionaryRepository.cs | 41 + .../Recruitment/EquipmentPictureRepository.cs | 21 + .../Recruitment/EquipmentRepository.cs | 21 + .../Recruitment/ExceptionsLogsRepository.cs | 26 + .../Recruitment/FeedbackPicRepository.cs | 22 + .../Recruitment/FeedbackRepository.cs | 22 + .../Recruitment/IndustryJobsRepository.cs | 18 + .../Recruitment/LoginLogsRepository.cs | 57 + .../Recruitment/MenuRepository.cs | 66 + .../Recruitment/MessageLogsRepository.cs | 21 + .../Recruitment/MessageRepository.cs | 40 + .../Recruitment/OperationLogsRepository.cs | 26 + .../Recruitment/OrderDetailRepository.cs | 22 + .../Recruitment/OrderRepository.cs | 22 + .../Recruitment/OrganizeRepository.cs | 43 + .../Recruitment/PaymentRecordRepository.cs | 21 + .../Recruitment/RechargeIntroRepository.cs | 21 + .../Recruitment/RechargeRepository.cs | 21 + .../Recruitment/RecruitmentRepository.cs | 34 + .../Recruitment/RegionRepository.cs | 68 + .../Recruitment/RoleAuthorizeRepository.cs | 98 + .../Recruitment/RoleDataRepository.cs | 50 + .../Recruitment/RoleRepository.cs | 18 + .../Recruitment/StatisticalRepository.cs | 34 + .../Recruitment/SystemTypeRepository.cs | 33 + .../Recruitment/UploadFileRepository.cs | 53 + .../Recruitment/UserRepository.cs | 87 + .../Recruitment/WxUnifyUserRepository.cs | 21 + .../Recruitment/WxUserRelationRepository.cs | 21 + .../Services/Recruitment/APPService.cs | 162 ++ .../Services/Recruitment/ActivityService.cs | 235 ++ .../Recruitment/AdminUserLogOnService.cs | 44 + .../Services/Recruitment/AdminUserService.cs | 285 +++ .../Services/Recruitment/ApiService.cs | 29 + .../Services/Recruitment/ApplyJobService.cs | 322 +++ .../Services/Recruitment/AreaService.cs | 129 + .../Services/Recruitment/AuditService.cs | 275 ++ .../Services/Recruitment/BannerService.cs | 179 ++ .../Recruitment/CallFeedbackService.cs | 110 + .../Recruitment/CertificationService.cs | 246 ++ .../Recruitment/CurrencyRecordService.cs | 99 + .../Services/Recruitment/CurrencyService.cs | 139 + .../Services/Recruitment/DictionaryService.cs | 145 ++ .../Services/Recruitment/EquipmentService.cs | 165 ++ .../Recruitment/ExceptionsLogsService.cs | 214 ++ .../Services/Recruitment/FeedbackService.cs | 107 + .../Recruitment/IndustryJobsService.cs | 148 ++ .../Services/Recruitment/LoginLogsService.cs | 225 ++ .../Services/Recruitment/MenuService.cs | 262 ++ .../Recruitment/MessageLogsService.cs | 109 + .../Services/Recruitment/MessageService.cs | 64 + .../Recruitment/OperationLogsService.cs | 228 ++ .../Recruitment/OrderDetailService.cs | 18 + .../Services/Recruitment/OrderService.cs | 18 + .../Services/Recruitment/OrganizeService.cs | 154 ++ .../Recruitment/PaymentRecordService.cs | 93 + .../Services/Recruitment/RechargeService.cs | 164 ++ .../Recruitment/RecruitmentService.cs | 282 +++ .../Services/Recruitment/RegionService.cs | 69 + .../Recruitment/RoleAuthorizeService.cs | 132 + .../Services/Recruitment/RoleDataService.cs | 29 + .../Services/Recruitment/RoleService.cs | 118 + .../Recruitment/StatisticalService.cs | 132 + .../Services/Recruitment/SystemTypeService.cs | 109 + .../Services/Recruitment/UploadFileService.cs | 69 + .../Services/Recruitment/UserService.cs | 173 ++ .../Recruitment/WxUserRelationService.cs | 53 + .../Yuebon.Security.Core.csproj | 92 + .../Znyc.Cloudcar.Admin.Security.Core.csproj | 81 + .../CommonService/Download/CodeRecord.cs | 15 + .../CommonService/Download/Config.cs | 21 + .../CommonService/Download/ConfigHelper.cs | 107 + .../CommonService/EventService.cs | 166 ++ .../CommonService/FixWeixinBugWeixinResult.cs | 139 + .../CommonService/LocationService.cs | 92 + .../Async/CustomMessageHandlerAsync_Events.cs | 29 + .../CustomMessageContext.cs | 52 + .../CustomMessageHandler.cs | 580 +++++ .../CustomMessageHandler_Events.cs | 584 +++++ .../OpenCheckMessageHandler.cs | 78 + .../CustomNetCoreWebSocketMessageHandler.cs | 77 + .../CustomWxOpenMessageContext.cs | 52 + .../CustomWxOpenMessageHandler.cs | 83 + .../OpenTicket/OpenTicketHelper.cs | 38 + .../WxApplet/WxAppletSubscribeMessage.cs | 132 + .../CommonService/TemplateMessage.cs | 77 + .../TemplateMessage/TemplateApi.cs | 132 + .../WeixinTemplate_ExceptionAlert.cs | 65 + .../WeixinTemplate_PaySuccess.cs | 29 + .../WeixinTemplate_Subscription.cs | 35 + .../WxOpenTemplateMessage_PaySuccessNotice.cs | 55 + .../CommonService/Utilities/Server.cs | 16 + .../Model/PostModel.cs | 31 + .../Model/WxMessage.cs | 14 + .../Model/WxUserInfo.cs | 73 + .../PublishProfiles/FolderProfile.pubxml | 13 + .../Wx/CommonHelper.cs | 313 +++ .../Wx/MessageHelper.cs | 101 + .../Yuebon.WeChat.Core.csproj | 49 + .../Znyc.Cloudcar.Admin.WeChat.Core.csproj | 38 + .../.config/dotnet-tools.json | 12 + .../Attributes/QuartzAttribute.cs | 48 + Znyc.Cloudcar.Admin.WebApi/Auth/ApiHandler.cs | 32 + .../Auth/IApiHandler.cs | 17 + .../Config/HangFireQueuesConfig.cs | 34 + .../Controllers/APPController.cs | 123 + .../Controllers/ActivityController.cs | 143 ++ .../Controllers/AdminUserController.cs | 407 +++ .../Controllers/ApplyJobController.cs | 191 ++ .../Controllers/AreaController.cs | 63 + .../Controllers/AuditController.cs | 129 + .../Controllers/BannerController.cs | 174 ++ .../Controllers/CallFeedbackController.cs | 108 + .../Controllers/CertificationController.cs | 146 ++ .../Controllers/CurrencyController.cs | 27 + .../Controllers/CurrencyRecordController.cs | 49 + .../Controllers/DictionaryController.cs | 373 +++ .../Controllers/EquipmentController.cs | 131 + .../Controllers/ExceptionsLogsController.cs | 81 + .../Controllers/FeedbackController.cs | 114 + .../Controllers/FilesController.cs | 297 +++ .../Controllers/FunctionController.cs | 81 + .../Controllers/IndustryJobsController.cs | 308 +++ .../Controllers/LoginController.cs | 293 +++ .../Controllers/LoginLogsController.cs | 80 + .../Controllers/MenuController.cs | 328 +++ .../Controllers/OperationLogsController.cs | 85 + .../Controllers/OrganizeController.cs | 279 ++ .../Controllers/PaymentRecordController.cs | 51 + .../Controllers/QuartzController.cs | 193 ++ .../Controllers/RechargeController.cs | 146 ++ .../Controllers/RecruitmentController.cs | 189 ++ .../Controllers/RegionController.cs | 83 + .../Controllers/RoleAuthorizeController.cs | 242 ++ .../Controllers/RoleController.cs | 202 ++ .../Controllers/RoleDataController.cs | 82 + .../Controllers/StatisticalController.cs | 157 ++ .../Controllers/SysSettingController.cs | 342 +++ .../Controllers/SystemTypeController.cs | 147 ++ .../Controllers/TokenController.cs | 205 ++ .../Controllers/UploadFileController.cs | 72 + .../Controllers/UserController.cs | 178 ++ .../Controllers/WeixinController.cs | 115 + Znyc.Cloudcar.Admin.WebApi/Dockerfile | 30 + Znyc.Cloudcar.Admin.WebApi/Program.cs | 51 + .../PublishProfiles/FolderProfile.pubxml | 20 + Znyc.Cloudcar.Admin.WebApi/Startup.cs | 579 +++++ .../Znyc.Cloudcar.Admin.WebApi.csproj | 71 + .../appsettings.Development.json | 128 + .../appsettings.Production.json | 119 + .../appsettings.Staging.json | 117 + Znyc.Cloudcar.Admin.WebApi/index.html | 87 + .../log4net.Production.config | 35 + Znyc.Cloudcar.Admin.WebApi/log4net.config | 35 + Znyc.Cloudcar.Admin.WebApi/logo.png | Bin 0 -> 9168 bytes .../wwwroot/favicon.ico | Bin 0 -> 1150 bytes .../xmlconfig/sys.config | 23 + Znyc.Cloudcar.AdminNetCore.sln | 67 + docker/Dockerfile | 11 + logo.png | Bin 0 -> 41421 bytes 641 files changed, 64357 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/AspNetCore.xml create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Common/CorsMiddleware.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Common/ErrCode.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Common/Initialization.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Common/MyApiException.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Common/Permission.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Common/SessionObject.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/ApiController.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/AreaApiController.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/ActionFilter.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/ExceptionHandlingAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/FunctionAuthorizationFilter.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/FunctionAuthorizeAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/HiddenApiAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/NoPermissionRequiredAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/SwaggerFileUploadFilter.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Mvc/TokenProvider.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/ViewModel/DBConnResult.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/ViewModel/DbConnInfo.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/ViewModel/SearchModel.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/ViewModel/UpdateEnableViewModel.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/ViewModel/VueCascaderModel.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/ViewModel/VuexMenusTree.cs create mode 100644 Znyc.Cloudcar.Admin.AspNetCore/Znyc.Cloudcar.Admin.AspNetCore.csproj create mode 100644 Znyc.Cloudcar.Admin.Commons/Attributes/AppDbContextFactoryAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Attributes/ShardingTableAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Attributes/UnitOfWorkAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Cache/CacheHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Cache/CacheProvider.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Cache/ICacheService.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Cache/MemoryCacheService.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Cache/RedisCacheService.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Commons.csproj create mode 100644 Znyc.Cloudcar.Admin.Commons/Config/Configs.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Const/CommonConst.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Const/CurrencyConst.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Const/ReturnConst.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/App/App.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/App/HostingStartup.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/App/HttpContextLocal.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Application/BaseApp.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Dapper/DapperDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DataManager/AppDBContextAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DataManager/DBServerProvider.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DataManager/DbConnectionOptions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DataManager/WriteAndReadEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DataManager/YuebonDbOptions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DataManager/YuebonDbOptionsSetup.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/BaseDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/DbContextFactory.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/DefaultModelBuilder.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/MySqlDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/OracleDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/PostgreSQLDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/SQLiteDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/SqlServerDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Dtos/DeletesInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Dtos/IInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Dtos/IOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Dtos/InputDtoValidateExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Dtos/SearchInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IDbContextCore.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IDbContextFactory.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IMySqlDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IOracleDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IPostgreSQLDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IDbContext/ISQLiteDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IDbContext/ISqlServerDbContext.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IRepositories/IReadOnlyRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IRepositories/IRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/IServices/IService.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/BaseEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/BaseViewModel.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/Entity.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/IBaseEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/ICreationAudited.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/IDataAuthEnabled.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/IDeleteAudited.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/IEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/IEntityHash.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/IExpirable.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/IModificationAudited.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Models/IMustHaveTenant.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Module/AutoMapperService.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Module/MoudleService.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Repositories/BaseRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Core/Services/BaseService.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Cos/CosOptions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Data/Check.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Data/MicroDataTable.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Data/MicroDataTableHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/DependencyInjection/IPrivateDependency.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/DependencyInjection/IScopedDependency.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/DependencyInjection/ISingletonDependency.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/DependencyInjection/ITransientDependency.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/Base64Util.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/Cryptography.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/DEncrypt.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/EncodeHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/EncryptHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/MD5Util.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/QQEncryptUtil.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/RSASecurityHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Encrypt/RSAUtils.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/ActivityStatusEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/BannerTypeEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/CallFeedbackStatusEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/CommonStatus.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/CurrencyEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/DatabaseType.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/DictionaryCodeEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/EquipmentState.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/HandleStatusEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/JobAction.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/JobRunResult.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/LinqExpressionType.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/MsgType.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/PlatformTypeEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/ProductStatusEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/ProductTypeEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/QueryOrderBy.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/UserCertificationEnum.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Enums/UserType.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extend/ExtDate.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extend/ExtIEnumerable.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extend/ExtInt.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extend/ExtQueryable.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extend/ExtString.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extend/Extlong.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extend/Reflect.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/ApiDescriptionExtension.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/AppServiceCollectionExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/CollectionExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/DateTimeExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/EntityFrameworkCoreExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/EnumExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/ExpressionExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/HttpContextExtentions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/ObjectExtension.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/ParameterCheckExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/SessionExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/SqlMapperExtensions.Async.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/SqlMapperExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/TypeExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Extensions/YuebonClaimTypes.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/AppVersionHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/BooleanJsonConverter.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/ByteConvertHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/ConvertHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/CookiesHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/DatetimeJsonConverter.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/DecimalJsonConverter.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/EmojiFilterHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/EntityMapper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/FileHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/FileQuartz.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/GuidUtils.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/HttpContextHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/HttpRequestHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/ImgHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/IntJsonConverter.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/NPOIHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/ObjectReplaceHtmlHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/RuntimeHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/SessionHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/SignHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/StringHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/UpperFirstCaseNamingPolicy.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Helpers/XmlConverter.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/IoC/IoCContainer.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Json/JsonHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Linq/EnumerableExtentions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Log/DbLogType.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Log/Log4netHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Mapping/MapperExtensions.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Net/IIPAddressParser.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Net/IPAddressRange.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Net/IpAddressUtil.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Net/RemoteIpParser.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Net/ReversProxyIpParser.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Net/TencentIp.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Options/AllowCacheApp.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Options/AppSetting.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Options/AssembleTypeConsts.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Options/CodeGenerateOption.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Options/DbContextOption.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Options/JwtOption.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Options/UIConstants.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Page/PageIfno.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Page/PageResult.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Page/PagerHelper.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Znyc.Cloudcar.Admin.Commons/Properties/Resources.Designer.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Properties/Resources.resx create mode 100644 Znyc.Cloudcar.Admin.Commons/Result/ResultOutPut.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Result/TokenResult.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Tree/JsTree.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Tree/JsTreeModel.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Tree/TreeSelect.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Tree/TreeSelectModel.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Tree/TreeView.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Tree/TreeViewModel.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Tree/VueRouterModel.cs create mode 100644 Znyc.Cloudcar.Admin.Commons/Znyc.Cloudcar.Admin.Commons.csproj create mode 100644 Znyc.Cloudcar.Admin.Hangfire/HangfireDispose.cs create mode 100644 Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoActivityJob.cs create mode 100644 Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoBannerJob.cs create mode 100644 Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoStatisticalJob.cs create mode 100644 Znyc.Cloudcar.Admin.Hangfire/Znyc.Cloudcar.Admin.Hangfire.csproj create mode 100644 Znyc.Cloudcar.Admin.MongoDb/Collection/GpsRealTime.cs create mode 100644 Znyc.Cloudcar.Admin.MongoDb/IRepositorys/IGpsRealTimeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.MongoDb/MongoContext.cs create mode 100644 Znyc.Cloudcar.Admin.MongoDb/Repositorys/GpsRealTimeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.MongoDb/Znyc.Cloudcar.Admin.MongoDb.Core.csproj create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Application/AreaApp.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Application/MenuApp.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Application/UploadFileApp.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Application/UserApp.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityAddInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityUpdateInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/SearchActivityModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminCurrentUser.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminUser/AdminUserInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminUser/AdminUserOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Api/ApiInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Api/ApiOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/App/AppInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/App/AppOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/ApplyJob/ApplyJobInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/ApplyJob/ApplyJobOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaPickerOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaSelect2OutDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Audit/AuditInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Audit/AuditOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerUpdateInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/SearchBannerModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/CallFeedbackInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/CallFeedbackOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/SearchCallFeedbackModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Certification/CertificationOutput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Currency/CurrencyInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Currency/CurrencyOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/CurrencyRecordInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/CurrencyRecordOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/SearchCurrencyRecordModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/DashboardOutModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryListOutput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Document/ImageOutput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentAddInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentUpdateInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/SearchEquipmentModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/ExceptionsLogs/ExceptionsLogsInPutDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/ExceptionsLogs/ExceptionsLogsOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackPicOutput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/SearchFeedbackModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Function/FunctionTreeTableOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Function/ModuleFunctionOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsTreeTableDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/LoginLogsInPutDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/LoginLogsOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/SearchLoginLogsModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuTreeTableOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageLogsInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageLogsOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/OperationLogsInPutDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/OperationLogsOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/SearchOperationLogsModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Order/OrderOutput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/OrderDetail/OrderDetailOutput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Organize/OrganizeInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Organize/OrganizeOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/PaymentRecordInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/PaymentRecordOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/SearchPaymentRecordModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeAddInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeUpdateInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/SearchRechargeModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/RechargeIntro/RechargeIntroAddInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/RechargeIntro/RechargeIntroOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/RecruitmentInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/RecruitmentOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/SearchRecruitmentModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Region/RegionOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeDataInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleDataInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleDataOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/SecurityProfile.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalListOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/SysSetting/SysSettingOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/SystemType/SystemTypeInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/SystemType/SystemTypeOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileResultOuputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/SearchUserModel.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserAllListFocusOutPutDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserExtendInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserExtendOutPutDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserFocusExtendOutPutDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserInPutDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserLogOnInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserLogOnOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOpenIdsInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOpenIdsOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserThemeInputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserWithAccessedCtrls.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUnifyUser/WxUnifyUserAddInput.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUnifyUser/WxUnifyUserOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUserRelation/WxUserRelationOutputDto.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/APPEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/ActivityEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/AdminUserEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/AdminUserLogOnEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/ApiEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/ApplyJobEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/AreaEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/AuditEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/BannerEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/CallFeedbackEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/CertificationEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/CurrencyEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/CurrencyRecordEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/DbLogsEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/DictionaryEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/EquipmentEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/EquipmentPictureEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/ExceptionsLogsEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/FeedbackEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/FeedbackPicEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/IndustryJobsEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/LogEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/LoginLogsEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/MenuEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/MessageEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/MessageLogsEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/OperationLogsEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/OrderDetailEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/OrderEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/OrganizeEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/PaymentRecordEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/RechargeEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/RechargeIntroEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/RecruitmentEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/RegionEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleAuthorizeEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleDataEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleEntityEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/StatisticalEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/SysSettingEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/SystemTypeEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/UploadFileEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/UserEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/UserExtendEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/UserFocusEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/UserNameCardViewEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/UserOpenIdsEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/WxUnifyUserEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Entitys/WxUserRelationEntity.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAPPRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IActivityRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAdminUserLogOnRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAdminUserRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IApiRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IApplyJobRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAreaRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAuditRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IBannerRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICallFeedbackRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICertificationRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICurrencyRecordRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICurrencyRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IDictionaryRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IEquipmentPictureRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IEquipmentRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IExceptionsLogsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IFeedbackPicRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IFeedbackRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IIndustryJobsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ILoginLogsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMenuRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMessageLogsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMessageRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOperationLogsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrderDetailRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrderRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrganizeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IPaymentRecordRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRechargeIntroRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRechargeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRecruitmentRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRegionRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleAuthorizeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleDataRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IStatisticalRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ISystemTypeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IUploadFileRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IUserRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IWxUnifyUserRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IWxUserRelationRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IAPPService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IActivityService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IAdminUserLogOnService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IAdminUserService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IApiService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IApplyJobService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IAreaService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IAuditService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IBannerService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/ICallFeedbackService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/ICertificationService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/ICurrencyRecordService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/ICurrencyService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IDictionaryService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IEquipmentService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IExceptionsLogsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IFeedbackService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IIndustryJobsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/ILoginLogsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IMenuService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IMessageLogsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IMessageService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IOperationLogsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IOrderDetailService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IOrderService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IOrganizeService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IPaymentRecordService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IRechargeService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IRecruitmentService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IRegionService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleAuthorizeService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleDataService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IStatisticalService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/ISystemTypeService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IUploadFileService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IUserService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/IServices/IWxUserRelationService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/APPRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ActivityRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AdminUserLogOnRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AdminUserRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ApiRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ApplyJobRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AreaRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AuditRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/BannerRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CallFeedbackRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CertificationRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CurrencyRecordRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CurrencyRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/DictionaryRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/EquipmentPictureRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/EquipmentRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ExceptionsLogsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/FeedbackPicRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/FeedbackRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/IndustryJobsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/LoginLogsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MenuRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MessageLogsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MessageRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OperationLogsRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrderDetailRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrderRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrganizeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/PaymentRecordRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RechargeIntroRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RechargeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RecruitmentRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RegionRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleAuthorizeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleDataRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/StatisticalRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/SystemTypeRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/UploadFileRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/UserRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/WxUnifyUserRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/WxUserRelationRepository.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/APPService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ActivityService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AdminUserLogOnService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AdminUserService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ApiService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ApplyJobService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AreaService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AuditService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/BannerService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CallFeedbackService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CertificationService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CurrencyRecordService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CurrencyService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/DictionaryService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/EquipmentService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ExceptionsLogsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/FeedbackService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/IndustryJobsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/LoginLogsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MenuService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MessageLogsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MessageService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OperationLogsService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrderDetailService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrderService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrganizeService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/PaymentRecordService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RechargeService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RecruitmentService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RegionService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleAuthorizeService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleDataService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/StatisticalService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/SystemTypeService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/UploadFileService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/UserService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/WxUserRelationService.cs create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Yuebon.Security.Core.csproj create mode 100644 Znyc.Cloudcar.Admin.Security.Core/Znyc.Cloudcar.Admin.Security.Core.csproj create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/CodeRecord.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/Config.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/ConfigHelper.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/EventService.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/FixWeixinBugWeixinResult.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/LocationService.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/Async/CustomMessageHandlerAsync_Events.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageContext.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler_Events.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/OpenMessageHandler/OpenCheckMessageHandler.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WebSocket/CustomNetCoreWebSocketMessageHandler.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WxOpenMessageHandler/CustomWxOpenMessageContext.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WxOpenMessageHandler/CustomWxOpenMessageHandler.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/OpenTicket/OpenTicketHelper.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/SubscribeMessage/WxApplet/WxAppletSubscribeMessage.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/TemplateApi.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_ExceptionAlert.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_PaySuccess.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_Subscription.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WxOpen/WxOpenTemplateMessage_PaySuccessNotice.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Utilities/Server.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/Model/PostModel.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/Model/WxMessage.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/Model/WxUserInfo.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/Wx/CommonHelper.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/Wx/MessageHelper.cs create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/Yuebon.WeChat.Core.csproj create mode 100644 Znyc.Cloudcar.Admin.WeChat.Core/Znyc.Cloudcar.Admin.WeChat.Core.csproj create mode 100644 Znyc.Cloudcar.Admin.WebApi/.config/dotnet-tools.json create mode 100644 Znyc.Cloudcar.Admin.WebApi/Attributes/QuartzAttribute.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Auth/ApiHandler.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Auth/IApiHandler.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Config/HangFireQueuesConfig.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/APPController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/ActivityController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/AdminUserController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/ApplyJobController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/AreaController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/AuditController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/BannerController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/CallFeedbackController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/CertificationController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/CurrencyController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/CurrencyRecordController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/DictionaryController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/EquipmentController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/ExceptionsLogsController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/FeedbackController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/FilesController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/FunctionController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/IndustryJobsController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/LoginController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/LoginLogsController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/MenuController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/OperationLogsController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/OrganizeController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/PaymentRecordController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/QuartzController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/RechargeController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/RecruitmentController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/RegionController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/RoleAuthorizeController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/RoleController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/RoleDataController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/StatisticalController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/SysSettingController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/SystemTypeController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/TokenController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/UploadFileController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/UserController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Controllers/WeixinController.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Dockerfile create mode 100644 Znyc.Cloudcar.Admin.WebApi/Program.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Properties/PublishProfiles/FolderProfile.pubxml create mode 100644 Znyc.Cloudcar.Admin.WebApi/Startup.cs create mode 100644 Znyc.Cloudcar.Admin.WebApi/Znyc.Cloudcar.Admin.WebApi.csproj create mode 100644 Znyc.Cloudcar.Admin.WebApi/appsettings.Development.json create mode 100644 Znyc.Cloudcar.Admin.WebApi/appsettings.Production.json create mode 100644 Znyc.Cloudcar.Admin.WebApi/appsettings.Staging.json create mode 100644 Znyc.Cloudcar.Admin.WebApi/index.html create mode 100644 Znyc.Cloudcar.Admin.WebApi/log4net.Production.config create mode 100644 Znyc.Cloudcar.Admin.WebApi/log4net.config create mode 100644 Znyc.Cloudcar.Admin.WebApi/logo.png create mode 100644 Znyc.Cloudcar.Admin.WebApi/wwwroot/favicon.ico create mode 100644 Znyc.Cloudcar.Admin.WebApi/xmlconfig/sys.config create mode 100644 Znyc.Cloudcar.AdminNetCore.sln create mode 100644 docker/Dockerfile create mode 100644 logo.png diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3729ff0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e62cc8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,316 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +bin/ +obj/ +logs/ +upload/ +*.[pdb] +**/bin/** +**/obj/** +.vs/* +**/wwwroot/Generatecode/** +**/wwwroot/upload/** + + + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]ogs/ +app_data/ +[Aa]pps/ +[Bb]in/ +[Oo]bj/ +app_data/ +[Aa]pps/ +**/[Bb]in/** +**/[Oo]bj/** +**.cache + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json +**.cache + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +# vue +.DS_Store +node_modules/ +dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +tests/**/coverage/ +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +.idea +.vscode +*.suo +*.ntvs* +*.njsproj + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc +*.dll +/Yuebon.Api/Yuebon.WebApi/wwwroot/upload +/Yuebon.Api/Yuebon.WebApi/upload/opp/20190912 +/Yuebon.Manager/Yuebon.WebApp/wwwroot/upload/cqinwn/opp/2019/11/18/2019111816150498189370_300x300.jpeg +/Yuebon.Manager/Yuebon.WebApp/wwwroot/upload/cqinwn/opp/2019/11/18/2019111816150498189370.jpeg +/Yuebon.Manager/Yuebon.WebApp/wwwroot/upload/cqinwn/opp/2019/11/18/2019111816130781914822_300x300.jpeg +/Yuebon.Manager/Yuebon.WebApp/wwwroot/upload/cqinwn/opp/2019/11/18/2019111816130781914822.jpeg +/Yuebon.Manager/Yuebon.WebApp/wwwroot/upload/cqinwn/opp/2019/11/18/2019111816104345142749_300x300.jpg +/Yuebon.Manager/Yuebon.WebApp/wwwroot/upload/cqinwn/opp/2019/11/18/2019111816104345142749.jpg +/Yuebon.Manager/Yuebon.WebApp/wwwroot/upload/cqinwn/opp/2019/11/18/2019111816092171662104_300x300.jpg +/Yuebon.Manager/Yuebon.WebApp/wwwroot/upload/cqinwn/opp/2019/11/18/2019111816092171662104.jpg +/Yuebon.NetCore/Yuebon.Commons/Core/DataManager/DbAppSettings.cs diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..11bbb18 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 8091 +EXPOSE 443 + +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["Znyc.Cloudcar.Admin.WebApi/Znyc.Cloudcar.Admin.WebApi.csproj", "Znyc.Cloudcar.Admin.WebApi/"] +COPY ["Znyc.Cloudcar.Admin.Security.Core/Znyc.Cloudcar.Admin.Security.Core.csproj", "Znyc.Cloudcar.Admin.Security.Core/"] +COPY ["Znyc.Cloudcar.Admin.Commons/Znyc.Cloudcar.Admin.Commons.csproj", "Znyc.Cloudcar.Admin.Commons/"] +COPY ["Znyc.Cloudcar.Admin.WeChat.Core/Znyc.Cloudcar.Admin.WeChat.Core.csproj", "Znyc.Cloudcar.Admin.WeChat.Core/"] +COPY ["Znyc.Cloudcar.Admin.MongoDb/Znyc.Cloudcar.Admin.MongoDb.Core.csproj", "Znyc.Cloudcar.Admin.MongoDb/"] +COPY ["Znyc.Cloudcar.Admin.AspNetCore/Znyc.Cloudcar.Admin.AspNetCore.csproj", "Znyc.Cloudcar.Admin.AspNetCore/"] +RUN dotnet restore "Znyc.Cloudcar.Admin.WebApi/Znyc.Cloudcar.Admin.WebApi.csproj" +COPY . . +WORKDIR "/src/Znyc.Cloudcar.Admin.WebApi" +RUN dotnet build "Znyc.Cloudcar.Admin.WebApi.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "Znyc.Cloudcar.Admin.WebApi.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Znyc.Cloudcar.Admin.WebApi.dll"] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..36b877e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 znyc_recruitment + +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/Znyc.Cloudcar.Admin.AspNetCore/AspNetCore.xml b/Znyc.Cloudcar.Admin.AspNetCore/AspNetCore.xml new file mode 100644 index 0000000..017b1d9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/AspNetCore.xml @@ -0,0 +1,804 @@ + + + + + Znyc.Cloudcar.Admin.AspNetCore + + + + + 错误代码描述 + + + + + 请求成功 + + + + + 请求成功代码0 + + + + + 请求失败 + + + + + 请求失败代码1 + + + + + 获取access_token时AppID或AppSecret错误。请开发者认真比对appid和AppSecret的正确性,或查看是否正在为恰当的应用调用接口 + + + + + 调用接口的服务器URL地址不正确,请联系供应商进行设置 + + + + + 请确保grant_type字段值为client_credential + + + + + 不合法的凭证类型 + + + + + 用户令牌accesstoken超时失效 + + + + + 您未被授权使用该功能,请重新登录试试或联系管理员进行处理 + + + + + 传递参数出现错误 + + + + + 更新数据失败 + + + + + 更新数据失败 + + + + + 物理删除数据失败 + + + + + 该用户不存在 + + + + + 该用户已存在 + + + + + 会员注册失败 + + + + + 查询数据不存在 + + + + + 自定义异常信息 + + + + + 异常消息 + + + + + 成功状态 + + + + + 提示代码 + + + + + 异常 + + + + + + + + + + + + + + + + + + + sso验证 + 其他站点通过后台Post来认证 + 或使用静态类Znyc.Cloudcar.Admin.Security.Application.SSO.AuthHelper访问 + + + + + 检验token是否有效 + + The token. + 请求Id备用参数. + + + + 根据token获取用户及用户可访问的所有资源 + + + 备用参数. + + + + 根据token获取用户名称 + + + 备用参数. + + + + 登录接口 + + 登录参数 + + + + + 注销登录 + + + 备用参数. + + + + 获取token + + + + + + 文件上传 + + + + + + + + + + 单文件上传接口 + + + 服务器存储的文件信息 + + + + 批量上传文件接口 + + + 服务器存储的文件信息 + + + + 批量上传文件 + + 文件 + 所属应用,如文章article + 所属应用ID,如文章id + + + + + 单个上传文件 + + + + + + + 实现文件上传到服务器保存,并生成缩略图 + + 文件名称 + 文件字节流 + + + + Identity控制器 + + + + + + + + + + 用户登录接口控制器 + + + + + 构造函数注入服务 + + + + + + 登录验证用户 + + 用户名 + 密码 + 返回Url + 返回用户User对象 + + + + Token令牌接口控制器 + + + + + + + + + + + 根据应用信息获得token令牌 + + 获取access_token填写client_credential + 用户唯一凭证,应用AppId + 应用密钥AppSecret + + + + + 验证token的合法性。 + + + + + + + 刷新token。 + + + + + + + 把object对象转换为ContentResult + + + + + + + WebApi控制器基类 + + + + + 当前登录的用户属性 + + + + + 把object对象转换为ContentResult + + + + + + + 验证token的合法性。如果不合法,返回MyApiException异常 + + + + + + 获取token + + + + + + 基本控制器,增删改查 + + 实体类型 + Service类型 + + + + 服务接口 + + + + + 构造方法 + + + + + + 在插入数据前对数据的修改操作 + + + + + + + 在更新数据前对数据的修改操作 + + + + + + + 在软删除数据前对数据的修改操作 + + + + + + + 异步新增数据 + + + + + + + 异步更新数据 + + + 主键Id + + + + + 物理删除 + + 主键Id + + + + 异步物理删除 + + 主键Id + + + + 软删除信息 + + 主键Id + 删除标识,默认为1:即设为删除,0:未删除 + + + + 异步软删除信息 + + 主键Id + 删除标识,默认为1:即设为删除,0:未删除 + + + + 设为数据有效性 + + 主键Id + 有效标识,默认为1:即设为无效,0:有效 + + + + 异步设为数据有效性 + + 主键Id + 有效标识,默认为1:即设为无效,0:有效 + + + + 根据主键Id获取一个对象信息 + + 主键Id + + + + + 根据条件查询数据库,并返回对象集合(用于分页数据显示) + + info + 指定对象的集合 + + + + 根据Request参数获取分页对象数据 + + + + + + 获取分页操作的查询条件 + + + + + + 表示一个特性,该特性用于全局捕获程序运行异常信息。 + + + + + + + + + + + + + + + + + + + + Swagger 上传文件过滤器 + + + + + 应用过滤器 + + + + + + + 隐藏接口,不生成到swagger文档展示 + + + + + 隐藏接口,不生成到swagger文档展示 + + + + + 实现Apply方法 + + + + + + + 功能权限授权验证 + + + + + + + + + + + + + + 权限 + + + + + 构造函数 + + + + + + Token令牌提供类 + + + + + 构造函数 + + + + + 构造函数,初花jwtmodel + + + + + + 直接通过appid和加密字符串获取访问令牌接口 + + 获取access_token填写client_credential + 用户唯一凭证 + 用户唯一凭证密钥,即appsecret + + + + + 检查用户的Token有效性 + + token令牌 + + + + + 根据用户获取token + + + + + + + 根据URL中的Token参数或Cookie获取token + + + + + + 检查用户登录状态 + + token + 备注信息 + + + + + 检查用户登录状态 + 通过URL中的Token参数或Cookie中的Token + + 备注信息 + + + + 获取当前登录的用户信息 + 通过URL中的Token参数或Cookie中的Token + + The remark. + LoginUserVM. + + + + 获取当前登录的用户名 + 通过URL中的Token参数或Cookie中的Token + + The remark. + System.String. + + + + 登录接口 + + 应用程序key. + 应用程序Secret. + 用户名 + 密码 + System.String. + + + + 注销 + + + + + 登录返回结果 + + + + + 跳转Url + + + + + token + + + + + 系统登录请求实体 + + + + + 账号 + + + + + 密码 + + + + + 系统编码 + + + + + 用户登录验证,主要用管理后台、H5和App应用用户登录 + + + + + + + 获取到的凭证值 + + + + + 获取到的凭证值 + + + + + 用户ID + + + + + 用户账号 + + + + + 用户名 + + + + + 昵称 + + + + + 头像 + + + + + 性别 + + + + + 头像 + + + + + 上级推广员 + + + + + 注册时间 + + + + + 角色编码,多个角色,使用“,”分格 + + + + + 其他对象 + + + + + 查询条件公共实体类 + + + + + 关键词 + + + + + 排序方式 默认asc + + + + + 排序字段 默认Id + + + + + 第几页 + + + + + 每页显示数量 + + + + + SessionObject是登录之后,给客户端传回的对象 + + + + + SessionKey + + + + + 当前登录的用户的信息 + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Common/CorsMiddleware.cs b/Znyc.Cloudcar.Admin.AspNetCore/Common/CorsMiddleware.cs new file mode 100644 index 0000000..dc3a8b7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Common/CorsMiddleware.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Common +{ + /// + /// 跨域中间件 + /// 解决net core 3.1 跨域 Cors 找不到 “Access-Control-Allow-Origin” + /// + public class CorsMiddleware + { + /// + /// + private readonly RequestDelegate _next; + + /// + /// + /// + public CorsMiddleware(RequestDelegate next) + { + _next = next; + } + + /// + /// + /// + /// + public async Task Invoke(HttpContext httpContext) + { + if (!httpContext.Response.Headers.ContainsKey("Access-Control-Allow-Origin")) + { + httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*"); + } + + await _next(httpContext); + } + } + + /// + /// + public static class CorsMiddlewareExtensions + { + public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Common/ErrCode.cs b/Znyc.Cloudcar.Admin.AspNetCore/Common/ErrCode.cs new file mode 100644 index 0000000..ee3cd1e --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Common/ErrCode.cs @@ -0,0 +1,115 @@ +namespace Znyc.Cloudcar.Admin.AspNetCore.Entitys +{ + /// + /// 错误代码描述 + /// + public static class ErrCode + { + /// + /// 请求成功 + /// + public static string err0 = "请求成功"; + + /// + /// 请求成功代码0 + /// + public static string successCode = "0"; + + /// + /// 请求失败 + /// + public static string err1 = "请求失败"; + + /// + /// 请求失败代码1 + /// + public static string failCode = "1"; + + /// + /// 获取access_token时AppID或AppSecret错误。请开发者认真比对appid和AppSecret的正确性,或查看是否正在为恰当的应用调用接口 + /// + public static string err40001 = + "获取access_token时AppID或AppSecret错误。请开发者认真比对appid和AppSecret的正确性,或查看是否正在为恰当的应用调用接口"; + + /// + /// 调用接口的服务器URL地址不正确,请联系供应商进行设置 + /// + public static string err40002 = "调用接口的服务器URL地址不正确,请联系供应商进行授权"; + + /// + /// 请确保grant_type字段值为client_credential + /// + public static string err40003 = "请确保grant_type字段值为client_credential"; + + /// + /// 不合法的凭证类型 + /// + public static string err40004 = "不合法的凭证类型"; + + /// + /// 用户令牌accesstoken超时失效 + /// + public static string err40005 = "用户令牌accesstoken超时失效"; + + /// + /// 您未被授权使用该功能,请重新登录试试或联系管理员进行处理 + /// + public static string err40006 = "您未被授权使用该功能,请重新登录试试或联系系统管理员进行处理"; + + /// + /// 传递参数出现错误 + /// + public static string err40007 = "传递参数出现错误"; + + /// + /// 用户未登录或超时 + /// + public static string err40008 = "用户未登录或超时"; + + /// + /// 程序异常 + /// + public static string err40110 = "程序异常"; + + /// + /// 新增数据失败 + /// + public static string err43001 = "新增数据失败"; + + /// + /// 更新数据失败 + /// + public static string err43002 = "更新数据失败"; + + /// + /// 物理删除数据失败 + /// + public static string err43003 = "删除数据失败"; + + /// + /// 该用户不存在 + /// + public static string err50001 = "该数据不存在"; + + /// + /// 该用户已存在 + /// + public static string err50002 = "用户已存在,请登录或重新注册!"; + + /// + /// 会员注册失败 + /// + public static string err50003 = "会员注册失败"; + + /// + /// 查询数据不存在 + /// + public static string err60001 = "查询数据不存在"; + + + + + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Common/Initialization.cs b/Znyc.Cloudcar.Admin.AspNetCore/Common/Initialization.cs new file mode 100644 index 0000000..687a932 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Common/Initialization.cs @@ -0,0 +1,25 @@ +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Common +{ + /// + /// 系统初始化内容 + /// + public abstract class Initialization + { + /// + /// 初始化 + /// + public virtual void Initial() + { + CacheHelper cacheHelper = new CacheHelper(); + SysSettingEntity sysSetting = XmlConverter.Deserialize("xmlconfig/sys.config"); + if (sysSetting != null) + { + cacheHelper.Add("SysSetting", sysSetting); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Common/MyApiException.cs b/Znyc.Cloudcar.Admin.AspNetCore/Common/MyApiException.cs new file mode 100644 index 0000000..12627c6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Common/MyApiException.cs @@ -0,0 +1,93 @@ +using System; +using System.Runtime.Serialization; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Common +{ + /// + /// 自定义异常信息 + /// + public class MyApiException : Exception + { + /// + /// 异常 + /// + /// + public MyApiException(string message) + { + Msg = message; + } + + /// + /// + /// + /// + public MyApiException(string message, string errcode) + { + Msg = message; + ErrCode = errcode; + } + + /// + /// + /// + /// + /// + public MyApiException(string message, bool success, string errcode) + { + Msg = message; + Success = success; + ErrCode = errcode; + } + + /// + /// + public MyApiException() + { + } + + /// + /// + /// + /// + protected MyApiException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + + /// + /// + /// + /// + public MyApiException(string message, Exception innerException) : base(message, innerException) + { + Msg = message; + throw innerException; + } + + /// + /// + /// + /// + /// + public MyApiException(string message, string errcode, Exception innerException) : base(message, innerException) + { + Msg = message; + ErrCode = errcode; + throw innerException; + } + + /// + /// 异常消息 + /// + public string Msg { get; set; } + + /// + /// 成功状态 + /// + public bool Success { get; set; } + + /// + /// 提示代码 + /// + public string ErrCode { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Common/Permission.cs b/Znyc.Cloudcar.Admin.AspNetCore/Common/Permission.cs new file mode 100644 index 0000000..91d893c --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Common/Permission.cs @@ -0,0 +1,64 @@ +using System; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Security.Dtos; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Common +{ + /// + /// 权限控制 + /// + public static class Permission + { + /// + /// 判断当前用户是否拥有某功能点的权限 + /// + /// 功能编码code + /// 用户id + /// + public static bool HasFunction(string functionCode, int userId) + { + bool hasFunction = false; + if (!string.IsNullOrEmpty(userId.ToString())) + { + if (string.IsNullOrEmpty(functionCode)) + { + hasFunction = true; + } + else + { + System.Collections.Generic.List listFunction = new CacheHelper().Get("User_Function_" + userId).ToJson() + .ToList(); + if (listFunction != null && listFunction.Count(t => t.EnCode == functionCode) > 0) + { + hasFunction = true; + } + } + } + + return hasFunction; + } + + /// + /// 判断是否为系统管理员或超级管理员 + /// + /// true:系统管理员或超级管理员,false:不是系统管理员或超级管理员 + /// + /// + public static bool IsAdmin(AdminCurrentUser AdminCurrentUser) + { + bool blnIsAdmin = false; + if (AdminCurrentUser != null) + { + if (AdminCurrentUser.Account == "admin" || + AdminCurrentUser.Role.Contains("administrators", StringComparison.Ordinal)) + { + return true; + } + } + + return blnIsAdmin; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Common/SessionObject.cs b/Znyc.Cloudcar.Admin.AspNetCore/Common/SessionObject.cs new file mode 100644 index 0000000..3f61b31 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Common/SessionObject.cs @@ -0,0 +1,20 @@ +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.WebApi.Common +{ + /// + /// SessionObject是登录之后,给客户端传回的对象 + /// + public class SessionObject + { + /// + /// SessionKey + /// + public string SessionKey { get; set; } + + /// + /// 当前登录的用户的信息 + /// + public AdminUserEntity LogonUser { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/ApiController.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/ApiController.cs new file mode 100644 index 0000000..f7aa7a4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/ApiController.cs @@ -0,0 +1,253 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Unicode; +using Znyc.Cloudcar.Admin.AspNetCore.Common; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Controllers +{ + /// + /// WebApi控制器基类 + /// + [ApiController] + [EnableCors("Cors")] + public class ApiController : Controller + { + /// + /// 当前登录的用户属性 + /// + public AdminCurrentUser CurrentUser; + + #region + + /// + /// 重写基类在Action执行之前的事情 + /// 根据token获得当前用户,允许匿名的不需要获取用户 + /// + /// 重写方法的参数 + public override void OnActionExecuting(ActionExecutingContext context) + { + try + { + ControllerActionDescriptor controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; + //匿名访问,不需要token认证、签名和登录 + Attribute allowanyone = + controllerActionDescriptor.MethodInfo.GetCustomAttribute(typeof(AllowAnonymousAttribute), true); + if (allowanyone != null) + { + return; + } + + CommonResult result = new CommonResult(); + //需要token认证 + string authHeader = context.HttpContext.Request.Headers["Authorization"]; //Header中的token + if (string.IsNullOrEmpty(authHeader)) + { + result.ErrCode = "40004"; + result.ErrMsg = ErrCode.err40004; + context.Result = ToJsonContent(result); + } + else + { + string token = string.Empty; + if (authHeader != null && authHeader.StartsWith("Bearer ", StringComparison.Ordinal)) + { + token = authHeader.Substring(7); + } + + TokenProvider tokenProvider = new TokenProvider(); + result = tokenProvider.ValidateToken(token); + //token验证失败 + if (!result.Success) + { + context.Result = ToJsonContent(result); + } + else + { + #region 是否需要验证用户登录以及相关的功能权限 + + //是否需要用户登录 + Attribute isDefined = + controllerActionDescriptor.MethodInfo.GetCustomAttribute( + typeof(NoPermissionRequiredAttribute)); + //不需要登录 + if (isDefined != null) + { + return; + } + //需要登录和验证功能权限 + if (result.ResData != null) + { + List claimlist = result.ResData as List; + string userId = claimlist[3].Value; + + Claim[] claims = + { + new(ZnycClaimTypes.UserId, userId), + new(ZnycClaimTypes.UserName, claimlist[2].Value), + new(ZnycClaimTypes.Role, claimlist[4].Value) + }; + ClaimsIdentity identity = new ClaimsIdentity(claims); + ClaimsPrincipal principal = new ClaimsPrincipal(identity); + context.HttpContext.User = principal; + CacheHelper yuebonCacheHelper = new CacheHelper(); + AdminCurrentUser user = yuebonCacheHelper.Get("login_user_" + userId); + if (user != null) + { + CurrentUser = user; + } + + bool isAdmin = Permission.IsAdmin(user); + if (!isAdmin) + { + IEnumerable authorizeAttributes = controllerActionDescriptor.MethodInfo + .GetCustomAttributes(typeof(FunctionAuthorizeAttribute), true) + .OfType(); + if (authorizeAttributes.FirstOrDefault() != null) + { + string function = authorizeAttributes.First().Function; + if (!string.IsNullOrEmpty(function)) + { + string functionCode = controllerActionDescriptor.ControllerName + "/" + function; + + bool bl = Permission.HasFunction(functionCode, userId.ToInt()); + if (!bl) + { + result.ErrCode = "40006"; + result.ErrMsg = ErrCode.err40006; + context.Result = ToJsonContent(result); + } + } + } + } + } + else + { + result.ErrCode = "40008"; + result.ErrMsg = ErrCode.err40008; + context.Result = ToJsonContent(result); + } + + #endregion 是否需要验证用户登录以及相关的功能权限 + } + } + } + catch (Exception ex) + { + Log4NetHelper.Error("", ex); + } + } + + #endregion + + /// + /// 把object对象转换为ContentResult + /// + /// + /// + [HttpPost] + [Route("api/ToJsonContent")] + protected IActionResult ToJsonContent(object obj) + { + return Content(obj.ToJson()); + } + + /// + /// 把object对象转换为ContentResult + /// + /// 转换对象 + /// 是否忽略空值 + /// + [HttpPost] + [Route("api/ToJsonContent")] + protected IActionResult ToJsonContent(object obj, bool isNull = false) + { + JsonSerializerOptions options = new JsonSerializerOptions + { + WriteIndented = true, //格式化json字符串 + AllowTrailingCommas = true, //可以结尾有逗号 + IgnoreNullValues = true, //可以有空值,转换json去除空值属性 + IgnoreReadOnlyProperties = true, //忽略只读属性 + PropertyNameCaseInsensitive = true, //忽略大小写 + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) + }; + options.Converters.Add(new DateTimeJsonConverter()); + return Content(JsonSerializer.Serialize(obj, options)); + } + + /// + /// 根据Request参数获取分页对象数据 + /// + /// + protected virtual PagerInfo GetPagerInfo() + { + int pageSize = Request.Query["length"].ToString() == null ? 1 : Request.Query["length"].ToString().ToInt(); + int pageIndex = 1; + string currentPage = Request.Query["CurrentPage"].ToString(); + if (string.IsNullOrWhiteSpace(currentPage)) + { + string start = Request.Query["start"].ToString(); + if (!string.IsNullOrWhiteSpace(start)) + { + pageIndex = start.ToInt() / pageSize + 1; + } + } + else + { + pageIndex = currentPage.ToInt(); + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = pageIndex, + PageSize = pageSize + }; + return pagerInfo; + } + + /// + /// 获取token + /// + /// + [HttpGet("GetToken")] + [HiddenApi] + public string GetToken() + { + string token = HttpContext.Request.Query["Token"]; + if (!string.IsNullOrEmpty(token)) + { + return token; + } + + string authHeader = HttpContext.Request.Headers["Authorization"]; //Header中的token + if (authHeader != null && authHeader.StartsWith("Bearer")) + { + token = authHeader.Substring("Bearer ".Length).Trim(); + return token; + } + + string cookie = HttpContext.Request.Cookies["Token"]; + return cookie == null ? string.Empty : cookie; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/AreaApiController.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/AreaApiController.cs new file mode 100644 index 0000000..808c816 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/AreaApiController.cs @@ -0,0 +1,373 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Controllers +{ + /// + /// 基本控制器,增删改查 + /// + /// 实体类型 + /// 数据输出实体类型 + /// 数据输入实体类型 + /// Service类型 + /// 主键数据类型 + [ApiController] + public abstract class AreaApiController : ApiController + where T : Entity + where TService : IService + where TODto : class + where TIDto : class + where TKey : IEquatable + { + #region 属性变量 + + /// + /// 服务接口 + /// + public TService _service; + + #endregion 属性变量 + + #region 构造函数及常用 + + /// + /// 构造方法 + /// + /// + public AreaApiController(TService service) + { + _service = service; + } + + #endregion 构造函数及常用 + + #region 查询单个实体 + + // /// + // /// 根据主键Id获取一个对象信息 + // /// + // /// 主键Id + // /// + // [HttpGet("GetById")] + //// [FunctionAuthorize("")] + // //[NoPermissionRequired] + // [AllowAnonymous] + // public virtual async Task> GetById(TKey id) + // { + // var result = new CommonResult(); + // var info = await _service.GetOutDtoAsync(id); + // if (info != null) + // { + // result.ErrCode = ErrCode.successCode; + // result.ResData = info; + // } + // else + // { + // result.ErrMsg = ErrCode.err50001; + // result.ErrCode = "50001"; + // } + + // return result; + // } + + #endregion 查询单个实体 + + //#region 返回集合的接口 + + ///// + ///// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + ///// + ///// 查询条件 + ///// 指定对象的集合 + //[HttpPost("FindWithPager")] + //[FunctionAuthorize("List")] + //public virtual CommonResult> FindWithPager(SearchInputDto search) + //{ + // var result = new CommonResult>(); + // result.ResData = _service.FindWithPager(search); + // result.ErrCode = ErrCode.successCode; + // return result; + //} + + ///// + ///// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + ///// + ///// + ///// + //[HttpPost("FindWithPagerAsync")] + //[FunctionAuthorize("List")] + //public virtual async Task>> FindWithPagerAsync(SearchInputDto search) + //{ + // var result = new CommonResult>(); + // result.ResData = await _service.FindWithPagerAsync(search); + // result.ErrCode = ErrCode.successCode; + // return result; + //} + + /// + /// 获取所有可用的 + /// + /// + //[HttpGet("GetAllEnable")] + //[FunctionAuthorize("List")] + //public virtual async Task>> GetAllEnable() + //{ + // var result = new CommonResult>(); + // var list = await _service.GetAllByIsNotDeleteAndEnabledMarkAsync(); + // var resultList = list.MapTo(); + // result.ResData = resultList; + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + + // return result; + //} + + #region 公共添加、修改、删除、软删除接口 + + /// + /// 在插入数据前对数据的修改操作 + /// + /// + /// + protected virtual void OnBeforeInsert(T info) + { + //留给子类对参数对象进行修改 + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected virtual void OnBeforeUpdate(T info) + { + //留给子类对参数对象进行修改 + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected virtual void OnBeforeSoftDelete(T info) + { + //留给子类对参数对象进行修改 + } + + ///// + ///// 异步新增数据,无效 + ///// + ///// + ///// + //[HttpPost("Insert")] + //[FunctionAuthorize("Add")] + //public virtual async Task InsertAsync(TIDto tinfo) + //{ + // var result = new CommonResult(); + // var info = tinfo.MapTo(); + // OnBeforeInsert(info); + // long ln = await _service.InsertAsync(info).ConfigureAwait(false); + // if (ln > 0) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrMsg = ErrCode.err43001; + // result.ErrCode = "43001"; + // } + + // return ToJsonContent(result); + //} + + ///// + ///// 异步更新数据,需要在业务模块控制器重写该方法,否则更新无效 + ///// + ///// + ///// + //[HttpPost("Update")] + //[FunctionAuthorize("Edit")] + //public virtual async Task UpdateAsync(TIDto inInfo) + //{ + // var result = new CommonResult(); + // return ToJsonContent(result); + //} + + ///// + ///// 物理删除 + ///// + ///// 主键Id + //[HttpDelete("Delete")] + //[FunctionAuthorize("Delete")] + //public virtual IActionResult Delete(TKey id) + //{ + // var result = new CommonResult(); + // var bl = _service.Delete(id); + // if (bl) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrMsg = ErrCode.err43003; + // result.ErrCode = "43003"; + // } + + // return ToJsonContent(result); + //} + + ///// + ///// 异步物理删除 + ///// + ///// 主键Id + //[HttpDelete("DeleteAsync")] + //[FunctionAuthorize("Delete")] + //public virtual async Task DeleteAsync(TKey id) + //{ + // var result = new CommonResult(); + // var bl = await _service.DeleteAsync(id).ConfigureAwait(false); + // if (bl) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrMsg = ErrCode.err43003; + // result.ErrCode = "43003"; + // } + + // return ToJsonContent(result); + //} + + ///// + ///// 异步批量物理删除 + ///// + ///// + //[HttpDelete("DeleteBatchAsync")] + //[FunctionAuthorize("Delete")] + //public virtual async Task DeleteBatchAsync(DeletesInputDto info) + //{ + // var result = new CommonResult(); + // var where = string.Empty; + // if (typeof(TKey) == typeof(string)) + // @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + // else if (typeof(TKey) == typeof(int)) @where = "id in (" + info.Ids.Join(",") + ")"; + // if (!string.IsNullOrEmpty(where)) + // { + // var bl = await _service.DeleteBatchWhereAsync(where).ConfigureAwait(false); + // if (bl) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrMsg = ErrCode.err43003; + // result.ErrCode = "43003"; + // } + // } + + // return ToJsonContent(result); + //} + + ///// + ///// 软删除信息 + ///// + ///// 主键Id + ///// 删除标识,默认为1:即设为删除,0:未删除 + //[HttpPost("DeleteSoft")] + //[FunctionAuthorize("DeleteSoft")] + //public virtual IActionResult DeleteSoft(TKey id, string bltag = "1") + //{ + // var result = new CommonResult(); + // var bl = false; + // if (bltag == "0") bl = true; + // var blResult = _service.DeleteSoft(bl, id, CurrentUser.UserId); + // if (blResult) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrMsg = ErrCode.err43002; + // result.ErrCode = "43002"; + // } + + // return ToJsonContent(result); + //} + + /// + /// 异步软删除信息 + /// + /// 主键Id + /// 删除标识,默认为1:即设为删除,0:未删除 + //[HttpDelete("DeleteSoftAsync")] + //[FunctionAuthorize("DeleteSoft")] + //public virtual async Task DeleteSoftAsync(TKey id, string bltag = "1") + //{ + // var result = new CommonResult(); + // var bl = false; + // if (bltag == "0") bl = true; + + // var blResult = await _service.DeleteSoftAsync(bl, id, CurrentUser.UserId); + // if (blResult) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrMsg = ErrCode.err43002; + // result.ErrCode = "43002"; + // } + + // return ToJsonContent(result); + //} + + ///// + ///// 异步批量软删除信息 + ///// + ///// + ///// + //[HttpDelete("DeleteSoftBatchAsync")] + //[FunctionAuthorize("DeleteSoft")] + //public virtual async Task DeleteSoftBatchAsync(UpdateEnableViewModel info) + //{ + // var result = new CommonResult(); + // var where = string.Empty; + // if (typeof(int) == typeof(string)) + // @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + // else if (typeof(int) == typeof(int)) @where = "id in (" + info.Ids.Join(",") + ")"; + + // if (!string.IsNullOrEmpty(where)) + // { + // var bl = false; + // if (info.Flag == "1") bl = true; + + // var blResult = await _service.DeleteSoftBatchAsync(bl, where, CurrentUser.UserId); + // if (blResult) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrMsg = ErrCode.err43002; + // result.ErrCode = "43002"; + // } + // } + + // return ToJsonContent(result); + //} + + #endregion 公共添加、修改、删除、软删除接口 + + // #endregion + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/ActionFilter.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/ActionFilter.cs new file mode 100644 index 0000000..0c05bcb --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/ActionFilter.cs @@ -0,0 +1,149 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Newtonsoft.Json; +using StackExchange.Profiling; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Core.App; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter +{ + /// + /// + public class ActionFilter : IAsyncActionFilter + { + private readonly IOperationLogsService _operationLogsService = App.GetService(); + + /// + /// + /// + /// + /// + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + MiniProfiler profiler = MiniProfiler.StartNew("StartNew"); + using (profiler.Step("Level1")) + { + // WriteLog(profiler); + + //执行Action + await next(); + } + // await WriteOperationLog(context, next); + + //WriteLog(profiler); + } + + public async Task WriteOperationLog(ActionExecutingContext context, ActionExecutionDelegate next) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + ActionExecutedContext actionExecutedContext = await next(); + sw.Stop(); + + //操作参数 + string args = JsonConvert.SerializeObject(context.ActionArguments); + //操作结果 + // var result = JsonConvert.SerializeObject(actionResult?.Value); + + try + { + OperationLogsEntity input = new OperationLogsEntity + { + UserName = new AdminCurrentUser().Name ?? "", + CreatedTime = DateTime.Now, + OperationTime = DateTime.Now, + CreatedUserId = new AdminCurrentUser().UserId, + RequestUrl = args, + OS = "PC", + IP = new AdminCurrentUser().CurrentLoginIP ?? "", + City = new AdminCurrentUser().IPAddressName ?? "", + CRUD = context.HttpContext.Request.Method.ToLower(), + Browser = "", + RequertData = "", + UserAgent = context.RouteData.Values["controller"].ToString() + // context.HttpContext.Request.Method.ToLower(), + // context.ActionDescriptor.AttributeRouteInfo.Template.ToLower(), + // sw.ElapsedMilliseconds + }; + + if (actionExecutedContext.Result is ObjectResult result && result.Value is CommonResult res) + { + input.RequertData = res.ErrCode; + } + //input.Msg = res.Success; + await _operationLogsService.InsertAsync(input); + } + catch (Exception) + { + // _logger.LogError("操作日志插入异常:{@ex}", ex); + } + } + + /// + /// sql跟踪 + /// 下载:MiniProfiler.AspNetCore + /// + /// + private void WriteLog(MiniProfiler profiler) + { + if (profiler?.Root != null) + { + Timing root = profiler.Root; + if (root.HasChildren) + { + GetSqlLog(root.Children); + } + } + } + + /// + /// 递归获取MiniProfiler内容 + /// + /// + private void GetSqlLog(List chil) + { + chil.ForEach(chill => + { + if (chill.CustomTimings?.Count > 0) + { + StringBuilder logSql = new StringBuilder(); + foreach (KeyValuePair> customTiming in chill.CustomTimings) + { + int i = 1; + customTiming.Value?.ForEach(value => + { + if (value.ExecuteType != "OpenAsync" && !value.CommandString.Contains("Connection")) + { + logSql.Append( + $"【{customTiming.Key}{i++}】{value.CommandString} 耗时 :{value.DurationMilliseconds} ms,状态 :{(value.Errored ? "失败" : "成功")}"); + } + }); + } + + Console.WriteLine($"sql+{logSql}"); + //var logEntity = new Log(); + //logEntity.Date = logEntity.CreatedTime = DateTime.Now; + //logEntity.Type = "SQL"; + //logEntity.Result = true; + //logEntity.Description = logSql.ToString(); + //_logService.Insert(logEntity); + } + else + { + if (chill.Children != null) + { + GetSqlLog(chill.Children); + } + } + }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/ExceptionHandlingAttribute.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/ExceptionHandlingAttribute.cs new file mode 100644 index 0000000..cc07bd2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/ExceptionHandlingAttribute.cs @@ -0,0 +1,102 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Unicode; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Common; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.Repositories; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter +{ + /// + /// 表示一个特性,该特性用于全局捕获程序运行异常信息。 + /// + public class ExceptionHandlingAttribute : ExceptionFilterAttribute + { + private readonly ExceptionsLogsRepository _exceptionsLogs = new(); + + /// + /// + /// + public override void OnException(ExceptionContext context) + { + Exception exception = context.Exception; + AdminCurrentUser CurrentUser = new AdminCurrentUser(); + string requestPath = context.HttpContext.Request.Path.ToString(); + string queryString = context.HttpContext.Request.QueryString.ToString(); + Type type = MethodBase.GetCurrentMethod().DeclaringType; + string exDesc = requestPath + queryString; + Log4NetHelper.Error(type, "全局捕获程序运行异常信息\n\r" + exDesc, context.Exception); + CommonResult result = new CommonResult(); + if (exception is MyApiException myApiex) + { + context.HttpContext.Response.StatusCode = 200; + context.ExceptionHandled = true; + result.ErrMsg = myApiex.Msg; + result.ErrCode = myApiex.ErrCode; + } + else + { + result.ErrMsg = "程序异常,服务端出现异常![异常消息]" + exception.Message; + result.ErrCode = "500"; + } + + JsonSerializerOptions options = new JsonSerializerOptions + { + WriteIndented = true, //格式化json字符串 + AllowTrailingCommas = true, //可以结尾有逗号 + //IgnoreNullValues = true, //可以有空值,转换json去除空值属性 + IgnoreReadOnlyProperties = true, //忽略只读属性 + PropertyNameCaseInsensitive = true, //忽略大小写 + //PropertyNamingPolicy = JsonNamingPolicy.CamelCase //命名方式是默认还是CamelCase + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) + }; + options.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); + context.Result = new JsonResult(result, options); + ExceptionsLogsEntity exceptionsLogs = new ExceptionsLogsEntity(); + IEnumerable identities = context.HttpContext.User.Identities; + ClaimsIdentity claimsIdentity = identities.First(); + if (claimsIdentity != null) + { + List claimlist = claimsIdentity.Claims as List; + if (claimlist.Count > 0) + { + string userId = claimlist[0].Value; + CacheHelper cacheHelper = new CacheHelper(); + AdminCurrentUser user = cacheHelper.Get("login_user_" + userId).ToJson().ToObject(); + if (user != null) + { + CurrentUser = user; + } + + exceptionsLogs.Id = YitIdHelper.NextId(); + exceptionsLogs.AppDomainName = requestPath; + exceptionsLogs.ErrorPage = queryString; + exceptionsLogs.UserName = CurrentUser.Name; + exceptionsLogs.IP = CurrentUser.CurrentLoginIP; + exceptionsLogs.ExceptionType = exception.GetType().Name; + exceptionsLogs.Message = exception.Message; + exceptionsLogs.StackTrace = exception.StackTrace; + exceptionsLogs.ExceptionTime = exceptionsLogs.CreatedTime = DateTime.Now; + exceptionsLogs.CreatedTime = DateTime.Now; + exceptionsLogs.CreatedUserId = CurrentUser.UserId; + exceptionsLogs.IsDeleted = false; + _exceptionsLogs.Insert(exceptionsLogs); + } + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/FunctionAuthorizationFilter.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/FunctionAuthorizationFilter.cs new file mode 100644 index 0000000..24afc5c --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/FunctionAuthorizationFilter.cs @@ -0,0 +1,74 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using System.Reflection; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Unicode; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Helpers; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Mvc +{ + /// + /// 功能权限授权验证 + /// + public class FunctionAuthorizationFilter : AuthorizeAttribute, IAuthorizationFilter + { + /// + /// 授权验证 + /// + /// + public void OnAuthorization(AuthorizationFilterContext context) + { + ControllerActionDescriptor controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; + //匿名访问,不需要token认证、签名和登录 + System.Attribute allowanyone = + controllerActionDescriptor.MethodInfo.GetCustomAttribute(typeof(AllowAnonymousAttribute), true); + if (allowanyone != null) + { + return; + } + + CommonResult result = new CommonResult(); + JsonSerializerOptions options = new JsonSerializerOptions + { + WriteIndented = true, //格式化json字符串 + AllowTrailingCommas = true, //可以结尾有逗号 + //IgnoreNullValues = true, //可以有空值,转换json去除空值属性 + IgnoreReadOnlyProperties = true, //忽略只读属性 + PropertyNameCaseInsensitive = true, //忽略大小写 + //PropertyNamingPolicy = JsonNamingPolicy.CamelCase //命名方式是默认还是CamelCase + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) + }; + options.Converters.Add(new DateTimeJsonConverter()); + + //需要token认证 + string authHeader = context.HttpContext.Request.Headers["Authorization"]; //Header中的token + if (string.IsNullOrEmpty(authHeader)) + { + result.ErrCode = "40004"; + result.ErrMsg = ErrCode.err40004; + context.Result = new JsonResult(result, options); + } + else + { + string token = string.Empty; + if (authHeader != null) + { + token = authHeader.Substring(7); + } + + TokenProvider tokenProvider = new TokenProvider(); + result = tokenProvider.ValidateToken(token); + //token验证失败 + if (!result.Success) + { + context.Result = new JsonResult(result, options); + } + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/FunctionAuthorizeAttribute.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/FunctionAuthorizeAttribute.cs new file mode 100644 index 0000000..b64fa15 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/FunctionAuthorizeAttribute.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Mvc.Filters; +using System; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Mvc +{ + /// + /// 功能权限属性配置 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class FunctionAuthorizeAttribute : ActionFilterAttribute + { + /// + /// 构造函数 + /// + /// 功能代码 + public FunctionAuthorizeAttribute(string function) + { + Function = function; + } + + /// + /// 功能权限 + /// + public string Function { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/HiddenApiAttribute.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/HiddenApiAttribute.cs new file mode 100644 index 0000000..1bac58f --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/HiddenApiAttribute.cs @@ -0,0 +1,49 @@ +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System; +using System.Linq; +using System.Reflection; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Mvc +{ + /// + /// 隐藏接口,不生成到swagger文档展示 + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] + public class HiddenApiAttribute : Attribute + { + } + + /// + /// 隐藏接口,不生成到swagger文档展示 + /// + public class HiddenApiFilter : IDocumentFilter + { + /// + /// 实现Apply方法 + /// + /// + /// + public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext documentFilterContext) + { + foreach (Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription apiDescription in documentFilterContext.ApiDescriptions) + { + if (apiDescription.TryGetMethodInfo(out MethodInfo methodInfo)) + { + if (methodInfo.GetCustomAttributes().OfType() + .Any()) + { + string key = "/" + apiDescription.RelativePath.TrimEnd('/'); + if (key.Contains("?")) + { + int idx = key.IndexOf("?", StringComparison.Ordinal); + key = key.Substring(0, idx); + } + + swaggerDoc.Paths.Remove(key); + } + } + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/NoPermissionRequiredAttribute.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/NoPermissionRequiredAttribute.cs new file mode 100644 index 0000000..f5d7b30 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/NoPermissionRequiredAttribute.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter +{ + /// + /// 不需要权限验证,不需要登录 + /// + public class NoPermissionRequiredAttribute : ActionFilterAttribute + { + /// + /// + /// + public override void OnActionExecuting(ActionExecutingContext filterContext) + { + base.OnActionExecuting(filterContext); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/SwaggerFileUploadFilter.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/SwaggerFileUploadFilter.cs new file mode 100644 index 0000000..0e0d5ad --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/Filter/SwaggerFileUploadFilter.cs @@ -0,0 +1,55 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System; +using System.Linq; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter +{ + /// + /// Swagger 上传文件过滤器 + /// + public class SwaggerFileUploadFilter : IOperationFilter + { + /// + /// 应用过滤器 + /// + /// + /// + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + { + #region 文件上传处理 + + if (!context.ApiDescription.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase) && + !context.ApiDescription.HttpMethod.Equals("PUT", StringComparison.OrdinalIgnoreCase)) + { + return; + } + + System.Collections.Generic.List fileParameters = context.ApiDescription.ActionDescriptor.Parameters + .Where(n => n.ParameterType == typeof(IFormFile)).ToList(); + if (fileParameters.Count < 0) + { + return; + } + + foreach (Microsoft.AspNetCore.Mvc.Abstractions.ParameterDescriptor fileParameter in fileParameters) + { + OpenApiParameter parameter = operation.Parameters.Single(n => n.Name == fileParameter.Name); + operation.Parameters.Remove(parameter); + operation.Parameters.Add(new OpenApiParameter + { + Name = parameter.Name, + In = ParameterLocation.Header, //"formData", + Description = parameter.Description, + Required = parameter.Required, + Content = parameter.Content + }); + } + + #endregion 文件上传处理 + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Mvc/TokenProvider.cs b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/TokenProvider.cs new file mode 100644 index 0000000..dcbe956 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Mvc/TokenProvider.cs @@ -0,0 +1,220 @@ +using IdentityModel; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using Znyc.Cloudcar.Admin.AspNetCore.Common; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.Commons.Core.App; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Options; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.AspNetCore.Mvc +{ + /// + /// Token令牌提供类 + /// + public class TokenProvider + { + private readonly JwtOption _jwtModel = App.GetService(); + private readonly IRoleService _roleService = App.GetService(); + + /// + /// 构造函数 + /// + public TokenProvider() + { + } + + /// + /// 构造函数,初花jwtmodel + /// + /// + public TokenProvider(JwtOption jwtModel) + { + _jwtModel = jwtModel; + } + + /// + /// 直接通过appid和加密字符串获取访问令牌接口 + /// + /// 获取access_token填写client_credential + /// 用户唯一凭证AppId + /// 用户唯一凭证密钥,即appsecret + /// + public TokenResult GenerateToken(string granttype, string appid, string secret) + { + byte[] keyByteArray = Encoding.UTF8.GetBytes(secret); + SymmetricSecurityKey signingKey = new SymmetricSecurityKey(keyByteArray); + DateTime expires = DateTime.UtcNow.Add(TimeSpan.FromMinutes(_jwtModel.Expiration)); + SigningCredentials signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); + SecurityTokenDescriptor tokenDescripor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(new[] + { + new(JwtClaimTypes.Audience, appid), + new Claim(JwtClaimTypes.Issuer, _jwtModel.Issuer), + new Claim(JwtClaimTypes.Subject, GrantType.ClientCredentials) + }, granttype), + Expires = expires, + //对称秘钥SymmetricSecurityKey + //签名证书(秘钥,加密算法)SecurityAlgorithms + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(keyByteArray), + SecurityAlgorithms.HmacSha256Signature) + }; + JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); + SecurityToken token = tokenHandler.CreateToken(tokenDescripor); + string tokenString = tokenHandler.WriteToken(token); + TokenResult result = new TokenResult + { + AccessToken = tokenString, + ExpiresIn = (int)TimeSpan.FromMinutes(_jwtModel.Expiration).TotalMinutes + }; + return result; + } + + /// + /// 检查用户的Token有效性 + /// + /// token令牌 + /// + public CommonResult ValidateToken(string token) + { + //返回的结果对象 + CommonResult result = new CommonResult(); + if (!string.IsNullOrEmpty(token)) + { + try + { + JwtSecurityToken jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token); + if (jwtToken != null) + { + #region 检查令牌对象内容 + + DateTime now = DateTime.UtcNow; + DateTime refreshTime = jwtToken.ValidFrom; + refreshTime = refreshTime.Add(TimeSpan.FromMinutes(_jwtModel.refreshJwtTime)); + if (now > refreshTime && jwtToken.Issuer == _jwtModel.Issuer) + { + result.ErrMsg = ErrCode.err40005; + result.ErrCode = "40005"; + } + else + { + if (jwtToken.Subject == GrantType.Password) + { + List claimlist = jwtToken?.Payload.Claims as List; + result.ResData = claimlist; + } + + result.ErrMsg = ErrCode.err0; + result.ErrCode = ErrCode.successCode; + } + + #endregion 检查令牌对象内容 + } + else + { + result.ErrMsg = ErrCode.err40004; + result.ErrCode = "40004"; + } + } + catch (Exception ex) + { + Log4NetHelper.Error("验证token异常", ex); + throw new MyApiException(ErrCode.err40004, "40004"); + } + } + else + { + result.ErrMsg = ErrCode.err40004; + result.ErrCode = "40004"; + } + + return result; + } + + /// + /// 根据用户获取token + /// + /// 用户信息 + /// 应用Id + /// + public TokenResult LoginToken(AdminUserEntity userInfo, string appid) + { + JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); + byte[] key = Encoding.UTF8.GetBytes(_jwtModel.Secret); + DateTime authTime = DateTime.UtcNow; //授权时间 + DateTime expires = authTime.Add(TimeSpan.FromMinutes(_jwtModel.Expiration)); //过期时间 + SecurityTokenDescriptor tokenDescripor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(new[] + { + new(JwtClaimTypes.Audience, appid), + new Claim(JwtClaimTypes.Issuer, _jwtModel.Issuer), + new Claim(JwtClaimTypes.Name, userInfo.Account), + new Claim(JwtClaimTypes.Id, userInfo.Id.ToString()), + new Claim(JwtClaimTypes.Role, _roleService.GetRoleEnCode(userInfo.RoleId.ToString())), + new Claim(JwtClaimTypes.Subject, GrantType.Password) + }), + Expires = expires, + //对称秘钥SymmetricSecurityKey + //签名证书(秘钥,加密算法)SecurityAlgorithms + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), + SecurityAlgorithms.HmacSha256Signature) + }; + SecurityToken token = tokenHandler.CreateToken(tokenDescripor); + string tokenString = tokenHandler.WriteToken(token); + TokenResult result = new TokenResult + { + AccessToken = tokenString, + ExpiresIn = (int)TimeSpan.FromMinutes(_jwtModel.Expiration).TotalMinutes + }; + return result; + } + + /// + /// 根据登录用户获取token + /// + /// 用户信息 + /// 应用Id + /// + public TokenResult GetUserToken(AdminUserEntity userInfo, string appid) + { + JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); + byte[] key = Encoding.UTF8.GetBytes(_jwtModel.Secret); + DateTime authTime = DateTime.UtcNow; //授权时间 + DateTime expires = authTime.Add(TimeSpan.FromMinutes(_jwtModel.Expiration)); //过期时间 + SecurityTokenDescriptor tokenDescripor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(new[] + { + new(JwtClaimTypes.Audience, appid), + new Claim(JwtClaimTypes.Issuer, _jwtModel.Issuer), + new Claim(JwtClaimTypes.Name, userInfo.Account), + new Claim(JwtClaimTypes.Id, userInfo.Id.ToString()), + new Claim(JwtClaimTypes.Role, userInfo.RoleId.ToString()), + new Claim(JwtClaimTypes.Subject, GrantType.Password) + }), + Expires = expires, + //对称秘钥SymmetricSecurityKey + //签名证书(秘钥,加密算法)SecurityAlgorithms + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), + SecurityAlgorithms.HmacSha256Signature) + }; + SecurityToken token = tokenHandler.CreateToken(tokenDescripor); + string tokenString = tokenHandler.WriteToken(token); + TokenResult result = new TokenResult + { + AccessToken = tokenString, + ExpiresIn = (int)TimeSpan.FromMinutes(_jwtModel.Expiration).TotalMinutes + }; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Properties/PublishProfiles/FolderProfile.pubxml b/Znyc.Cloudcar.Admin.AspNetCore/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..377dd20 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,16 @@ + + + + + False + False + True + Release + Any CPU + FileSystem + bin\Release\net6.0\publish\ + FileSystem + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/DBConnResult.cs b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/DBConnResult.cs new file mode 100644 index 0000000..8e716d8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/DBConnResult.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.Serialization; + +namespace Znyc.Cloudcar.Admin.AspNetCore.ViewModel +{ + /// + /// 数据库连接返回结果实体 + /// + [Serializable] + public class DBConnResult + { + /// + /// 未加密字符串 + /// + [DataMember] + public string ConnStr { get; set; } + + /// + /// 数据库名称 + /// + [DataMember] + public string EncryptConnStr { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/DbConnInfo.cs b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/DbConnInfo.cs new file mode 100644 index 0000000..0a1cb42 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/DbConnInfo.cs @@ -0,0 +1,48 @@ +using System; +using System.Runtime.Serialization; + +namespace Znyc.Cloudcar.Admin.AspNetCore.ViewModel +{ + /// + /// 数据库连接字符串实体 + /// + [Serializable] + public class DbConnInfo + { + /// + /// 访问地址 + /// + [DataMember] + public string DbAddress { get; set; } + + /// + /// 端口,默认SQLServer为1433;Mysql为3306 + /// + [DataMember] + public int DbPort { get; set; } + + /// + /// 数据库名称 + /// + [DataMember] + public string DbName { get; set; } + + /// + /// 用户名 + /// + [DataMember] + public string DbUserName { get; set; } + + /// + /// 访问密码 + /// + [DataMember] + public string DbPassword { get; set; } + + /// + /// 数据库类型 + /// + [DataMember] + public string DbType { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/SearchModel.cs b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/SearchModel.cs new file mode 100644 index 0000000..e827337 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/SearchModel.cs @@ -0,0 +1,34 @@ +using System; +using System.Runtime.Serialization; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.AspNetCore.ViewModel +{ + /// + /// 查询条件公共实体类 + /// + [Serializable] + [DataContract] + public class SearchModel : PagerInfo + { + /// + /// 关键词 + /// + public string Keywords { get; set; } + + /// + /// 编码/代码 + /// + public string EnCode { get; set; } + + /// + /// 排序方式 默认asc + /// + public string Order { get; set; } + + /// + /// 排序字段 默认Id + /// + public string Sort { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/UpdateEnableViewModel.cs b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/UpdateEnableViewModel.cs new file mode 100644 index 0000000..1891b2f --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/UpdateEnableViewModel.cs @@ -0,0 +1,22 @@ +using System; + +namespace Znyc.Cloudcar.Admin.AspNetCore.ViewModel +{ + /// + /// 批量更新操作传入参数,如设为禁用、有效、软删除; + /// 物理删除操作是Flag无效不用传参 + /// + [Serializable] + public class UpdateEnableViewModel + { + /// + /// 主键Id集合 + /// + public dynamic[] Ids { get; set; } + + /// + /// 有效标识,默认为1:即设为无效,0:有效 + /// + public string Flag { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/VueCascaderModel.cs b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/VueCascaderModel.cs new file mode 100644 index 0000000..577b725 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/VueCascaderModel.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.AspNetCore.ViewModel +{ + /// + /// Vue Cascader 级联选择模型 + /// + [Serializable] + public class VueCascaderModel + { + /// + /// 值 + /// + public string value { get; set; } + + /// + /// 显示名称 + /// + public string label { get; set; } + + /// + /// 子集 + /// + public List children { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/VuexMenusTree.cs b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/VuexMenusTree.cs new file mode 100644 index 0000000..a368f13 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/ViewModel/VuexMenusTree.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.AspNetCore.ViewModel +{ + /// + /// Vuex菜单模型 + /// + [Serializable] + public class VuexMenusTreeModel + { + /// + /// 字符串,对应当前路由的路径,总是解析为绝对路径 + /// + public string path { get; set; } + + /// + /// 命名视图组件 + /// + public string component { get; set; } + + /// + /// 重定向地址,在面包屑中点击会重定向去的地址 + /// + public string redirect { get; set; } + + /// + /// 设定路由的名字,一定要填写不然使用keep-alive时会出现各种问题 + /// + public string name { get; set; } + + /// + /// 在根路由设置权限,这样它下面所以的子路由都继承了这个权限 + /// + public Meta meta { get; set; } + + /// + /// 子菜单 + /// + public List children { get; set; } + } + + /// + /// VuexMenus路由模型 + /// + [Serializable] + public class VuexMenus + { + /// + /// 访问路径 + /// + public string path { get; set; } + + /// + /// 对应模块 + /// + public string component { get; set; } + + /// + /// 重定向地址,在面包屑中点击会重定向去的地址 + /// + public string redirect { get; set; } + + /// + /// 设定路由的名字,一定要填写不然使用keep-alive时会出现各种问题 + /// + public string name { get; set; } + + /// + /// + public Meta meta { get; set; } + } + + /// + /// 路由元信息模型 + /// + [Serializable] + public class Meta + { + /// + /// 设置该路由在侧边栏和面包屑中展示的名字 + /// + public string title { get; set; } + + /// + /// 设置该路由的图标 + /// + public string icon { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.AspNetCore/Znyc.Cloudcar.Admin.AspNetCore.csproj b/Znyc.Cloudcar.Admin.AspNetCore/Znyc.Cloudcar.Admin.AspNetCore.csproj new file mode 100644 index 0000000..42c2b83 --- /dev/null +++ b/Znyc.Cloudcar.Admin.AspNetCore/Znyc.Cloudcar.Admin.AspNetCore.csproj @@ -0,0 +1,73 @@ + + + + net6.0 + + Library + + + + + Znyc.Admin + true + true + 1.0 + + true + true + + true + Znyc.Recruitment.Admin.AspNetCore + + 1.3.1.37 + MIT + + + bin\Release\Znyc.Recruitment.Admin.AspNetCore.xml + bin\Release\ + + + + bin\Debug\ + bin\Debug\Znyc.Recruitment.Admin.AspNetCore.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Attributes/AppDbContextFactoryAttribute.cs b/Znyc.Cloudcar.Admin.Commons/Attributes/AppDbContextFactoryAttribute.cs new file mode 100644 index 0000000..01efe88 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Attributes/AppDbContextFactoryAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Attributes +{ + /// + /// 数据库上下文配置 + /// + public class AppDbContextFactoryAttribute : Attribute + { + /// + /// + /// 数据库配置名称 + public AppDbContextFactoryAttribute(string dbConfigName) + { + DbConfigName = dbConfigName; + } + + /// + /// 数据库配置名称 + /// + public string DbConfigName { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Attributes/ShardingTableAttribute.cs b/Znyc.Cloudcar.Admin.Commons/Attributes/ShardingTableAttribute.cs new file mode 100644 index 0000000..9d21151 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Attributes/ShardingTableAttribute.cs @@ -0,0 +1,39 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Znyc.Cloudcar.Admin.Commons.Attributes +{ + /// + /// 数据库分表特性 + /// + public class ShardingTableAttribute : TableAttribute + { + /// + /// + /// + public ShardingTableAttribute(string name) : base(name) + { + Suffix = "yyyyMMdd"; + Splitter = "_"; + } + + /// + /// + /// + /// + /// + public ShardingTableAttribute(string name, string splitter = "_", string suffix = "yyyyMMdd") : base(name) + { + Suffix = suffix; + } + + /// + /// 分隔符 + /// + public string Splitter { get; set; } = "_"; + + /// + /// 分表后缀格式。默认值:_yyyyMMdd + /// + public string Suffix { get; set; } = "yyyyMMdd"; + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Attributes/UnitOfWorkAttribute.cs b/Znyc.Cloudcar.Admin.Commons/Attributes/UnitOfWorkAttribute.cs new file mode 100644 index 0000000..b4de7a2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Attributes/UnitOfWorkAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Attributes +{ + /// + /// 工作单元 + /// 仅用来做特性标记 + /// + public class UnitOfWorkAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Cache/CacheHelper.cs b/Znyc.Cloudcar.Admin.Commons/Cache/CacheHelper.cs new file mode 100644 index 0000000..a9657b4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Cache/CacheHelper.cs @@ -0,0 +1,406 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Core.App; + +namespace Znyc.Cloudcar.Admin.Commons.Cache +{ + /// + /// 缓存操作帮助类 + /// + public class CacheHelper + { + /// + /// 缓存提供模式 + /// + private static CacheProvider cacheProvider; + + /// + /// 缓存接口 + /// + private readonly ICacheService cacheservice; + + /// + /// + public CacheHelper() + { + cacheProvider = App.GetService(); + if (cacheProvider == null) + { + throw new ArgumentNullException(nameof(cacheProvider)); + } + + cacheservice = App.GetService(); + } + + /// + /// 使用MemoryCache缓存操作 + /// + /// 是否使用MemoryCache + public CacheHelper(bool isMemoryCache = false) + { + cacheProvider = App.GetService(); + if (cacheProvider == null) + { + throw new ArgumentNullException(nameof(cacheProvider)); + } + + if (isMemoryCache) + { + cacheservice = App.GetService(); + } + else + { + cacheservice = App.GetService(); + } + } + + #region 验证缓存项是否存在 + + /// + /// 验证缓存项是否存在,TryGetValue 来检测 Key是否存在的 + /// + /// 缓存Key + /// + public bool Exists(string key) + { + return cacheservice.Exists(key); + } + + #endregion 验证缓存项是否存在 + + #region 添加缓存 + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// + public bool Add(string key, object value) + { + return cacheservice.Add(key, value); + } + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// 绝对过期时长 + /// + public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) + { + return cacheservice.Add(key, value, expiresSliding, expiressAbsoulte); + } + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// 缓存时长 + /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// + public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + return cacheservice.Add(key, value, expiresIn, isSliding); + } + + #endregion 添加缓存 + + #region 删除缓存 + + /// + /// 删除缓存 + /// + /// 缓存Key + /// + public bool Remove(string key) + { + return cacheservice.Remove(key); + } + + /// + /// 批量删除缓存 + /// + /// 缓存Key集合 + /// + public void RemoveAll(IEnumerable keys) + { + cacheservice.RemoveAll(keys); + } + + /// + /// 删除匹配到的缓存 + /// + /// + /// + public void RemoveByPattern(string pattern) + { + cacheservice.RemoveByPattern(pattern); + } + + /// + /// 删除所有缓存 + /// + public void RemoveCacheAll() + { + cacheservice.RemoveCacheAll(); + } + + #endregion 删除缓存 + + #region 获取缓存 + + /// + /// 获取缓存 + /// + /// 缓存Key + /// + public T Get(string key) where T : class + { + return cacheservice.Get(key); + } + + /// + /// 获取缓存 + /// + /// 缓存Key + /// + public object Get(string key) + { + return cacheservice.Get(key); + } + + /// + /// 获取缓存集合 + /// + /// 缓存Key集合 + /// + public IDictionary GetAll(IEnumerable keys) + { + return cacheservice.GetAll(keys); + } + + #endregion 获取缓存 + + #region 修改缓存 + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// + public bool Replace(string key, object value) + { + return cacheservice.Replace(key, value); + } + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// 绝对过期时长 + /// + public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) + { + return cacheservice.Replace(key, value, expiresSliding, expiressAbsoulte); + } + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// 缓存时长 + /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// + public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + return cacheservice.Replace(key, value, expiresIn, isSliding); + } + + #endregion 修改缓存 + + #region Hash + + /// + /// + /// + /// + /// + /// + public bool HSet(string key, string filed, object value) + { + return cacheservice.HSet(key, filed, value); + } + + /// + /// + /// + /// + /// + /// + public Task HSetAsync(string key, string filed, object value) + { + return cacheservice.HSetAsync(key, filed, value); + } + + /// + /// + /// + /// + /// + public Task HMSetAsync(string key, object[] value) + { + return cacheservice.HMSetAsync(key, value); + } + + /// + /// + /// + /// + /// + public bool HMSet(string key, object[] value) + { + return cacheservice.HMSet(key, value); + } + + /// + /// + /// + /// + /// + public string[] HMGet(string key, string[] filed) + { + return cacheservice.HMGet(key, filed); + } + + /// + /// + /// + /// + /// + public Task HMGetAsync(string key, string filed) + { + return cacheservice.HMGetAsync(key, filed); + } + + /// + /// + /// + /// + /// + public long HDel(string key, string[] filed) + { + return cacheservice.HDel(key, filed); + } + + /// + /// + /// + /// + /// + public Task HDelAsync(string key, string filed) + { + return cacheservice.HDelAsync(key, filed); + } + + /// + /// + /// + /// + /// + public bool HExists(string key, string filed) + { + return cacheservice.HExists(key, filed); + } + + /// + /// + /// + /// + /// + public Task HExistsAsync(string key, string filed) + { + return cacheservice.HExistsAsync(key, filed); + } + + /// + /// + /// + /// + /// + public Task HIncrAsync(string key, string filed) + { + return cacheservice.HIncrByAsync(key, filed); + } + + /// + /// + /// + /// + /// + public long HIncr(string key, string filed) + { + return cacheservice.HIncrBy(key, filed); + } + + /// + /// + /// + /// + public Task> HGetAllAsync(string key) + { + return cacheservice.HGetAllAsync(key); + } + + /// + /// + /// + /// + public Dictionary HGetAll(string key) + { + return cacheservice.HGetAll(key); + } + + /// + /// + /// + /// + /// + public Task HGetAsync(string key, string filed) + { + return cacheservice.HGetAsync(key, filed); + } + + /// + /// + /// + /// + /// + /// + public Task HSetNxAsync(string key, string filed, object value) + { + return cacheservice.HSetNxAsync(key, filed, value); + } + + /// + /// + /// + /// + /// + /// + public bool HSetNx(string key, string filed, object value) + { + return cacheservice.HSetNx(key, filed, value); + } + + #endregion Hash + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Cache/CacheProvider.cs b/Znyc.Cloudcar.Admin.Commons/Cache/CacheProvider.cs new file mode 100644 index 0000000..95d1b9e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Cache/CacheProvider.cs @@ -0,0 +1,23 @@ +namespace Znyc.Cloudcar.Admin.Commons.Cache +{ + /// + /// 缓存提供模式,使用Redis或MemoryCache + /// + public class CacheProvider + { + /// + /// 是否使用Redis + /// + public bool IsUseRedis { get; set; } + + /// + /// Redis连接 + /// + public string ConnectionString { get; set; } + + /// + /// Redis实例名称 + /// + public string InstanceName { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Cache/ICacheService.cs b/Znyc.Cloudcar.Admin.Commons/Cache/ICacheService.cs new file mode 100644 index 0000000..bf3264f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Cache/ICacheService.cs @@ -0,0 +1,305 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.Commons.Cache +{ + /// + /// 缓存服务接口 + /// + public interface ICacheService + { + #region 验证缓存项是否存在 + + /// + /// 验证缓存项是否存在 + /// + /// 缓存Key + /// + bool Exists(string key); + + #endregion 验证缓存项是否存在 + + #region 添加缓存 + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// + bool Add(string key, object value); + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// 绝对过期时长 + /// + bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte); + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// 缓存时长 + /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// + bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false); + + /// + /// + /// + /// + /// + /// + Task HashSetAsync(string key, string filed, object value); + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// + Task AddAsync(string key, object value); + + /// + /// / + /// + /// + /// + /// + /// + /// + Task AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false); + + #endregion 添加缓存 + + #region 删除缓存 + + /// + /// 删除缓存 + /// + /// 缓存Key + /// + bool Remove(string key); + + /// + /// 批量删除缓存 + /// + /// 缓存Key集合 + /// + void RemoveAll(IEnumerable keys); + + /// + /// 使用通配符找出所有的key然后逐个删除 + /// + /// 通配符 + void RemoveByPattern(string pattern); + + /// + /// 删除所有缓存 + /// + void RemoveCacheAll(); + + /// + /// 删除缓存 + /// + /// 缓存Key + /// + Task RemoveAsync(string key); + + #endregion 删除缓存 + + #region 获取缓存 + + /// + /// 获取缓存 + /// + /// 缓存Key + /// + T Get(string key) where T : class; + + /// + /// 获取缓存 + /// + /// 缓存Key + /// + object Get(string key); + + /// + /// 获取缓存集合 + /// + /// 缓存Key集合 + /// + IDictionary GetAll(IEnumerable keys); + + #endregion 获取缓存 + + #region 修改缓存 + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// + bool Replace(string key, object value); + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// 绝对过期时长 + /// + bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte); + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// 缓存时长 + /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// + bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false); + + #endregion 修改缓存 + + #region Hash + + /// + /// + /// + /// + /// + /// + bool HSet(string key, string filed, object value); + + /// + /// + /// + /// + /// + /// + Task HSetAsync(string key, string filed, object value); + + /// + /// + /// + /// + /// + Task HMSetAsync(string key, object[] value); + + /// + /// + /// + /// + /// + bool HMSet(string key, object[] value); + + /// + /// + /// + /// + /// + string[] HMGet(string key, string[] filed); + + /// + /// + /// + /// + /// + Task HMGetAsync(string key, string filed); + + /// + /// + /// + /// + /// + long HDel(string key, string[] filed); + + /// + /// + /// + /// + /// + Task HDelAsync(string key, string filed); + + /// + /// + /// + /// + /// + bool HExists(string key, string filed); + + /// + /// + /// + /// + /// + Task HExistsAsync(string key, string filed); + + /// + /// 自增 + /// + /// + /// + /// + Task HIncrByAsync(string key, string filed); + + /// + /// 自增 + /// + /// + /// + /// + long HIncrBy(string key, string filed); + + /// + /// 获取所有 + /// + /// + /// + Task> HGetAllAsync(string key); + + /// + /// 获取所有 + /// + /// + /// + Dictionary HGetAll(string key); + + /// + /// + /// + /// + /// + Task HGetAsync(string key, string filed); + + /// + /// 设置一个键值对(不存在,则创建;否则,修改) + /// + /// + /// + /// + /// + Task HSetNxAsync(string key, string filed, object value); + + /// + /// 设置一个键值对(不存在,则创建;否则,修改) + /// + /// + /// + /// + /// + bool HSetNx(string key, string filed, object value); + + #endregion + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Cache/MemoryCacheService.cs b/Znyc.Cloudcar.Admin.Commons/Cache/MemoryCacheService.cs new file mode 100644 index 0000000..55a9b98 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Cache/MemoryCacheService.cs @@ -0,0 +1,594 @@ +using Microsoft.Extensions.Caching.Memory; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.Commons.Cache +{ + /// + /// MemoryCache缓存操作 + /// + public class MemoryCacheService : ICacheService + { + /// + /// + protected IMemoryCache _cache; + + /// + /// + /// + public MemoryCacheService(IMemoryCache cache) + { + _cache = cache; + } + + #region 验证缓存项是否存在 + + /// + /// 验证缓存项是否存在,TryGetValue 来检测 Key是否存在的 + /// + /// 缓存Key + /// + public bool Exists(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.TryGetValue(key, out object cached); + } + + #endregion 验证缓存项是否存在 + + public Task AddAsync(string key, object value) + { + throw new NotImplementedException(); + } + + public Task AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + throw new NotImplementedException(); + } + + public Task RemoveAsync(string key) + { + throw new NotImplementedException(); + } + + /// + /// + public void Dispose() + { + if (_cache != null) + { + _cache.Dispose(); + } + + GC.SuppressFinalize(this); + } + + #region 添加缓存 + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// + public bool Add(string key, object value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + _cache.Set(key, value); + return Exists(key); + } + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// 绝对过期时长 + /// + public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + _cache.Set(key, value, + new MemoryCacheEntryOptions() + .SetSlidingExpiration(expiresSliding) + .SetAbsoluteExpiration(expiressAbsoulte) + ); + + return Exists(key); + } + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// 缓存时长 + /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// + public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (isSliding) + { + _cache.Set(key, value, + new MemoryCacheEntryOptions() + .SetSlidingExpiration(expiresIn) + ); + } + else + { + _cache.Set(key, value, + new MemoryCacheEntryOptions() + .SetAbsoluteExpiration(expiresIn) + ); + } + + return Exists(key); + } + + public Task HashSetAsync(string key, string filed, object value) + { + throw new NotImplementedException(); + } + + #endregion 添加缓存 + + #region 删除缓存 + + /// + /// 删除缓存 + /// + /// 缓存Key + /// + public bool Remove(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + _cache.Remove(key); + + return !Exists(key); + } + + /// + /// 批量删除缓存 + /// + /// 缓存Key集合 + /// + public void RemoveAll(IEnumerable keys) + { + if (keys == null) + { + throw new ArgumentNullException(nameof(keys)); + } + + keys.ToList().ForEach(item => _cache.Remove(item)); + } + + /// + /// 删除所有缓存 + /// + public void RemoveCacheAll() + { + List l = GetCacheKeys(); + foreach (string s in l) + { + Remove(s); + } + } + + /// + /// 删除匹配到的缓存 + /// + /// + /// + public void RemoveByPattern(string pattern) + { + IList l = SearchCacheRegex(pattern); + foreach (string s in l) + { + Remove(s); + } + } + + /// + /// 搜索 匹配到的缓存 + /// + /// + /// + public IList SearchCacheRegex(string pattern) + { + List cacheKeys = GetCacheKeys(); + List l = cacheKeys.Where(k => Regex.IsMatch(k, pattern)).ToList(); + return l.AsReadOnly(); + } + + #endregion 删除缓存 + + #region 获取缓存 + + /// + /// 获取缓存 + /// + /// 缓存Key + /// + public T Get(string key) where T : class + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.Get(key) as T; + } + + /// + /// 获取缓存 + /// + /// 缓存Key + /// + public object Get(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.Get(key); + } + + /// + /// 获取缓存集合 + /// + /// 缓存Key集合 + /// + public IDictionary GetAll(IEnumerable keys) + { + if (keys == null) + { + throw new ArgumentNullException(nameof(keys)); + } + + Dictionary dict = new Dictionary(); + + keys.ToList().ForEach(item => dict.Add(item, _cache.Get(item))); + + return dict; + } + + /// + /// 获取所有缓存键 + /// + /// + public List GetCacheKeys() + { + const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; + object entries = _cache.GetType().GetField("_entries", flags).GetValue(_cache); + IDictionary cacheItems = entries as IDictionary; + List keys = new List(); + if (cacheItems == null) + { + return keys; + } + + foreach (DictionaryEntry cacheItem in cacheItems) + { + keys.Add(cacheItem.Key.ToString()); + } + + return keys; + } + + #endregion 获取缓存 + + #region 修改缓存 + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// + public bool Replace(string key, object value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (Exists(key)) + { + if (!Remove(key)) + { + return false; + } + } + + return Add(key, value); + } + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// 绝对过期时长 + /// + public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (Exists(key)) + { + if (!Remove(key)) + { + return false; + } + } + + return Add(key, value, expiresSliding, expiressAbsoulte); + } + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// 缓存时长 + /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// + public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (Exists(key)) + { + if (!Remove(key)) + { + return false; + } + } + + return Add(key, value, expiresIn, isSliding); + } + + #endregion 修改缓存 + + #region Hash + + /// + /// + /// + /// + /// + /// + public bool HSet(string key, string filed, object value) + { + return RedisHelper.HSet(key, filed, value); + } + + /// + /// + /// + /// + /// + /// + public Task HSetAsync(string key, string filed, object value) + { + return RedisHelper.HSetAsync(key, filed, value); + } + + /// + /// + /// + /// + /// + public Task HMSetAsync(string key, object[] value) + { + return RedisHelper.HMSetAsync(key, value); + } + + /// + /// + /// + /// + /// + public bool HMSet(string key, object[] value) + { + return RedisHelper.HMSet(key, value); + } + + /// + /// + /// + /// + /// + public string[] HMGet(string key, string[] filed) + { + return RedisHelper.HMGet(key, filed); + } + + /// + /// + /// + /// + /// + public Task HMGetAsync(string key, string filed) + { + return RedisHelper.HMGetAsync(key, filed); + } + + /// + /// + /// + /// + /// + public long HDel(string key, string[] filed) + { + return RedisHelper.HDel(key, filed); + } + + /// + /// + /// + /// + /// + public Task HDelAsync(string key, string filed) + { + return RedisHelper.HDelAsync(key, filed); + } + + /// + /// + /// + /// + /// + public bool HExists(string key, string filed) + { + return RedisHelper.HExists(key, filed); + } + + /// + /// + /// + /// + /// + public Task HExistsAsync(string key, string filed) + { + return RedisHelper.HExistsAsync(key, filed); + } + + /// + /// + /// + /// + /// + public Task HIncrByAsync(string key, string filed) + { + return RedisHelper.HIncrByAsync(key, filed); + } + + /// + /// + /// + /// + /// + public long HIncrBy(string key, string filed) + { + return RedisHelper.HIncrBy(key, filed); + } + + /// + /// + /// + /// + public Task> HGetAllAsync(string key) + { + return RedisHelper.HGetAllAsync(key); + } + + /// + /// + /// + /// + public Dictionary HGetAll(string key) + { + return RedisHelper.HGetAll(key); + } + + /// + /// + /// + /// + /// + public async Task HGetAsync(string key, string filed) + { + return await RedisHelper.HGetAsync(key, filed); + } + + /// + /// + /// + /// + /// + /// + public Task HSetNxAsync(string key, string filed, object value) + { + return RedisHelper.HSetNxAsync(key, filed, value); + } + + /// + /// + /// + /// + /// + /// + public bool HSetNx(string key, string filed, object value) + { + return RedisHelper.HSetNx(key, filed, value); + } + + #endregion Hash + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Cache/RedisCacheService.cs b/Znyc.Cloudcar.Admin.Commons/Cache/RedisCacheService.cs new file mode 100644 index 0000000..0d2cca0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Cache/RedisCacheService.cs @@ -0,0 +1,634 @@ +using Microsoft.Extensions.Caching.StackExchangeRedis; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.Commons.Cache +{ + /// + /// Redis缓存操作 + /// + public class RedisCacheService : ICacheService + { + /// + /// + private readonly ConnectionMultiplexer _connection; + + /// + /// + private readonly string _instance; + + private readonly JsonSerializerOptions _jsonOptions; + + /// + /// + protected IDatabase _cache; + + /// + /// + /// + /// + /// + public RedisCacheService(RedisCacheOptions options, JsonSerializerOptions jsonOptions, int database = 0) + { + _connection = ConnectionMultiplexer.Connect(options.Configuration); + _cache = _connection.GetDatabase(database); + _instance = options.InstanceName; + _jsonOptions = jsonOptions; + } + + /// + /// + /// + /// + public string GetKeyForRedis(string key) + { + return _instance + key; + } + + public void Dispose() + { + if (_connection != null) + { + _connection.Dispose(); + } + + GC.SuppressFinalize(this); + } + + #region 验证缓存项是否存在 + + /// + /// 验证缓存项是否存在 + /// + /// 缓存Key + /// + public bool Exists(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.KeyExists(GetKeyForRedis(key)); + } + + /// + /// 验证缓存项是否存在 + /// + /// 缓存Key + /// + public Task ExistsAsync(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.KeyExistsAsync(GetKeyForRedis(key)); + } + + #endregion 验证缓存项是否存在 + + #region 添加缓存 + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// + public bool Add(string key, object value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.StringSet(GetKeyForRedis(key), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, _jsonOptions))); + } + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效) + /// 绝对过期时长 + /// + public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.StringSet(GetKeyForRedis(key), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, _jsonOptions)), expiressAbsoulte); + } + + /// + /// 添加缓存 + /// + /// 缓存Key + /// 缓存Value + /// 缓存时长 + /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间,Redis中无效) + /// + public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.StringSet(GetKeyForRedis(key), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, _jsonOptions)), expiresIn); + } + + public Task AddAsync(string key, object value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.StringSetAsync(GetKeyForRedis(key), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, _jsonOptions))); + } + + public Task AddAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.StringSetAsync(GetKeyForRedis(key), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, _jsonOptions)), expiressAbsoulte); + } + + public Task AddAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.StringSetAsync(GetKeyForRedis(key), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, _jsonOptions)), expiresIn); + } + + public Task HashSetAsync(string key, string filed, object value) + { + return _cache.HashSetAsync(GetKeyForRedis(key), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(filed, _jsonOptions)), + Encoding.UTF8.GetBytes(JsonSerializer.Serialize(value, _jsonOptions))); + } + + #endregion 添加缓存 + + #region 删除缓存 + + /// + /// 删除缓存 + /// + /// 缓存Key + /// + public bool Remove(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.KeyDelete(GetKeyForRedis(key)); + } + + /// + /// 批量删除缓存 + /// + /// 缓存Key集合 + /// + public void RemoveAll(IEnumerable keys) + { + if (keys == null) + { + throw new ArgumentNullException(nameof(keys)); + } + + keys.ToList().ForEach(item => Remove(item)); + } + + /// + /// + /// + /// + public Task RemoveAsync(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + return _cache.KeyDeleteAsync(GetKeyForRedis(key)); + } + + public Task RemoveAllAsync(IEnumerable keys) + { + //if (keys == null) + //{ + throw new ArgumentNullException(nameof(keys)); + //} + + //keys.ToList().ForEach(item => RemoveAsync(item)); + } + + /// + /// 使用通配符找出所有的key然后逐个删除 + /// + /// 通配符 + public virtual void RemoveByPattern(string pattern) + { + foreach (System.Net.EndPoint ep in _connection.GetEndPoints()) + { + IServer server = _connection.GetServer(ep); + IEnumerable keys = server.Keys(pattern: "*" + pattern + "*", database: _cache.Database); + foreach (RedisKey key in keys) + { + _cache.KeyDelete(key); + } + } + } + + /// + /// 删除所有缓存 + /// + public void RemoveCacheAll() + { + RemoveByPattern(""); + } + + #endregion 删除缓存 + + #region 获取缓存 + + /// + /// 获取缓存 + /// + /// 缓存Key + /// + public T Get(string key) where T : class + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + RedisValue value = _cache.StringGet(GetKeyForRedis(key)); + + if (!value.HasValue) + { + return default; + } + + return JsonSerializer.Deserialize(value, _jsonOptions); + } + + /// + /// 获取缓存 + /// + /// 缓存Key + /// + public object Get(string key) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + RedisValue value = _cache.StringGet(GetKeyForRedis(key)); + + if (!value.HasValue) + { + return null; + } + + return JsonSerializer.Deserialize(value, _jsonOptions); + //string json = value.ToString(); + //return Newtonsoft.Json.JsonConvert.DeserializeObject(json); + } + + /// + /// 获取缓存集合 + /// + /// 缓存Key集合 + /// + public IDictionary GetAll(IEnumerable keys) + { + if (keys == null) + { + throw new ArgumentNullException(nameof(keys)); + } + + Dictionary dict = new Dictionary(); + + keys.ToList().ForEach(item => dict.Add(item, Get(GetKeyForRedis(item)))); + + return dict; + } + + public Task GetAsync(string key) where T : class + { + throw new NotImplementedException(); + } + + public Task GetAsync(string key) + { + throw new NotImplementedException(); + } + + public Task> GetAllAsync(IEnumerable keys) + { + throw new ArgumentNullException(nameof(keys)); + } + + #endregion 获取缓存 + + #region 修改缓存 + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// + public bool Replace(string key, object value) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (Exists(key)) + { + if (!Remove(key)) + { + return false; + } + } + + return Add(key, value); + } + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// 滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// 绝对过期时长 + /// + public bool Replace(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (Exists(key)) + { + if (!Remove(key)) + { + return false; + } + } + + return Add(key, value, expiresSliding, expiressAbsoulte); + } + + /// + /// 修改缓存 + /// + /// 缓存Key + /// 新的缓存Value + /// 缓存时长 + /// 是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) + /// + public bool Replace(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (Exists(key)) + { + if (!Remove(key)) + { + return false; + } + } + + return Add(key, value, expiresIn, isSliding); + } + + public Task ReplaceAsync(string key, object value) + { + throw new NotImplementedException(); + } + + public Task ReplaceAsync(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte) + { + throw new NotImplementedException(); + } + + public Task ReplaceAsync(string key, object value, TimeSpan expiresIn, bool isSliding = false) + { + throw new NotImplementedException(); + } + + #endregion 修改缓存 + + #region Hash + + /// + /// + /// + /// + /// + /// + public bool HSet(string key, string filed, object value) + { + return RedisHelper.HSet(key, filed, value); + } + + /// + /// + /// + /// + /// + /// + public Task HSetAsync(string key, string filed, object value) + { + return RedisHelper.HSetAsync(key, filed, value); + } + + /// + /// + /// + /// + /// + public Task HMSetAsync(string key, object[] value) + { + return RedisHelper.HMSetAsync(key, value); + } + + /// + /// + /// + /// + /// + public bool HMSet(string key, object[] value) + { + return RedisHelper.HMSet(key, value); + } + + /// + /// + /// + /// + /// + public string[] HMGet(string key, string[] filed) + { + return RedisHelper.HMGet(key, filed); + } + + /// + /// + /// + /// + /// + public Task HMGetAsync(string key, string filed) + { + return RedisHelper.HMGetAsync(key, filed); + } + + /// + /// + /// + /// + /// + public long HDel(string key, string[] filed) + { + return RedisHelper.HDel(key, filed); + } + + /// + /// + /// + /// + /// + public Task HDelAsync(string key, string filed) + { + return RedisHelper.HDelAsync(key, filed); + } + + /// + /// + /// + /// + /// + public bool HExists(string key, string filed) + { + return RedisHelper.HExists(key, filed); + } + + /// + /// + /// + /// + /// + public Task HExistsAsync(string key, string filed) + { + return RedisHelper.HExistsAsync(key, filed); + } + + /// + /// + /// + /// + /// + public Task HIncrByAsync(string key, string filed) + { + return RedisHelper.HIncrByAsync(key, filed); + } + + /// + /// + /// + /// + /// + public long HIncrBy(string key, string filed) + { + return RedisHelper.HIncrBy(key, filed); + } + + /// + /// + /// + /// + public Task> HGetAllAsync(string key) + { + return RedisHelper.HGetAllAsync(key); + } + + /// + /// + /// + /// + public Dictionary HGetAll(string key) + { + return RedisHelper.HGetAll(key); + } + + /// + /// + /// + /// + /// + public async Task HGetAsync(string key, string filed) + { + return await RedisHelper.HGetAsync(key, filed); + } + + /// + /// + /// + /// + /// + /// + public Task HSetNxAsync(string key, string filed, object value) + { + return RedisHelper.HSetNxAsync(key, filed, value); + } + + /// + /// + /// + /// + /// + /// + public bool HSetNx(string key, string filed, object value) + { + return RedisHelper.HSetNx(key, filed, value); + } + + #endregion Hash + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Commons.csproj b/Znyc.Cloudcar.Admin.Commons/Commons.csproj new file mode 100644 index 0000000..873c458 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Commons.csproj @@ -0,0 +1,235 @@ + + + + net5.0 + Yuebon + 上海越邦网络科技有限公司 + YuebonNetCore开发框架基础库 + YuebonNetCore开发框架基础库 + 上海越邦网络科技有限公司 版权所有 + true + https://gitee.com/yuebon/YuebonNetCore + 1.3.1.32 + true + + + https://gitee.com/yuebon/YuebonNetCore + LICENSE + logo.png + 1.3.1.32 + + + + bin\Debug\ZNYC.Admin.Commons.xml + bin\Debug\ + + + + bin\Release\ + bin\Release\ZNYC.Admin.Commons.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + Always + + + + + + + + diff --git a/Znyc.Cloudcar.Admin.Commons/Config/Configs.cs b/Znyc.Cloudcar.Admin.Commons/Config/Configs.cs new file mode 100644 index 0000000..612f16d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Config/Configs.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.Configuration; +using Znyc.Cloudcar.Admin.Commons.Core.App; + +namespace Znyc.Cloudcar.Admin.Commons +{ + /// + /// 配置文件读取操作 + /// + public class Configs + { + public static IConfiguration configuration; + + static Configs() + { + configuration = App.GetService(); + } + + /// + /// 根据Key获取数配置内容 + /// + /// + /// + public static IConfigurationSection GetSection(string key) + { + return configuration.GetSection(key); + } + + /// + /// 根据section和key获取配置内容 + /// + /// + /// + /// + public static string GetConfigurationValue(string section, string key) + { + return GetSection(section)?[key]; + } + + /// + /// 根据Key获取数据库连接字符串 + /// + /// + /// + public static string GetConnectionString(string key) + { + return configuration.GetConnectionString(key); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Const/CommonConst.cs b/Znyc.Cloudcar.Admin.Commons/Const/CommonConst.cs new file mode 100644 index 0000000..40acb26 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Const/CommonConst.cs @@ -0,0 +1,79 @@ + +namespace Znyc.Cloudcar.Admin.Commons +{ + /// + /// 默认常量 + /// + public static class CommonConst + { + /// + /// 薪资待遇 + /// + public const long Dictionary_Welfare = 1; + + /// + /// 工作经验 + /// + public const long Dictionary_Experience = 2; + + /// + /// 活动 + /// + public const long Dictionary_Activity = 3; + + /// + /// 默认图片地址 + /// + public const string Default_Image_Prefix = + "https://zhongnengyunche.com/cloudcar/wx/upload/avatar/"; + + /// + /// 默认头像名称 + /// + public const string Default_AvataUrl = "Default_AvatarUrl.png"; + + /// + /// 默认实名图片地址 + /// + public const string Default_Identity_Prefix = + "https://zhongnengyunche.com/authentication/{0}/"; + + /// + /// 默认名称 + /// + public const string Default_UserName = "先生"; + + + /// + /// 默认Banner图片地址 + /// + public const string Default_Banner_Prefix = "https://zhongnengyunche.com/cloudcar/wx/upload/banner/"; + + /// + /// 默认意见反馈图片地址 + /// + public const string Default_FeedbackPic_Prefix = "https://zhongnengyunche.com/cloudcar/wx/upload/feedback/"; + + /// + /// 默认活动图片地址 + /// + public const string Default_Activity_Prefix = "https://zhongnengyunche.com/cloudcar/wx/upload/activity/"; + + + /// + /// 充值活动详情-名称 + /// + public const string RechargeIntro_Name = "{0}云币"; + + + /// + /// 充值活动详情-描述 + /// + public const string RechargeIntro_Description = "{0}云币(可拨打{0}个电话)"; + + /// + /// 空字符串 + /// + public const string String_Empty = " "; + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Const/CurrencyConst.cs b/Znyc.Cloudcar.Admin.Commons/Const/CurrencyConst.cs new file mode 100644 index 0000000..cf0be48 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Const/CurrencyConst.cs @@ -0,0 +1,90 @@ +namespace Znyc.Cloudcar.Admin.Commons +{ + /// + /// 系统 + /// + public class SystemConst + { + /// + /// 当前环境 + /// + public const string ASPNETCORE_ENVIRONMENT = "ASPNETCORE_ENVIRONMENT"; + } + + /// + /// 积分常量 + /// + public class CurrencyConst + { + /// + /// 首次登陆 + /// + public const int FirstLogin = 3; + + /// + /// 邀新用户 + /// + public const int NewUsers = 2; + + /// + /// 每日分享 + /// + public const int DailyShare = 1; + + /// + /// 实名认证 + /// + public const int RealName = 1; + + /// + /// 每日签到 + /// + public const int Signin = 1; + + /// + /// 拔打求职电话 + /// + public const int CallApplyJobPhone = 1; + + /// + /// 拔打招聘电话 + /// + public const int CallCloudcarPhone = 1; + + /// + /// 招聘置顶 + /// + public const int TopCloudcar = 50; + + /// + /// 求职置顶 + /// + public const int TopApplyJob = 50; + + /// + /// 刷新招聘 + /// + public const int RefreshCloudcar = 5; + + /// + /// 刷新求职 + /// + public const int RefreshApplyJob = 1; + } + + /// + /// 积分操作类型常量 + /// + public class CurrencyOperatingTypeConst + { + /// + /// 增加 + /// + public const string Add = "+"; + + /// + /// 减少 + /// + public const string Reduce = "-"; + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Const/ReturnConst.cs b/Znyc.Cloudcar.Admin.Commons/Const/ReturnConst.cs new file mode 100644 index 0000000..76cc4fb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Const/ReturnConst.cs @@ -0,0 +1,115 @@ +namespace Znyc.Cloudcar.Admin.Commons +{ + + /// + /// 返回 + /// + public static class ReturnConst + { + + /// + /// + /// + public const string Password_Error = "密码错误,请重新输入。"; + + /// + /// + /// + public const string User_Not_Exist = "系统不存在该用户,请重新确认。"; + + /// + /// + /// + public const string User_Disable = "该用户已被禁用,请联系管理员。"; + + /// + /// 审批结果-通过 + /// + public const string Approved = "审核通过"; + + /// + /// 备注 + /// + public const string Approved_Note = "欢迎点击转发分享"; + + /// + /// 审批结果-失败 + /// + public const string Audit_Failed = "审核失败"; + + /// + /// + /// + public const string Year = "年"; + + /// + /// + /// + public const string Month = "月"; + + /// + /// + /// + public const string Day = "日"; + + /// + /// 审批类型-求职失败 + /// + public const string Job_Audit_Failed = "发布的求职信息审核失败"; + + /// + /// 审批类型-招聘失败 + /// + public const string Cloud_Audit_Failed = "发布的设备信息审核失败"; + + /// + /// 审批类型-求职通过 + /// + public const string Cloud_Approved = "您的设备信息审核通过"; + + /// + /// 审批类型-招聘通过 + /// + public const string Recruit_Approved = "您的招聘信息审核通过"; + + /// + /// 审批类型-实名认证通过 + /// + public const string RealName_Approved = "您的实名认证信息认证成功"; + + /// + /// 审批类型-实名认证失败 + /// + public const string RealName_Audit_Failed = "您的实名认证信息认证失败"; + + /// + /// 结束时间必须大于开始时间 + /// + public const string Time_Error = "结束时间必须大于开始时间!"; + + /// + /// 结束时间必须大于当前时间 + /// + public const string EndTime_Error = "结束时间必须大于当前时间!"; + + /// + /// 时间重叠 + /// + public const string Time_Overlap = "请检查开始日期时间和结束日期时间!存在重叠时间!"; + + /// + /// 信息不存在 + /// + public const string Not_Exist = "该信息不存在!"; + + /// + /// 活动类型进行中 + /// + public const string Activity_Ongoing = "该活动类型正在进行中"; + + /// + /// 字典分类编码不能重复 + /// + public const string Dictionary_Code_Exist = "字典分类编码不能重复"; + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Core/App/App.cs b/Znyc.Cloudcar.Admin.Commons/Core/App/App.cs new file mode 100644 index 0000000..4f6e079 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/App/App.cs @@ -0,0 +1,289 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Znyc.Cloudcar.Admin.Commons.Core.App +{ + /// + /// 全局应用类 + /// + public static class App + { + /// + /// 全局配置选项 + /// + public static IConfiguration Configuration; + + /// + /// 应用服务 + /// + public static IServiceCollection Services; + + /// + /// 全局配置构建器 + /// + private static IConfigurationBuilder ConfigurationBuilder; + + /// + /// 私有环境变量,避免重复解析 + /// + private static IWebHostEnvironment _webHostEnvironment; + + /// + /// 应用有效程序集 + /// + public static readonly IEnumerable Assemblies; + + /// + /// 有效程序集类型 + /// + public static readonly IEnumerable EffectiveTypes; + + /// + /// 构造函数 + /// + static App() + { + // 编译配置 + // Configuration =ConfigurationBuilder.Build(); + } + + /// + /// 应用环境,如,是否是开发环境,生产环境等 + /// + public static IWebHostEnvironment WebHostEnvironment => + _webHostEnvironment ??= GetService(); + + /// + /// 服务提供器 + /// + public static IServiceProvider ServiceProvider => + HttpContext?.RequestServices ?? Services.BuildServiceProvider(); + + /// + /// 获取请求上下文 + /// + public static HttpContext HttpContext => HttpContextLocal.Current(); + + /// + /// 获取请求生命周期的服务 + /// + /// + /// + public static TService GetService() + where TService : class + { + return GetService(typeof(TService)) as TService; + } + + /// + /// 获取请求生命周期的服务 + /// + /// + /// + public static object GetService(Type type) + { + return ServiceProvider.GetService(type); + } + + /// + /// 获取请求生命周期的服务 + /// + /// + /// + public static TService GetRequiredService() + where TService : class + { + return GetRequiredService(typeof(TService)) as TService; + } + + /// + /// 获取请求生命周期的服务 + /// + /// + /// + public static object GetRequiredService(Type type) + { + return ServiceProvider.GetRequiredService(type); + } + + /// + /// 获取选项 + /// + /// 强类型选项类 + /// TOptions + public static TOptions GetOptions() + where TOptions : class, new() + { + return GetService>()?.Value; + } + + /// + /// 获取选项 + /// + /// 强类型选项类 + /// TOptions + public static TOptions GetOptionsMonitor() + where TOptions : class, new() + { + return GetService>()?.CurrentValue; + } + + /// + /// 获取选项 + /// + /// 强类型选项类 + /// TOptions + public static TOptions GetOptionsSnapshot() + where TOptions : class, new() + { + return GetService>()?.Value; + } + + #region + + /// + /// 添加配置文件 + /// + /// + /// + internal static void AddConfigureFiles(IConfigurationBuilder config, IHostEnvironment env) + { + // 读取忽略的配置文件 + string[] ignoreConfigurationFiles = config.Build() + .GetSection("IgnoreConfigurationFiles").Get() + ?? Array.Empty(); + + // 加载配置 + AutoAddJsonFiles(config, env, ignoreConfigurationFiles); + AutoAddXmlFiles(config, env, ignoreConfigurationFiles); + + // 存储配置 + ConfigurationBuilder = config; + } + + /// + /// 自动加载自定义 .json 配置文件 + /// + /// + /// + /// + public static void AutoAddJsonFiles(IConfigurationBuilder config, IHostEnvironment env, + string[] ignoreConfigurationFiles) + { + // 获取程序目录下的所有配置文件 + IEnumerable jsonFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.json", SearchOption.TopDirectoryOnly) + .Union( + Directory.GetFiles(Directory.GetCurrentDirectory(), "*.json", SearchOption.TopDirectoryOnly) + ) + .Where(u => !excludeJsons.Contains(Path.GetFileName(u)) && + !ignoreConfigurationFiles.Contains(Path.GetFileName(u)) && + !runtimeJsonSuffixs.Any(j => u.EndsWith(j))); + + if (!jsonFiles.Any()) + { + return; + } + + // 获取环境变量名 + string envName = env.EnvironmentName; + List envFiles = new List(); + + // 自动加载配置文件 + foreach (string jsonFile in jsonFiles) + { + // 处理带环境的配置文件 + if (Path.GetFileNameWithoutExtension(jsonFile).EndsWith($".{envName}")) + { + envFiles.Add(jsonFile); + continue; + } + + config.AddJsonFile(jsonFile, true, true); + } + + // 配置带环境的配置文件 + envFiles.ForEach(u => config.AddJsonFile(u, true, true)); + } + + /// + /// 自动加载自定义 .xml 配置文件 + /// + /// + /// + /// + public static void AutoAddXmlFiles(IConfigurationBuilder config, IHostEnvironment env, + string[] ignoreConfigurationFiles) + { + // 获取程序目录下的所有配置文件,必须以 .config.xml 结尾 + IEnumerable xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml", SearchOption.TopDirectoryOnly) + .Union( + Directory.GetFiles(Directory.GetCurrentDirectory(), "*.xml", SearchOption.TopDirectoryOnly) + ) + .Where(u => !ignoreConfigurationFiles.Contains(Path.GetFileName(u)) && + u.EndsWith(".config.xml", StringComparison.OrdinalIgnoreCase)); + + if (!xmlFiles.Any()) + { + return; + } + + // 获取环境变量名 + string envName = env.EnvironmentName; + List envFiles = new List(); + + // 自动加载配置文件 + foreach (string xmlFile in xmlFiles) + { + // 处理带环境的配置文件 + if (Path.GetFileNameWithoutExtension(xmlFile).EndsWith($".{envName}.config")) + { + envFiles.Add(xmlFile); + continue; + } + + config.AddXmlFile(xmlFile, true, true); + } + + // 配置带环境的配置文件 + envFiles.ForEach(u => config.AddXmlFile(u, true, true)); + } + + /// + /// 默认排除配置项 + /// + private static readonly string[] excludeJsons = + { + "appsettings.json", + "appsettings.Development.json", + "appsettings.Production.json", + "bundleconfig.json", + "bundleconfig.Development.json", + "bundleconfig.Production.json", + "compilerconfig.json", + "compilerconfig.Development.json", + "compilerconfig.Production.json" + }; + + /// + /// 排除运行时 Json 后缀 + /// + private static readonly string[] runtimeJsonSuffixs = + { + "deps.json", + "runtimeconfig.dev.json", + "runtimeconfig.prod.json", + "runtimeconfig.json" + }; + + #endregion + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/App/HostingStartup.cs b/Znyc.Cloudcar.Admin.Commons/Core/App/HostingStartup.cs new file mode 100644 index 0000000..ba55d32 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/App/HostingStartup.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Hosting; +using Znyc.Cloudcar.Admin.Commons.Core.App; + +//通过HostingStartup指定要启动的类型 +[assembly: HostingStartup(typeof(HostingStartup))] + +namespace Znyc.Cloudcar.Admin.Commons.Core.App +{ + /// + /// 配置程序启动时自动注入 + /// + public sealed class HostingStartup : IHostingStartup + { + /// + /// 配置应用启动 + /// + /// + public void Configure(IWebHostBuilder builder) + { + //可以添加配置 + builder.ConfigureAppConfiguration((hostingContext, config) => + { + // 自动装载配置 + App.AddConfigureFiles(config, hostingContext.HostingEnvironment); + }); + + //可以添加ConfigureServices + // 自动注入 AddApp() 服务 + builder.ConfigureServices(services => { }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/App/HttpContextLocal.cs b/Znyc.Cloudcar.Admin.Commons/Core/App/HttpContextLocal.cs new file mode 100644 index 0000000..e5fa8de --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/App/HttpContextLocal.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading; + +namespace Znyc.Cloudcar.Admin.Commons.Core.App +{ + /// + /// 获取 HttpContext 上下文 + /// + public static class HttpContextLocal + { + private static Func _asyncLocalAccessor; + private static Func _holderAccessor; + private static Func _httpContextAccessor; + + /// + /// 获取当前 HttpContext 对象 + /// + /// + public static HttpContext Current() + { + object asyncLocal = (_asyncLocalAccessor ??= CreateAsyncLocalAccessor())(); + if (asyncLocal == null) + { + return null; + } + + object holder = (_holderAccessor ??= CreateHolderAccessor(asyncLocal))(asyncLocal); + if (holder == null) + { + return null; + } + + return (_httpContextAccessor ??= CreateHttpContextAccessor(holder))(holder); + + // 创建异步本地访问器 + static Func CreateAsyncLocalAccessor() + { + FieldInfo fieldInfo = typeof(HttpContextAccessor).GetField("_httpContextCurrent", + BindingFlags.Static | BindingFlags.NonPublic); + MemberExpression field = Expression.Field(null, fieldInfo); + return Expression.Lambda>(field).Compile(); + } + + // 创建常驻 HttpContext 访问器 + static Func CreateHolderAccessor(object asyncLocal) + { + Type holderType = asyncLocal.GetType().GetGenericArguments()[0]; + MethodInfo method = typeof(AsyncLocal<>).MakeGenericType(holderType).GetProperty("Value").GetGetMethod(); + ParameterExpression target = Expression.Parameter(typeof(object)); + UnaryExpression convert = Expression.Convert(target, asyncLocal.GetType()); + MethodCallExpression getValue = Expression.Call(convert, method); + return Expression.Lambda>(getValue, target).Compile(); + } + + // 获取 HttpContext 访问器 + static Func CreateHttpContextAccessor(object holder) + { + ParameterExpression target = Expression.Parameter(typeof(object)); + UnaryExpression convert = Expression.Convert(target, holder.GetType()); + MemberExpression field = Expression.Field(convert, "Context"); + UnaryExpression convertAsResult = Expression.Convert(field, typeof(HttpContext)); + return Expression.Lambda>(convertAsResult, target).Compile(); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Application/BaseApp.cs b/Znyc.Cloudcar.Admin.Commons/Core/Application/BaseApp.cs new file mode 100644 index 0000000..cb4c73a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Application/BaseApp.cs @@ -0,0 +1,461 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.Application +{ + /// + /// 业务层基类,Service用于普通的数据库操作 + /// + /// 实体类型 + /// 实体类型 + /// Service类型 + /// 主键类型 + public class BaseApp + where T : Entity + where TDto : class + where TService : IService + { + /// + /// 用于普通的数据库操作 + /// + /// The service. + protected IService service; + + /// + /// + /// + public BaseApp(IService _service) + { + service = _service; + } + + /// + /// 同步物理删除实体。 + /// + /// 实体 + /// + public virtual bool Delete(T entity) + { + return service.Delete(entity); + } + + /// + /// 同步物理删除实体。 + /// + /// 主键 + /// + public virtual bool Delete(Tkey id) + { + return service.Delete(id); + } + + /// + /// 异步物理删除实体。 + /// + /// 主键 + /// + public virtual Task DeleteAsync(Tkey id) + { + return service.DeleteAsync(id); + } + + /// + /// 异步物理删除实体。 + /// + /// 实体 + /// + public virtual Task DeleteAsync(T entity) + { + return service.DeleteAsync(entity); + } + + /// + /// 按主键批量删除 + /// + /// + /// + public virtual bool DeleteBatch(IList ids) + { + return service.DeleteBatch(ids); + } + + /// + /// 按条件批量删除 + /// + /// 条件 + /// + public virtual bool DeleteBatchWhere(string where) + { + return service.DeleteBatchWhere(where); + } + + /// + /// 软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// 主键ID + /// 操作用户 + /// + public virtual bool DeleteSoft(bool bl, Tkey id, int userId) + { + return service.DeleteSoft(bl, id, userId); + } + + /// + /// 异步软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// 主键ID + /// 操作用户 + /// + public virtual Task DeleteSoftAsync(bool bl, Tkey id, int userId) + { + return service.DeleteSoftAsync(bl, id, userId); + } + + /// + /// 同步查询单个实体。 + /// + /// 主键 + /// + public virtual T Get(Tkey id) + { + return service.Get(id); + } + + /// + /// 同步查询单个实体。 + /// + /// 查询条件 + /// + public virtual T GetWhere(string where) + { + return service.GetWhere(where); + } + + /// + /// 异步查询单个实体。 + /// + /// 查询条件 + /// + public virtual async Task GetWhereAsync(string where) + { + return await service.GetWhereAsync(where); + } + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// + public virtual IEnumerable GetListTopWhere(int top, string where = null) + { + return service.GetListTopWhere(top, where); + } + + /// + /// 同步查询所有实体。 + /// + /// + public virtual IEnumerable GetAll() + { + return service.GetAll(); + } + + /// + /// 异步步查询所有实体。 + /// + /// + public virtual Task> GetAllAsync() + { + return service.GetAllAsync(); + } + + /// + /// + /// + /// + public virtual Task GetAsync(Tkey id) + { + return service.GetAsync(id); + } + + /// + /// 根据查询条件查询数据 + /// + /// 查询条件 + /// + public virtual IEnumerable GetListWhere(string where = null) + { + return service.GetListWhere(where); + } + + /// + /// 异步根据查询条件查询数据 + /// + /// 查询条件 + /// + public virtual async Task> GetListWhereAsync(string where = null) + { + return await service.GetListWhereAsync(where); + } + + /// + /// 同步新增实体。 + /// + /// 实体 + /// + public virtual long Insert(T entity) + { + return service.Insert(entity); + } + + /// + /// 异步步新增实体。 + /// + /// 实体 + /// + public virtual Task InsertAsync(T entity) + { + return service.InsertAsync(entity); + } + + /// + /// 同步更新实体。 + /// + /// 实体 + /// 主键ID + /// + public virtual bool Update(T entity, Tkey id) + { + return service.Update(entity, id); + } + + /// + /// 异步更新实体。 + /// + /// 实体 + /// 主键ID + /// + public virtual Task UpdateAsync(T entity, Tkey id) + { + return service.UpdateAsync(entity, id); + } + + /// + /// 更新某一字段值 + /// + /// 字段 + /// 字段值 + /// 条件,为空更新所有内容 + /// + public virtual bool UpdateTableField(string strField, string fieldValue, string where) + { + return service.UpdateTableField(strField, fieldValue, where); + } + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// + public virtual IEnumerable GetAllByIsIsDeleted(string where = null) + { + return service.GetAllByIsIsDeleted(where); + } + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// + public virtual IEnumerable GetAllByIsNotIsDeleted(string where = null) + { + return service.GetAllByIsNotIsDeleted(where); + } + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// + public virtual IEnumerable GetAllByIsEnabledMark(string where = null) + { + return service.GetAllByIsEnabledMark(where); + } + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// + public virtual IEnumerable GetAllByIsNotEnabledMark(string where = null) + { + return service.GetAllByIsNotEnabledMark(where); + } + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// + public virtual IEnumerable GetAllByIsNotDeleteAndEnabledMark(string where = null) + { + return service.GetAllByIsNotDeleteAndEnabledMark(where); + } + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// + public virtual async Task> GetAllByIsIsDeletedAsync(string where = null) + { + return await service.GetAllByIsIsDeletedAsync(where); + } + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// + public virtual async Task> GetAllByIsNotIsDeletedAsync(string where = null) + { + return await service.GetAllByIsNotIsDeletedAsync(where); + } + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// + public virtual async Task> GetAllByIsEnabledMarkAsync(string where = null) + { + return await service.GetAllByIsEnabledMarkAsync(where); + } + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// + public virtual async Task> GetAllByIsNotEnabledMarkAsync(string where = null) + { + return await service.GetAllByIsNotEnabledMarkAsync(where); + } + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// + public virtual async Task> GetAllByIsNotDeleteAndEnabledMarkAsync(string where = null) + { + return await service.GetAllByIsNotDeleteAndEnabledMarkAsync(where); + } + + /// + /// 设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// + public virtual bool SetEnabledMark(bool bl, Tkey id, int userId = 0) + { + return service.SetEnabledMark(bl, id, userId); + } + + /// + /// 异步设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// + public virtual async Task SetEnabledMarkAsync(bool bl, Tkey id, int userId = 0) + { + return await service.SetEnabledMarkAsync(bl, id, userId); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info) + { + return service.FindWithPager(condition, info); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info, string fieldToSort) + { + return service.FindWithPager(condition, info, fieldToSort); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 是否降序 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info, string fieldToSort, bool desc) + { + return service.FindWithPager(condition, info, fieldToSort, desc); + } + + /// + /// 分页查询,自行封装sql语句 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + public virtual List FindWithPagerSql(string condition, PagerInfo info, string fieldToSort, bool desc) + { + return service.FindWithPagerSql(condition, info, fieldToSort, desc); + } + + /// + /// 分页查询包含用户信息 + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// + public virtual List FindWithPagerRelationUser(string condition, PagerInfo info, string fieldToSort, + bool desc) + { + return service.FindWithPagerRelationUser(condition, info, fieldToSort, desc); + } + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// + public virtual int GetCountByWhere(string condition) + { + return service.GetCountByWhere(condition); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Dapper/DapperDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/Dapper/DapperDbContext.cs new file mode 100644 index 0000000..c1f6818 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Dapper/DapperDbContext.cs @@ -0,0 +1,128 @@ +using System.Data; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; + +namespace Znyc.Cloudcar.Admin.Commons.Core.Dapper +{ + /// + /// 注册的时候 InstancePerLifetimeScope + /// 线程内唯一(也就是单个请求内唯一) + /// + public class DapperDbContext + { + private IDbConnection dbConnection { get; set; } + + /// + /// 事务 + /// + public IDbTransaction DbTransaction { get; set; } + + /// + /// 是否已被提交 + /// + public bool Committed { get; private set; } = true; + + /// + /// 获取的数据库连接 + /// + /// + /// + /// + public IDbConnection GetConnection(bool masterDb = true) where T : class + { + if (dbConnection == null || dbConnection.State == ConnectionState.Closed) + { + dbConnection = DBServerProvider.GetDBConnection(masterDb); + } + + //if (MiniProfiler.Current != null) + //{ + // dbConnection = new StackExchange.Profiling.Data.ProfiledDbConnection((DbConnection)dbConnection, MiniProfiler.Current); + //} + return dbConnection; + } + + /// + /// 开启事务 + /// + public void BeginTransaction() + { + Committed = false; + bool isClosed = dbConnection.State == ConnectionState.Closed; + if (isClosed) + { + dbConnection.Open(); + } + + DbTransaction = dbConnection?.BeginTransaction(); + } + + /// + /// 事务提交 + /// + public void CommitTransaction() + { + DbTransaction?.Commit(); + Committed = true; + Dispose(); + } + + /// + /// 事务回滚 + /// + public void RollBackTransaction() + { + DbTransaction?.Rollback(); + Committed = true; + Dispose(); + } + + #region Dispose实现 + + private bool disposedValue; // 要检测冗余调用 + + /// + /// 释放 + /// + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: 释放托管状态(托管对象)。 + } + + // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 + // TODO: 将大型字段设置为 null。 + + disposedValue = true; + } + + if (dbConnection != null) + { + DbTransaction.Dispose(); + dbConnection.Dispose(); + } + } + + /// + /// 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。 + /// + public void Dispose() + { + // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + Dispose(true); + + DbTransaction?.Dispose(); + if (dbConnection.State == ConnectionState.Open) + { + dbConnection?.Close(); + } + // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。 + // GC.SuppressFinalize(this); + } + + #endregion Dispose实现 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DataManager/AppDBContextAttribute.cs b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/AppDBContextAttribute.cs new file mode 100644 index 0000000..92208e5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/AppDBContextAttribute.cs @@ -0,0 +1,24 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Core.DataManager +{ + /// + /// 数据库连接配置特性 + /// + public class AppDBContextAttribute : Attribute + { + /// + /// 构造函数 + /// + /// + public AppDBContextAttribute(string dbConfigName) + { + DbConfigName = dbConfigName; + } + + /// + /// 数据库配置名称 + /// + public string DbConfigName { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DataManager/DBServerProvider.cs b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/DBServerProvider.cs new file mode 100644 index 0000000..217f7c3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/DBServerProvider.cs @@ -0,0 +1,230 @@ +using Microsoft.Data.Sqlite; +using Microsoft.Extensions.Configuration; +using MySql.Data.MySqlClient; +using Npgsql; +using Oracle.ManagedDataAccess.Client; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Reflection; +using Znyc.Cloudcar.Admin.Commons.Encrypt; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Extensions; + +namespace Znyc.Cloudcar.Admin.Commons.Core.DataManager +{ + /// + /// 数据库服务提供者 + /// + public class DBServerProvider + { + /// + /// 数据库配置名称 + /// + private static string dbConfigName = ""; + + /// + /// 数据库连接 + /// + private static IDbConnection dbConnection; + + #region Dapper Context + + /// + /// 获取默认数据库连接 + /// + /// + public static string GetConnectionString() + { + return GetConnectionString(dbConfigName); + } + + /// + /// + /// + /// + public static string GetConnectionString(string key) + { + return dbConfigName = key ?? dbConfigName; + } + + /// + /// 获取数据库连接 + /// + /// 是否访问主库,默认为是,否则访问从库即只读数据库 + /// + public static IDbConnection GetDBConnection(bool masterDb = true) + { + DbConnectionOptions connectionOptions = GeDbConnectionOptions(masterDb); + string defaultSqlConnectionString = connectionOptions.ConnectionString; + DatabaseType dbType = connectionOptions.DatabaseType; + if (dbType == DatabaseType.SqlServer) + { + dbConnection = new SqlConnection(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.MySql) + { + dbConnection = new MySqlConnection(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.Oracle) + { + dbConnection = new OracleConnection(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.SQLite) + { + dbConnection = new SqliteConnection(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.Npgsql) + { + dbConnection = new NpgsqlConnection(defaultSqlConnectionString); + } + else + { + throw new NotSupportedException("The database is not supported"); + } + + return dbConnection; + } + + /// + /// 获取数据库连接 + /// + /// 是否访问主库,默认为是,否则访问从库即只读数据库 + /// + public static IDbConnection GetDBConnection(bool masterDb = true) + { + DbConnectionOptions connectionOptions = GeDbConnectionOptions(masterDb); + string defaultSqlConnectionString = connectionOptions.ConnectionString; + DatabaseType dbType = connectionOptions.DatabaseType; + if (dbType == DatabaseType.SqlServer) + { + dbConnection = new SqlConnection(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.MySql) + { + dbConnection = new MySqlConnection(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.Oracle) + { + dbConnection = new OracleConnection(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.SQLite) + { + dbConnection = new SqliteConnection(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.Npgsql) + { + dbConnection = new NpgsqlConnection(defaultSqlConnectionString); + } + else + { + throw new NotSupportedException("The database is not supported"); + } + + return dbConnection; + } + + /// + /// 获取数据库连接连接配置 + /// + /// 数据实体 + /// 是否访问主库,默认为是,否则访问从库即只读数据库 + /// + public static DbConnectionOptions GeDbConnectionOptions(bool masterDb = true) + { + dbConfigName = typeof(TEntity).GetCustomAttribute(false)?.DbConfigName ?? + dbConfigName; + bool conStringEncrypt = Configs.GetConfigurationValue("AppSetting", "ConStringEncrypt").ToBool(); + if (string.IsNullOrEmpty(dbConfigName)) + { + dbConfigName = Configs.GetConfigurationValue("AppSetting", "DefaultDataBase"); + } + + Dictionary dictRead = Configs.GetSection("DbConnections:" + dbConfigName + ":ReadDb") + .Get>(); + + DbConnectionOptions dbConnectionOptions = new DbConnectionOptions(); + bool isDBReadWriteSeparate = Configs.GetConfigurationValue("AppSetting", "IsDBReadWriteSeparate").ToBool(); + if (masterDb || !isDBReadWriteSeparate) + { + dbConnectionOptions.ConnectionString = + Configs.GetConfigurationValue("DbConnections:" + dbConfigName + ":MasterDB", "ConnectionString"); + dbConnectionOptions.DatabaseType = (DatabaseType)Enum.Parse(typeof(DatabaseType), + Configs.GetConfigurationValue("DbConnections:" + dbConfigName + ":MasterDB", "DatabaseType")); + } + else + { + dbConnectionOptions = GetReadConn(dictRead); + } + + if (conStringEncrypt) + { + dbConnectionOptions.ConnectionString = DEncrypt.Decrypt(dbConnectionOptions.ConnectionString); + } + + return dbConnectionOptions; + } + + /// + /// 获取数据库连接连接配置 + /// + /// 是否访问主库,默认为是,否则访问从库即只读数据库 + /// + public static DbConnectionOptions GeDbConnectionOptions(bool masterDb = true) + { + bool conStringEncrypt = Configs.GetConfigurationValue("AppSetting", "ConStringEncrypt").ToBool(); + if (string.IsNullOrEmpty(dbConfigName)) + { + dbConfigName = Configs.GetConfigurationValue("AppSetting", "DefaultDataBase"); + } + + Dictionary dictRead = Configs.GetSection("DbConnections:" + dbConfigName + ":ReadDb") + .Get>(); + + DbConnectionOptions dbConnectionOptions = new DbConnectionOptions(); + bool isDBReadWriteSeparate = Configs.GetConfigurationValue("AppSetting", "IsDBReadWriteSeparate").ToBool(); + if (masterDb || !isDBReadWriteSeparate) + { + dbConnectionOptions.ConnectionString = + Configs.GetConfigurationValue("DbConnections:" + dbConfigName + ":MasterDB", "ConnectionString"); + dbConnectionOptions.DatabaseType = (DatabaseType)Enum.Parse(typeof(DatabaseType), + Configs.GetConfigurationValue("DbConnections:" + dbConfigName + ":MasterDB", "DatabaseType")); + } + else + { + dbConnectionOptions = GetReadConn(dictRead); + } + + if (conStringEncrypt) + { + dbConnectionOptions.ConnectionString = DEncrypt.Decrypt(dbConnectionOptions.ConnectionString); + } + + return dbConnectionOptions; + } + + /// + /// 按从库数据库连接的策略进行返回连接对象,实现从库的负载均衡 + /// + /// + /// + private static DbConnectionOptions GetReadConn(Dictionary slaveData) + { + DbConnectionOptions connectionOptions = new DbConnectionOptions(); + string queryDBStrategy = Configs.GetConfigurationValue("AppSetting", "QueryDBStrategy"); + if (queryDBStrategy == "Random") //随机策略 + { + int index = new Random().Next(0, slaveData.Count - 1); + connectionOptions = slaveData[index.ToString()]; + } + else if (queryDBStrategy == "Polling") //轮询策略 + { + } + + return connectionOptions; + } + + #endregion Dapper Context + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DataManager/DbConnectionOptions.cs b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/DbConnectionOptions.cs new file mode 100644 index 0000000..f5e62c2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/DbConnectionOptions.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.Enums; + +namespace Znyc.Cloudcar.Admin.Commons.Core.DataManager +{ + /// + /// 定义主数据和从数据库配置选项 + /// + public class DbConnections + { + /// + /// 主数据库 + /// + public DbConnectionOptions MassterDB { get; set; } + + /// + /// 从数据库 + /// + public List ReadDB { get; set; } + } + + /// + /// 数据库配置选项,定义数据库连接字符串、数据库类型和访问权重 + /// + public class DbConnectionOptions + { + /// + /// 数据库连接字符 + /// + public string ConnectionString { get; set; } + + /// + /// 数据库类型 + /// + public DatabaseType DatabaseType { get; set; } + + /// + /// 访问权重,值越大权重越低 + /// + public int DbLevel { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DataManager/WriteAndReadEnum.cs b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/WriteAndReadEnum.cs new file mode 100644 index 0000000..1aea316 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/WriteAndReadEnum.cs @@ -0,0 +1,23 @@ +namespace Znyc.Cloudcar.Admin.Commons.DataManager +{ + /// + /// 数据库读、写操作枚举 + /// + public enum WriteAndReadEnum + { + /// + /// 写操作 + /// + Write, + + /// + /// 读操作 + /// + Read, + + /// + /// 默认,不区分读写 + /// + Default + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DataManager/YuebonDbOptions.cs b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/YuebonDbOptions.cs new file mode 100644 index 0000000..e15c1f9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/YuebonDbOptions.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.Enums; + +namespace Znyc.Cloudcar.Admin.Commons.Core.DataManager +{ + public class ZnycDbOptions + { + /// + /// 默认数据库类型 + /// + public DatabaseType DefaultDatabaseType { get; set; } = DatabaseType.SqlServer; + + /// + /// 数据库连接配置 + /// + public IDictionary DbConnections { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DataManager/YuebonDbOptionsSetup.cs b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/YuebonDbOptionsSetup.cs new file mode 100644 index 0000000..0ba6b97 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DataManager/YuebonDbOptionsSetup.cs @@ -0,0 +1,64 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Znyc.Cloudcar.Admin.Commons.Core.DataManager +{ + public class ZnycDbOptionsSetup : IConfigureOptions + { + private readonly IConfiguration _configuration; + + public ZnycDbOptionsSetup(IConfiguration configuration) + { + _configuration = configuration; + } + + /// + /// 配置options各属性信息 + /// + /// + public void Configure(ZnycDbOptions options) + { + SetDbConnectionsOptions(options); + } + + private void SetDbConnectionsOptions(ZnycDbOptions options) + { + Dictionary dbConnectionMap = new Dictionary(); + options.DbConnections = dbConnectionMap; + + string dbConfigName = Configs.GetConfigurationValue("AppSetting", "DefaultDataBase"); + IConfiguration section = _configuration.GetSection("DbConnections:" + dbConfigName); + Dictionary dict = section.Get>(); + if (dict == null || dict.Count == 0) + { + string connectionString = _configuration["ConnectionStrings:DefaultDbContext"]; + if (connectionString == null) + { + return; + } + + dbConnectionMap.Add("DefaultDb", new DbConnectionOptions + { + ConnectionString = connectionString, + DatabaseType = options.DefaultDatabaseType + }); + + return; + } + + IGrouping ambiguous = dict.Keys.GroupBy(d => d).FirstOrDefault(d => d.Count() > 1); + if (ambiguous != null) + { + throw new Exception($"数据上下文配置中存在多个配置节点拥有同一个数据库连接名称,存在二义性:{ambiguous.First()}"); + } + + foreach (KeyValuePair db in dict) + { + dbConnectionMap.Add(db.Key, db.Value); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/BaseDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/BaseDbContext.cs new file mode 100644 index 0000000..a884903 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/BaseDbContext.cs @@ -0,0 +1,796 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Attributes; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.DbContextCore +{ + /// + /// DbContext上下文的实现 + /// + public class BaseDbContext : DbContext, IDbContextCore + { + /// + /// + protected BaseDbContext() + { + } + + /// + /// + /// + public BaseDbContext(DbConnectionOptions dbConnectionOptions) + { + this.dbConnectionOptions = dbConnectionOptions; + } + + /// + /// 配置,初始化数据库引擎 + /// + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (dbConnectionOptions == null) + { + dbConnectionOptions = DBServerProvider.GeDbConnectionOptions(); + } + + string defaultSqlConnectionString = dbConnectionOptions.ConnectionString; + + DatabaseType dbType = dbConnectionOptions.DatabaseType; + if (dbType == DatabaseType.SqlServer) + { + optionsBuilder.UseSqlServer(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.MySql) + { + optionsBuilder.UseMySql(defaultSqlConnectionString, new MySqlServerVersion(new Version(5, 7, 1))); + } + else if (dbType == DatabaseType.Oracle) + { + optionsBuilder.UseOracle(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.SQLite) + { + optionsBuilder.UseSqlite(defaultSqlConnectionString); + } + else if (dbType == DatabaseType.Npgsql) + { + optionsBuilder.UseNpgsql(defaultSqlConnectionString); + } + else + { + throw new NotSupportedException("The database is not supported"); + } + //使用查询跟踪行为 + optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); + base.OnConfiguring(optionsBuilder); + } + + /// + /// 模型创建 + /// + /// + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + MappingEntityTypes(modelBuilder); + base.OnModelCreating(modelBuilder); + } + + /// + /// + /// + private void MappingEntityTypes(ModelBuilder modelBuilder) + { + IList assemblies = RuntimeHelper.GetAllZnycAssemblies(); + foreach (Assembly assembly in assemblies) + { + IEnumerable entityTypes = assembly.GetTypes() + .Where(type => !string.IsNullOrWhiteSpace(type.Namespace)) + .Where(type => type.IsClass) + .Where(type => type.BaseType != null) + .Where(type => typeof(Entity).IsAssignableFrom(type) || type.IsSubclassOf(typeof(BaseViewModel))); + + foreach (Type entityType in entityTypes) + { + if (modelBuilder.Model.FindEntityType(entityType) != null || entityType.Name == "Entity" || + entityType.Name == "BaseEntity`1") + { + continue; + } + + TableAttribute table = entityType.GetCustomAttributes().FirstOrDefault(); + modelBuilder.Model.AddEntityType(entityType).SetTableName(table.Name); + + IMutableEntityType ientityTypes = modelBuilder.Model.FindEntityType(entityType); + ShardingTableAttribute attr = entityType.GetCustomAttributes().FirstOrDefault(); + if (attr != null && entityType != null) + { + modelBuilder.Model.FindEntityType(entityType) + .SetTableName($"{entityType.Name}{attr.Splitter}{DateTime.Now.ToString(attr.Suffix)}"); + } + + if (typeof(IDeleteAudited).IsAssignableFrom(typeof(Entity))) + { + modelBuilder.Entity().HasQueryFilter(m => ((IDeleteAudited)m).IsDeleted == false); + } + + if (IsMultiTenant) + { + if (typeof(IMustHaveTenant).IsAssignableFrom(typeof(Entity))) + { + modelBuilder.Entity().HasQueryFilter(m => ((IMustHaveTenant)m).TenantId == ""); + } + } + } + } + } + + #region 基础参数 + + /// + /// 数据库配置名称,可在子类指定不同的配置名称,用于访问不同的数据库 + /// + protected string dbConfigName = ""; + + /// + /// 是否开启多租户 + /// + protected bool isMultiTenant = false; + + /// + /// + protected DbConnectionOptions dbConnectionOptions; + + /// + /// 数据库访问对象的外键约束 + /// + public bool IsMultiTenant => isMultiTenant; + + /// + /// + /// + public DatabaseFacade GetDatabase() + { + return Database; + } + + #endregion 基础参数 + + #region 接口实现 + + /// + /// 新增实体 + /// + /// + /// + /// + public new virtual int Add(T entity) where T : class + { + base.Add(entity); + return SaveChanges(); + } + + /// + /// 新增实体 + /// + /// + /// + /// + public virtual async Task AddAsync(T entity) where T : class + { + await base.AddAsync(entity); + return await SaveChangesAsync(); + } + + /// + /// 批量新增 + /// + /// + /// + /// + public virtual int AddRange(ICollection entities) where T : class + { + base.AddRange(entities); + return SaveChanges(); + } + + /// + /// 批量新增 + /// + /// + /// + /// + public virtual async Task AddRangeAsync(ICollection entities) where T : class + { + await base.AddRangeAsync(entities); + return await SaveChangesAsync(); + } + + /// + /// 统计数量Count() + /// + /// + /// 查询条件 + /// + public virtual int Count(Expression> where = null) where T : class + { + return where == null ? GetDbSet().Count() : GetDbSet().Count(where); + } + + /// + /// 统计数量Count() + /// + /// + /// 查询条件 + /// + public virtual async Task CountAsync(Expression> where = null) where T : class + { + return await (where == null ? GetDbSet().CountAsync() : GetDbSet().CountAsync(where)); + } + + /// + /// 物理删除数据 + /// + /// + /// 主键类型 + /// 主键 + /// + public virtual int Delete(TKey key) where T : Entity + { + T entity = Find(key); + Remove(entity); + return SaveChanges(); + } + + /// + /// 执行Sql,返回影响记录行数 + /// + /// + /// + /// + public virtual int ExecuteSqlWithNonQuery(string sql, params object[] parameters) + { + return Database.ExecuteSqlRaw(sql, parameters); + } + + /// + /// 执行Sql,返回影响记录行数 + /// + /// + /// + /// + public virtual async Task ExecuteSqlWithNonQueryAsync(string sql, params object[] parameters) + { + return await Database.ExecuteSqlRawAsync(sql, parameters); + } + + /// + /// 编辑更新保存实体 + /// + /// + /// + /// + public virtual int Edit(T entity) where T : class + { + base.Update(entity); + base.Entry(entity).State = EntityState.Modified; + return SaveChanges(); + } + + /// + /// 批量更新保存实体 + /// 以添加状态开始跟踪给定的实体和任何其他尚未被跟踪的可访问实体 + /// + /// + /// + /// + public virtual int EditRange(ICollection entities) where T : class + { + GetDbSet().AttachRange(entities.ToArray()); + return SaveChanges(); + } + + /// + /// 是否存在,存在返回true,不存在返回false + /// + /// + /// 查询条件 + /// + public virtual bool Exist(Expression> where = null) where T : class + { + return where == null ? GetDbSet().Any() : GetDbSet().Any(where); + } + + /// + /// 是否存在,存在返回true,不存在返回false + /// + /// + /// + /// + public virtual async Task ExistAsync(Expression> where = null) where T : class + { + return await Task.FromResult(Exist(where)); + } + + /// + /// 根据条件进行查询数据 + /// + /// + /// + /// 查询条件 + /// + public virtual IQueryable FilterWithInclude(Func, IQueryable> include, + Expression> where) where T : class + { + IQueryable result = GetDbSet().AsQueryable(); + if (where != null) + { + result = GetDbSet().Where(@where); + } + + if (include != null) + { + result = include(result); + } + + return result; + } + + /// + /// 根据主键查询实体 + /// + /// + /// + /// + public virtual T Find(object key) where T : class + { + return base.Find(key); + } + + /// + /// 根据主键查询实体 + /// + /// + /// + /// + public virtual T Find(string key) where T : class + { + return base.Find(key); + } + + /// + /// 根据主键查询实体 + /// + /// + /// + /// + /// + public virtual T Find(TKey key) where T : Entity + { + return base.Find(key); + } + + /// + /// 根据主键查询实体 + /// + /// + /// + /// + public virtual async Task FindAsync(object key) where T : class + { + return await base.FindAsync(key); + } + + /// + /// 根据主键查询实体 + /// + /// + /// + /// + /// + public virtual async Task FindAsync(TKey key) where T : Entity + { + return await base.FindAsync(key); + } + + /// + /// 根据条件查询实体,返回实体集合 + /// + /// + /// 查询条件 + /// 是否启用模型跟踪,默认为false不跟踪 + /// + public virtual IQueryable Get(Expression> where = null, bool asNoTracking = false) + where T : class + { + IQueryable query = GetDbSet().AsQueryable(); + if (where != null) + { + query = query.Where(@where); + } + + if (asNoTracking) + { + query = query.AsNoTracking(); + } + + return query; + } + + /// + /// 获取所有实体类型 + /// + /// + public virtual List GetAllEntityTypes() + { + return Model.GetEntityTypes().ToList(); + } + + /// + /// + /// + /// + public virtual DbSet GetDbSet() where T : class + { + if (Model.FindEntityType(typeof(T)) != null) + { + return Set(); + } + + throw new Exception( + $"类型{typeof(T).Name}未在数据库上下文中注册,请先在DbContextOption设置ModelAssemblyName以将所有实体类型注册到数据库上下文中。"); + } + + /// + /// 根据条件查询一个实体, + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + public virtual T GetSingleOrDefault(Expression> where = null) where T : class + { + return where == null ? GetDbSet().SingleOrDefault() : GetDbSet().SingleOrDefault(where); + } + + /// + /// 根据条件查询一个实体, + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + public virtual async Task GetSingleOrDefaultAsync(Expression> where = null) where T : class + { + return await (where == null + ? GetDbSet().SingleOrDefaultAsync() + : GetDbSet().SingleOrDefaultAsync(where)); + } + + /// + /// 根据条件查询一个实体, + /// 异步返回序列的第一个元素,如果序列不包含元素,则返回默认值。 + /// 引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + public virtual async Task GetFirstOrDefaultAsync(Expression> where = null) where T : class + { + return await (where == null + ? GetDbSet().FirstOrDefaultAsync() + : GetDbSet().FirstOrDefaultAsync(where)); + } + + /// + /// 更新指定字段的值 + /// + /// + /// 数据实体 + /// 指定字段 + /// + public virtual int Update(T model, params string[] updateColumns) where T : class + { + if (updateColumns != null && updateColumns.Length > 0) + { + if (Entry(model).State == EntityState.Added || + Entry(model).State == EntityState.Detached) + { + GetDbSet().Attach(model); + } + + foreach (string propertyName in updateColumns) + { + Entry(model).Property(propertyName).IsModified = true; + } + } + else + { + Entry(model).State = EntityState.Modified; + } + + return SaveChanges(); + } + + /// + /// 批量插入 + /// + /// + /// 数据实体集合 + /// 数据库表名称 + public virtual void BulkInsert(IList entities, string destinationTableName = null) where T : class + { + if (!Database.IsSqlServer() && !Database.IsMySql()) + { + throw new NotSupportedException("This method only supports for SQL Server or MySql."); + } + } + + /// + /// Sql查询,并返回实体 + /// + /// 查询对象实体 + /// 返回/输出实体 + /// sql语句 + /// SQL参数 + /// + public virtual List SqlQuery(string sql, params object[] parameters) + where T : class + { + return GetDbSet().FromSqlRaw(sql, parameters).Cast().ToList(); + } + + /// + /// Sql查询,并返回实体 + /// + /// 查询对象实体 + /// 返回/输出实体 + /// sql语句 + /// SQL参数 + /// + public virtual async Task> SqlQueryAsync(string sql, params object[] parameters) + where T : class + where TView : class + { + return await GetDbSet().FromSqlRaw(sql, parameters).Cast().ToListAsync(); + } + + /// + /// 分页查询,SQL语句查询,返回指定输出对象集合 + /// + /// 查询对象实体 + /// 返回/输出实体 + /// sql语句 + /// 排序条件 + /// 当前页 + /// 每页显示数量 + /// + /// + public virtual PageResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, + int pageSize, + Action eachAction = null) where T : class where TView : class + { + throw new NotImplementedException(); + } + + /// + /// 分页查询,SQL语句查询,返回数据实体集合 + /// + /// 查询对象实体 + /// sql语句 + /// 排序条件 + /// 当前页 + /// 每页显示数量 + /// 查询SQL参数 + /// + public virtual PageResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, + params DbParameter[] parameters) where T : class, new() + { + throw new NotImplementedException(); + } + + #region 显式编译的查询,提高查询性能 + + /// + /// 根据主键查询返回一个实体,该方法是显式编译的查询 + /// + /// + /// 主键类型 + /// 主键值 + /// + public T GetByCompileQuery(TKey id) where T : Entity + { + return EF.CompileQuery((DbContext context, TKey id) => context.Set().Find(id))(this, id); + } + + /// + /// 根据主键查询返回一个实体,该方法是显式编译的查询 + /// + /// + /// 主键类型 + /// 主键值 + /// + public Task GetByCompileQueryAsync(TKey id) where T : Entity + { + return EF.CompileAsyncQuery((DbContext context, TKey id) => context.Set().Find(id))(this, id); + } + + /// + /// 根据条件查询返回实体集合,该方法是显式编译的查询 + /// + /// + /// 查询条件 + /// + public IList GetByCompileQuery(Expression> filter) where T : class + { + if (filter == null) + { + filter = m => true; + } + + return EF.CompileQuery((DbContext context) => context.Set().AsNoTracking().Where(filter).ToList())(this); + } + + /// + /// 根据条件查询返回实体集合,该方法是显式编译的查询 + /// + /// + /// 查询条件 + /// + public Task> GetByCompileQueryAsync(Expression> filter) where T : class + { + if (filter == null) + { + filter = m => true; + } + + return EF.CompileAsyncQuery((DbContext context) => + context.Set().AsNoTracking().Where(filter).ToList())(this); + } + + /// + /// 根据条件查询一个实体,该方法是显式编译的查询 + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + public T FirstOrDefaultByCompileQuery(Expression> filter) where T : class + { + if (filter == null) + { + filter = m => true; + } + + return EF.CompileQuery((DbContext context) => context.Set().AsNoTracking().FirstOrDefault(filter))(this); + } + + /// + /// 根据条件查询一个实体,该方法是显式编译的查询 + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + public Task FirstOrDefaultByCompileQueryAsync(Expression> filter) where T : class + { + if (filter == null) + { + filter = m => true; + } + + return EF.CompileAsyncQuery((DbContext context) => + context.Set().AsNoTracking().FirstOrDefault(filter))(this); + } + + /// + /// 根据条件查询一个实体,启用模型跟踪,该方法是显式编译的查询 + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + public T FirstOrDefaultWithTrackingByCompileQuery(Expression> filter) where T : class + { + if (filter == null) + { + filter = m => true; + } + + return EF.CompileQuery((DbContext context) => context.Set().FirstOrDefault(filter))(this); + } + + /// + /// 根据条件查询一个实体,启用模型跟踪,该方法是显式编译的查询 + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + public Task FirstOrDefaultWithTrackingByCompileQueryAsync(Expression> filter) + where T : class + { + if (filter == null) + { + filter = m => true; + } + + return EF.CompileAsyncQuery((DbContext context) => context.Set().FirstOrDefault(filter))(this); + } + + /// + /// 统计数量Count(),该方法是显式编译的查询 + /// + /// + /// 查询条件 + /// + public int CountByCompileQuery(Expression> filter) where T : class + { + if (filter == null) + { + filter = m => true; + } + + return EF.CompileQuery((DbContext context) => context.Set().Count(filter))(this); + } + + /// + /// 统计数量Count(),该方法是显式编译的查询 + /// + /// + /// 查询条件 + /// + public Task CountByCompileQueryAsync(Expression> filter) where T : class + { + if (filter == null) + { + filter = m => true; + } + + return EF.CompileAsyncQuery((DbContext context) => context.Set().Count(filter))(this); + } + + /// + /// 根据sql语句返回DataTable数据 + /// + /// Sql语句 + /// 执行超时时间,默认30毫秒 + /// DbParameter[]参数 + /// + public virtual DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + throw new NotImplementedException(); + } + + /// + /// 根据sql语句返回List数据 + /// + /// Sql语句 + /// 执行超时时间,默认30毫秒 + /// DbParameter[] 参数 + /// + public virtual List GetDataTables(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + throw new NotImplementedException(); + } + + #endregion 显式编译的查询,提高查询性能 + + #endregion 接口实现 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/DbContextFactory.cs b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/DbContextFactory.cs new file mode 100644 index 0000000..bc193f4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/DbContextFactory.cs @@ -0,0 +1,101 @@ +using Microsoft.Extensions.DependencyInjection; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; +using Znyc.Cloudcar.Admin.Commons.DataManager; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Options; + +namespace Znyc.Cloudcar.Admin.Commons.DbContextCore +{ + /// + /// 上下文工厂类 + /// + public class DbContextFactory : IDbContextFactory + { + /// + /// + public static DbContextFactory Instance => new(); + + /// + /// 服务 + /// + public IServiceCollection ServiceCollection { get; set; } + + /// + /// 创建数据库读写上下文 + /// + /// 指定读、写操作 + /// + public BaseDbContext CreateContext(WriteAndReadEnum writeAndRead) + { + DbConnectionOptions dbConnectionOptions = new DbConnectionOptions(); + switch (writeAndRead) + { + case WriteAndReadEnum.Write: + dbConnectionOptions = DBServerProvider.GeDbConnectionOptions(); + break; + + case WriteAndReadEnum.Read: + dbConnectionOptions = DBServerProvider.GeDbConnectionOptions(false); + break; + + default: + dbConnectionOptions = DBServerProvider.GeDbConnectionOptions(); + break; + } + + return new BaseDbContext(dbConnectionOptions); + } + + /// + /// 创建数据库读写上下文 + /// + /// + /// 指定读、写操作 + /// + public BaseDbContext CreateContext(WriteAndReadEnum writeAndRead) + { + DbConnectionOptions dbConnectionOptions = new DbConnectionOptions(); + switch (writeAndRead) + { + case WriteAndReadEnum.Write: + dbConnectionOptions = DBServerProvider.GeDbConnectionOptions(); + break; + + case WriteAndReadEnum.Read: + dbConnectionOptions = DBServerProvider.GeDbConnectionOptions(false); + break; + + default: + dbConnectionOptions = DBServerProvider.GeDbConnectionOptions(); + break; + } + + return new BaseDbContext(dbConnectionOptions); + } + + /// + /// 向服务注入上下文 + /// + /// + /// + public void AddDbContext(DbContextOption option) + where TContext : BaseDbContext, IDbContextCore + { + ServiceCollection.AddDbContext(option); + } + + /// + /// 向服务注入上下文 + /// + /// 上下文接口 + /// 上下文实现类 + /// + public void AddDbContext(DbContextOption option) + where ITContext : IDbContextCore + where TContext : BaseDbContext, ITContext + { + ServiceCollection.AddDbContext(option); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/DefaultModelBuilder.cs b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/DefaultModelBuilder.cs new file mode 100644 index 0000000..42127de --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/DefaultModelBuilder.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Conventions; + +namespace Znyc.Cloudcar.Admin.Commons.EfDbContext +{ + public class DefaultModelBuilder : ModelBuilder + { + public DefaultModelBuilder(ConventionSet conventions) : base(conventions) + { + } + + public override ModelBuilder ApplyConfiguration(IEntityTypeConfiguration configuration) + { + return base.ApplyConfiguration(configuration); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/MySqlDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/MySqlDbContext.cs new file mode 100644 index 0000000..c8f246d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/MySqlDbContext.cs @@ -0,0 +1,124 @@ +using Microsoft.EntityFrameworkCore; +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Data.Common; +using System.IO; +using System.Linq; +using System.Reflection; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.IDbContext; + +namespace Znyc.Cloudcar.Admin.Commons.DbContextCore +{ + /// + /// + public class MySqlDbContext : BaseDbContext, IMySqlDbContext + { + /// + /// 批量插入 + /// + /// + /// 数据实体集合 + /// 数据库表名称 + public override void BulkInsert(IList entities, string destinationTableName = null) + { + if (entities == null || !entities.Any()) + { + return; + } + + if (string.IsNullOrEmpty(destinationTableName)) + { + string mappingTableName = typeof(T).GetCustomAttribute()?.Name; + destinationTableName = string.IsNullOrEmpty(mappingTableName) ? typeof(T).Name : mappingTableName; + } + + MySqlBulkInsert(entities, destinationTableName); + } + + public override DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + return GetDataTables(sql, cmdTimeout, parameters).FirstOrDefault(); + } + + public override List GetDataTables(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + List dts = new List(); + //TODO: connection 不能dispose 或者 用using,否则下次获取connection会报错提示“the connectionstring property has not been initialized。” + DbConnection connection = Database.GetDbConnection(); + if (connection.State != ConnectionState.Open) + { + connection.Open(); + } + + using (MySqlCommand cmd = new MySqlCommand(sql, (MySqlConnection)connection)) + { + cmd.CommandTimeout = cmdTimeout; + if (parameters != null && parameters.Length > 0) + { + cmd.Parameters.AddRange(parameters); + } + + using (MySqlDataAdapter da = new MySqlDataAdapter(cmd)) + { + using (DataSet ds = new DataSet()) + { + da.Fill(ds); + foreach (DataTable table in ds.Tables) + { + dts.Add(table); + } + } + } + } + + connection.Close(); + + return dts; + } + + /// + /// + /// + /// + /// + private void MySqlBulkInsert(IList entities, string destinationTableName) where T : class + { + string tmpDir = Path.Combine(AppContext.BaseDirectory, "Temp"); + if (!Directory.Exists(tmpDir)) + { + Directory.CreateDirectory(tmpDir); + } + + string csvFileName = Path.Combine(tmpDir, $"{DateTime.Now:yyyyMMddHHmmssfff}.csv"); + if (!File.Exists(csvFileName)) + { + File.Create(csvFileName); + } + + string separator = ","; + entities.SaveToCsv(csvFileName, separator); + MySqlConnection conn = (MySqlConnection)Database.GetDbConnection(); + if (conn.State != ConnectionState.Open) + { + conn.Open(); + } + + MySqlBulkLoader bulk = new MySqlBulkLoader(conn) + { + NumberOfLinesToSkip = 0, + TableName = destinationTableName, + FieldTerminator = separator, + FieldQuotationCharacter = '"', + EscapeCharacter = '"', + LineTerminator = "\r\n" + }; + bulk.LoadAsync(); + conn.Close(); + File.Delete(csvFileName); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/OracleDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/OracleDbContext.cs new file mode 100644 index 0000000..c8e3ea5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/OracleDbContext.cs @@ -0,0 +1,69 @@ +using Microsoft.EntityFrameworkCore; +using Oracle.ManagedDataAccess.Client; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.IDbContext; + +namespace Znyc.Cloudcar.Admin.Commons.DbContextCore +{ + /// + /// Oracle上下文 + /// + public class OracleDbContext : BaseDbContext, IOracleDbContext + { + /// + /// + /// + /// + /// + /// + public override DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + return GetDataTables(sql, cmdTimeout, parameters).FirstOrDefault(); + } + + /// + /// + /// + /// + /// + /// + public override List GetDataTables(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + List dts = new List(); + //TODO: connection 不能dispose 或者 用using,否则下次获取connection会报错提示“the connectionstring property has not been initialized。” + DbConnection connection = Database.GetDbConnection(); + if (connection.State != ConnectionState.Open) + { + connection.Open(); + } + + using (OracleCommand cmd = new OracleCommand(sql, (OracleConnection)connection)) + { + cmd.CommandTimeout = cmdTimeout; + if (parameters != null && parameters.Length > 0) + { + cmd.Parameters.AddRange(parameters); + } + + using (OracleDataAdapter da = new OracleDataAdapter(cmd)) + { + using (DataSet ds = new DataSet()) + { + da.Fill(ds); + foreach (DataTable table in ds.Tables) + { + dts.Add(table); + } + } + } + } + + connection.Close(); + + return dts; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/PostgreSQLDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/PostgreSQLDbContext.cs new file mode 100644 index 0000000..d2e80ca --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/PostgreSQLDbContext.cs @@ -0,0 +1,80 @@ +using Microsoft.EntityFrameworkCore; +using Npgsql; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Encrypt; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.IDbContext; + +namespace Znyc.Cloudcar.Admin.Commons.DbContextCore +{ + public class PostgreSQLDbContext : BaseDbContext, IPostgreSQLDbContext + { + public override DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + return GetDataTables(sql, cmdTimeout, parameters).FirstOrDefault(); + } + + public override List GetDataTables(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + List dts = new List(); + //TODO: connection 不能dispose 或者 用using,否则下次获取connection会报错提示“the connectionstring property has not been initialized。” + DbConnection connection = Database.GetDbConnection(); + if (connection.State != ConnectionState.Open) + { + connection.Open(); + } + + using (NpgsqlCommand cmd = new NpgsqlCommand(sql, (NpgsqlConnection)connection)) + { + cmd.CommandTimeout = cmdTimeout; + if (parameters != null && parameters.Length > 0) + { + cmd.Parameters.AddRange(parameters); + } + + using (NpgsqlDataAdapter da = new NpgsqlDataAdapter(cmd)) + { + using (DataSet ds = new DataSet()) + { + da.Fill(ds); + foreach (DataTable table in ds.Tables) + { + dts.Add(table); + } + } + } + } + + connection.Close(); + + return dts; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + string conStringEncrypt = Configs.GetConfigurationValue("AppSetting", "ConStringEncrypt"); + isMultiTenant = Configs.GetConfigurationValue("AppSetting", "IsMultiTenant").ToBool(); + if (string.IsNullOrEmpty(dbConfigName)) + { + dbConfigName = Configs.GetConfigurationValue("AppSetting", "DefaultDataBase"); + } + + string defaultSqlConnectionString = Configs.GetConnectionString(dbConfigName); + if (conStringEncrypt == "true") + { + defaultSqlConnectionString = DEncrypt.Decrypt(defaultSqlConnectionString); + } + + string dbType = dbConfigName.ToUpper(); + if (dbType.Contains("NPGSQL")) + { + optionsBuilder.UseNpgsql(defaultSqlConnectionString); + } + + base.OnConfiguring(optionsBuilder); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/SQLiteDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/SQLiteDbContext.cs new file mode 100644 index 0000000..93013a7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/SQLiteDbContext.cs @@ -0,0 +1,62 @@ +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.IDbContext; + +namespace Znyc.Cloudcar.Admin.Commons.DbContextCore +{ + /// + /// SQLite数据库操作 + /// + public class SQLiteDbContext : BaseDbContext, ISQLiteDbContext + { + /// + /// + /// + /// + /// + /// + public override DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + return GetDataTables(sql, cmdTimeout, parameters).FirstOrDefault(); + } + + /// + /// + /// + /// + /// + /// + public override List GetDataTables(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + List dts = new List(); + //TODO: connection 不能dispose 或者 用using,否则下次获取connection会报错提示“the connectionstring property has not been initialized。” + DbConnection connection = Database.GetDbConnection(); + if (connection.State != ConnectionState.Open) + { + connection.Open(); + } + + using (SqliteCommand cmd = new SqliteCommand(sql, (SqliteConnection)connection)) + { + cmd.CommandTimeout = cmdTimeout; + if (parameters != null && parameters.Length > 0) + { + cmd.Parameters.AddRange(parameters); + } + + using (SqliteDataReader reader = cmd.ExecuteReader()) + { + dts.Add(reader.GetSchemaTable()); + } + } + + connection.Close(); + + return dts; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/SqlServerDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/SqlServerDbContext.cs new file mode 100644 index 0000000..799d697 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/DbContextCore/SqlServerDbContext.cs @@ -0,0 +1,225 @@ +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Reflection; +using Znyc.Cloudcar.Admin.Commons.Extend; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.DbContextCore +{ + /// + /// Sql Server数据库上下文 + /// + public class SqlServerDbContext : BaseDbContext, ISqlServerDbContext + { + /// + /// 批量插入 + /// + /// + /// 数据实体集合 + /// 如果为 null,则使用 TModel 名称作为 destinationTableName + /// + public override void BulkInsert(IList entities, string destinationTableName = null) + { + if (entities == null || !entities.Any()) + { + return; + } + + if (string.IsNullOrEmpty(destinationTableName)) + { + string mappingTableName = typeof(T).GetCustomAttribute()?.Name; + destinationTableName = string.IsNullOrEmpty(mappingTableName) ? typeof(T).Name : mappingTableName; + } + + SqlBulkInsert(entities, destinationTableName); + } + + /// + /// 分页查询,SQL语句查询,返回指定输出对象集合 + /// + /// 查询对象实体 + /// 返回/输出实体 + /// sql语句 + /// 排序条件 + /// 当前页 + /// 每页显示数量 + /// + /// + public override PageResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, + int pageSize, + Action eachAction = null) + { + int total = SqlQuery($"select count(1) from ({sql}) as s").FirstOrDefault(); + List jsonResults = SqlQuery( + $"select * from (select *,row_number() over (order by {string.Join(",", orderBys)}) as RowId from ({sql}) as s) as t where RowId between {pageSize * (pageIndex - 1) + 1} and {pageSize * pageIndex} order by {string.Join(",", orderBys)}") + .ToList(); + if (eachAction != null) + { + jsonResults = jsonResults.Each(eachAction).ToList(); + } + + return new PageResult + { + CurrentPage = pageIndex, + ItemsPerPage = pageSize, + TotalItems = total + }; + } + + /// + /// 分页查询,SQL语句查询,返回数据实体集合 + /// + /// 查询对象实体 + /// sql语句 + /// 排序条件 + /// 当前页 + /// 每页显示数量 + /// 查询SQL参数 + /// + public override PageResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, + int pageSize, + params DbParameter[] parameters) + { + int total = (int)this.ExecuteScalar($"select count(1) from ({sql}) as s"); + List jsonResults = GetDataTable( + $"select * from (select *,row_number() over (order by {string.Join(",", orderBys)}) as RowId from ({sql}) as s) as t where RowId between {pageSize * (pageIndex - 1) + 1} and {pageSize * pageIndex} order by {string.Join(",", orderBys)}") + .ToList(); + return new PageResult + { + CurrentPage = pageIndex, + ItemsPerPage = pageSize, + TotalItems = total, + Items = jsonResults + }; + } + + /// + /// 根据sql语句返回DataTable数据 + /// + /// Sql语句 + /// 执行超时时间,默认30毫秒 + /// DbParameter[]参数 + /// + public override DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + return GetDataTables(sql, cmdTimeout, parameters).FirstOrDefault(); + } + + /// + /// 根据sql语句返回List数据 + /// + /// Sql语句 + /// 执行超时时间,默认30毫秒 + /// DbParameter[] 参数 + /// + public override List GetDataTables(string sql, int cmdTimeout = 30, params DbParameter[] parameters) + { + List dts = new List(); + //TODO: connection 不能dispose 或者 用using,否则下次获取connection会报错提示“the connectionstring property has not been initialized。” + DbConnection connection = Database.GetDbConnection(); + if (connection.State != ConnectionState.Open) + { + connection.Open(); + } + + using (SqlCommand cmd = new SqlCommand(sql, (SqlConnection)connection)) + { + cmd.CommandTimeout = cmdTimeout; + if (parameters != null && parameters.Length > 0) + { + cmd.Parameters.AddRange(parameters); + } + + using (SqlDataAdapter da = new SqlDataAdapter(cmd)) + { + using (DataSet ds = new DataSet()) + { + da.Fill(ds); + foreach (DataTable table in ds.Tables) + { + dts.Add(table); + } + } + } + } + + connection.Close(); + + return dts; + } + + /// + /// 批量插入 + /// + /// + /// 数据实体集合 + /// 如果为 null,则使用 TModel 名称作为 destinationTableName + /// + private void SqlBulkInsert(IList entities, string destinationTableName = null) where T : class + { + using (DataTable dt = entities.ToDataTable()) + { + dt.TableName = destinationTableName; + SqlConnection conn = (SqlConnection)Database.GetDbConnection(); + if (conn.State != ConnectionState.Open) + { + conn.Open(); + } + + using (SqlTransaction tran = conn.BeginTransaction()) + { + try + { + SqlBulkCopy bulk = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran) + { + BatchSize = entities.Count, + DestinationTableName = dt.TableName + }; + GenerateColumnMappings(bulk.ColumnMappings); + bulk.WriteToServerAsync(dt); + tran.Commit(); + } + catch (Exception) + { + tran.Rollback(); + throw; + } + } + + conn.Close(); + } + } + + /// + /// 字段与实体关系映射 + /// + /// + /// + private void GenerateColumnMappings(SqlBulkCopyColumnMappingCollection mappings) + where T : class + { + PropertyInfo[] properties = typeof(T).GetProperties(); + foreach (PropertyInfo property in properties) + { + if (property.GetCustomAttributes().Any()) + { + mappings.Add(new SqlBulkCopyColumnMapping(property.Name, typeof(T).Name + property.Name)); + } + else + { + mappings.Add(new SqlBulkCopyColumnMapping(property.Name, property.Name)); + } + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Dtos/DeletesInputDto.cs b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/DeletesInputDto.cs new file mode 100644 index 0000000..8313f81 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/DeletesInputDto.cs @@ -0,0 +1,16 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Core.Dtos +{ + /// + /// 批量物理删除操作传参 + /// + [Serializable] + public class DeletesInputDto + { + /// + /// 主键Id集合 + /// + public dynamic[] Ids { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Dtos/IInputDto.cs b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/IInputDto.cs new file mode 100644 index 0000000..1b46dd1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/IInputDto.cs @@ -0,0 +1,14 @@ +namespace Znyc.Cloudcar.Admin.Commons.Dtos +{ + /// + /// 定义输入DTO + /// + /// + public interface IInputDto + { + /// + /// 获取或设置 主键,唯一标识 + /// + TKey Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Dtos/IOutputDto.cs b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/IOutputDto.cs new file mode 100644 index 0000000..85d84c5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/IOutputDto.cs @@ -0,0 +1,9 @@ +namespace Znyc.Cloudcar.Admin.Commons.Dtos +{ + /// + /// 定义输出DTO + /// + public interface IOutputDto + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Dtos/InputDtoValidateExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/InputDtoValidateExtensions.cs new file mode 100644 index 0000000..8672ea8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/InputDtoValidateExtensions.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Reflection; +using Znyc.Cloudcar.Admin.Commons.Data; +using Znyc.Cloudcar.Admin.Commons.Extensions; + +namespace Znyc.Cloudcar.Admin.Commons.Dtos +{ + /// + /// 验证扩展 + /// + public static class InputDtoValidateExtensions + { + private static readonly ConcurrentDictionary> + _dict + = new(); + + /// + /// InputDto属性验证 + /// + public static void Validate(this IEnumerable> dtos) + { + IInputDto[] inputDtos = dtos as IInputDto[] ?? dtos.ToArray(); + Check.NotNull(inputDtos, nameof(dtos)); + foreach (IInputDto dto in inputDtos) + { + Validate(dto); + } + } + + /// + /// InputDto属性验证 + /// + public static void Validate(this IInputDto dto) + { + Check.NotNull(dto, nameof(dto)); + Type type = dto.GetType(); + if (!_dict.TryGetValue(type, out ConcurrentDictionary dict)) + { + PropertyInfo[] properties = type.GetProperties(); + dict = new ConcurrentDictionary(); + if (properties.Length == 0) + { + _dict[type] = dict; + return; + } + + foreach (PropertyInfo property in properties) + { + dict[property] = null; + } + + _dict[type] = dict; + } + + foreach (PropertyInfo property in dict.Keys) + { + if (!dict.TryGetValue(property, out ValidationAttribute[] attributes) || attributes == null) + { + attributes = property.GetAttributes(); + dict[property] = attributes; + } + + if (attributes.Length == 0) + { + continue; + } + + object value = property.GetValue(dto); + foreach (ValidationAttribute attribute in attributes) + { + attribute.Validate(value, property.Name); + } + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Dtos/SearchInputDto.cs b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/SearchInputDto.cs new file mode 100644 index 0000000..e3428b2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Dtos/SearchInputDto.cs @@ -0,0 +1,39 @@ +using System; +using System.Runtime.Serialization; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.Dtos +{ + /// + /// 查询条件公共实体类 + /// + [Serializable] + [DataContract] + public class SearchInputDto : PagerInfo + { + /// + /// 关键字查询 + /// + public string Keywords { get; set; } + + /// + /// 编码/代码 + /// + public string EnCode { get; set; } + + /// + /// 排序方式 默认asc + /// + public string Order { get; set; } + + /// + /// 排序字段 默认Id + /// + public string Sort { get; set; } = "ModifiedTime"; + + /// + /// 查询条件 + /// + public T Filter { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IDbContextCore.cs b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IDbContextCore.cs new file mode 100644 index 0000000..f8fb84a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IDbContextCore.cs @@ -0,0 +1,491 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.IDbContext +{ + /// + /// 上下文基础接口 + /// + public interface IDbContextCore : IDisposable + { + /// + /// + /// + DatabaseFacade GetDatabase(); + + #region 删除 + + /// + /// 物理删除数据 + /// + /// + /// 主键类型 + /// 主键 + /// + int Delete(TKey key) where T : Entity; + + /// + /// 根据条件删除一个实体,返回影响记录行数 + /// + /// + /// 条件 + /// + ////int Delete(Expression> @where) where T : class; + /// + /// 根据条件删除一个实体,返回影响记录行数 + /// + /// + /// 条件 + /// + //Task DeleteAsync(Expression> @where) where T : class; + + #endregion 删除 + + /// + /// 执行Sql语句,返回影响记录行数 + /// + /// + /// + /// + int ExecuteSqlWithNonQuery(string sql, params object[] parameters); + + /// + /// 执行Sql,返回影响记录行数 + /// + /// + /// + /// + Task ExecuteSqlWithNonQueryAsync(string sql, params object[] parameters); + + /// + /// 批量插入 + /// + /// + /// 数据实体集合 + /// 数据库表名称,默认为实体名称 + /// + void BulkInsert(IList entities, string destinationTableName = null) + where T : class; + + /// + /// Sql查询,并返回实体集合 + /// + /// 查询对象实体 + /// 返回/输出实体 + /// sql语句 + /// SQL参数 + /// + List SqlQuery(string sql, params object[] parameters) + where T : class; + + /// + /// Sql查询,并返回实体集合 + /// + /// 查询对象实体 + /// 返回/输出实体 + /// sql语句 + /// SQL参数 + /// + Task> SqlQueryAsync(string sql, params object[] parameters) + where T : class + where TView : class; + + /// + /// 分页查询,SQL语句查询,返回指定输出对象集合 + /// + /// 查询对象实体 + /// 返回/输出实体 + /// sql语句 + /// 排序条件 + /// 当前页 + /// 每页显示数量 + /// + /// + PageResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, + Action eachAction = null) + where T : class + where TView : class; + + /// + /// 分页查询,SQL语句查询,返回数据实体集合 + /// + /// 查询对象实体 + /// sql语句 + /// 排序条件 + /// 当前页 + /// 每页显示数量 + /// 查询SQL参数 + /// + PageResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, + params DbParameter[] parameters) where T : class, new(); + + /// + /// 保存到数据库 + /// + /// + int SaveChanges(); + + /// + /// 保存到数据库 + /// + /// 更改成功发送到数据库后是否调用AcceptAllChanges() + /// + int SaveChanges(bool acceptAllChangesOnSuccess); + + /// + /// 保存到数据库 + /// + /// 是否等待任务完成时要观察 + /// + Task SaveChangesAsync(CancellationToken cancellationToken = default); + + /// + /// 保存到数据库 + /// + /// 是否更改成功发送到数据库后是否调用AcceptAllChanges() + /// 是否等待任务完成时要观察 + /// + Task SaveChangesAsync(bool acceptAllChangesOnSuccess, + CancellationToken cancellationToken = default); + + /// + /// 根据sql语句返回DataTable数据 + /// + /// Sql语句 + /// 执行超时时间,默认30毫秒 + /// DbParameter[]参数 + /// + DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters); + + /// + /// 根据sql语句返回List集合数据 + /// + /// Sql语句 + /// 执行超时时间,默认30毫秒 + /// DbParameter[]参数 + /// + List GetDataTables(string sql, int cmdTimeout = 30, params DbParameter[] parameters); + + #region 新增 + + /// + /// 新增实体 + /// + /// + /// + /// + int Add(T entity) where T : class; + + /// + /// 异步新增 + /// + /// + /// + /// + Task AddAsync(T entity) where T : class; + + /// + /// 批量新增 + /// + /// + /// + /// + int AddRange(ICollection entities) where T : class; + + /// + /// 异步批量新增 + /// + /// + /// + /// + Task AddRangeAsync(ICollection entities) where T : class; + + #endregion 新增 + + #region 更新 + + /// + /// 更新保存实体 + /// + /// + /// + /// + int Edit(T entity) where T : class; + + /// + /// 批量更新保存实体 + /// + /// + /// + /// + int EditRange(ICollection entities) where T : class; + + /// + /// 更新指定字段的值 + /// + /// + /// 数据实体 + /// 指定字段 + /// + int Update(T model, params string[] updateColumns) where T : class; + + /// + /// 按条件更新, + /// + /// + /// 条件 + /// + /// + //int Update(Expression> @where, Expression> updateFactory) where T : class; + + /// + /// 按条件更新, + /// + /// + /// 条件 + /// + /// + // Task UpdateAsync(Expression> @where, Expression> updateFactory) + // where T : class; + + #endregion 更新 + + #region 查询 + + /// + /// 根据条件统计数量Count() + /// + /// + /// 查询条件 + /// + int Count(Expression> where = null) where T : class; + + /// + /// 根据条件异步统计数量Count() + /// + /// + /// 查询条件 + /// + Task CountAsync(Expression> where = null) where T : class; + + /// + /// 是否存在,存在返回true,不存在返回false + /// + /// + /// 查询条件 + /// + bool Exist(Expression> where = null) where T : class; + + /// + /// 是否存在,存在返回true,不存在返回false + /// + /// + /// 查询条件 + /// + Task ExistAsync(Expression> where = null) where T : class; + + /// + /// 根据条件进行查询数据 + /// + /// + /// + /// 查询数据 + /// + IQueryable FilterWithInclude(Func, IQueryable> include, Expression> where) + where T : class; + + /// + /// 根据主键查询实体 + /// + /// + /// 主键值 + /// + T Find(object key) where T : class; + + /// + /// 根据主键查询实体 + /// + /// + /// 主键值 + /// + T Find(string key) where T : class; + + /// + /// 根据主键查询实体 + /// + /// + /// 主键类型 + /// 主键值 + /// + T Find(TKey key) where T : Entity; + + /// + /// 根据主键查询实体 + /// + /// + /// 主键值 + /// + Task FindAsync(object key) where T : class; + + /// + /// 根据主键查询实体 + /// + /// + /// 主键类型 + /// 主键值 + /// + Task FindAsync(TKey key) where T : Entity; + + /// + /// 根据条件查询实体,返回实体集合 + /// + /// + /// 查询条件 + /// 是否启用模型跟踪,默认为false不跟踪 + /// + IQueryable Get(Expression> where = null, bool asNoTracking = false) where T : class; + + /// + /// 获取所有实体类型 + /// + /// + List GetAllEntityTypes(); + + /// + /// + /// + /// + DbSet GetDbSet() where T : class; + + /// + /// 根据条件查询一个实体, + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + T GetSingleOrDefault(Expression> where = null) where T : class; + + /// + /// 根据条件查询一个实体, + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + Task GetSingleOrDefaultAsync(Expression> where = null) where T : class; + + /// + /// 根据条件查询一个实体, + /// 异步返回序列的第一个元素,如果序列不包含元素,则返回默认值。 + /// 引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + Task GetFirstOrDefaultAsync(Expression> where = null) where T : class; + + #endregion 查询 + + #region 显式编译的查询,提高查询性能 + + /// + /// 根据主键查询返回一个实体,该方法是显式编译的查询 + /// + /// + /// 主键类型 + /// 主键值 + /// + T GetByCompileQuery(TKey id) where T : Entity; + + /// + /// 根据主键查询返回一个实体,该方法是显式编译的查询 + /// + /// + /// 主键类型 + /// 主键值 + /// + Task GetByCompileQueryAsync(TKey id) where T : Entity; + + /// + /// 根据条件查询返回实体集合,该方法是显式编译的查询 + /// + /// + /// 查询条件 + /// + IList GetByCompileQuery(Expression> filter) where T : class; + + /// + /// 根据条件查询返回实体集合,该方法是显式编译的查询 + /// + /// + /// 查询条件 + /// + Task> GetByCompileQueryAsync(Expression> filter) where T : class; + + /// + /// 根据条件查询一个实体,该方法是显式编译的查询 + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + T FirstOrDefaultByCompileQuery(Expression> filter) where T : class; + + /// + /// 根据条件查询一个实体,该方法是显式编译的查询 + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + Task FirstOrDefaultByCompileQueryAsync(Expression> filter) where T : class; + + /// + /// 根据条件查询一个实体,启用模型跟踪,该方法是显式编译的查询 + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + T FirstOrDefaultWithTrackingByCompileQuery(Expression> filter) where T : class; + + /// + /// 根据条件查询一个实体,启用模型跟踪,该方法是显式编译的查询 + /// 检验序列中是否包含有元素。引用类型的默认值default(T)为null,表示在序列中没有找到元素。 + /// + /// + /// 查询条件 + /// + Task FirstOrDefaultWithTrackingByCompileQueryAsync(Expression> filter) where T : class; + + /// + /// 统计数量Count(),该方法是显式编译的查询 + /// + /// + /// 查询条件 + /// + int CountByCompileQuery(Expression> filter) where T : class; + + /// + /// 统计数量Count(),该方法是显式编译的查询 + /// + /// + /// 查询条件 + /// + Task CountByCompileQueryAsync(Expression> filter) where T : class; + + #endregion 显式编译的查询,提高查询性能 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IDbContextFactory.cs b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IDbContextFactory.cs new file mode 100644 index 0000000..f1f2baf --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IDbContextFactory.cs @@ -0,0 +1,24 @@ +using Znyc.Cloudcar.Admin.Commons.DataManager; +using Znyc.Cloudcar.Admin.Commons.DbContextCore; + +namespace Znyc.Cloudcar.Admin.Commons.IDbContext +{ + /// + /// + public interface IDbContextFactory + { + /// + /// + /// 指定读、写操作 + /// + BaseDbContext CreateContext(WriteAndReadEnum writeAndRead); + + /// + /// 创建数据库读写上下文 + /// + /// + /// 指定读、写操作 + /// + BaseDbContext CreateContext(WriteAndReadEnum writeAndRead); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IMySqlDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IMySqlDbContext.cs new file mode 100644 index 0000000..ba99efb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IMySqlDbContext.cs @@ -0,0 +1,6 @@ +namespace Znyc.Cloudcar.Admin.Commons.IDbContext +{ + public interface IMySqlDbContext : IDbContextCore + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IOracleDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IOracleDbContext.cs new file mode 100644 index 0000000..bb5fed3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IOracleDbContext.cs @@ -0,0 +1,6 @@ +namespace Znyc.Cloudcar.Admin.Commons.IDbContext +{ + public interface IOracleDbContext : IDbContextCore + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IPostgreSQLDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IPostgreSQLDbContext.cs new file mode 100644 index 0000000..5554bbc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/IPostgreSQLDbContext.cs @@ -0,0 +1,6 @@ +namespace Znyc.Cloudcar.Admin.Commons.IDbContext +{ + public interface IPostgreSQLDbContext : IDbContextCore + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/ISQLiteDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/ISQLiteDbContext.cs new file mode 100644 index 0000000..cbe6fee --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/ISQLiteDbContext.cs @@ -0,0 +1,6 @@ +namespace Znyc.Cloudcar.Admin.Commons.IDbContext +{ + public interface ISQLiteDbContext : IDbContextCore + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/ISqlServerDbContext.cs b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/ISqlServerDbContext.cs new file mode 100644 index 0000000..eafc5fc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IDbContext/ISqlServerDbContext.cs @@ -0,0 +1,6 @@ +namespace Znyc.Cloudcar.Admin.Commons.IDbContext +{ + public interface ISqlServerDbContext : IDbContextCore + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IRepositories/IReadOnlyRepository.cs b/Znyc.Cloudcar.Admin.Commons/Core/IRepositories/IReadOnlyRepository.cs new file mode 100644 index 0000000..1f21046 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IRepositories/IReadOnlyRepository.cs @@ -0,0 +1,14 @@ +using System; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Commons.Core.IRepositories +{ + /// + /// 只读仓储接口,提供查询相关方法 + /// + /// + /// + public interface IReadOnlyRepository : IDisposable where T : Entity + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IRepositories/IRepository.cs b/Znyc.Cloudcar.Admin.Commons/Core/IRepositories/IRepository.cs new file mode 100644 index 0000000..51e291f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IRepositories/IRepository.cs @@ -0,0 +1,833 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.IRepositories +{ + /// + /// 定义泛型接口,实体仓储模型的数据标准操作 + /// + /// 实体类型 + /// 主键类型 + public interface IRepository : IDisposable where T : Entity + { + #region dapper 操作 + + #region 新增 + + /// + /// 同步新增实体。 + /// + /// 实体 + /// 事务对象 + /// + long Insert(T entity, IDbTransaction trans = null); + + /// + /// 异步新增实体。 + /// + /// 实体 + /// 事务对象 + /// + Task InsertAsync(T entity, IDbTransaction trans = null); + + /// + /// 异步新增实体返回主键 + /// + /// + /// + /// + Task InsertReturnPrimaryKeyAsync(T entity, IDbTransaction trans = null); + + /// + /// 同步批量新增实体。 + /// + /// 实体集合 + /// + void Insert(List entities); + + #endregion 新增 + + #region 删除 + + /// + /// 同步物理删除实体。 + /// + /// 实体 + /// + bool Delete(T entity); + + /// + /// 异步物理删除实体。 + /// + /// 实体 + /// 事务对象 + /// + Task DeleteAsync(T entity, IDbTransaction trans = null); + + /// + /// 同步物理删除实体。 + /// + /// 主键 + /// 事务对象 + /// + bool Delete(TKey primaryKey, IDbTransaction trans = null); + + /// + /// 异步物理删除实体。 + /// + /// 主键 + /// 事务对象 + /// + Task DeleteAsync(TKey primaryKey, IDbTransaction trans = null); + + /// + /// 按主键批量删除 + /// + /// + /// 事务对象 + /// + bool DeleteBatch(IList ids, IDbTransaction trans = null); + + /// + /// 按条件批量删除 + /// + /// 条件 + /// 事务对象 + /// + bool DeleteBatchWhere(string where, IDbTransaction trans = null); + + /// + /// 异步按条件批量删除 + /// + /// 条件 + /// 事务对象 + /// + Task DeleteBatchWhereAsync(string where, IDbTransaction trans = null); + + #endregion 删除 + + #region 更新操作 + + #region 更新实体或批量更新 + + /// + /// 同步更新实体。 + /// + /// 实体 + /// 主键ID + /// 事务对象 + /// + bool Update(T entity, TKey primaryKey, IDbTransaction trans = null); + + /// + /// 异步更新实体。 + /// + /// 实体 + /// 主键ID + /// 事务对象 + /// + Task UpdateAsync(T entity, TKey primaryKey, IDbTransaction trans = null); + + #endregion 更新实体或批量更新 + + #region 更新某一字段值 + + /// + /// 更新某一字段值 + /// + /// 字段 + /// 字段值 + /// 条件,为空更新所有内容 + /// + /// + bool UpdateTableField(string strField, string fieldValue, string where, IDbTransaction trans = null); + + /// + /// 异步更新某一字段值 + /// + /// 字段 + /// 字段值 + /// 条件,为空更新所有内容 + /// + /// + Task UpdateTableFieldAsync(string strField, string fieldValue, string where, IDbTransaction trans = null); + + /// + /// 更新某一字段值,字段值为数字 + /// + /// 字段 + /// 字段值数字 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + bool UpdateTableField(string strField, int fieldValue, string where, IDbTransaction trans = null); + + /// + /// 更新某一字段值,字段值为数字 + /// + /// 字段 + /// 字段值数字 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + Task UpdateTableFieldAsync(string strField, int fieldValue, string where, IDbTransaction trans = null); + + #endregion 更新某一字段值 + + #region 逻辑删除 + + /// + /// 同步软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// + bool DeleteSoft(bool bl, TKey primaryKey, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// c + /// 主键ID + /// 操作用户 + /// 事务对象 + /// + Task DeleteSoftAsync(bool bl, TKey primaryKey, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步批量软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// c + /// 条件 + /// 操作用户 + /// 事务对象 + /// + Task DeleteSoftBatchAsync(bool bl, string where, long userId = 0, IDbTransaction trans = null); + + #endregion 逻辑删除 + + #region 数据有效性 + + /// + /// 设置数据有效性,将IsEnabled设置为1-有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// + bool SetEnabledMark(bool bl, TKey primaryKey, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// + Task SetEnabledMarkAsync(bool bl, TKey primaryKey, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步按条件设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 条件 + /// 操作用户 + /// 事务对象 + /// + Task SetEnabledMarkByWhereAsync(bool bl, string where, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步按条件设置数据的状态,将State设置为0:审核中,1:正常,-1:停用,-2:停用 + /// + /// 0:审核中,1:正常,-1:停用,-2:停用 + /// 条件 + /// 操作用户 + /// 事务对象 + /// + Task SetStatusByWhereAsync(int bl, string where, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步按条件设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 条件 + /// 参数 + /// 操作用户 + /// 事务对象 + /// + Task SetEnabledMarkByWhereAsync(bool bl, string where, object paramparameters = null, long userId = 0, + IDbTransaction trans = null); + + #endregion 数据有效性 + + #endregion 更新操作 + + #region 查询 + + #region 单个实体 + + /// + /// 同步查询单个实体。 + /// + /// 主键 + /// + T Get(TKey primaryKey); + + /// + /// 异步查询单个实体。 + /// + /// 主键 + /// + Task GetAsync(TKey primaryKey); + + /// + /// 同步查询单个实体。 + /// + /// 查询条件 + /// + T GetWhere(string where); + + /// + /// 异步查询单个实体。 + /// + /// 查询条件 + /// + Task GetWhereAsync(string where); + + #endregion 单个实体 + + /// + /// 获取所有数据,谨慎使用 + /// + /// 事务对象 + /// + IEnumerable GetAll(IDbTransaction trans = null); + + /// + /// 获取所有数据,谨慎使用 + /// + /// 事务对象 + /// + Task> GetAllAsync(IDbTransaction trans = null); + + /// + /// 根据查询条件查询数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetListWhere(string where = null, IDbTransaction trans = null); + + /// + /// 异步根据查询条件查询数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetListWhereAsync(string where = null, IDbTransaction trans = null); + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetListTopWhere(int top, string where = null, IDbTransaction trans = null); + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// 事务对象 + /// + Task> GetListTopWhereAsync(int top, string where = null, IDbTransaction trans = null); + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsIsDeleted(string where = null, IDbTransaction trans = null); + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsNotIsDeleted(string where = null, IDbTransaction tran = null); + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsEnabledMark(string where = null, IDbTransaction tran = null); + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsNotEnabledMark(string where = null, IDbTransaction tran = null); + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsNotDeleteAndEnabledMark(string where = null, IDbTransaction tran = null); + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsIsDeletedAsync(string where = null, IDbTransaction tran = null); + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsNotIsDeletedAsync(string where = null, IDbTransaction tran = null); + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsEnabledMarkAsync(string where = null, IDbTransaction tran = null); + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsNotEnabledMarkAsync(string where = null, IDbTransaction tran = null); + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsNotDeleteAndEnabledMarkAsync(string where = null, IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 是否降序 + /// 事务对象 + /// 指定对象的集合 + Task> FindWithPagerAsync(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 是否降序 + /// 事务对象 + /// 指定对象的集合 + List FindWithPager(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 事务对象 + /// 指定对象的集合 + Task> FindWithPagerAsync(string condition, PagerInfo info, string fieldToSort, + IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 事务对象 + /// 指定对象的集合 + List FindWithPager(string condition, PagerInfo info, string fieldToSort, IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 事务对象 + /// 指定对象的集合 + Task> FindWithPagerAsync(string condition, PagerInfo info, IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 事务对象 + /// 指定对象的集合 + List FindWithPager(string condition, PagerInfo info, IDbTransaction trans = null); + + /// + /// 分页查询,自行封装sql语句(仅支持sql server) + /// 非常复杂的查询,可在具体业务模块重写该方法 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + /// + Task> FindWithPagerSqlAsync(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 分页查询,自行封装sql语句(仅支持sql server) + /// 非常复杂的查询,可在具体业务模块重写该方法 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + /// + List FindWithPagerSql(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 分页查询包含用户信息(仅支持sql server) + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// 事务 + /// + Task> FindWithPagerRelationUserAsync(string condition, PagerInfo info, string fieldToSort, + bool desc, IDbTransaction trans = null); + + /// + /// 分页查询包含用户信息(仅支持sql server) + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// 事务 + /// + List FindWithPagerRelationUser(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// 统计字段名称 + /// + int GetCountByWhere(string condition, string fieldName = "*"); + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// 统计字段名称 + /// + Task GetCountByWhereAsync(string condition, string fieldName = "*"); + + /// + /// / + /// + /// + Task GetCount(); + + /// + /// 根据条件查询获取某个字段的最大值 + /// + /// 字段 + /// 条件 + /// 事务 + /// 返回字段的最大值 + Task GetMaxValueByFieldAsync(string strField, string where, IDbTransaction trans = null); + + /// + /// 根据条件统计某个字段之和,sum(字段) + /// + /// 字段 + /// 条件 + /// 事务 + /// 返回字段求和后的值 + Task GetSumValueByFieldAsync(string strField, string where, IDbTransaction trans = null); + + #endregion 查询 + + #region 多表批量操作,支持事务 + + /// + /// 多表操作--事务 + /// + /// 事务 + /// 超时 + /// + Task> + ExecuteTransactionAsync(List> trans, int? commandTimeout = null); + + /// + /// 多表操作--事务 + /// + /// 事务 + /// 超时 + /// + Tuple ExecuteTransaction(List> trans, int? commandTimeout = null); + + #endregion 多表批量操作,支持事务 + + #endregion dapper 操作 + + #region EF 操作 + + #region Insert 新增 + + /// + /// 新增实体 + /// + /// + /// + int Add(T entity); + + /// + /// 新增实体 + /// + /// + /// + Task AddAsync(T entity); + + /// + /// 批量新增,数量量较多是推荐使用BulkInsert() + /// + /// + /// + int AddRange(ICollection entities); + + /// + /// 批量新增,数量量较多是推荐使用BulkInsert() + /// + /// + /// + Task AddRangeAsync(ICollection entities); + + /// + /// 批量新增SqlBulk方式,效率最高 + /// + /// + /// + void BulkInsert(IList entities, string destinationTableName = null); + + /// + /// 执行新增的sql语句 + /// + /// 新增Sql语句 + /// + int AddBySql(string sql); + + #endregion Insert 新增 + + #region Delete 删除 + + /// + /// 根据主键删除数据 + /// + /// + /// + int Delete(TKey key); + + /// + /// 执行删除数据Sql语句 + /// + /// 删除的Sql语句 + /// + int DeleteBySql(string sql); + + #endregion Delete 删除 + + #region Update 更新 + + /// + /// 更新一个实体数据 + /// + /// + /// + int Edit(T entity); + + /// + /// 批量更新数据实体 + /// + /// + /// + int EditRange(ICollection entities); + + /// + /// 更新指定字段的值 + /// + /// + /// 数据实体 + /// 指定字段 + /// + int Update(T model, params string[] updateColumns); + + /// + /// 执行更新数据的Sql语句 + /// + /// 更新数据的Sql语句 + /// + int UpdateBySql(string sql); + + #endregion Update 更新 + + #region Query 查询 + + /// + /// 根据条件统计数量Count() + /// + /// + /// + int Count(Expression> where = null); + + /// + /// 根据条件统计数量Count() + /// + /// + /// + Task CountAsync(Expression> where = null); + + /// + /// 是否存在,存在返回true,不存在返回false + /// + /// + /// + bool Exist(Expression> where = null); + + /// + /// 是否存在,存在返回true,不存在返回false + /// + /// + /// + Task ExistAsync(Expression> where = null); + + /// + /// 根据主键获取实体。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + T GetSingle(TKey key); + + /// + /// 根据主键获取实体。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + Task GetSingleAsync(TKey key); + + /// + /// 获取单个实体。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + T GetSingleOrDefault(Expression> where = null); + + /// + /// 获取单个实体。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + Task GetSingleOrDefaultAsync(Expression> where = null); + + /// + /// 获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + IList Get(Expression> where = null); + + /// + /// 获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + Task> GetAsync(Expression> where = null); + + /// + /// 分页获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// 查询条件 + /// 分页信息 + /// 排序方式 + /// 排序字段 + /// + IEnumerable GetByPagination(Expression> where, PagerInfo pagerInfo, bool asc = true, + params Expression>[] orderby); + + /// + /// sql语句查询数据集 + /// + /// + /// + List GetBySql(string sql); + + /// + /// sql语句查询数据集,返回输出Dto实体 + /// + /// 返回结果对象 + /// + /// + List GetViews(string sql); + + /// + /// 查询视图 + /// + /// 返回结果对象 + /// 视图名称 + /// 查询条件 + /// + List GetViews(string viewName, Func where); + + #endregion Query 查询 + + #endregion EF 操作 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/IServices/IService.cs b/Znyc.Cloudcar.Admin.Commons/Core/IServices/IService.cs new file mode 100644 index 0000000..91da60f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/IServices/IService.cs @@ -0,0 +1,629 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.IServices +{ + /// + /// 泛型应用服务接口 + /// + /// + /// + /// + public interface IService : IDisposable where T : Entity + where TODto : class + { + /// + /// 同步查询单个实体。 + /// + /// 主键 + /// + T Get(TKey id); + + /// + /// 同步查询单个实体。 + /// + /// 主键 + /// + TODto GetOutDto(TKey id); + + /// + /// 异步查询单个实体。 + /// + /// 主键 + /// + Task GetOutDtoAsync(TKey id); + + /// + /// 异步查询单个实体。 + /// + /// 主键 + /// + Task GetAsync(TKey id); + + /// + /// 同步查询单个实体。 + /// + /// 查询条件 + /// 事务对象 + /// + T GetWhere(string where, IDbTransaction trans = null); + + /// + /// 同步查询单个实体。 + /// + /// 查询条件 + /// 事务对象 + /// + TODto GetOutDtoWhere(string where, IDbTransaction trans = null); + + /// + /// 异步查询单个实体。 + /// + /// 查询条件 + /// 事务对象 + /// + Task GetWhereAsync(string where, IDbTransaction trans = null); + + /// + /// 异步查询单个实体。 + /// + /// 查询条件 + /// 事务对象 + /// + Task GetOutDtoWhereAsync(string where, IDbTransaction trans = null); + + /// + /// 同步查询所有实体。 + /// + /// 事务对象 + /// + IEnumerable GetAll(IDbTransaction trans = null); + + /// + /// 异步查询所有实体。 + /// + /// 事务对象 + /// + Task> GetAllAsync(IDbTransaction trans = null); + + /// + /// 根据查询条件查询数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetListWhere(string where = null, IDbTransaction trans = null); + + /// + /// 异步根据查询条件查询数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetListWhereAsync(string where = null, IDbTransaction trans = null); + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetListTopWhere(int top, string where = null, IDbTransaction trans = null); + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// 事务对象 + /// + Task> GetListTopWhereAsync(int top, string where = null, IDbTransaction trans = null); + + /// + /// 同步新增实体。 + /// + /// 实体 + /// 事务对象 + /// + long Insert(T entity, IDbTransaction trans = null); + + /// + /// 异步新增实体。 + /// + /// 实体 + /// 事务对象 + /// + Task InsertAsync(T entity, IDbTransaction trans = null); + + /// + /// 异步新增实体返回主键 + /// + /// + /// + /// + Task InsertReturnPrimaryKeyAsync(T entity, IDbTransaction trans = null); + + /// + /// 同步批量新增实体。 + /// + /// 实体集合 + /// + void Insert(List entities); + + /// + /// 同步更新实体。 + /// + /// 实体 + /// 主键ID + /// 事务对象 + /// + bool Update(T entity, TKey id, IDbTransaction trans = null); + + /// + /// 异步更新实体。 + /// + /// 实体 + /// 主键ID + /// 事务对象 + /// + Task UpdateAsync(T entity, TKey id, IDbTransaction trans = null); + + /// + /// 更新某一字段值 + /// + /// 字段 + /// 字段值 + /// 条件,为空更新所有内容 + /// + /// + bool UpdateTableField(string strField, string fieldValue, string where, IDbTransaction trans = null); + + /// + /// 异步更新某一字段值 + /// + /// 字段 + /// 字段值 + /// 条件,为空更新所有内容 + /// + /// + Task UpdateTableFieldAsync(string strField, string fieldValue, string where, IDbTransaction trans = null); + + /// + /// 更新某一字段值,字段值为数字 + /// + /// 字段 + /// 字段值数字 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + bool UpdateTableField(string strField, int fieldValue, string where, IDbTransaction trans = null); + + /// + /// 更新某一字段值,字段值为数字 + /// + /// 字段 + /// 字段值数字 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + Task UpdateTableFieldAsync(string strField, int fieldValue, string where, IDbTransaction trans = null); + + /// + /// 同步物理删除实体。 + /// + /// 实体 + /// 事务对象 + /// + bool Delete(T entity, IDbTransaction trans = null); + + /// + /// 异步物理删除实体。 + /// + /// 实体 + /// 事务对象 + /// + Task DeleteAsync(T entity, IDbTransaction trans = null); + + /// + /// 同步物理删除实体。 + /// + /// 主键 + /// 事务对象 + /// + bool Delete(TKey id, IDbTransaction trans = null); + + /// + /// 异步物理删除实体。 + /// + /// 主键 + /// 事务对象 + /// + Task DeleteAsync(TKey id, IDbTransaction trans = null); + + /// + /// 按主键批量删除 + /// + /// + /// 事务对象 + /// + bool DeleteBatch(IList ids, IDbTransaction trans = null); + + /// + /// 按条件批量删除 + /// + /// 条件 + /// 事务对象 + /// + bool DeleteBatchWhere(string where, IDbTransaction trans = null); + + /// + /// 异步按条件批量删除 + /// + /// 条件 + /// 事务对象 + /// + Task DeleteBatchWhereAsync(string where, IDbTransaction trans = null); + + /// + /// 同步软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// + bool DeleteSoft(bool bl, TKey id, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// c + /// 主键ID + /// 操作用户 + /// 事务对象 + /// + Task DeleteSoftAsync(bool bl, TKey id, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步批量软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// c + /// 条件 + /// 操作用户 + /// 事务对象 + /// + Task DeleteSoftBatchAsync(bool bl, string where, long userId = 0, IDbTransaction trans = null); + + /// + /// 设置数据有效性,将IsEnabled设置为1-有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// + bool SetEnabledMark(bool bl, TKey id, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// + Task SetEnabledMarkAsync(bool bl, TKey id, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步按条件设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 条件 + /// 操作用户 + /// 事务对象 + /// + Task SetEnabledMarkByWhereAsync(bool bl, string where, long userId = 0, IDbTransaction trans = null); + + /// + /// 异步按条件设置数据的状态,将State设置为0:审核中,1:正常,-1:停用,-2:停用 + /// + /// 0:审核中,1:正常,-1:停用,-2:停用 + /// 条件 + /// 操作用户 + /// 事务对象 + /// + Task SetStatusByWhereAsync(int bl, string where, long userId = 0, + IDbTransaction trans = null); + + + /// + /// 异步按条件设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 条件 + /// + /// 操作用户 + /// 事务对象 + /// + Task SetEnabledMarkByWhereAsync(bool bl, string where, object paramparameters = null, long userId = 0, + IDbTransaction trans = null); + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsIsDeleted(string where = null, IDbTransaction trans = null); + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsNotIsDeleted(string where = null, IDbTransaction tran = null); + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsEnabledMark(string where = null, IDbTransaction tran = null); + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsNotEnabledMark(string where = null, IDbTransaction tran = null); + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// 事务对象 + /// + IEnumerable GetAllByIsNotDeleteAndEnabledMark(string where = null, IDbTransaction tran = null); + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsIsDeletedAsync(string where = null, IDbTransaction tran = null); + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsNotIsDeletedAsync(string where = null, IDbTransaction tran = null); + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsEnabledMarkAsync(string where = null, IDbTransaction tran = null); + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsNotEnabledMarkAsync(string where = null, IDbTransaction tran = null); + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// 事务对象 + /// + Task> GetAllByIsNotDeleteAndEnabledMarkAsync(string where = null, IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 是否降序 + /// 事务对象 + /// 指定对象的集合 + Task> FindWithPagerAsync(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 是否降序 + /// 事务对象 + /// 指定对象的集合 + List FindWithPager(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 事务对象 + /// 指定对象的集合 + Task> FindWithPagerAsync(string condition, PagerInfo info, string fieldToSort, + IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 事务对象 + /// 指定对象的集合 + List FindWithPager(string condition, PagerInfo info, string fieldToSort, IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 事务对象 + /// 指定对象的集合 + Task> FindWithPagerAsync(string condition, PagerInfo info, IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 事务对象 + /// 指定对象的集合 + List FindWithPager(string condition, PagerInfo info, IDbTransaction trans = null); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 指定对象的集合 + PageResult FindWithPager(SearchInputDto search); + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 指定对象的集合 + Task> FindWithPagerAsync(SearchInputDto search); + + /// + /// 分页查询,自行封装sql语句(仅支持sql server) + /// 非常复杂的查询,可在具体业务模块重写该方法 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + /// + Task> FindWithPagerSqlAsync(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 分页查询,自行封装sql语句(仅支持sql server) + /// 非常复杂的查询,可在具体业务模块重写该方法 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + /// + List FindWithPagerSql(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 分页查询包含用户信息(仅支持sql server) + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// 事务 + /// + Task> FindWithPagerRelationUserAsync(string condition, PagerInfo info, string fieldToSort, + bool desc, IDbTransaction trans = null); + + /// + /// 分页查询包含用户信息(仅支持sql server) + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// 事务 + /// + List FindWithPagerRelationUser(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null); + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// 统计字段名称 + /// + int GetCountByWhere(string condition, string fieldName = "*"); + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// 统计字段名称 + /// + Task GetCountByWhereAsync(string condition, string fieldName = "*"); + + /// + /// 获取总条数 + /// + /// + Task GetCount(); + + /// + /// 根据条件查询获取某个字段的最大值 + /// + /// 字段 + /// 条件 + /// 事务 + /// 返回字段的最大值 + Task GetMaxValueByFieldAsync(string strField, string where, IDbTransaction trans = null); + + /// + /// 根据条件统计某个字段之和,sum(字段) + /// + /// 字段 + /// 条件 + /// 事务 + /// 返回字段求和后的值 + Task GetSumValueByFieldAsync(string strField, string where, IDbTransaction trans = null); + + /// + /// 多表操作--事务 + /// + /// 事务 + /// 超时 + /// + Task> + ExecuteTransactionAsync(List> trans, int? commandTimeout = null); + + /// + /// 多表操作--事务 + /// + /// 事务 + /// 超时 + /// + Tuple ExecuteTransaction(List> trans, int? commandTimeout = null); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/BaseEntity.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/BaseEntity.cs new file mode 100644 index 0000000..6708528 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/BaseEntity.cs @@ -0,0 +1,55 @@ +using System; +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 定义领域对象框架实体类的基类,系统默认主键为Id + /// + /// 实体主键类型 + [Serializable] + public abstract class BaseEntity : Entity, IBaseEntity + { + /// + /// 创建者Id + /// + [Description("创建者Id")] + public TKey CreatedUserId { get; set; } + + /// + /// 创建时间 + /// + [Description("创建时间")] + public DateTime CreatedTime { get; set; } + + /// + /// 是否删除 + /// + [Description("是否删除")] + public bool IsDeleted { get; set; } = false; + + /// + /// 修改者Id + /// + [Description("修改者Id")] + public TKey ModifiedUserId { get; set; } + + /// + /// 修改时间 + /// + [Description("修改时间")] + public DateTime ModifiedTime { get; set; } + + /// + /// Id + /// + [Description("Id")] + public TKey Id { get; set; } + } + + /// + /// + public class BaseEntity : BaseEntity + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/BaseViewModel.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/BaseViewModel.cs new file mode 100644 index 0000000..9883e86 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/BaseViewModel.cs @@ -0,0 +1,12 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 所有数据库视图对应实体类必须继承此类 + /// + [Serializable] + public abstract class BaseViewModel : IEntity + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/Entity.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/Entity.cs new file mode 100644 index 0000000..377659d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/Entity.cs @@ -0,0 +1,9 @@ +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 实体基类 + /// + public abstract class Entity : IEntity + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/IBaseEntity.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/IBaseEntity.cs new file mode 100644 index 0000000..b37b222 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/IBaseEntity.cs @@ -0,0 +1,14 @@ +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 数据模型接口 + /// + /// 实体主键类型 + public interface IBaseEntity : IEntity + { + /// + /// 获取 实体唯一标识,主键 + /// + TKey Id { get; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/ICreationAudited.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/ICreationAudited.cs new file mode 100644 index 0000000..0e9aa70 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/ICreationAudited.cs @@ -0,0 +1,20 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 定义创建审计信息:给实体添加创建时的 创建人CreatedUserId,创建时间CreatedTime 的审计信息,这些值将在数据层执行 创建Insert 时自动赋值。 + /// + public interface ICreationAudited + { + /// + /// 获取或设置 创建日期 + /// + DateTime CreatedTime { get; set; } + + /// + /// 获取或设置 创建用户主键 + /// + long CreatedUserId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/IDataAuthEnabled.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/IDataAuthEnabled.cs new file mode 100644 index 0000000..da16af6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/IDataAuthEnabled.cs @@ -0,0 +1,18 @@ +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 定义数据权限的更新,删除状态 + /// + public interface IDataAuthEnabled + { + /// + /// 获取或设置 是否可更新的数据权限状态 + /// + bool Updatable { get; set; } + + /// + /// 获取或设置 是否可删除的数据权限状态 + /// + bool Deletable { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/IDeleteAudited.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/IDeleteAudited.cs new file mode 100644 index 0000000..ba7c0e8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/IDeleteAudited.cs @@ -0,0 +1,13 @@ +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 定义逻辑删除功能审计信息 + /// + public interface IDeleteAudited + { + /// + /// 获取或设置 逻辑删除标记 + /// + bool IsDeleted { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/IEntity.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/IEntity.cs new file mode 100644 index 0000000..464503d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/IEntity.cs @@ -0,0 +1,9 @@ +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 实体基接口,是所有实体的基接口 + /// + public interface IEntity + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/IEntityHash.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/IEntityHash.cs new file mode 100644 index 0000000..1304604 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/IEntityHash.cs @@ -0,0 +1,10 @@ +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 定义实体Hash功能,对实体的属性值进行Hash,确定实体是否存在变化, + /// 这些变化可用于系统初始化时确定是否需要进行数据同步 + /// + public interface IEntityHash + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/IExpirable.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/IExpirable.cs new file mode 100644 index 0000000..da267e0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/IExpirable.cs @@ -0,0 +1,20 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 定义可过期性,包含生效时间和过期时间:给实体添加 生效时间BeginTime,过期时间EndTime 的属性 + /// + public interface IExpirable + { + /// + /// 获取或设置 生效时间 + /// + DateTime? BeginTime { get; set; } + + /// + /// 获取或设置 过期时间 + /// + DateTime? EndTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/IModificationAudited.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/IModificationAudited.cs new file mode 100644 index 0000000..1ada274 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/IModificationAudited.cs @@ -0,0 +1,20 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 定义更新审计的信息 + /// + public interface IModificationAudited + { + /// + /// 获取或设置 最后修改用户 + /// + string ModifiedUserId { get; set; } + + /// + /// 获取或设置 最后修改时间 + /// + DateTime? ModifiedTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Models/IMustHaveTenant.cs b/Znyc.Cloudcar.Admin.Commons/Core/Models/IMustHaveTenant.cs new file mode 100644 index 0000000..f2aa649 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Models/IMustHaveTenant.cs @@ -0,0 +1,13 @@ +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 定义多租户实体信息 + /// + public interface IMustHaveTenant + { + /// + /// 租户Id + /// + string TenantId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Module/AutoMapperService.cs b/Znyc.Cloudcar.Admin.Commons/Core/Module/AutoMapperService.cs new file mode 100644 index 0000000..c9741b7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Module/AutoMapperService.cs @@ -0,0 +1,22 @@ +using AutoMapper; +using Microsoft.Extensions.DependencyInjection; +using System; +using Znyc.Cloudcar.Admin.Commons.Mapping; + +namespace Znyc.Cloudcar.Admin.Commons.Module +{ + /// + /// AutoMapperService + /// + public class AutoMapperService + { + /// + /// + /// + public static void UsePack(IServiceProvider provider) + { + IMapper mapper = provider.GetService(); + MapperExtensions.SetMapper(mapper); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Module/MoudleService.cs b/Znyc.Cloudcar.Admin.Commons/Core/Module/MoudleService.cs new file mode 100644 index 0000000..ca4ddf2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Module/MoudleService.cs @@ -0,0 +1,88 @@ +using AutoMapper; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Yuebon.Commons.Repositories; +using Yuebon.Commons.IoC; +using Yuebon.Commons.Linq; +using Yuebon.Commons.Log; + +namespace Yuebon.Commons.Module +{ + /// + /// 模块服务 + /// + public class MoudleService + { + /// + /// 实现应用模块程序集的注册服务 + /// + /// + /// + public static IServiceProvider LoaderMoudleService(IServiceCollection services) + { + // services.AddScoped(typeof(IUnitOfWork), typeof(UnitOfWork)); + var apps = AppContext.BaseDirectory + "Apps"; + if (!Directory.Exists(apps)) + { + Directory.CreateDirectory(apps); + } + // 把 Apps 下的动态库拷贝一份来运行, + // 使 Apps 中的动态库不会在运行时被占用(以便重新编译) + var targetPath = PrepareShadowCopies(); + // 从 Shadow Copy 目录加载 Assembly 并注册到 Mvc 中 + //LoadFromShadowCopies(targetPath); + + string PrepareShadowCopies() + { + // 准备 Shadow Copy 的目标目录 + var target = Path.Combine(AppContext.BaseDirectory, "app_data", "apps-cache"); + + if (!Directory.Exists(target)) + { + Directory.CreateDirectory(target); + } + // 找到插件目录下 bin 目录中的 .dll,拷贝 + Directory.EnumerateDirectories(apps) + .Select(path => Path.Combine(path, "bin")) + .Where(Directory.Exists) + .SelectMany(bin => Directory.EnumerateFiles(bin, "*.dll")) + .ForEach(dll => File.Copy(dll, Path.Combine(target, Path.GetFileName(dll)), true)); + + return target; + } + + DirectoryInfo folder = new DirectoryInfo(targetPath); + List myAssembly = new List(); + myAssembly.Add(Assembly.Load("Yuebon.Security.Core")); + if (File.Exists(AppContext.BaseDirectory+ "Yuebon.Messages.Core.dll")) + { + myAssembly.Add(Assembly.Load("Yuebon.Messages.Core")); + } + foreach (FileInfo finfo in folder.GetFiles("*.Core.dll")) + { + try + { + myAssembly.Add(Assembly.LoadFrom(finfo.FullName)); + string dllNamespaceStr = finfo.Name.Substring(0, finfo.Name.IndexOf(".Core")); + IoCContainer.RegisterFrom(finfo.FullName); + IoCContainer.RegisterLoadFrom(finfo.FullName, dllNamespaceStr); + Log4NetHelper.Info("注入应用模块" + finfo.Name + "成功"); + } + catch (Exception ex) + { + Log4NetHelper.Error("注入应用模块" + finfo.Name + "失败\r\n" , ex); + } + } + + services.AddAutoMapper(myAssembly); + services.AddScoped(); + + return IoCContainer.Build(services); + } + + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Repositories/BaseRepository.cs b/Znyc.Cloudcar.Admin.Commons/Core/Repositories/BaseRepository.cs new file mode 100644 index 0000000..ed55433 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Repositories/BaseRepository.cs @@ -0,0 +1,2255 @@ +using Dapper; +using Dapper.Contrib.Extensions; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Core.Dapper; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; +using Znyc.Cloudcar.Admin.Commons.DataManager; +using Znyc.Cloudcar.Admin.Commons.DependencyInjection; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.Repositories +{ + /// + /// 泛型仓储,实现泛型仓储接口 + /// + /// 实体类型 + /// 实体主键类型 + public abstract class BaseRepository : IRepository, ITransientDependency + where T : Entity + { + #region 构造函数及基本配置 + + /// + /// EF DBContext + /// + private readonly IDbContextCore _dbContext; + + private readonly IDbContextFactory _dbContextFactory; + + /// + /// + protected DbSet DbSet => DbContext.GetDbSet(); + + /// + /// 获取访问数据库配置 + /// + protected DbConnectionOptions dbConnectionOptions = DBServerProvider.GeDbConnectionOptions(); + + /// + /// 需要初始化的对象表名 + /// + protected string tableName = typeof(T).GetCustomAttribute(false)?.Name; + + /// + /// 数据库参数化访问的占位符 + /// + protected string parameterPrefix = "@"; + + /// + /// 防止和保留字、关键字同名的字段格式,如[value] + /// + protected string safeFieldFormat = "[{0}]"; + + /// + /// 数据库的主键字段名,若主键不是Id请重载BaseRepository设置 + /// + protected string primaryKey = "Id"; + + /// + /// 排序字段 + /// + protected string sortField; + + /// + /// 是否为降序 + /// + protected bool isDescending = true; + + /// + /// 选择的字段,默认为所有(*) + /// + protected string selectedFields = " * "; + + /// + /// 是否开启多租户 + /// + protected bool isMultiTenant = false; + + /// + /// 排序字段 + /// + public string SortField + { + get => sortField; + set => sortField = value; + } + + public string PrimaryKey => primaryKey; + + /// + /// 构造方法 + /// + public BaseRepository() + { + } + + /// + /// 构造方法,注入上下文 + /// + /// 上下文 + public BaseRepository(IDbContextCore dbContext) + { + if (dbContext == null) + { + throw new ArgumentNullException(nameof(dbContext)); + } + + _dbContext = dbContext; + } + + /// + /// 构造方法,注入上下文 + /// + /// 上下文 + public BaseRepository(IDbContextFactory dbContextFactory) + { + _dbContextFactory = dbContextFactory; + } + + #endregion 构造函数及基本配置 + + #region Dapper 操作 + + /// + /// 用Dapper原生方法操作数据,支持读写操作 + /// + public IDbConnection DapperConn => new DapperDbContext().GetConnection(); + + /// + /// 用Dapper原生方法,仅用于只读数据库 + /// + public IDbConnection DapperConnRead => new DapperDbContext().GetConnection(false); + + #region 查询获得对象和列表 + + /// + /// 根据id获取一个对象 + /// + /// 主键 + /// + public virtual T Get(TKey primaryKey) + { + return DapperConnRead.Get(primaryKey); + } + + /// + /// 异步根据id获取一个对象 + /// + /// 主键 + /// + public virtual async Task GetAsync(TKey primaryKey) + { + return await DapperConnRead.GetAsync(primaryKey); + } + + /// + /// 根据条件获取一个对象 + /// + /// 查询条件 + /// + public virtual T GetWhere(string where) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"select * from `{tableName}` "; + sql += " where " + where; + return DapperConnRead.QueryFirstOrDefault(sql); + } + + /// + /// 根据条件异步获取一个对象 + /// + /// 查询条件 + /// + public virtual async Task GetWhereAsync(string where) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"select * from `{tableName}` "; + sql += " where " + where; + + return await DapperConnRead.QueryFirstOrDefaultAsync(sql); + } + + /// + /// 获取所有数据,谨慎使用 + /// + /// 事务 + /// + public virtual IEnumerable GetAll(IDbTransaction trans = null) + { + return GetListWhere(); + } + + /// + /// 获取所有数据,谨慎使用 + /// + /// + /// + public virtual async Task> GetAllAsync(IDbTransaction trans = null) + { + return await GetListWhereAsync(); + } + + /// + /// 根据查询条件获取数据集合 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetListWhere(string where = null, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sql = $"select {selectedFields} from `{tableName}` "; + if (!string.IsNullOrWhiteSpace(where)) + { + sql += " where " + @where; + } + + return DapperConnRead.Query(sql, trans); + } + + /// + /// 根据查询条件获取数据集合 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetListWhereAsync(string where = null, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sql = $"select {selectedFields} from `{tableName}` where IsDeleted=0"; + if (!string.IsNullOrWhiteSpace(where)) + { + sql += " and" + @where; + } + + return await DapperConnRead.QueryAsync(sql, trans); + } + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetListTopWhere(int top, string where = null, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sql = $"select top {top} {selectedFields} from " + tableName; + ; + if (dbConnectionOptions.DatabaseType == DatabaseType.SqlServer) + { + if (!string.IsNullOrWhiteSpace(where)) + { + sql += " where " + @where; + } + } + else if (dbConnectionOptions.DatabaseType == DatabaseType.MySql) + { + sql = $"select {selectedFields} from " + tableName; + + if (!string.IsNullOrWhiteSpace(where)) + { + sql += " where " + @where; + } + + sql += $" LIMIT 0,{top}; "; + } + + return DapperConnRead.Query(sql, trans); + } + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetListTopWhereAsync(int top, string where = null, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sql = $"select top {top} {selectedFields} from " + tableName; + if (dbConnectionOptions.DatabaseType == DatabaseType.SqlServer) + { + if (!string.IsNullOrWhiteSpace(where)) + { + sql += " where " + @where; + } + } + else if (dbConnectionOptions.DatabaseType == DatabaseType.MySql) + { + sql = $"select {selectedFields} from " + tableName; + + if (!string.IsNullOrWhiteSpace(where)) + { + sql += " where " + @where; + } + + sql += $" LIMIT 0,{top}; "; + } + + return await DapperConnRead.QueryAsync(sql, trans); + } + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetAllByIsIsDeleted(string where = null, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsDeleted=1 "; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return GetListWhere(sqlWhere, trans); + } + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetAllByIsNotIsDeleted(string where = null, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsDeleted=0 "; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return GetListWhere(sqlWhere, trans); + } + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetAllByIsEnabledMark(string where = null, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsEnabled=1 "; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return GetListWhere(sqlWhere, trans); + } + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetAllByIsNotEnabledMark(string where = null, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsEnabled=0 "; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return GetListWhere(sqlWhere, trans); + } + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetAllByIsNotDeleteAndEnabledMark(string where = null, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsDeleted=0"; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return GetListWhere(sqlWhere, trans); + } + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetAllByIsIsDeletedAsync(string where = null, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsDeleted=1"; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return await GetListWhereAsync(sqlWhere, trans); + } + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetAllByIsNotIsDeletedAsync(string where = null, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsDeleted=0 "; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return await GetListWhereAsync(sqlWhere, trans); + } + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetAllByIsEnabledMarkAsync(string where = null, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsEnabled=1 "; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return await GetListWhereAsync(sqlWhere, trans); + } + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetAllByIsNotDeleteAndEnabledMarkAsync(string where = null, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " IsDeleted=0"; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return await GetListWhereAsync(sqlWhere, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 事务对象 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info, IDbTransaction trans = null) + { + return FindWithPager(condition, info, SortField, isDescending, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 事务对象 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info, string fieldToSort, + IDbTransaction trans = null) + { + return FindWithPager(condition, info, fieldToSort, isDescending, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 事务对象 + /// 指定对象的集合 + public virtual async Task> FindWithPagerAsync(string condition, PagerInfo info, string fieldToSort, + IDbTransaction trans = null) + { + return await FindWithPagerAsync(condition, info, fieldToSort, isDescending, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 事务对象 + /// 指定对象的集合 + public virtual async Task> FindWithPagerAsync(string condition, PagerInfo info, + IDbTransaction trans = null) + { + return await FindWithPagerAsync(condition, info, SortField, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// 事务对象 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null) + { + List list = new List(); + + if (HasInjectionData(condition)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", condition)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(condition)) + { + condition = "1=1"; + } + + PagerHelper pagerHelper = new PagerHelper(tableName, selectedFields, fieldToSort, info.PageSize, + info.CurrenetPageIndex, desc, condition); + + string pageSql = pagerHelper.GetPagingSql(true, dbConnectionOptions.DatabaseType); + pageSql += ";" + pagerHelper.GetPagingSql(false, dbConnectionOptions.DatabaseType); + + SqlMapper.GridReader reader = DapperConnRead.QueryMultiple(pageSql); + info.RecordCount = reader.ReadFirst(); + list = reader.Read().AsList(); + return list; + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// 事务对象 + /// 指定对象的集合 + public virtual async Task> FindWithPagerAsync(string condition, PagerInfo info, string fieldToSort, + bool desc, IDbTransaction trans = null) + { + List list = new List(); + + if (HasInjectionData(condition)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", condition)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(condition)) + { + condition = " IsDeleted=0 "; + } + + PagerHelper pagerHelper = new PagerHelper(tableName, selectedFields, fieldToSort, info.PageSize, + info.CurrenetPageIndex, desc, condition); + + string pageSql = pagerHelper.GetPagingSql(true, dbConnectionOptions.DatabaseType); + pageSql += ";" + pagerHelper.GetPagingSql(false, dbConnectionOptions.DatabaseType); + + SqlMapper.GridReader reader = await DapperConnRead.QueryMultipleAsync(pageSql); + info.RecordCount = reader.ReadFirst(); + list = reader.Read().AsList(); + return list; + } + + /// + /// 分页查询,自行封装sql语句(仅支持sql server) + /// 非常复杂的查询,可在具体业务模块重写该方法 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + /// + public virtual List FindWithPagerSql(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null) + { + List list = new List(); + if (HasInjectionData(condition)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", condition)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(condition)) + { + condition = "1=1"; + } + + StringBuilder sb = new StringBuilder(); + int startRows = (info.CurrenetPageIndex - 1) * info.PageSize + 1; //起始记录 + int endNum = info.CurrenetPageIndex * info.PageSize; //结束记录 + string strOrder = string.Format(" {0} {1}", fieldToSort, desc ? "DESC" : "ASC"); + sb.AppendFormat("SELECT count(*) as RecordCount FROM (select {0} FROM {1} where {2}) AS main_temp;", + primaryKey, tableName, condition); + sb.AppendFormat( + "SELECT * FROM ( SELECT ROW_NUMBER() OVER (order by {0}) AS rows ,{1} FROM {2} where {3}) AS main_temp where rows BETWEEN {4} and {5}", + strOrder, selectedFields, tableName, condition, startRows, endNum); + SqlMapper.GridReader reader = DapperConnRead.QueryMultiple(sb.ToString()); + info.RecordCount = reader.ReadFirst(); + list = reader.Read().AsList(); + return list; + } + + /// + /// 分页查询,自行封装sql语句(仅支持sql server) + /// 非常复杂的查询,可在具体业务模块重写该方法 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + /// + public virtual async Task> FindWithPagerSqlAsync(string condition, PagerInfo info, string fieldToSort, + bool desc, IDbTransaction trans = null) + { + if (HasInjectionData(condition)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", condition)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(condition)) + { + condition = "1=1"; + } + + StringBuilder sb = new StringBuilder(); + int startRows = (info.CurrenetPageIndex - 1) * info.PageSize + 1; //起始记录 + int endNum = info.CurrenetPageIndex * info.PageSize; //结束记录 + string strOrder = string.Format(" {0} {1}", fieldToSort, desc ? "DESC" : "ASC"); + sb.AppendFormat("SELECT count(*) as RecordCount FROM (select {0} FROM {1} where {2}) AS main_temp;", + primaryKey, tableName, condition); + sb.AppendFormat( + "SELECT * FROM ( SELECT ROW_NUMBER() OVER (order by {0}) AS rows ,{1} FROM {2} where {3}) AS main_temp where rows BETWEEN {4} and {5}", + strOrder, selectedFields, tableName, condition, startRows, endNum); + SqlMapper.GridReader reader = await DapperConnRead.QueryMultipleAsync(sb.ToString()); + info.RecordCount = reader.ReadFirst(); + List list = reader.Read().AsList(); + return list; + } + + /// + /// 分页查询包含用户信息(仅支持sql server) + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// 事务 + /// + public virtual List FindWithPagerRelationUser(string condition, PagerInfo info, string fieldToSort, + bool desc, IDbTransaction trans = null) + { + if (HasInjectionData(condition)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", condition)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(condition)) + { + condition = "1=1"; + } + + StringBuilder sb = new StringBuilder(); + int startRows = (info.CurrenetPageIndex - 1) * info.PageSize + 1; //起始记录 + int endNum = info.CurrenetPageIndex * info.PageSize; //结束记录 + string strOrder = string.Format(" {0} {1}", fieldToSort, desc ? "DESC" : "ASC"); + sb.AppendFormat( + "SELECT count(*) as RecordCount FROM (select t1.{0} FROM {1} t1 inner join sys_adminuser t2 on t1.CreatedUserId = t2.Id where {2}) AS main_temp;", + primaryKey, tableName, condition); + sb.AppendFormat( + "SELECT * FROM (SELECT ROW_NUMBER() OVER (order by {0}) AS rows ,t1.{1},t2.Account as Account,t2.UserName as UserName,t2.RealName as RealName,t2.HeadIcon as HeadIcon ,t2.MobilePhone as MobilePhone FROM {2} t1 inner join sys_adminuser t2 on t1.CreatedUserId = t2.Id " + + "where {3}) AS main_temp where rows BETWEEN {4} and {5}", strOrder, selectedFields, tableName, + condition, startRows, endNum); + + SqlMapper.GridReader reader = DapperConnRead.QueryMultiple(sb.ToString()); + info.RecordCount = reader.ReadFirst(); + List list = reader.Read().AsList(); + return list; + } + + /// + /// 分页查询包含用户信息(仅支持sql server) + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// 事务 + /// + public virtual async Task> FindWithPagerRelationUserAsync(string condition, PagerInfo info, + string fieldToSort, bool desc, IDbTransaction trans = null) + { + if (HasInjectionData(condition)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", condition)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(condition)) + { + condition = "1=1"; + } + + StringBuilder sb = new StringBuilder(); + int startRows = (info.CurrenetPageIndex - 1) * info.PageSize + 1; //起始记录 + int endNum = info.CurrenetPageIndex * info.PageSize; //结束记录 + string strOrder = string.Format(" {0} {1}", fieldToSort, desc ? "DESC" : "ASC"); + sb.AppendFormat( + "SELECT count(*) as RecordCount FROM (select t1.{0} FROM {1} t1 inner join sys_adminuser t2 on t1.CreatedUserId = t2.Id where {2}) AS main_temp;", + primaryKey, tableName, condition); + sb.AppendFormat( + "SELECT * FROM (SELECT ROW_NUMBER() OVER (order by {0}) AS rows ,t1.{1},t2.Account as Account,t2.UserName as UserName,t2.RealName as RealName,t2.HeadIcon as HeadIcon ,t2.MobilePhone as MobilePhone FROM {2} t1 inner join sys_adminuser t2 on t1.CreatedUserId = t2.Id " + + "where {3}) AS main_temp where rows BETWEEN {4} and {5}", strOrder, selectedFields, tableName, + condition, startRows, endNum); + + SqlMapper.GridReader reader = await DapperConnRead.QueryMultipleAsync(sb.ToString()); + info.RecordCount = reader.ReadFirst(); + List list = reader.Read().AsList(); + return list; + } + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// 统计字段名称 + /// + public virtual int GetCountByWhere(string condition, string fieldName = "*") + { + if (HasInjectionData(condition)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", condition)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(condition)) + { + condition = "1=1"; + } + + string sql = $"select count({fieldName}) from `{tableName}` where "; + if (!string.IsNullOrWhiteSpace(condition)) + { + sql = sql + condition; + } + + return DapperConnRead.Query(sql).FirstOrDefault(); + } + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// 统计字段名称 + /// + public virtual async Task GetCountByWhereAsync(string condition, string fieldName = "*") + { + if (HasInjectionData(condition)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", condition)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(condition)) + { + condition = "1=1"; + } + + string sql = $"select count({fieldName}) from `{tableName}` where IsDeleted=0 and "; + if (!string.IsNullOrWhiteSpace(condition)) + { + sql = sql + condition; + } + + return await DapperConnRead.QueryFirstAsync(sql); + } + + /// + /// 根据条件统计数据 + /// + /// + public virtual async Task GetCount() + { + string sql = $"select count(*) from `{tableName}` where IsDeleted=0 "; + return await DapperConnRead.QueryFirstAsync(sql); + } + + /// + /// 根据条件查询获取某个字段的最大值 + /// + /// 字段 + /// 条件 + /// 事务 + /// 返回字段的最大值 + public virtual async Task GetMaxValueByFieldAsync(string strField, string where, + IDbTransaction trans = null) + { + string sql = $"select isnull(MAX({strField}),0) as maxVaule from `{tableName}` "; + if (dbConnectionOptions.DatabaseType == DatabaseType.MySql) + { + sql = $"select if(isnull(MAX({strField})),0,MAX({strField})) as maxVaule from `{tableName}` "; + } + + if (!string.IsNullOrEmpty(where)) + { + sql += " where " + @where; + } + + return await DapperConnRead.QueryFirstAsync(sql); + } + + /// + /// 根据条件统计某个字段之和,sum(字段) + /// + /// 字段 + /// 条件 + /// 事务 + /// 返回字段求和后的值 + public virtual async Task GetSumValueByFieldAsync(string strField, string where, + IDbTransaction trans = null) + { + string sql = $"select isnull(sum({strField}),0) as sumVaule from {tableName} "; + if (dbConnectionOptions.DatabaseType == DatabaseType.MySql) + { + sql = $"select if(isnull(sum({strField})),0,sum({strField})) as sumVaule from {tableName}"; + } + + if (!string.IsNullOrEmpty(where)) + { + sql += " where " + @where; + } + + return await DapperConnRead.QueryFirstAsync(sql); + } + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetAllByIsNotEnabledMarkAsync(string where = null, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + string sqlWhere = " EnabledMark=0"; + if (!string.IsNullOrWhiteSpace(where)) + { + sqlWhere += " and " + @where; + } + + return await GetListWhereAsync(sqlWhere, trans); + } + + #endregion 查询获得对象和列表 + + #region 新增、修改和删除 + + /// + /// 新增 + /// + /// + /// 事务对象 + /// + public virtual long Insert(T entity, IDbTransaction trans = null) + { + return DapperConn.Insert(entity); + } + + /// + /// 异步新增 + /// + /// + /// 事务对象 + /// 1新增成功,0新增失败 + public virtual async Task InsertAsync(T entity, IDbTransaction trans = null) + { + return await DapperConn.InsertAsync(entity); + } + + /// + /// 异步新增实体返回主键 + /// + /// + /// + /// + public virtual async Task InsertReturnPrimaryKeyAsync(T entity, IDbTransaction trans = null) + { + return await DapperConn.InsertReturnPrimaryKeyAsync(entity); + } + + /// + /// 批量插入数据 + /// + /// + /// 执行成功返回true,否则为false + public virtual void Insert(List entities) + { + DbContext.BulkInsert(entities); + } + + /// + /// 更新 + /// + /// + /// 主键 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool Update(T entity, TKey primaryKey, IDbTransaction trans = null) + { + return DbContext.Edit(entity) > 0; + } + + /// + /// 更新 + /// + /// + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool Update(T entity, IDbTransaction trans = null) + { + return DbContext.Edit(entity) > 0; + } + + /// + /// + /// + /// + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task UpdateAsync(T entity, TKey primaryKey, IDbTransaction trans = null) + { + return await DapperConn.UpdateAsync(entity); + } + + /// + /// 同步物理删除实体。 + /// + /// 实体 + /// + public virtual bool Delete(T entity) + { + DbContext.GetDbSet().Remove(entity); + return DbContext.SaveChanges() > 0; + } + + /// + /// 异步物理删除实体。 + /// + /// 实体 + /// 事务对象 + /// + public virtual async Task DeleteAsync(T entity, IDbTransaction trans = null) + { + DbContext.GetDbSet().Remove(entity); + return await DbContext.SaveChangesAsync() > 0; + } + + /// + /// 物理删除信息 + /// + /// + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool Delete(TKey primaryKey, IDbTransaction trans = null) + { + List> param = new List>(); + string sql = $"delete from `{tableName}` where " + PrimaryKey + "=@PrimaryKey"; + Tuple tupel = new Tuple(sql, new { PrimaryKey = primaryKey }); + + param.Add(tupel); + Tuple result = ExecuteTransaction(param); + return result.Item1; + } + + /// + /// 异步物理删除信息 + /// + /// + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task DeleteAsync(TKey primaryKey, IDbTransaction trans = null) + { + List> param = new List>(); + string sql = $"delete from `{tableName}` where " + PrimaryKey + "=@PrimaryKey"; + Tuple tupel = new Tuple(sql, new { PrimaryKey = primaryKey }); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 按主键批量删除 + /// + /// 主键Id List集合 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool DeleteBatch(IList ids, IDbTransaction trans = null) + { + List> param = new List>(); + string sql = $"delete from `{tableName}` where PrimaryKey in (@PrimaryKey)"; + Tuple tupel = new Tuple(sql, new { PrimaryKey = ids }); + + param.Add(tupel); + Tuple result = ExecuteTransaction(param); + return result.Item1; + } + + /// + /// 按条件批量删除 + /// + /// 条件 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool DeleteBatchWhere(string where, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + List> param = new List>(); + string sql = $"delete from `{tableName}` where " + where; + Tuple tupel = new Tuple(sql, null); + + param.Add(tupel); + Tuple result = ExecuteTransaction(param); + return result.Item1; + } + + /// + /// 按条件批量删除 + /// + /// 条件 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task DeleteBatchWhereAsync(string where, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + List> param = new List>(); + string sql = $"delete from `{tableName}` where " + where; + Tuple tupel = new Tuple(sql, null); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 根据指定对象的ID和用户ID,从数据库中删除指定对象(用于记录人员的操作日志) + /// + /// 指定对象的ID + /// 用户ID + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool DeleteByUser(TKey primaryKey, int userId, IDbTransaction trans = null) + { + List> param = new List>(); + string sql = $"delete from `{tableName}` where " + PrimaryKey + " = @PrimaryKey"; + Tuple tupel = new Tuple(sql, new { PrimaryKey = primaryKey }); + param.Add(tupel); + Tuple result = ExecuteTransaction(param); + return result.Item1; + } + + /// + /// 异步根据指定对象的ID和用户ID,从数据库中删除指定对象(用于记录人员的操作日志) + /// + /// 指定对象的ID + /// 用户ID + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task DeleteByUserAsync(TKey primaryKey, int userId, IDbTransaction trans = null) + { + List> param = new List>(); + string sql = $"delete from `{tableName}` where " + PrimaryKey + " = @PrimaryKey"; + Tuple tupel = new Tuple(sql, new { PrimaryKey = primaryKey }); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 逻辑删除信息,bl为true时将IsDeleted设置为1删除,bl为flase时将IsDeleted设置为10-恢复删除 + /// + /// true为不删除,false删除 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool DeleteSoft(bool bl, TKey primaryKey, long userId = 0, IDbTransaction trans = null) + { + string sql = $"update `{tableName}` set "; + if (bl) + { + sql += "IsDeleted=0 "; + } + else + { + sql += "IsDeleted=1 "; + } + + DateTime deleteTime = DateTime.Now; + sql += ",ModifiedTime=@ModifiedTime where " + PrimaryKey + "=@PrimaryKey"; + List> param = new List>(); + Tuple tupel = new Tuple(sql, new { PrimaryKey = primaryKey, DeleteTime = deleteTime }); + param.Add(tupel); + Tuple result = ExecuteTransaction(param); + return result.Item1; + } + + /// + /// 异步逻辑删除信息,bl为true时将IsDeleted设置为0删除,bl为flase时将IsDeleted设置为1-恢复删除 + /// + /// true为不删除,false删除 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task DeleteSoftAsync(bool bl, TKey primaryKey, long userId = 0, + IDbTransaction trans = null) + { + string sql = $"update `{tableName}` set "; + if (bl) + { + sql += "IsDeleted=0 "; + } + else + { + sql += "IsDeleted=1 "; + } + + DateTime deleteTime = DateTime.Now; + sql += ",ModifiedTime=@ModifiedTime,ModifiedUserId=@ModifiedUserId where " + PrimaryKey + "=@PrimaryKey"; + List> param = new List>(); + Tuple tupel = new Tuple(sql, new { PrimaryKey = primaryKey, ModifiedTime = deleteTime, ModifiedUserId = userId }); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 异步批量软删除信息,bl为true时将IsDeleted设置为0删除,bl为flase时将IsDeleted设置为1-恢复删除 + /// + /// true为不删除,false删除 + /// c + /// 条件 + /// 操作用户 + /// 事务对象 + /// + public virtual async Task DeleteSoftBatchAsync(bool bl, string where, long userId = 0, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"update `{tableName}` set "; + if (bl) + { + sql += "IsDeleted=0 "; + } + else + { + sql += "IsDeleted=1 "; + } + + DateTime deleteTime = DateTime.Now; + sql += ",ModifiedTime=@ModifiedTime,ModifiedUserId=@ModifiedUserId where " + where; + + List> param = new List>(); + Tuple tupel = new Tuple(sql, new { ModifiedTime = deleteTime, ModifiedUserId = userId }); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 设置数据有效性,将IsEnabled设置为1-有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool SetEnabledMark(bool bl, TKey primaryKey, long userId = 0, IDbTransaction trans = null) + { + string sql = $"update `{tableName}` set "; + if (bl) + { + sql += "IsEnabled=1 "; + } + else + { + sql += "IsEnabled=0 "; + } + + DateTime ModifiedTime = DateTime.Now; + sql += ",ModifiedTime=@ModifiedTime where " + PrimaryKey + "=@PrimaryKey"; + + List> param = new List>(); + Tuple tupel = new Tuple(sql, new { PrimaryKey = primaryKey, ModifiedTime }); + param.Add(tupel); + Tuple result = ExecuteTransaction(param); + return result.Item1; + } + + /// + /// 异步设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task SetEnabledMarkAsync(bool bl, TKey primaryKey, long userId = 0, + IDbTransaction trans = null) + { + string sql = $"update `{tableName}` set "; + if (bl) + { + sql += "IsEnabled=1 "; + } + else + { + sql += "IsEnabled=0 "; + } + + if (!string.IsNullOrEmpty(userId.ToString())) + { + sql += ",ModifiedUserId='" + userId + "'"; + } + + DateTime ModifiedTime = DateTime.Now; + sql += ",ModifiedTime=@ModifiedTime where " + PrimaryKey + "=@PrimaryKey"; + + List> param = new List>(); + Tuple tupel = new Tuple(sql, new { PrimaryKey, ModifiedTime }); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 异步按条件设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 条件 + /// 操作用户 + /// 事务对象 + /// + public virtual async Task SetEnabledMarkByWhereAsync(bool bl, string where, long userId = 0, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"update `{tableName}` set "; + if (bl) + { + sql += "IsEnabled=1 "; + } + else + { + sql += "IsEnabled=0 "; + } + + if (!string.IsNullOrEmpty(userId.ToString())) + { + sql += ",ModifiedUserId='" + userId + "'"; + } + + DateTime ModifiedTime = DateTime.Now; + sql += ",ModifiedTime=@ModifiedTime where " + where; + + List> param = new List>(); + Tuple tupel = new Tuple(sql, new { ModifiedTime }); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 异步按条件设置数据的状态,将State设置为0:审核中,1:正常,-1:停用,-2:停用 + /// + /// 0:审核中,1:正常,-1:停用,-2:停用 + /// 条件 + /// 操作用户 + /// 事务对象 + /// + public virtual async Task SetStatusByWhereAsync(int bl, string where, long userId = 0, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"update `{tableName}` set "; + if (bl == (int)CommonStatus.REVIEW) + { + sql += "State=0 "; + } + else if (bl == (int)CommonStatus.ENABLE) + { + sql += "State=1 "; + } + else if (bl == (int)CommonStatus.DISABLE) + { + sql += "State=-1 "; + } + else + { + sql += "State=-2 "; + } + + if (!string.IsNullOrEmpty(userId.ToString())) + { + sql += ",ModifiedUserId='" + userId + "'"; + } + + DateTime ModifiedTime = DateTime.Now; + sql += ",ModifiedTime=@ModifiedTime where " + where; + + List> param = new List>(); + Tuple tupel = new Tuple(sql, new { ModifiedTime }); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 异步按条件设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 条件 + /// + /// + /// + /// + public virtual async Task SetEnabledMarkByWhereAsync(bool bl, string where, object paramparameters = null, + long userId = 0, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"update `{tableName}` set "; + if (bl) + { + sql += "IsEnabled=1 "; + } + else + { + sql += "IsEnabled=0 "; + } + + if (!string.IsNullOrEmpty(userId.ToString())) + { + sql += ",ModifiedUserId='" + userId + "'"; + } + + DateTime ModifiedTime = DateTime.Now; + sql += ",ModifiedTime=@ModifiedTime " + where; + + List> param = new List>(); + Tuple tupel = new Tuple(sql, new { ModifiedTime, paramparameters }); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 更新某一字段值,字段值字符类型 + /// + /// 字段 + /// 字段值字符类型 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool UpdateTableField(string strField, string fieldValue, string where, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"update `{tableName}` set " + strField + "='" + fieldValue + "'"; + if (!string.IsNullOrEmpty(where)) + { + sql += " where " + @where; + } + + List> param = new List>(); + Tuple tupel = new Tuple(sql, null); + param.Add(tupel); + Tuple result = ExecuteTransaction(param); + return result.Item1; + } + + /// + /// 更新某一字段值,字段值字符类型 + /// + /// 字段 + /// 字段值字符类型 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task UpdateTableFieldAsync(string strField, string fieldValue, string where, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"update `{tableName}` set " + strField + "='" + fieldValue + "'"; + if (!string.IsNullOrEmpty(where)) + { + sql += " where " + @where; + } + + List> param = new List>(); + Tuple tupel = new Tuple(sql, null); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 更新某一字段值,字段值为数字 + /// + /// 字段 + /// 字段值数字 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool UpdateTableField(string strField, int fieldValue, string where, IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"update `{tableName}` set " + strField + "=" + fieldValue + ""; + if (!string.IsNullOrEmpty(where)) + { + sql += " where " + @where; + } + + List> param = new List>(); + Tuple tupel = new Tuple(sql, null); + param.Add(tupel); + Tuple result = ExecuteTransaction(param); + return result.Item1; + } + + /// + /// 更新某一字段值,字段值为数字 + /// + /// 字段 + /// 字段值数字 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task UpdateTableFieldAsync(string strField, int fieldValue, string where, + IDbTransaction trans = null) + { + if (HasInjectionData(where)) + { + Log4NetHelper.Info(string.Format("检测出SQL注入的恶意数据, {0}", where)); + throw new Exception("检测出SQL注入的恶意数据"); + } + + if (string.IsNullOrEmpty(where)) + { + @where = "1=1"; + } + + string sql = $"update `{tableName}` set " + strField + "=" + fieldValue + ""; + if (!string.IsNullOrEmpty(where)) + { + sql += " where " + @where; + } + + List> param = new List>(); + Tuple tupel = new Tuple(sql, null); + param.Add(tupel); + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + + /// + /// 多表多数据操作批量插入、更新、删除--事务 + /// + /// 事务 + /// 超时 + /// + public async Task> ExecuteTransactionAsync(List> trans, + int? commandTimeout = null) + { + if (!trans.Any()) + { + return new Tuple(false, "执行事务SQL语句不能为空!"); + } + + using (IDbConnection connection = DapperConn) + { + bool isClosed = connection.State == ConnectionState.Closed; + if (isClosed) + { + connection.Open(); + } + + using (IDbTransaction transaction = connection.BeginTransaction()) + { + try + { + foreach (Tuple tran in trans) + { + await connection.ExecuteAsync(tran.Item1, tran.Item2, transaction, commandTimeout); + } + //提交事务 + transaction.Commit(); + return new Tuple(true, string.Empty); + } + catch (Exception ex) + { + //回滚事务 + Log4NetHelper.Error("", ex); + transaction.Rollback(); + connection.Close(); + connection.Dispose(); + DapperConn.Close(); + DapperConn.Dispose(); + throw ex; + } + finally + { + connection.Close(); + connection.Dispose(); + DapperConn.Close(); + DapperConn.Dispose(); + } + } + } + } + + /// + /// 多表多数据操作批量插入、更新、删除--事务 + /// + /// 事务 + /// 超时 + /// + public Tuple ExecuteTransaction(List> trans, int? commandTimeout = null) + { + if (!trans.Any()) + { + return new Tuple(false, "执行事务SQL语句不能为空!"); + } + + using (IDbConnection connection = DapperConn) + { + bool isClosed = connection.State == ConnectionState.Closed; + if (isClosed) + { + connection.Open(); + } + //开启事务 + using (IDbTransaction transaction = connection.BeginTransaction()) + { + try + { + foreach (Tuple tran in trans) + { + connection.Execute(tran.Item1, tran.Item2, transaction, commandTimeout); + } + //提交事务 + transaction.Commit(); + return new Tuple(true, string.Empty); + } + catch (Exception ex) + { + //回滚事务 + Log4NetHelper.Error("", ex); + transaction.Rollback(); + connection.Close(); + connection.Dispose(); + DapperConn.Close(); + DapperConn.Dispose(); + return new Tuple(false, ex.ToString()); + } + finally + { + connection.Close(); + connection.Dispose(); + DapperConn.Close(); + DapperConn.Dispose(); + } + } + } + } + + #endregion 新增、修改和删除 + + #endregion Dapper 操作 + + #region EF操作 + + /// + /// EF 上下文接口,可读可写 + /// + public virtual IDbContextCore DbContext => _dbContext; + + /// + /// EF 上下文接口,仅可读 + /// + public virtual IDbContextCore DbContextRead => _dbContextFactory.CreateContext(WriteAndReadEnum.Read); + + #region 新增 + + /// + /// 新增实体 + /// + /// + /// + public virtual int Add(T entity) + { + return DbContext.Add(entity); + } + + /// + /// 新增实体 + /// + /// + /// + public virtual async Task AddAsync(T entity) + { + return await DbContext.AddAsync(entity); + } + + /// + /// 批量新增实体,数量量较多是推荐使用BulkInsert() + /// + /// + /// + public virtual int AddRange(ICollection entities) + { + return DbContext.AddRange(entities); + } + + /// + /// 批量新增实体,数量量较多是推荐使用BulkInsert() + /// + /// + /// + public virtual async Task AddRangeAsync(ICollection entities) + { + return await DbContext.AddRangeAsync(entities); + } + + /// + /// 批量新增SqlBulk方式,效率最高 + /// + /// 数据实体集合 + /// 数据库表名称,默认为实体名称 + public virtual void BulkInsert(IList entities, string destinationTableName = null) + { + DbContext.BulkInsert(entities, destinationTableName); + } + + /// + /// 执行新增的sql语句 + /// + /// 新增Sql语句 + /// + public int AddBySql(string sql) + { + return DbContext.ExecuteSqlWithNonQuery(sql); + } + + #endregion 新增 + + #region Update + + /// + /// 更新数据实体 + /// + /// + /// + public virtual int Edit(T entity) + { + return DbContext.Edit(entity); + } + + /// + /// 批量更新数据实体 + /// + /// + /// + public virtual int EditRange(ICollection entities) + { + return DbContext.EditRange(entities); + } + + /// + /// 更新指定字段的值 + /// + /// 数据实体 + /// 指定字段 + /// + public virtual int Update(T model, params string[] updateColumns) + { + DbContext.Update(model, updateColumns); + return DbContext.SaveChanges(); + } + + /// + /// 执行更新数据的Sql语句 + /// + /// 更新数据的Sql语句 + /// + public int UpdateBySql(string sql) + { + return DbContext.ExecuteSqlWithNonQuery(sql); + } + + #endregion Update + + #region Delete + + /// + /// 根据主键删除数据 + /// + /// + /// + public virtual int Delete(TKey key) + { + return DbContext.Delete(key); + } + + /// + /// 执行删除数据Sql语句 + /// + /// 删除的Sql语句 + /// + public int DeleteBySql(string sql) + { + return DbContext.ExecuteSqlWithNonQuery(sql); + } + + #endregion Delete + + #region Query + + /// + /// 根据条件统计数量Count() + /// + /// + /// + public virtual int Count(Expression> where = null) + { + return DbContext.Count(where); + } + + /// + /// 根据条件统计数量Count() + /// + /// + /// + public virtual async Task CountAsync(Expression> where = null) + { + return await DbContext.CountAsync(where); + } + + /// + /// 是否存在,存在返回true,不存在返回false + /// + /// + /// + public virtual bool Exist(Expression> where = null) + { + return DbContext.Exist(where); + } + + /// + /// 是否存在,存在返回true,不存在返回false + /// + /// + /// + public virtual async Task ExistAsync(Expression> where = null) + { + return await DbContext.ExistAsync(where); + } + + /// + /// 根据主键获取实体。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + public virtual T GetSingle(TKey key) + { + return DbContext.Find(key); + } + + /// + /// 根据主键获取实体。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + public virtual async Task GetSingleAsync(TKey key) + { + return await DbContext.FindAsync(key); + } + + /// + /// 获取单个实体。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + public virtual T GetSingleOrDefault(Expression> where = null) + { + return DbContext.GetSingleOrDefault(where); + } + + /// + /// 获取单个实体。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + public virtual async Task GetSingleOrDefaultAsync(Expression> where = null) + { + return await DbContext.GetSingleOrDefaultAsync(where); + } + + /// + /// 获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + public virtual IList Get(Expression> where = null) + { + return DbContext.GetByCompileQuery(where); + } + + /// + /// 获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// + /// + public virtual async Task> GetAsync(Expression> where = null) + { + return await DbContext.GetByCompileQueryAsync(where); + } + + /// + /// 分页获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 + /// + /// 查询条件 + /// 分页信息 + /// 排序方式 + /// 排序字段 + /// + public virtual IEnumerable GetByPagination(Expression> where, PagerInfo pagerInfo, + bool asc = false, params Expression>[] orderby) + { + IQueryable filter = DbContext.Get(where); + if (orderby != null) + { + foreach (Expression> func in @orderby) + { + filter = asc ? filter.OrderBy(func).AsQueryable() : filter.OrderByDescending(func).AsQueryable(); + } + } + + pagerInfo.RecordCount = filter.Count(); + return filter.Skip(pagerInfo.PageSize * (pagerInfo.CurrenetPageIndex - 1)).Take(pagerInfo.PageSize); + } + + /// + /// sql语句查询数据集 + /// + /// + /// + public List GetBySql(string sql) + { + return DbContext.SqlQuery(sql); + } + + /// + /// sql语句查询数据集,返回输出Dto实体 + /// + /// + /// + /// + public List GetViews(string sql) + { + List list = DbContext.SqlQuery(sql); + return list; + } + + /// + /// 查询视图 + /// + /// 返回结果对象 + /// 视图名称 + /// 查询条件 + /// + public List GetViews(string viewName, Func where) + { + List list = DbContext.SqlQuery($"select * from {viewName}"); + if (where != null) + { + return list.Where(@where).ToList(); + } + + return list; + } + + #endregion Query + + #endregion EF操作 + + #region 辅助类方法 + + /// + /// 验证是否存在注入代码(条件语句) + /// + /// + public virtual bool HasInjectionData(string inputData) + { + if (string.IsNullOrEmpty(inputData)) + { + return false; + } + + //里面定义恶意字符集合 + //验证inputData是否包含恶意集合 + //if (Regex.IsMatch(inputData.ToLower(), GetRegexString())) + //{ + // return true; + //} + + return false; + } + + /// + /// 获取正则表达式 + /// + /// + private static string GetRegexString() + { + //构造SQL的注入关键字符 + string[] strBadChar = + { + "select\\s", + "from\\s", + "insert\\s", + "delete\\s", + "update\\s", + "drop\\s", + "truncate\\s", + "exec\\s", + "count\\(", + "declare\\s", + "asc\\(", + "mid\\(", + //"char\\(", + "net user", + "xp_cmdshell", + "/add\\s", + "exec master.dbo.xp_cmdshell", + "net localgroup administrators" + }; + + //构造正则表达式 + string str_Regex = ".*("; + for (int i = 0; i < strBadChar.Length - 1; i++) + { + str_Regex += strBadChar[i] + "|"; + } + + str_Regex += strBadChar[^1] + ").*"; + + return str_Regex; + } + + #endregion 辅助类方法 + + #region IDisposable Support + + private bool disposedValue; // 要检测冗余调用 + + /// + /// + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: 释放托管状态(托管对象)。 + } + + // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 + // TODO: 将大型字段设置为 null。 + + disposedValue = true; + } + + if (DbContext != null) + { + DbContext.Dispose(); + } + + if (DapperConn != null) + { + DapperConn?.Dispose(); + } + } + + // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。 + // ~BaseRepository() { + // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + // Dispose(false); + // } + + /// + /// + public void Dispose() + { + // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + Dispose(true); + + DbContext?.Dispose(); + DapperConn?.Dispose(); + // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。 + // GC.SuppressFinalize(this); + } + + #endregion IDisposable Support + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Core/Services/BaseService.cs b/Znyc.Cloudcar.Admin.Commons/Core/Services/BaseService.cs new file mode 100644 index 0000000..b2c4d9e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Core/Services/BaseService.cs @@ -0,0 +1,1006 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Security.Claims; +using System.Text.Json; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.DependencyInjection; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; + +namespace Znyc.Cloudcar.Admin.Commons.Services +{ + /// + /// + /// + /// + /// + public abstract class BaseService : IService, ITransientDependency + where T : Entity + where TODto : class + where TKey : IEquatable + { + private readonly IHttpContextAccessor _accessor; + + /// + /// + protected IRepository repository; + + /// + /// + /// + protected BaseService(IRepository iRepository) + { + repository = iRepository; + } + + /// + /// + /// + /// + protected BaseService(IRepository iRepository, IHttpContextAccessor accessor) + { + _accessor = accessor; + repository = iRepository; + } + + /// + /// 同步物理删除实体。 + /// + /// 实体 + /// 事务对象 + /// + public virtual bool Delete(T entity, IDbTransaction trans = null) + { + return repository.Delete(entity); + } + + /// + /// 同步物理删除实体。 + /// + /// 主键 + /// 事务对象 + /// + public virtual bool Delete(TKey id, IDbTransaction trans = null) + { + return repository.Delete(id, trans); + } + + /// + /// 异步物理删除实体。 + /// + /// 主键 + /// 事务对象 + /// + public virtual Task DeleteAsync(TKey id, IDbTransaction trans = null) + { + return repository.DeleteAsync(id, trans); + } + + /// + /// 异步物理删除实体。 + /// + /// 实体 + /// 事务对象 + /// + public virtual Task DeleteAsync(T entity, IDbTransaction trans = null) + { + return repository.DeleteAsync(entity, trans); + } + + /// + /// 按主键批量删除 + /// + /// + /// + /// + public virtual bool DeleteBatch(IList ids, IDbTransaction trans = null) + { + return repository.DeleteBatch(ids, trans); + } + + /// + /// 按条件批量删除 + /// + /// 条件 + /// + /// + public virtual bool DeleteBatchWhere(string where, IDbTransaction trans = null) + { + return repository.DeleteBatchWhere(where, trans); + } + + /// + /// 按条件批量删除 + /// + /// 条件 + /// + /// + public virtual async Task DeleteBatchWhereAsync(string where, IDbTransaction trans = null) + { + return await repository.DeleteBatchWhereAsync(where, trans); + } + + /// + /// 软删除信息,将IsDeleted设置为1-删除,0-恢复删除 + /// + /// true为不删除,false删除 + /// 主键ID + /// 操作用户 + /// + /// + public virtual bool DeleteSoft(bool bl, TKey id, long userId, IDbTransaction trans = null) + { + return repository.DeleteSoft(bl, id, userId, trans); + } + + /// + /// 异步软删除信息,bl为true时将IsDeleted设置为0删除,bl为flase时将IsDeleted设置为1-恢复删除 + /// + /// true为不删除,false删除 + /// 主键ID + /// 操作用户 + /// + /// + public virtual async Task DeleteSoftAsync(bool bl, TKey id, long userId, IDbTransaction trans = null) + { + return await repository.DeleteSoftAsync(bl, id, userId, trans); + } + + /// + /// 异步批量软删除信息,bl为true时将IsDeleted设置为0删除,bl为flase时将IsDeleted设置为1-恢复删除 + /// + /// true为不删除,false删除 + /// c + /// 条件 + /// 操作用户 + /// 事务对象 + /// + public virtual async Task DeleteSoftBatchAsync(bool bl, string where, long userId = 0, + IDbTransaction trans = null) + { + return await repository.DeleteSoftBatchAsync(bl, where, userId, trans); + } + + /// + /// 同步查询单个实体。 + /// + /// 主键 + /// + public virtual T Get(TKey id) + { + return repository.Get(id); + } + + /// + /// 同步查询单个实体。 + /// + /// 主键 + /// + public virtual TODto GetOutDto(TKey id) + { + return repository.Get(id).MapTo(); + } + + /// + /// 同步查询单个实体。 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual T GetWhere(string where, IDbTransaction trans = null) + { + return repository.GetWhere(where); + } + + /// + /// 同步查询单个实体。 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual TODto GetOutDtoWhere(string where, IDbTransaction trans = null) + { + return repository.GetWhere(where).MapTo(); + } + + /// + /// 异步查询单个实体。 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task GetWhereAsync(string where, IDbTransaction trans = null) + { + return await repository.GetWhereAsync(where); + } + + /// + /// 异步查询单个实体。 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task GetOutDtoWhereAsync(string where, IDbTransaction trans = null) + { + T info = await repository.GetWhereAsync(where); + return info.MapTo(); + } + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetListTopWhere(int top, string where = null, IDbTransaction trans = null) + { + return repository.GetListTopWhere(top, where); + } + + /// + /// 根据查询条件查询前多少条数据 + /// + /// 多少条数据 + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetListTopWhereAsync(int top, string where = null, + IDbTransaction trans = null) + { + return await repository.GetListTopWhereAsync(top, where); + } + + /// + /// 同步查询所有实体。 + /// + /// 事务对象 + /// + public virtual IEnumerable GetAll(IDbTransaction trans = null) + { + return repository.GetAll(trans); + } + + /// + /// 异步步查询所有实体。 + /// + /// 事务对象 + /// + public virtual Task> GetAllAsync(IDbTransaction trans = null) + { + return repository.GetAllAsync(trans); + } + + /// + /// 异步查询单个实体。 + /// + /// 主键 + /// + public virtual async Task GetAsync(TKey id) + { + return await repository.GetAsync(id); + } + + /// + /// 异步查询单个实体。 + /// + /// 主键 + /// + public virtual async Task GetOutDtoAsync(TKey id) + { + T info = await repository.GetAsync(id); + return info.MapTo(); + } + + /// + /// 根据查询条件查询数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual IEnumerable GetListWhere(string where = null, IDbTransaction trans = null) + { + return repository.GetListWhere(where, trans); + } + + /// + /// 异步根据查询条件查询数据 + /// + /// 查询条件 + /// 事务对象 + /// + public virtual async Task> GetListWhereAsync(string where = null, IDbTransaction trans = null) + { + return await repository.GetListWhereAsync(where, trans); + } + + /// + /// 同步新增实体。 + /// + /// 实体 + /// 事务对象 + /// + public virtual long Insert(T entity, IDbTransaction trans = null) + { + return repository.Insert(entity, trans); + } + + /// + /// 异步步新增实体。 + /// + /// 实体 + /// 事务对象 + /// + public virtual Task InsertAsync(T entity, IDbTransaction trans = null) + { + return repository.InsertAsync(entity, trans); + } + + /// + /// 异步新增实体返回主键 + /// + /// + /// + /// + public virtual Task InsertReturnPrimaryKeyAsync(T entity, IDbTransaction trans = null) + { + return repository.InsertReturnPrimaryKeyAsync(entity, trans); + } + + /// + /// 同步批量新增实体。 + /// + /// 实体集合 + /// + public virtual void Insert(List entities) + { + repository.Insert(entities); + } + + /// + /// 同步更新实体。 + /// + /// 实体 + /// 主键ID + /// 事务对象 + /// + public virtual bool Update(T entity, TKey id, IDbTransaction trans = null) + { + return repository.Update(entity, id, trans); + } + + /// + /// 异步更新实体。 + /// + /// 实体 + /// 主键ID + /// 事务对象 + /// + public virtual Task UpdateAsync(T entity, TKey id, IDbTransaction trans = null) + { + return repository.UpdateAsync(entity, id, trans); + } + + /// + /// 更新某一字段值,字段值字符类型 + /// + /// 字段 + /// 字段值字符类型 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool UpdateTableField(string strField, string fieldValue, string where, + IDbTransaction trans = null) + { + return repository.UpdateTableField(strField, fieldValue, where, trans); + } + + /// + /// 更新某一字段值,字段值字符类型 + /// + /// 字段 + /// 字段值字符类型 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task UpdateTableFieldAsync(string strField, string fieldValue, string where, + IDbTransaction trans = null) + { + return await repository.UpdateTableFieldAsync(strField, fieldValue, where, trans); + } + + /// + /// 更新某一字段值,字段值数字类型 + /// + /// 字段 + /// 字段值数字 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual bool UpdateTableField(string strField, int fieldValue, string where, IDbTransaction trans = null) + { + return repository.UpdateTableField(strField, fieldValue, where, trans); + } + + /// + /// 更新某一字段值,字段值数字类型 + /// + /// 字段 + /// 字段值数字 + /// 条件,为空更新所有内容 + /// 事务对象 + /// 执行成功返回true,否则为false + public virtual async Task UpdateTableFieldAsync(string strField, int fieldValue, string where, + IDbTransaction trans = null) + { + return await repository.UpdateTableFieldAsync(strField, fieldValue, where, trans); + } + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// + /// + public virtual IEnumerable GetAllByIsIsDeleted(string where = null, IDbTransaction trans = null) + { + return repository.GetAllByIsIsDeleted(where, trans); + } + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// + /// + public virtual IEnumerable GetAllByIsNotIsDeleted(string where = null, IDbTransaction trans = null) + { + return repository.GetAllByIsNotIsDeleted(where, trans); + } + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// + /// + public virtual IEnumerable GetAllByIsEnabledMark(string where = null, IDbTransaction trans = null) + { + return repository.GetAllByIsEnabledMark(where, trans); + } + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// + /// + public virtual IEnumerable GetAllByIsNotEnabledMark(string where = null, IDbTransaction trans = null) + { + return repository.GetAllByIsNotEnabledMark(where, trans); + } + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// + /// + public virtual IEnumerable GetAllByIsNotDeleteAndEnabledMark(string where = null, + IDbTransaction trans = null) + { + return repository.GetAllByIsNotDeleteAndEnabledMark(where, trans); + } + + /// + /// 查询软删除的数据,如果查询条件为空,即查询所有软删除的数据 + /// + /// 查询条件 + /// + /// + public virtual async Task> GetAllByIsIsDeletedAsync(string where = null, + IDbTransaction trans = null) + { + return await repository.GetAllByIsIsDeletedAsync(where, trans); + } + + /// + /// 查询未软删除的数据,如果查询条件为空,即查询所有未软删除的数据 + /// + /// 查询条件 + /// + /// + public virtual async Task> GetAllByIsNotIsDeletedAsync(string where = null, + IDbTransaction trans = null) + { + return await repository.GetAllByIsNotIsDeletedAsync(where, trans); + } + + /// + /// 查询有效的数据,如果查询条件为空,即查询所有有效的数据 + /// + /// 查询条件 + /// + /// + public virtual async Task> GetAllByIsEnabledMarkAsync(string where = null, + IDbTransaction trans = null) + { + return await repository.GetAllByIsEnabledMarkAsync(where, trans); + } + + /// + /// 查询无效的数据,如果查询条件为空,即查询所有无效的数据 + /// + /// 查询条件 + /// + /// + public virtual async Task> GetAllByIsNotEnabledMarkAsync(string where = null, + IDbTransaction trans = null) + { + return await repository.GetAllByIsNotEnabledMarkAsync(where, trans); + } + + /// + /// 查询未软删除且有效的数据,如果查询条件为空,即查询所有数据 + /// + /// 查询条件 + /// + /// + public virtual async Task> GetAllByIsNotDeleteAndEnabledMarkAsync(string where = null, + IDbTransaction trans = null) + { + return await repository.GetAllByIsNotDeleteAndEnabledMarkAsync(where, trans); + } + + /// + /// 设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// + /// + public virtual bool SetEnabledMark(bool bl, TKey id, long userId = 0, IDbTransaction trans = null) + { + return repository.SetEnabledMark(bl, id, userId, trans); + } + + /// + /// 异步设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 主键ID + /// 操作用户 + /// + /// + public virtual async Task SetEnabledMarkAsync(bool bl, TKey id, long userId = 0, + IDbTransaction trans = null) + { + return await repository.SetEnabledMarkAsync(bl, id, userId, trans); + } + + /// + /// 异步按条件设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// true为有效,false无效 + /// 条件 + /// 操作用户 + /// 事务对象 + /// + public virtual async Task SetEnabledMarkByWhereAsync(bool bl, string where, long userId = 0, + IDbTransaction trans = null) + { + return await repository.SetEnabledMarkByWhereAsync(bl, where, userId, trans); + } + + /// + /// 异步按条件设置数据的状态,将State设置为0:审核中,1:正常,-1:停用,-2:停用 + /// + /// 0:审核中,1:正常,-1:停用,-2:停用 + /// 条件 + /// 操作用户 + /// 事务对象 + /// + public virtual async Task SetStatusByWhereAsync(int bl, string where, long userId = 0, + IDbTransaction trans = null) + { + return await repository.SetStatusByWhereAsync(bl, where, userId, trans); + } + + /// + /// 异步按条件设置数据有效性,将IsEnabled设置为1:有效,0-为无效 + /// + /// + /// + /// + /// + /// + /// + public virtual async Task SetEnabledMarkByWhereAsync(bool bl, string where, object paramparameters = null, + long userId = 0, IDbTransaction trans = null) + { + return await repository.SetEnabledMarkByWhereAsync(bl, where, paramparameters, userId, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 事务对象 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info, IDbTransaction trans = null) + { + return repository.FindWithPager(condition, info, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 事务对象 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info, string fieldToSort, + IDbTransaction trans = null) + { + return repository.FindWithPager(condition, info, fieldToSort, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 是否降序 + /// 事务对象 + /// 指定对象的集合 + public virtual List FindWithPager(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null) + { + return repository.FindWithPager(condition, info, fieldToSort, desc, trans); + } + + /// + /// 分页查询,自行封装sql语句(仅支持sql server) + /// 非常复杂的查询,可在具体业务模块重写该方法 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + /// + public virtual List FindWithPagerSql(string condition, PagerInfo info, string fieldToSort, bool desc, + IDbTransaction trans = null) + { + return repository.FindWithPagerSql(condition, info, fieldToSort, desc, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 排序方式 + /// 事务对象 + /// 指定对象的集合 + public virtual async Task> FindWithPagerAsync(string condition, PagerInfo info, string fieldToSort, + bool desc, IDbTransaction trans = null) + { + return await repository.FindWithPagerAsync(condition, info, fieldToSort, desc, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// 查询条件变换时请重写该方法。 + /// + /// 查询的条件 + /// 指定对象的集合 + public virtual PageResult FindWithPager(SearchInputDto search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(); + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = repository.FindWithPager(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// 查询条件变换时请重写该方法。 + /// + /// 查询的条件 + /// 指定对象的集合 + public virtual async Task> FindWithPagerAsync(SearchInputDto search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(); + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 事务对象 + /// 指定对象的集合 + public virtual async Task> FindWithPagerAsync(string condition, PagerInfo info, string fieldToSort, + IDbTransaction trans = null) + { + return await repository.FindWithPagerAsync(condition, info, fieldToSort, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 事务对象 + /// 指定对象的集合 + public virtual async Task> FindWithPagerAsync(string condition, PagerInfo info, + IDbTransaction trans = null) + { + return await repository.FindWithPagerAsync(condition, info, trans); + } + + /// + /// 分页查询,自行封装sql语句(仅支持sql server) + /// 非常复杂的查询,可在具体业务模块重写该方法 + /// + /// 查询条件 + /// 分页信息 + /// 排序字段 + /// 排序方式 true为desc,false为asc + /// + /// + public virtual async Task> FindWithPagerSqlAsync(string condition, PagerInfo info, string fieldToSort, + bool desc, IDbTransaction trans = null) + { + return await repository.FindWithPagerAsync(condition, info, fieldToSort, desc, trans); + } + + /// + /// 分页查询包含用户信息(仅支持sql server) + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// 事务 + /// + public virtual async Task> FindWithPagerRelationUserAsync(string condition, PagerInfo info, + string fieldToSort, bool desc, IDbTransaction trans = null) + { + return await repository.FindWithPagerRelationUserAsync(condition, info, fieldToSort, desc, trans); + } + + /// + /// 分页查询包含用户信息(仅支持sql server) + /// 查询主表别名为t1,用户表别名为t2,在查询字段需要注意使用t1.xxx格式,xx表示主表字段 + /// 用户信息主要有用户账号:Account、昵称:UserName、真实姓名:RealName、头像:HeadIcon、手机号:MobilePhone + /// 输出对象请在Dtos中进行自行封装,不能是使用实体Model类 + /// + /// 查询条件字段需要加表别名 + /// 分页信息 + /// 排序字段,也需要加表别名 + /// 排序方式 + /// 事务 + /// + public virtual List FindWithPagerRelationUser(string condition, PagerInfo info, string fieldToSort, + bool desc, IDbTransaction trans = null) + { + return repository.FindWithPagerRelationUser(condition, info, fieldToSort, desc, trans); + } + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// 统计字段名称 + /// + public virtual int GetCountByWhere(string condition, string fieldName = "*") + { + return repository.GetCountByWhere(condition, fieldName); + } + + /// + /// 根据条件统计数据 + /// + /// 查询条件 + /// 统计字段名称 + /// + public virtual async Task GetCountByWhereAsync(string condition, string fieldName = "*") + { + return await repository.GetCountByWhereAsync(condition, fieldName); + } + + /// + /// + /// + public virtual async Task GetCount() + { + return await repository.GetCount(); + } + + /// + /// 根据条件查询获取某个字段的最大值 + /// + /// 字段 + /// 条件 + /// 事务 + /// 返回字段的最大值 + public virtual async Task GetMaxValueByFieldAsync(string strField, string where, + IDbTransaction trans = null) + { + return await repository.GetMaxValueByFieldAsync(strField, where); + } + + /// + /// 根据条件统计某个字段之和,sum(字段) + /// + /// 字段 + /// 条件 + /// 事务 + /// 返回字段求和后的值 + public virtual async Task GetSumValueByFieldAsync(string strField, string where, + IDbTransaction trans = null) + { + return await repository.GetSumValueByFieldAsync(strField, where); + } + + /// + /// 多表操作--事务 + /// + /// 事务 + /// 超时 + /// + public virtual async Task> ExecuteTransactionAsync(List> trans, + int? commandTimeout = null) + { + return await repository.ExecuteTransactionAsync(trans, commandTimeout); + } + + /// + /// 多表操作--事务 + /// + /// 事务 + /// 超时 + /// + public virtual Tuple ExecuteTransaction(List> trans, + int? commandTimeout = null) + { + return repository.ExecuteTransaction(trans, commandTimeout); + } + + /// + /// 获取当前登录用户的数据访问权限 + /// + /// 是否开启,默认开启 + /// + protected virtual string GetDataPrivilege(bool blDeptCondition = true) + { + string where = "1=1"; + //开权限数据过滤 + if (blDeptCondition) + { + IEnumerable identities = HttpContextHelper.HttpContext.User.Identities; + ClaimsIdentity claimsIdentity = identities.First(); + List claimlist = claimsIdentity.Claims as List; + CacheHelper cacheHelper = new CacheHelper(); + if (claimlist[1].Value != "admin") + { + //如果公司过滤条件不为空,那么需要进行过滤 + List list = JsonSerializer.Deserialize>(cacheHelper + .Get("User_RoleData_" + claimlist[0].Value).ToJson()); + if (list.Count() > 0) + { + string DataFilterCondition = string.Join(",", list.ToArray()); + if (!string.IsNullOrEmpty(DataFilterCondition)) + { + where += string.Format(" and (DeptId in ('{0}') or CreatedUserId='{1}')", + DataFilterCondition.Replace(",", "','"), claimlist[0].Value); + } + } + else + { + where += string.Format(" and CreatedUserId='{0}'", claimlist[0].Value); + } + + bool isMultiTenant = Configs.GetConfigurationValue("AppSetting", "IsMultiTenant").ToBool(); + if (isMultiTenant) + { + where += string.Format(" and TenantId='{0}'", claimlist[3].Value); + } + } + } + + return where; + } + + #region IDisposable Support + + private bool disposedValue; // 要检测冗余调用 + + /// + /// + /// + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: 释放托管状态(托管对象)。 + } + + // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 + // TODO: 将大型字段设置为 null。 + + disposedValue = true; + } + } + + // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。 + // ~BaseService() { + // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + // Dispose(false); + // } + + /// + /// 添加此代码以正确实现可处置模式 + /// + void IDisposable.Dispose() + { + // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + Dispose(true); + // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。 + // GC.SuppressFinalize(this); + } + + #endregion IDisposable Support + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Cos/CosOptions.cs b/Znyc.Cloudcar.Admin.Commons/Cos/CosOptions.cs new file mode 100644 index 0000000..44122ee --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Cos/CosOptions.cs @@ -0,0 +1,22 @@ +namespace Znyc.Cloudcar.Admin.Commons.Cos +{ + /// + /// Cos储存桶配置 + /// + public class CosOptions + { + public string SecretId { get; set; } + + public string SecretKey { get; set; } + + public string Bucket { get; set; } + + public string Region { get; set; } + + public string AllowPrefix { get; set; } + + public int DurationSeconds { get; set; } + + public string[] AllowActions { get; set; } + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Data/Check.cs b/Znyc.Cloudcar.Admin.Commons/Data/Check.cs new file mode 100644 index 0000000..5f45dbf --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Data/Check.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Properties; + +namespace Znyc.Cloudcar.Admin.Commons.Data +{ + /// + /// 参数合法性检查类 + /// + [DebuggerStepThrough] + public static class Check + { + /// + /// 验证指定值的断言是否为真,如果不为真,抛出指定消息的指定类型 + /// 异常 + /// + /// 异常类型 + /// 要验证的断言。 + /// 异常消息。 + private static void Require(bool assertion, string message) + where TException : Exception + { + if (assertion) + { + return; + } + + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException(nameof(message)); + } + + TException exception = (TException)Activator.CreateInstance(typeof(TException), message); + throw exception; + } + + /// + /// 验证指定值的断言表达式是否为真,不为值抛出异常 + /// + /// + /// 要验证的断言表达式 + /// 异常消息 + public static void Required(T value, Func assertionFunc, string message) + { + if (assertionFunc == null) + { + throw new ArgumentNullException(nameof(assertionFunc)); + } + + Require(assertionFunc(value), message); + } + + /// + /// 验证指定值的断言表达式是否为真,不为真抛出异常 + /// + /// 要判断的值的类型 + /// 抛出的异常类型 + /// 要判断的值 + /// 要验证的断言表达式 + /// 异常消息 + public static void Required(T value, Func assertionFunc, string message) + where TException : Exception + { + if (assertionFunc == null) + { + throw new ArgumentNullException("assertionFunc"); + } + + Require(assertionFunc(value), message); + } + + /// + /// 检查参数不能为空引用,否则抛出异常。 + /// + /// + /// 参数名称 + /// + public static void NotNull(T value, string paramName) + { + Require(value != null, string.Format(Resources.ParameterCheck_NotNull, paramName)); + } + + /// + /// 检查字符串不能为空引用或空字符串,否则抛出异常或异常。 + /// + /// + /// 参数名称。 + /// + /// + public static void NotNullOrEmpty(string value, string paramName) + { + Require(!string.IsNullOrEmpty(value), + string.Format(Resources.ParameterCheck_NotNullOrEmpty_String, paramName)); + } + + /// + /// 检查Guid值不能为Guid.Empty,否则抛出异常。 + /// + /// + /// 参数名称。 + /// + public static void NotEmpty(Guid value, string paramName) + { + Require(value != Guid.Empty, + string.Format(Resources.ParameterCheck_NotEmpty_Guid, paramName)); + } + + /// + /// 检查集合不能为空引用或空集合,否则抛出异常或异常。 + /// + /// 集合项的类型。 + /// + /// 参数名称。 + /// + /// + public static void NotNullOrEmpty(IReadOnlyList list, string paramName) + { + NotNull(list, paramName); + Require(list.Any(), + string.Format(Resources.ParameterCheck_NotNullOrEmpty_Collection, paramName)); + } + + /// + /// 检查集合中没有包含值为null的项 + /// + public static void HasNoNulls(IReadOnlyList list, string paramName) + { + NotNull(list, paramName); + Require(list.All(m => m != null), + string.Format(Resources.ParameterCheck_NotContainsNull_Collection, paramName)); + } + + /// + /// 检查参数必须小于[或可等于,参数]指定值,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 要比较的值。 + /// 是否可等于。 + /// + public static void LessThan(T value, string paramName, T target, bool canEqual = false) + where T : IComparable + { + bool flag = canEqual ? value.CompareTo(target) <= 0 : value.CompareTo(target) < 0; + string format = canEqual ? Resources.ParameterCheck_NotLessThanOrEqual : Resources.ParameterCheck_NotLessThan; + Require(flag, string.Format(format, paramName, target)); + } + + /// + /// 检查参数必须大于[或可等于,参数]指定值,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 要比较的值。 + /// 是否可等于。 + /// + public static void GreaterThan(T value, string paramName, T target, bool canEqual = false) + where T : IComparable + { + bool flag = canEqual ? value.CompareTo(target) >= 0 : value.CompareTo(target) > 0; + string format = canEqual + ? Resources.ParameterCheck_NotGreaterThanOrEqual + : Resources.ParameterCheck_NotGreaterThan; + Require(flag, string.Format(format, paramName, target)); + } + + /// + /// 检查参数必须在指定范围之间,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 比较范围的起始值。 + /// 比较范围的结束值。 + /// 是否可等于起始值 + /// 是否可等于结束值 + /// + public static void Between(T value, string paramName, T start, T end, bool startEqual = false, + bool endEqual = false) + where T : IComparable + { + bool flag = startEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0; + string message = startEqual + ? string.Format(Resources.ParameterCheck_Between, paramName, start, end) + : string.Format(Resources.ParameterCheck_BetweenNotEqual, paramName, start, end, start); + Require(flag, message); + + flag = endEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0; + message = endEqual + ? string.Format(Resources.ParameterCheck_Between, paramName, start, end) + : string.Format(Resources.ParameterCheck_BetweenNotEqual, paramName, start, end, end); + Require(flag, message); + } + + /// + /// 检查指定路径的文件夹必须存在,否则抛出异常。 + /// + /// + /// 参数名称。 + /// + /// + public static void DirectoryExists(string directory, string paramName = null) + { + NotNull(directory, paramName); + Require(Directory.Exists(directory), + string.Format(Resources.ParameterCheck_DirectoryNotExists, directory)); + } + + /// + /// 检查指定路径的文件必须存在,否则抛出异常。 + /// + /// + /// 参数名称。 + /// 当文件路径为null时 + /// 当文件路径不存在时 + public static void FileExists(string filename, string paramName = null) + { + NotNull(filename, paramName); + Require(File.Exists(filename), + string.Format(Resources.ParameterCheck_FileNotExists, filename)); + } + + /// + /// 检查各属性的合法性,否则抛出异常 + /// + public static void Validate(IInputDto dto, string paramName) + { + NotNull(dto, paramName); + dto.Validate(); + } + + /// + /// 检查各属性的合法性,否则抛出异常 + /// + public static void Validate(TInputDto[] dtos, string paramName) + where TInputDto : IInputDto + { + NotNull(dtos, paramName); + foreach (TInputDto dto in dtos) + { + dto.Validate(); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Data/MicroDataTable.cs b/Znyc.Cloudcar.Admin.Commons/Data/MicroDataTable.cs new file mode 100644 index 0000000..4ea346f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Data/MicroDataTable.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Commons.Data +{ + /// + /// 查询结果数据表样式 + /// + public class MicroDataTable + { + /// + /// 整个查询语句结果的总条数,而非本DataTable的条数 + /// + public int TotalCount { get; set; } + + /// + /// 数据列名称 + /// + public List Columns { get; set; } = new(); + + /// + /// 数据记录 + /// + public List Rows { get; set; } = new(); + + /// + /// 主键 + /// + public MicroDataColumn[] PrimaryKey { get; set; } + + public MicroDataRow NewRow() + { + return new(Columns, new object[Columns.Count]); + } + } + + public class MicroDataColumn + { + public string ColumnName { get; set; } + public Type ColumnType { get; set; } + } + + public class MicroDataRow + { + private readonly object[] _ItemArray; + + public MicroDataRow(List columns, object[] itemArray) + { + Columns = columns; + _ItemArray = itemArray; + } + + public List Columns { get; } + + public object this[int index] + { + get => _ItemArray[index]; + set => _ItemArray[index] = value; + } + + public object this[string columnName] + { + get + { + int i = 0; + foreach (MicroDataColumn column in Columns) + { + if (column.ColumnName == columnName) + { + break; + } + + i++; + } + + return _ItemArray[i]; + } + set + { + int i = 0; + foreach (MicroDataColumn column in Columns) + { + if (column.ColumnName == columnName) + { + break; + } + + i++; + } + + _ItemArray[i] = value; + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Data/MicroDataTableHelper.cs b/Znyc.Cloudcar.Admin.Commons/Data/MicroDataTableHelper.cs new file mode 100644 index 0000000..9e972e4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Data/MicroDataTableHelper.cs @@ -0,0 +1,52 @@ +using System.Data.Common; + +namespace Znyc.Cloudcar.Admin.Commons.Data +{ + public class MicroDataTableHelper + { + /// + /// DbDataReaders 数据转化Datatable + /// + /// + /// + /// + /// + public static MicroDataTable FillDataTable(DbDataReader reader, int pageIndex, int pageSize) + { + bool defined = false; + MicroDataTable table = new MicroDataTable(); + int index = 0; + int beginIndex = pageSize * pageIndex; + int endIndex = pageSize * (pageIndex + 1) - 1; + while (reader.Read()) + { + object[] values = new object[reader.FieldCount]; + if (!defined) + { + for (int i = 0; i < reader.FieldCount; i++) + { + MicroDataColumn column = new MicroDataColumn + { + ColumnName = reader.GetName(i), + ColumnType = reader.GetFieldType(i) + }; + table.Columns.Add(column); + } + + defined = true; + } + + if (index >= beginIndex && index <= endIndex) + { + reader.GetValues(values); + table.Rows.Add(new MicroDataRow(table.Columns, values)); + } + + index++; + } + + table.TotalCount = index; + return table; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/DependencyInjection/IPrivateDependency.cs b/Znyc.Cloudcar.Admin.Commons/DependencyInjection/IPrivateDependency.cs new file mode 100644 index 0000000..832c55d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/DependencyInjection/IPrivateDependency.cs @@ -0,0 +1,9 @@ +namespace Znyc.Cloudcar.Admin.Commons.DependencyInjection +{ + /// + /// 依赖空接口(禁止外部继承) + /// + public interface IPrivateDependency + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/DependencyInjection/IScopedDependency.cs b/Znyc.Cloudcar.Admin.Commons/DependencyInjection/IScopedDependency.cs new file mode 100644 index 0000000..45ec5e5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/DependencyInjection/IScopedDependency.cs @@ -0,0 +1,9 @@ +namespace Znyc.Cloudcar.Admin.Commons.DependencyInjection +{ + /// + /// 作用域服务注册依赖 + /// + public interface IScopedDependency : IPrivateDependency + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/DependencyInjection/ISingletonDependency.cs b/Znyc.Cloudcar.Admin.Commons/DependencyInjection/ISingletonDependency.cs new file mode 100644 index 0000000..20cb6d6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/DependencyInjection/ISingletonDependency.cs @@ -0,0 +1,9 @@ +namespace Znyc.Cloudcar.Admin.Commons.DependencyInjection +{ + /// + /// 单例服务注册依赖 + /// + public interface ISingletonDependency : IPrivateDependency + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/DependencyInjection/ITransientDependency.cs b/Znyc.Cloudcar.Admin.Commons/DependencyInjection/ITransientDependency.cs new file mode 100644 index 0000000..64da641 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/DependencyInjection/ITransientDependency.cs @@ -0,0 +1,9 @@ +namespace Znyc.Cloudcar.Admin.Commons.DependencyInjection +{ + /// + /// 暂时服务注册依赖 + /// + public interface ITransientDependency : IPrivateDependency + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/Base64Util.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/Base64Util.cs new file mode 100644 index 0000000..36bd87f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/Base64Util.cs @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons +{ + /// + /// 基于Base64的加密编码辅助类, + /// 可以设置不同的密码表来获取不同的编码与解码 + /// + public class Base64Util + { + /// + /// + protected static Base64Util s_b64 = new(); + + /// + /// 密码表 + /// + protected string m_codeTable = @"ABCDEFGHIJKLMNOPQRSTUVWXYZbacdefghijklmnopqrstu_wxyz0123456789*-"; + + /// + /// 补码 + /// + protected string m_pad = "v"; + + /// + /// + protected Dictionary m_t1 = new(); + + /// + /// + protected Dictionary m_t2 = new(); + + /// + /// 构造函数,初始化编码表 + /// + public Base64Util() + { + InitDict(); + } + + /// + /// 密码表 + /// + public string CodeTable + { + get => m_codeTable; + set + { + if (value == null) + { + throw new Exception("密码表不能为null"); + } + + if (value.Length < 64) + { + throw new Exception("密码表长度必须至少为64"); + } + + ValidateRepeat(value); + ValidateEqualPad(value, m_pad); + m_codeTable = value; + InitDict(); + } + } + + /// + /// 补码 + /// + public string Pad + { + get => m_pad; + set + { + if (value == null) + { + throw new Exception("密码表的补码不能为null"); + } + + if (value.Length != 1) + { + throw new Exception("密码表的补码长度必须为1"); + } + + ValidateEqualPad(m_codeTable, value); + m_pad = value; + InitDict(); + } + } + + /// + /// 使用默认的密码表加密字符串 + /// + /// 待加密字符串 + /// + public static string Encrypt(string input) + { + return s_b64.Encode(input); + } + + /// + /// 使用默认的密码表解密字符串 + /// + /// 待解密字符串 + /// + public static string Decrypt(string input) + { + return s_b64.Decode(input); + } + + /// + /// 获取具有标准的Base64密码表的加密类 + /// + /// + public static Base64Util GetStandardBase64() + { + Base64Util b64 = new Base64Util + { + Pad = "=", + CodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + }; + return b64; + } + + /// + /// 返回编码后的字符串 + /// + /// 原字符串 + /// + public string Encode(string source) + { + if (source == null || source == "") + { + return ""; + } + + StringBuilder sb = new StringBuilder(); + byte[] tmp = Encoding.UTF8.GetBytes(source); + int remain = tmp.Length % 3; + int patch = 3 - remain; + if (remain != 0) + { + Array.Resize(ref tmp, tmp.Length + patch); + } + + int cnt = (int)Math.Ceiling(tmp.Length * 1.0 / 3); + for (int i = 0; i < cnt; i++) + { + sb.Append(EncodeUnit(tmp[i * 3], tmp[i * 3 + 1], tmp[i * 3 + 2])); + } + + if (remain != 0) + { + sb.Remove(sb.Length - patch, patch); + for (int i = 0; i < patch; i++) + { + sb.Append(m_pad); + } + } + + return sb.ToString(); + } + + /// + /// + /// + /// + protected string EncodeUnit(params byte[] unit) + { + int[] obj = new int[4]; + obj[0] = (unit[0] & 0xfc) >> 2; + obj[1] = ((unit[0] & 0x03) << 4) + ((unit[1] & 0xf0) >> 4); + obj[2] = ((unit[1] & 0x0f) << 2) + ((unit[2] & 0xc0) >> 6); + obj[3] = unit[2] & 0x3f; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < obj.Length; i++) + { + sb.Append(GetEC(obj[i])); + } + + return sb.ToString(); + } + + /// + /// + /// + /// + protected char GetEC(int code) + { + return m_t1[code]; //m_codeTable[code]; + } + + /// + /// 获得解码字符串 + /// + /// 原字符串 + /// + public string Decode(string source) + { + if (source == null || source == "") + { + return ""; + } + + List list = new List(); + char[] tmp = source.ToCharArray(); + int remain = tmp.Length % 4; + if (remain != 0) + { + Array.Resize(ref tmp, tmp.Length - remain); + } + + int patch = source.IndexOf(m_pad); + if (patch != -1) + { + patch = source.Length - patch; + } + + int cnt = tmp.Length / 4; + for (int i = 0; i < cnt; i++) + { + DecodeUnit(list, tmp[i * 4], tmp[i * 4 + 1], tmp[i * 4 + 2], tmp[i * 4 + 3]); + } + + for (int i = 0; i < patch; i++) + { + list.RemoveAt(list.Count - 1); + } + + return Encoding.UTF8.GetString(list.ToArray()); + } + + /// + /// 获得解码字符串 + /// + /// + /// + protected void DecodeUnit(List byteArr, params char[] chArray) + { + int[] res = new int[3]; + byte[] unit = new byte[chArray.Length]; + for (int i = 0; i < chArray.Length; i++) + { + unit[i] = FindChar(chArray[i]); + } + + res[0] = (unit[0] << 2) + ((unit[1] & 0x30) >> 4); + res[1] = ((unit[1] & 0xf) << 4) + ((unit[2] & 0x3c) >> 2); + res[2] = ((unit[2] & 0x3) << 6) + unit[3]; + for (int i = 0; i < res.Length; i++) + { + byteArr.Add((byte)res[i]); + } + } + + /// + /// + /// + /// + protected byte FindChar(char ch) + { + int pos = m_t2[ch]; //m_codeTable.IndexOf(ch); + return (byte)pos; + } + + /// + /// 初始化双向哈希字典 + /// + protected void InitDict() + { + m_t1.Clear(); + m_t2.Clear(); + m_t2.Add(m_pad[0], -1); + for (int i = 0; i < m_codeTable.Length; i++) + { + m_t1.Add(i, m_codeTable[i]); + m_t2.Add(m_codeTable[i], i); + } + } + + /// + /// 检查字符串中的字符是否有重复 + /// + /// 待检查字符串 + /// + protected void ValidateRepeat(string input) + { + for (int i = 0; i < input.Length; i++) + { + if (input.LastIndexOf(input[i]) > i) + { + throw new Exception("密码表中含有重复字符:" + input[i]); + } + } + } + + /// + /// 检查字符串是否包含补码字符 + /// + /// 待检查字符串 + /// + protected void ValidateEqualPad(string input, string pad) + { + if (input.IndexOf(pad) > -1) + { + throw new Exception("密码表中包含了补码字符:" + pad); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/Cryptography.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/Cryptography.cs new file mode 100644 index 0000000..fc34bf7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/Cryptography.cs @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.Security.Cryptography; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons +{ + /// + /// 用于webapi 生成票据使用,公开 + /// + public sealed class Cryptography + { + /// + /// + /// + /// + /// + public static string AES_encrypt(string tmpStr, string encodingAESKey) + { + string str = tmpStr + GetMD5_32(encodingAESKey); + return GetMD5_32(SHA256(str)) + GetMD5_32(tmpStr); + } + + /// + /// SHA256函数 + /// + /// 原始字符串 + /// SHA256结果(返回长度为44字节的字符串) + public static string SHA256(string str) + { + byte[] SHA256Data = Encoding.UTF8.GetBytes(str); + SHA256Managed Sha256 = new SHA256Managed(); + byte[] Result = Sha256.ComputeHash(SHA256Data); + return Convert.ToBase64String(Result); //返回长度为44字节的字符串 + } + + /// + /// 获得32位的MD5加密 + /// + public static string GetMD5_32(string input) + { + MD5 md5 = MD5.Create(); + byte[] data = md5.ComputeHash(Encoding.Default.GetBytes(input)); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < data.Length; i++) + { + sb.Append(data[i].ToString("x2")); + } + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/DEncrypt.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/DEncrypt.cs new file mode 100644 index 0000000..5b359ae --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/DEncrypt.cs @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.Security.Cryptography; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Encrypt +{ + /// + /// Encrypt 的加密/解密。 + /// + public class DEncrypt + { + #region 使用 缺省密钥字符串 加密/解密string + + /// + /// 使用缺省密钥字符串加密string + /// + /// 明文 + /// 密文 + public static string Encrypt(string original) + { + return Encrypt(original, "ZnycSOFT"); + } + + /// + /// 使用缺省密钥字符串解密string + /// + /// 密文 + /// 明文 + public static string Decrypt(string original) + { + return Decrypt(original, "ZnycSOFT", Encoding.Default); + } + + #endregion 使用 缺省密钥字符串 加密/解密string + + #region 使用 给定密钥字符串 加密/解密string + + /// + /// 使用给定密钥字符串加密string + /// + /// 原始文字 + /// 密钥 + /// 密文 + public static string Encrypt(string original, string key) + { + byte[] buff = Encoding.Default.GetBytes(original); + byte[] kb = Encoding.Default.GetBytes(key); + return Convert.ToBase64String(Encrypt(buff, kb)); + } + + /// + /// 使用给定密钥字符串解密string + /// + /// 密文 + /// 密钥 + /// 明文 + public static string Decrypt(string original, string key) + { + return Decrypt(original, key, Encoding.Default); + } + + /// + /// 使用给定密钥字符串解密string,返回指定编码方式明文 + /// + /// 密文 + /// 密钥 + /// 字符编码方案 + /// 明文 + public static string Decrypt(string encrypted, string key, Encoding encoding) + { + byte[] buff = Convert.FromBase64String(encrypted); + byte[] kb = Encoding.Default.GetBytes(key); + return encoding.GetString(Decrypt(buff, kb)); + } + + #endregion 使用 给定密钥字符串 加密/解密string + + #region 使用 缺省密钥字符串 加密/解密/byte[] + + /// + /// 使用缺省密钥字符串解密byte[] + /// + /// 密文 + /// 密钥 + /// 明文 + public static byte[] Decrypt(byte[] encrypted) + { + byte[] key = Encoding.Default.GetBytes("ZnycSOFT"); + return Decrypt(encrypted, key); + } + + /// + /// 使用缺省密钥字符串加密 + /// + /// 原始数据 + /// 密钥 + /// 密文 + public static byte[] Encrypt(byte[] original) + { + byte[] key = Encoding.Default.GetBytes("ZnycSOFT"); + return Encrypt(original, key); + } + + #endregion 使用 缺省密钥字符串 加密/解密/byte[] + + #region 使用 给定密钥 加密/解密/byte[] + + /// + /// 生成MD5摘要 + /// + /// 数据源 + /// 摘要 + public static byte[] MakeMD5(byte[] original) + { + MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider(); + byte[] keyhash = hashmd5.ComputeHash(original); + hashmd5 = null; + return keyhash; + } + + /// + /// 使用给定密钥加密 + /// + /// 明文 + /// 密钥 + /// 密文 + public static byte[] Encrypt(byte[] original, byte[] key) + { + TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider + { + Key = MakeMD5(key), + Mode = CipherMode.ECB + }; + + return des.CreateEncryptor().TransformFinalBlock(original, 0, original.Length); + } + + /// + /// 使用给定密钥解密数据 + /// + /// 密文 + /// 密钥 + /// 明文 + public static byte[] Decrypt(byte[] encrypted, byte[] key) + { + TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider + { + Key = MakeMD5(key), + Mode = CipherMode.ECB + }; + + return des.CreateDecryptor().TransformFinalBlock(encrypted, 0, encrypted.Length); + } + + #endregion 使用 给定密钥 加密/解密/byte[] + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/EncodeHelper.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/EncodeHelper.cs new file mode 100644 index 0000000..223e141 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/EncodeHelper.cs @@ -0,0 +1,650 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; + +namespace Znyc.Cloudcar.Admin.Commons.Encrypt +{ + /// + /// DES对称加解密、AES RijndaelManaged加解密、Base64加密解密、MD5加密等操作辅助类 + /// + public sealed class EncodeHelper + { + /// + /// SHA256函数 + /// + /// 原始字符串 + /// SHA256结果(返回长度为44字节的字符串) + public static string SHA256(string str) + { + byte[] SHA256Data = Encoding.UTF8.GetBytes(str); + SHA256Managed Sha256 = new SHA256Managed(); + byte[] Result = Sha256.ComputeHash(SHA256Data); + return Convert.ToBase64String(Result); //返回长度为44字节的字符串 + } + + /// + /// 加密字符串 + /// + /// 待加密的字符串 + /// + public static string EncryptString(string input) + { + return MD5Util.AddMD5Profix(Base64Util.Encrypt(MD5Util.AddMD5Profix(input))); + //return Base64.Encrypt(MD5.AddMD5Profix(Base64.Encrypt(input))); + } + + /// + /// 解密加过密的字符串 + /// + /// 待解密的字符串 + /// 解密失败是否抛异常 + /// + public static string DecryptString(string input, bool throwException) + { + string res = ""; + try + { + res = input; // Base64.Decrypt(input); + if (MD5Util.ValidateValue(res)) + { + return MD5Util.RemoveMD5Profix(Base64Util.Decrypt(MD5Util.RemoveMD5Profix(res))); + } + + throw new Exception("字符串无法转换成功!"); + } + catch + { + if (throwException) + { + throw; + } + + return ""; + } + } + + #region DES对称加密解密 + + /// + /// 注意DEFAULT_ENCRYPT_KEY的长度为8位(如果要增加或者减少key长度,调整IV的长度就是了) + /// + public const string DEFAULT_ENCRYPT_KEY = "12345678"; + + /// + /// 使用默认加密 + /// + /// + /// + public static string DesEncrypt(string strText) + { + try + { + return DesEncrypt(strText, DEFAULT_ENCRYPT_KEY); + } + catch + { + return ""; + } + } + + /// + /// 使用默认解密 + /// + /// 解密字符串 + /// + public static string DesDecrypt(string strText) + { + try + { + return DesDecrypt(strText, DEFAULT_ENCRYPT_KEY); + } + catch + { + return ""; + } + } + + /// + /// 加密字符串,注意strEncrKey的长度为8位 + /// + /// 待加密字符串 + /// 加密键 + /// + public static string DesEncrypt(string strText, string strEncrKey) + { + byte[] byKey = null; + byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; + + byKey = Encoding.UTF8.GetBytes(strEncrKey.Substring(0, 8)); + DESCryptoServiceProvider des = new DESCryptoServiceProvider(); + byte[] inputByteArray = Encoding.UTF8.GetBytes(strText); + MemoryStream ms = new MemoryStream(); + CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write); + cs.Write(inputByteArray, 0, inputByteArray.Length); + cs.FlushFinalBlock(); + return Convert.ToBase64String(ms.ToArray()); + } + + /// + /// 解密字符串,注意strEncrKey的长度为8位 + /// + /// 待解密的字符串 + /// 解密键 + /// 解密后的字符串 + public static string DesDecrypt(string strText, string sDecrKey) + { + byte[] byKey = null; + byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; + byte[] inputByteArray = new byte[strText.Length]; + + byKey = Encoding.UTF8.GetBytes(sDecrKey.Substring(0, 8)); + DESCryptoServiceProvider des = new DESCryptoServiceProvider(); + inputByteArray = Convert.FromBase64String(strText); + MemoryStream ms = new MemoryStream(); + CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write); + cs.Write(inputByteArray, 0, inputByteArray.Length); + cs.FlushFinalBlock(); + Encoding encoding = new UTF8Encoding(); + return encoding.GetString(ms.ToArray()); + } + + /// + /// 加密数据文件,注意strEncrKey的长度为8位 + /// + /// 待加密的文件路径 + /// 输出文件路径 + /// 加密键 + public static void DesEncrypt(string m_InFilePath, string m_OutFilePath, string strEncrKey) + { + byte[] byKey = null; + byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; + + byKey = Encoding.UTF8.GetBytes(strEncrKey.Substring(0, 8)); + FileStream fin = new FileStream(m_InFilePath, FileMode.Open, FileAccess.Read); + FileStream fout = new FileStream(m_OutFilePath, FileMode.OpenOrCreate, FileAccess.Write); + fout.SetLength(0); + //Create variables to help with read and write. + byte[] bin = new byte[100]; //This is intermediate storage for the encryption. + long rdlen = 0; //This is the total number of bytes written. + long totlen = fin.Length; //This is the total length of the input file. + int len; //This is the number of bytes to be written at a time. + + DES des = new DESCryptoServiceProvider(); + CryptoStream encStream = new CryptoStream(fout, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write); + + //Read from the input file, then encrypt and write to the output file. + while (rdlen < totlen) + { + len = fin.Read(bin, 0, 100); + encStream.Write(bin, 0, len); + rdlen = rdlen + len; + } + + encStream.Close(); + fout.Close(); + fin.Close(); + } + + /// + /// 解密数据文件,注意strEncrKey的长度为8位 + /// + /// 待解密的文件路径 + /// 输出路径 + /// 解密键 + public static void DesDecrypt(string m_InFilePath, string m_OutFilePath, string sDecrKey) + { + byte[] byKey = null; + byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; + + byKey = Encoding.UTF8.GetBytes(sDecrKey.Substring(0, 8)); + FileStream fin = new FileStream(m_InFilePath, FileMode.Open, FileAccess.Read); + FileStream fout = new FileStream(m_OutFilePath, FileMode.OpenOrCreate, FileAccess.Write); + fout.SetLength(0); + //Create variables to help with read and write. + byte[] bin = new byte[100]; //This is intermediate storage for the encryption. + long rdlen = 0; //This is the total number of bytes written. + long totlen = fin.Length; //This is the total length of the input file. + int len; //This is the number of bytes to be written at a time. + + DES des = new DESCryptoServiceProvider(); + CryptoStream encStream = new CryptoStream(fout, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write); + + //Read from the input file, then encrypt and write to the output file. + while (rdlen < totlen) + { + len = fin.Read(bin, 0, 100); + encStream.Write(bin, 0, len); + rdlen = rdlen + len; + } + + encStream.Close(); + fout.Close(); + fin.Close(); + } + + #endregion DES对称加密解密 + + #region 对称加密算法AES RijndaelManaged加密解密 + + private static readonly string Default_AES_Key = "@#Znycqinwn123"; + + private static readonly byte[] Keys = + { + 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, + 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F + }; + + /// + /// 对称加密算法AES RijndaelManaged加密(RijndaelManaged(AES)算法是块式加密算法) + /// + /// 待加密字符串 + /// 加密结果字符串 + public static string AES_Encrypt(string encryptString) + { + return AES_Encrypt(encryptString, Default_AES_Key); + } + + /// + /// 对称加密算法AES RijndaelManaged加密(RijndaelManaged(AES)算法是块式加密算法) + /// + /// 待加密字符串 + /// 加密密钥,须半角字符 + /// 加密结果字符串 + public static string AES_Encrypt(string encryptString, string encryptKey) + { + encryptKey = GetSubString(encryptKey, 32, ""); + encryptKey = encryptKey.PadRight(32, ' '); + + RijndaelManaged rijndaelProvider = new RijndaelManaged + { + Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32)), + IV = Keys + }; + ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor(); + + byte[] inputData = Encoding.UTF8.GetBytes(encryptString); + byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length); + + return Convert.ToBase64String(encryptedData); + } + + /// + /// 对称加密算法AES RijndaelManaged解密字符串 + /// + /// 待解密的字符串 + /// 解密成功返回解密后的字符串,失败返源串 + public static string AES_Decrypt(string decryptString) + { + return AES_Decrypt(decryptString, Default_AES_Key); + } + + /// + /// 对称加密算法AES RijndaelManaged解密字符串 + /// + /// 待解密的字符串 + /// 解密密钥,和加密密钥相同 + /// 解密成功返回解密后的字符串,失败返回空 + public static string AES_Decrypt(string decryptString, string decryptKey) + { + try + { + decryptKey = GetSubString(decryptKey, 32, ""); + decryptKey = decryptKey.PadRight(32, ' '); + + RijndaelManaged rijndaelProvider = new RijndaelManaged + { + Key = Encoding.UTF8.GetBytes(decryptKey), + IV = Keys + }; + ICryptoTransform rijndaelDecrypt = rijndaelProvider.CreateDecryptor(); + + byte[] inputData = Convert.FromBase64String(decryptString); + byte[] decryptedData = rijndaelDecrypt.TransformFinalBlock(inputData, 0, inputData.Length); + + return Encoding.UTF8.GetString(decryptedData); + } + catch + { + return string.Empty; + } + } + + /// + /// 按字节长度(按字节,一个汉字为2个字节)取得某字符串的一部分 + /// + /// 源字符串 + /// 所取字符串字节长度 + /// 附加字符串(当字符串不够长时,尾部所添加的字符串,一般为"...") + /// 某字符串的一部分 + private static string GetSubString(string sourceString, int length, string tailString) + { + return GetSubString(sourceString, 0, length, tailString); + } + + /// + /// 按字节长度(按字节,一个汉字为2个字节)取得某字符串的一部分 + /// + /// 源字符串 + /// 索引位置,以0开始 + /// 所取字符串字节长度 + /// 附加字符串(当字符串不够长时,尾部所添加的字符串,一般为"...") + /// 某字符串的一部分 + private static string GetSubString(string sourceString, int startIndex, int length, string tailString) + { + string myResult = sourceString; + + //当是日文或韩文时(注:中文的范围:\u4e00 - \u9fa5, 日文在\u0800 - \u4e00, 韩文为\xAC00-\xD7A3) + if (Regex.IsMatch(sourceString, "[\u0800-\u4e00]+") || + Regex.IsMatch(sourceString, "[\xAC00-\xD7A3]+")) + { + //当截取的起始位置超出字段串长度时 + if (startIndex >= sourceString.Length) + { + return string.Empty; + } + + return sourceString.Substring(startIndex, + length + startIndex > sourceString.Length ? sourceString.Length - startIndex : length); + } + + //中文字符,如"中国人民abcd123" + if (length <= 0) + { + return string.Empty; + } + + byte[] bytesSource = Encoding.Default.GetBytes(sourceString); + + //当字符串长度大于起始位置 + if (bytesSource.Length > startIndex) + { + int endIndex = bytesSource.Length; + + //当要截取的长度在字符串的有效长度范围内 + if (bytesSource.Length > startIndex + length) + { + endIndex = length + startIndex; + } + else + { + //当不在有效范围内时,只取到字符串的结尾 + length = bytesSource.Length - startIndex; + tailString = ""; + } + + int[] anResultFlag = new int[length]; + int nFlag = 0; + //字节大于127为双字节字符 + for (int i = startIndex; i < endIndex; i++) + { + if (bytesSource[i] > 127) + { + nFlag++; + if (nFlag == 3) + { + nFlag = 1; + } + } + else + { + nFlag = 0; + } + + anResultFlag[i] = nFlag; + } + + //最后一个字节为双字节字符的一半 + if (bytesSource[endIndex - 1] > 127 && anResultFlag[length - 1] == 1) + { + length = length + 1; + } + + byte[] bsResult = new byte[length]; + Array.Copy(bytesSource, startIndex, bsResult, 0, length); + myResult = Encoding.Default.GetString(bsResult); + myResult = myResult + tailString; + + return myResult; + } + + return string.Empty; + } + + /// + /// 加密文件流 + /// + /// 文件流对象 + /// 加密键 + /// + public static CryptoStream AES_EncryptStrream(FileStream fs, string encryptKey) + { + encryptKey = GetSubString(encryptKey, 32, ""); + encryptKey = encryptKey.PadRight(32, ' '); + + RijndaelManaged rijndaelProvider = new RijndaelManaged + { + Key = Encoding.UTF8.GetBytes(encryptKey), + IV = Keys + }; + + ICryptoTransform encrypto = rijndaelProvider.CreateEncryptor(); + CryptoStream cytptostreamEncr = new CryptoStream(fs, encrypto, CryptoStreamMode.Write); + return cytptostreamEncr; + } + + /// + /// 解密文件流 + /// + /// 文件流对象 + /// 解密键 + /// + public static CryptoStream AES_DecryptStream(FileStream fs, string decryptKey) + { + decryptKey = GetSubString(decryptKey, 32, ""); + decryptKey = decryptKey.PadRight(32, ' '); + + RijndaelManaged rijndaelProvider = new RijndaelManaged + { + Key = Encoding.UTF8.GetBytes(decryptKey), + IV = Keys + }; + ICryptoTransform Decrypto = rijndaelProvider.CreateDecryptor(); + CryptoStream cytptostreamDecr = new CryptoStream(fs, Decrypto, CryptoStreamMode.Read); + return cytptostreamDecr; + } + + /// + /// 对指定文件加密 + /// + /// 输入文件 + /// 输出文件 + /// + public static bool AES_EncryptFile(string InputFile, string OutputFile) + { + try + { + string decryptKey = "www.iqidi.com"; + + FileStream fr = new FileStream(InputFile, FileMode.Open); + FileStream fren = new FileStream(OutputFile, FileMode.Create); + CryptoStream Enfr = AES_EncryptStrream(fren, decryptKey); + byte[] bytearrayinput = new byte[fr.Length]; + fr.Read(bytearrayinput, 0, bytearrayinput.Length); + Enfr.Write(bytearrayinput, 0, bytearrayinput.Length); + Enfr.Close(); + fr.Close(); + fren.Close(); + } + catch + { + //文件异常 + return false; + } + + return true; + } + + /// + /// 对指定的文件解压缩 + /// + /// 输入文件 + /// 输出文件 + /// + public static bool AES_DecryptFile(string InputFile, string OutputFile) + { + try + { + string decryptKey = "www.iqidi.com"; + FileStream fr = new FileStream(InputFile, FileMode.Open); + FileStream frde = new FileStream(OutputFile, FileMode.Create); + CryptoStream Defr = AES_DecryptStream(fr, decryptKey); + byte[] bytearrayoutput = new byte[1024]; + int m_count = 0; + + do + { + m_count = Defr.Read(bytearrayoutput, 0, bytearrayoutput.Length); + frde.Write(bytearrayoutput, 0, m_count); + if (m_count < bytearrayoutput.Length) + { + break; + } + } while (true); + + Defr.Close(); + fr.Close(); + frde.Close(); + } + catch + { + //文件异常 + return false; + } + + return true; + } + + #endregion 对称加密算法AES RijndaelManaged加密解密 + + #region Base64加密解密 + + /// + /// Base64是一種使用64基的位置計數法。它使用2的最大次方來代表僅可列印的ASCII 字元。 + /// 這使它可用來作為電子郵件的傳輸編碼。在Base64中的變數使用字元A-Z、a-z和0-9 , + /// 這樣共有62個字元,用來作為開始的64個數字,最後兩個用來作為數字的符號在不同的 + /// 系統中而不同。 + /// Base64加密 + /// + /// Base64方式加密字符串 + /// + public static string Base64Encrypt(string str) + { + byte[] encbuff = Encoding.UTF8.GetBytes(str); + return Convert.ToBase64String(encbuff); + } + + /// + /// Base64解密字符串 + /// + /// 待解密的字符串 + /// + public static string Base64Decrypt(string str) + { + byte[] decbuff = Convert.FromBase64String(str); + return Encoding.UTF8.GetString(decbuff); + } + + #endregion Base64加密解密 + + #region MD5加密 + + /// + /// 使用MD5加密字符串 + /// + /// 待加密的字符串 + /// MD5加密后的字符串 + public static string MD5Encrypt(string strText) + { + MD5 md5 = new MD5CryptoServiceProvider(); + byte[] result = md5.ComputeHash(Encoding.Default.GetBytes(strText)); + return Encoding.Default.GetString(result); + } + + /// + /// 使用MD5加密的Hash表 + /// + /// 待加密字符串 + /// + public static string MD5EncryptHash(string input) + { + MD5 md5 = new MD5CryptoServiceProvider(); + //the GetBytes method returns byte array equavalent of a string + byte[] res = md5.ComputeHash(Encoding.Default.GetBytes(input), 0, input.Length); + char[] temp = new char[res.Length]; + //copy to a char array which can be passed to a String constructor + Array.Copy(res, temp, res.Length); + //return the result as a string + return new string(temp); + } + + /// + /// 使用Md5加密为16进制字符串 + /// + /// 待加密字符串 + /// + public static string MD5EncryptHashHex(string input) + { + MD5 md5 = new MD5CryptoServiceProvider(); + //the GetBytes method returns byte array equavalent of a string + byte[] res = md5.ComputeHash(Encoding.Default.GetBytes(input), 0, input.Length); + + string returnThis = string.Empty; + + for (int i = 0; i < res.Length; i++) + { + returnThis += Uri.HexEscape((char)res[i]); + } + + returnThis = returnThis.Replace("%", ""); + returnThis = returnThis.ToLower(); + + return returnThis; + } + + /// + /// MD5 三次加密算法.计算过程: (QQ使用) + /// 1. 验证码转为大写 + /// 2. 将密码使用这个方法进行三次加密后,与验证码进行叠加 + /// 3. 然后将叠加后的内容再次MD5一下,得到最终验证码的值 + /// + /// 待加密字符串 + /// + public static string EncyptMD5_3_16(string s) + { + MD5 md5 = MD5.Create(); + byte[] bytes = Encoding.ASCII.GetBytes(s); + byte[] bytes1 = md5.ComputeHash(bytes); + byte[] bytes2 = md5.ComputeHash(bytes1); + byte[] bytes3 = md5.ComputeHash(bytes2); + + StringBuilder sb = new StringBuilder(); + foreach (byte item in bytes3) + { + sb.Append(item.ToString("x").PadLeft(2, '0')); + } + + return sb.ToString().ToUpper(); + } + + #endregion MD5加密 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/EncryptHelper.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/EncryptHelper.cs new file mode 100644 index 0000000..034c4fc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/EncryptHelper.cs @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Encrypt +{ + /// + /// + public class EncryptHelper + { + /// + /// + /// + /// + /// + public static string ComputeHash(string source, string key) + { + if (source == null) + { + return ""; + } + + string text = "abcdefghjklmnopqrstuvwxyz"; + if (source.Length < 0x1a) + { + source = source + text.Substring(source.Length); + } + + byte[] inArray = Encoding.Unicode.GetBytes(source); + int length = inArray.Length; + if (key == null || key.Length == 0) + { + key = "Encryptheqinwn"; + } + + byte[] bytes = Encoding.Unicode.GetBytes(key); + byte num2 = Convert.ToByte(bytes.Length); + byte num3 = 2; + byte index = 0; + for (int i = 0; i < length; i++) + { + byte[] buffer3; + IntPtr ptr; + byte num5 = (byte)(bytes[index] | num2); + num5 = (byte)(num5 & num3); + (buffer3 = inArray)[(int)(ptr = (IntPtr)i)] = (byte)(buffer3[(int)ptr] ^ num5); + num3 = (byte)(num3 + 1); + if (num3 > 0xfd) + { + num3 = 2; + } + + index = (byte)(index + 1); + if (index >= num2) + { + index = 0; + } + } + + return Convert.ToBase64String(inArray, 0, inArray.Length); + } + + /// + /// + /// + /// + /// + public static string EncryptStr(string source, string key) + { + key = key.PadLeft(8, 'x'); + return EncodeHelper.DesEncrypt(source, key); + } + + /// + /// + /// + /// + /// + public static string UnEncryptStr(string source, string key) + { + key = key.PadLeft(8, 'x'); + return EncodeHelper.DesDecrypt(source, key); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/MD5Util.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/MD5Util.cs new file mode 100644 index 0000000..2019687 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/MD5Util.cs @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Encrypt +{ + /// + /// MD5各种长度加密字符、验证MD5等操作辅助类 + /// + public class MD5Util + { + /// + /// 获得32位的MD5加密 + /// + public static string GetMD5_32(string input) + { + MD5 md5 = MD5.Create(); + byte[] data = md5.ComputeHash(Encoding.Default.GetBytes(input)); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < data.Length; i++) + { + sb.Append(data[i].ToString("x2")); + } + + return sb.ToString(); + } + + /// + /// 获得16位的MD5加密 + /// + public static string GetMD5_16(string input) + { + return GetMD5_32(input).Substring(8, 16); + } + + /// + /// 获得8位的MD5加密 + /// + public static string GetMD5_8(string input) + { + return GetMD5_32(input).Substring(8, 8); + } + + /// + /// 获得4位的MD5加密 + /// + public static string GetMD5_4(string input) + { + return GetMD5_32(input).Substring(8, 4); + } + + /// + /// 添加MD5的前缀,便于检查有无篡改 + /// + public static string AddMD5Profix(string input) + { + return GetMD5_4(input) + input; + } + + /// + /// 移除MD5的前缀 + /// + public static string RemoveMD5Profix(string input) + { + return input.Substring(4); + } + + /// + /// 验证MD5前缀处理的字符串有无被篡改 + /// + public static bool ValidateValue(string input) + { + bool res = false; + if (input.Length >= 4) + { + string tmp = input.Substring(4); + if (input.Substring(0, 4) == GetMD5_4(tmp)) + { + res = true; + } + } + + return res; + } + + #region MD5签名验证 + + /// + /// 对给定文件路径的文件加上标签 + /// + /// 要加密的文件的路径 + /// 标签的值 + public static bool AddMD5(string path) + { + bool IsNeed = true; + + if (CheckMD5(path)) //已进行MD5处理 + { + IsNeed = false; + } + + try + { + FileStream fsread = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + byte[] md5File = new byte[fsread.Length]; + fsread.Read(md5File, 0, (int)fsread.Length); // 将文件流读取到Buffer中 + fsread.Close(); + + if (IsNeed) + { + string result = MD5Buffer(md5File, 0, md5File.Length); // 对Buffer中的字节内容算MD5 + byte[] md5 = Encoding.ASCII.GetBytes(result); // 将字符串转换成字节数组以便写人到文件中 + FileStream fsWrite = new FileStream(path, FileMode.Open, FileAccess.ReadWrite); + fsWrite.Write(md5File, 0, md5File.Length); // 将文件,MD5值 重新写入到文件中。 + fsWrite.Write(md5, 0, md5.Length); + fsWrite.Close(); + } + else + { + FileStream fsWrite = new FileStream(path, FileMode.Open, FileAccess.ReadWrite); + fsWrite.Write(md5File, 0, md5File.Length); + fsWrite.Close(); + } + } + catch + { + return false; + } + + return true; + } + + /// + /// 对给定路径的文件进行验证,如果一致返回True,否则返回False + /// + /// + /// 是否加了标签或是否标签值与内容值一致 + public static bool CheckMD5(string path) + { + try + { + FileStream get_file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + byte[] md5File = new byte[get_file.Length]; // 读入文件 + get_file.Read(md5File, 0, (int)get_file.Length); + get_file.Close(); + + string result = MD5Buffer(md5File, 0, md5File.Length - 32); // 对文件除最后32位以外的字节计算MD5,这个32是因为标签位为32位。 + string md5 = Encoding.ASCII.GetString(md5File, md5File.Length - 32, 32); //读取文件最后32位,其中保存的就是MD5值 + return result == md5; + } + catch + { + return false; + } + } + + /// + /// 计算文件的MD5值 + /// + /// MD5签名文件字符数组 + /// 计算起始位置 + /// 计算终止位置 + /// 计算结果 + private static string MD5Buffer(byte[] MD5File, int index, int count) + { + MD5CryptoServiceProvider get_md5 = new MD5CryptoServiceProvider(); + byte[] hash_byte = get_md5.ComputeHash(MD5File, index, count); + string result = BitConverter.ToString(hash_byte); + + result = result.Replace("-", ""); + return result; + } + + #endregion MD5签名验证 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/QQEncryptUtil.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/QQEncryptUtil.cs new file mode 100644 index 0000000..a962e95 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/QQEncryptUtil.cs @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Encrypt +{ + /// + /// QQ密码加密操作辅助类 + /// + public class QQEncryptUtil + { + /// + /// QQ根据密码及验证码对数据进行加密 + /// + /// 原始密码 + /// 验证码 + /// + public static string EncodePasswordWithVerifyCode(string password, string verifyCode) + { + return MD5(MD5_3(password) + verifyCode.ToUpper()); + } + + private static string MD5_3(string arg) + { + System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); + + byte[] buffer = Encoding.ASCII.GetBytes(arg); + buffer = md5.ComputeHash(buffer); + buffer = md5.ComputeHash(buffer); + buffer = md5.ComputeHash(buffer); + + return BitConverter.ToString(buffer).Replace("-", "").ToUpper(); + } + + private static string MD5(string arg) + { + System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); + + byte[] buffer = Encoding.ASCII.GetBytes(arg); + buffer = md5.ComputeHash(buffer); + + return BitConverter.ToString(buffer).Replace("-", "").ToUpper(); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/RSASecurityHelper.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/RSASecurityHelper.cs new file mode 100644 index 0000000..085e4d0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/RSASecurityHelper.cs @@ -0,0 +1,273 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Encrypt +{ + /// + /// 非对称加密、解密、验证辅助类 + /// + public class RSASecurityHelper + { + /// + /// 默认公钥。必须是8位字符的密钥字符串(不能有特殊字符) + /// + private const string DESENCRYPT_KEY = "Znyc.Cloudcar.Admin.com"; + + /// + /// 非对称加密生成的私钥和公钥 + /// + /// 公钥,必须是8位字符的密钥字符串(不能有特殊字符) + /// 私钥 + public static void GenerateRSAKey(out string privateKey, out string publicKey) + { + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + privateKey = rsa.ToXmlString(true); + publicKey = rsa.ToXmlString(false); + } + + #region 非对称数据加密(公钥加密) + + /// + /// 非对称加密字符串数据,返回加密后的数据 + /// + /// 待加密的字符串 + /// + public static string RSAEncrypt(string originalString) + { + return RSAEncrypt(originalString, DESENCRYPT_KEY); + } + + /// + /// 非对称加密字节数组,返回加密后的数据 + /// + /// 待加密的字节数组 + public static string RSAEncrypt(byte[] originalBytes) + { + return RSAEncrypt(originalBytes, DESENCRYPT_KEY); + } + + /// + /// 非对称加密字符串数据,返回加密后的数据 + /// + /// 待加密的字符串 + /// 公钥,必须是8位字符的密钥字符串(不能有特殊字符) + /// 加密后的数据 + public static string RSAEncrypt(string originalString, string publicKey) + { + if (string.IsNullOrEmpty(publicKey) && publicKey.Length != 8) + { + publicKey = DESENCRYPT_KEY; + } + + byte[] PlainTextBArray; + byte[] CypherTextBArray; + string Result; + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.FromXmlString(publicKey); + PlainTextBArray = new UnicodeEncoding().GetBytes(originalString); + CypherTextBArray = rsa.Encrypt(PlainTextBArray, false); + Result = Convert.ToBase64String(CypherTextBArray); + return Result; + } + + /// + /// 非对称加密字节数组,返回加密后的数据 + /// + /// 待加密的字节数组 + /// 公钥,必须是8位字符的密钥字符串(不能有特殊字符) + /// 返回加密后的数据 + public static string RSAEncrypt(byte[] originalBytes, string publicKey) + { + if (string.IsNullOrEmpty(publicKey) && publicKey.Length != 8) + { + publicKey = DESENCRYPT_KEY; + } + + byte[] CypherTextBArray; + string Result; + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.FromXmlString(publicKey); + CypherTextBArray = rsa.Encrypt(originalBytes, false); + Result = Convert.ToBase64String(CypherTextBArray); + return Result; + } + + #endregion 非对称数据加密(公钥加密) + + #region 非对称解密(私钥解密) + + /// + /// 非对称解密字符串,返回解密后的数据 + /// + /// 私钥 + /// 待解密数据 + /// 返回解密后的数据 + public static string RSADecrypt(string privateKey, string encryptedString) + { + byte[] PlainTextBArray; + byte[] DypherTextBArray; + string Result; + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.FromXmlString(privateKey); + PlainTextBArray = Convert.FromBase64String(encryptedString); + DypherTextBArray = rsa.Decrypt(PlainTextBArray, false); + Result = new UnicodeEncoding().GetString(DypherTextBArray); + return Result; + } + + /// + /// 非对称解密字节数组,返回解密后的数据 + /// + /// 私钥 + /// 待解密数据 + /// + public static string RSADecrypt(string privateKey, byte[] encryptedBytes) + { + byte[] DypherTextBArray; + string Result; + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.FromXmlString(privateKey); + DypherTextBArray = rsa.Decrypt(encryptedBytes, false); + Result = new UnicodeEncoding().GetString(DypherTextBArray); + return Result; + } + + #endregion 非对称解密(私钥解密) + + #region 非对称加密签名、验证 + + /// + /// 使用非对称加密签名数据 + /// + /// 私钥 + /// 待加密的字符串 + /// 加密后的数据 + public static string RSAEncrypSignature(string originalString, string privateKey) + { + string signature; + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + rsa.FromXmlString(privateKey); //私钥 + // 加密对象 + RSAPKCS1SignatureFormatter f = new RSAPKCS1SignatureFormatter(rsa); + f.SetHashAlgorithm("SHA1"); + byte[] source = Encoding.ASCII.GetBytes(originalString); + SHA1Managed sha = new SHA1Managed(); + byte[] result = sha.ComputeHash(source); + byte[] b = f.CreateSignature(result); + signature = Convert.ToBase64String(b); + } + + return signature; + } + + /// + /// 对私钥加密的字符串,使用公钥对其进行验证 + /// + /// 未加密的文本,如机器码 + /// 加密后的文本,如注册序列号 + /// 非对称加密的公钥 + /// 如果验证成功返回True,否则为False + public static bool Validate(string originalString, string encrytedString, string publicKey) + { + bool bPassed = false; + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) + { + try + { + rsa.FromXmlString(publicKey); //公钥 + RSAPKCS1SignatureDeformatter formatter = new RSAPKCS1SignatureDeformatter(rsa); + formatter.SetHashAlgorithm("SHA1"); + + byte[] key = Convert.FromBase64String(encrytedString); //验证 + SHA1Managed sha = new SHA1Managed(); + byte[] name = sha.ComputeHash(Encoding.ASCII.GetBytes(originalString)); + if (formatter.VerifySignature(name, key)) + { + bPassed = true; + } + } + catch + { + } + } + + return bPassed; + } + + #endregion 非对称加密签名、验证 + + #region Hash 加密 + + /// Hash 加密 + /// + /// + public static int HashEncrypt(string str2Hash) + { + const int salt = 100716; // 盐值 + str2Hash += "Commons"; // 增加一个常量字符串 + + int len = str2Hash.Length; + int result = (str2Hash[len - 1] - 31) * 95 + salt; + for (int i = 0; i < len - 1; i++) + { + result = result * 95 + (str2Hash[i] - 32); + } + + return result; + } + + /// + /// MD5加密 + /// + /// 待加密字串 + /// 加密后的字串 + public static string ComputeMD5(string str) + { + byte[] hashValue = ComputeMD5Data(str); + return BitConverter.ToString(hashValue).Replace("-", ""); + } + + /// + /// MD5加密 + /// + /// 待加密字串 + /// 加密后的字串 + public static byte[] ComputeMD5Data(string input) + { + byte[] buffer = Encoding.UTF8.GetBytes(input); + return MD5.Create().ComputeHash(buffer); + } + + /// + /// MD5加密 + /// + /// 待加密数据 + /// 加密后的字串 + public static byte[] ComputeMD5Data(byte[] data) + { + return MD5.Create().ComputeHash(data); + } + + /// + /// MD5加密 + /// + /// 待加密流 + /// 加密后的字串 + public static byte[] ComputeMD5Data(Stream stream) + { + return MD5.Create().ComputeHash(stream); + } + + #endregion Hash 加密 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Encrypt/RSAUtils.cs b/Znyc.Cloudcar.Admin.Commons/Encrypt/RSAUtils.cs new file mode 100644 index 0000000..85f52a4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Encrypt/RSAUtils.cs @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using Newtonsoft.Json; +using System.IO; +using System.Security.Cryptography; + +namespace Znyc.Cloudcar.Admin.Commons.Encrypt +{ + /// + /// RSA加解密工具 + /// + public static class RSAUtils + { + /// + /// 从本地文件中读取用来签发Token的 RSA Key。 + /// + /// 存放密钥的文件夹路径 + /// + /// + /// + public static bool TryGetKeyParameters(string filePath, bool withPrivate, out RSAParameters keyParameters) + { + string filename = withPrivate ? "key.json" : "key.public.json"; + keyParameters = default; + if (Directory.Exists(filePath) == false) + { + return false; + } + + keyParameters = + JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine(filePath, filename))); + return true; + } + + /// + /// 生成并保存 RSA 公钥与私钥。 + /// + /// 存放密钥的文件夹路径 + /// + public static RSAParameters GenerateAndSaveKey(string filePath) + { + RSAParameters publicKeys, privateKeys; + using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048)) + { + try + { + privateKeys = rsa.ExportParameters(true); + publicKeys = rsa.ExportParameters(false); + } + finally + { + rsa.PersistKeyInCsp = false; + } + } + + File.WriteAllText(Path.Combine(filePath, "key.json"), JsonConvert.SerializeObject(privateKeys)); + File.WriteAllText(Path.Combine(filePath, "key.public.json"), JsonConvert.SerializeObject(publicKeys)); + return privateKeys; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/ActivityStatusEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/ActivityStatusEnum.cs new file mode 100644 index 0000000..fc46149 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/ActivityStatusEnum.cs @@ -0,0 +1,26 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 广告、活动状态 + /// + public enum ActivityStatusEnum + { + /// + /// 未开始 + /// + [Description("未开始")] NotStart = 0, + + /// + /// 进行中 + /// + [Description("进行中")] Ongoing = 1, + + /// + /// 已结束 + /// + [Description("已结束")] End = 2 + + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/BannerTypeEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/BannerTypeEnum.cs new file mode 100644 index 0000000..ba5f566 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/BannerTypeEnum.cs @@ -0,0 +1,25 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// Banner类型枚举 + /// + public enum BannerTypeEnum + { + /// + /// 未关联 + /// + [Description("未关联")] NotAssociated = 0, + + /// + /// 电话 + /// + [Description("电话")] phone = 1, + + /// + /// 链接 + /// + [Description("链接")] Link = 2 + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/CallFeedbackStatusEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/CallFeedbackStatusEnum.cs new file mode 100644 index 0000000..a91428f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/CallFeedbackStatusEnum.cs @@ -0,0 +1,30 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 通话评价状态枚举 + /// + public enum CallFeedbackStatusEnum + { + /// + /// 真实有效 + /// + [Description("真实有效")] Real = 1, + + /// + /// 已经找到 + /// + [Description("已经找到")] Found = 2, + + /// + /// 联系不上 + /// + [Description("联系不上")] ContactFail = 3, + + /// + /// 虚假信息 + /// + [Description("虚假信息")] FalseInformation = 4 + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/CommonStatus.cs b/Znyc.Cloudcar.Admin.Commons/Enums/CommonStatus.cs new file mode 100644 index 0000000..485372c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/CommonStatus.cs @@ -0,0 +1,30 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 公共状态 + /// + public enum CommonStatus + { + /// + /// 正常 + /// + [Description("正常")] ENABLE = 1, + + /// + /// 停用 + /// + [Description("停用")] DISABLE = -1, + + /// + /// 删除 + /// + [Description("删除")] DELETED = -2, + + /// + /// 审核中 + /// + [Description("审核中")] REVIEW = 0 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/CurrencyEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/CurrencyEnum.cs new file mode 100644 index 0000000..e12c456 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/CurrencyEnum.cs @@ -0,0 +1,168 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 积分类型枚举 + /// + public enum CreditsTypeEnum + { + /// + /// 正式积分 + /// + [Description("正式积分")] Formal = 1, + + /// + /// 临时积分 + /// + [Description("临时积分")] Temporary = 2 + } + + /// + /// 操作类型枚举 + /// + public enum OperatingTypeEnum + { + /// + /// 增加 + /// + [Description("收入")] Add = 1, + + /// + /// 减少 + /// + [Description("支出")] Reduce = 2, + + /// + /// 冻结 + /// + [Description("冻结")] Freeze = 3 + } + + /// + /// 云币来源类型 + /// + public enum CurrencyTypeEnum + { + /// + /// 首次登陆 + /// + [Description("首次登陆")] FirstLogin = 1, + + /// + /// 邀新用户 + /// + [Description("邀新用户")] NewUsers = 2, + + /// + /// 每日分享 + /// + [Description("每日分享")] DailyShare = 3, + + /// + /// 关注公众号 + /// + [Description("关注公众号")] FocusOn = 4, + + /// + /// 个人海报 + /// + [Description("个人海报")] PersonalPoster = 14, + + /// + /// 发布招聘 + /// + [Description("发布招聘")] Cloudcar = 5, + + /// + /// 发布求职 + /// + [Description("发布求职")] ApplyJob = 6, + + /// + /// 实名认证 + /// + [Description("实名认证")] RealName = 7, + + /// + /// 每日签到 + /// + [Description("每日签到")] Signin = 8, + + /// + /// 积分充值 + /// + [Description("积分充值")] BuyCurrency = 9, + + /// + /// 抽奖赚积分 + /// + [Description("抽奖赚积分")] LuckyDraw = 10, + + /// + /// 兑换奖品 + /// + [Description("兑换奖品")] Conversion = 11, + + /// + /// 拔打求职电话 + /// + [Description("拔打求职电话")] CallApplyJobPhone = 12, + + /// + /// 拔打电话 + /// + [Description("拔打招聘电话")] CallCloudcarPhone = 13, + + /// + /// 求职置顶 + /// + [Description("置顶求职信息")] TopApplyJob = 15, + + /// + /// 招聘置顶 + /// + [Description("置顶招聘信息")] TopCloudcar = 16, + + /// + /// 刷新招聘信息 + /// + [Description("刷新招聘")] RefreshCloudcar = 17, + + /// + /// 刷新求职信息 + /// + [Description("刷新求职")] RefreshApplyJob = 18, + + /// + /// 求职置顶 + /// + [Description("置顶求职退还")] ReturnTopApplyJob = 19, + + /// + /// 招聘置顶 + /// + [Description("置顶招聘退还")] RenturnTopCloudcar = 20, + } + + /// + /// 操作积分类型 + /// + public enum CreditsStatusEnum + { + /// + /// 有效 + /// + [Description("有效")] Valid = 1, + + /// + /// 已过期 + /// + [Description("已过期")] Expired = 2, + + /// + /// 冻结 + /// + [Description("冻结")] Freeze = 3 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/DatabaseType.cs b/Znyc.Cloudcar.Admin.Commons/Enums/DatabaseType.cs new file mode 100644 index 0000000..7e19666 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/DatabaseType.cs @@ -0,0 +1,43 @@ +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 数据库类型枚举 + /// + public enum DatabaseType + { + /// + /// SqlServer数据库 + /// + SqlServer = 0, + + /// + /// Oracle数据库 + /// + Oracle, + + /// + /// Access数据库 + /// + Access, + + /// + /// MySql数据库 + /// + MySql, + + /// + /// SQLite数据库 + /// + SQLite, + + /// + /// PostgreSQL数据库 + /// + PostgreSQL, + + /// + /// Npgsql数据库 + /// + Npgsql + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/DictionaryCodeEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/DictionaryCodeEnum.cs new file mode 100644 index 0000000..8a12f9a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/DictionaryCodeEnum.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + + /// + /// + /// + public enum DictionaryCodeEnum + { + BC=10000 + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/EquipmentState.cs b/Znyc.Cloudcar.Admin.Commons/Enums/EquipmentState.cs new file mode 100644 index 0000000..eb00a18 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/EquipmentState.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 设备状态枚举 + /// + public enum EquipmentState + { + + /// + /// 未通过 + /// + [Description("未通过")] Fail = 0, + + /// + /// 审核中 + /// + [Description("审核中")] InReview = 10, + + /// + /// 出售中 + /// + [Description("出售中")] Selling = 20, + + /// + /// 已成交 + /// + [Description("已成交")] Traded = 30, + + /// + /// 已下架 + /// + [Description("已下架")] Shelved = 99, + + /// + /// 撤销审核 + /// + [Description("撤销审核")] Revocation = 50 + + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/HandleStatusEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/HandleStatusEnum.cs new file mode 100644 index 0000000..9bede21 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/HandleStatusEnum.cs @@ -0,0 +1,24 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// + public enum HandleStatusEnum + { + /// + /// 审核中 + /// + [Description("未审核")] InReview = 0, + + /// + /// 审核通过 + /// + [Description("审核通过")] Finding = 1, + + /// + /// 未通过 + /// + [Description("未通过")] Fail = 4 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/JobAction.cs b/Znyc.Cloudcar.Admin.Commons/Enums/JobAction.cs new file mode 100644 index 0000000..5bd9275 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/JobAction.cs @@ -0,0 +1,19 @@ +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 任务操作 + /// + public enum JobAction + { + 新增 = 1, + 删除 = 2, + 修改 = 3, + 暂停 = 4, + 停止 = 5, + 开启 = 6, + 立即执行 = 7, + 执行中 = 8, + 开始, + 结束 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/JobRunResult.cs b/Znyc.Cloudcar.Admin.Commons/Enums/JobRunResult.cs new file mode 100644 index 0000000..43d2f6b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/JobRunResult.cs @@ -0,0 +1,17 @@ +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// + public enum JobRunResult + { + 新增 = 1, + 删除 = 2, + 修改 = 3, + 暂停 = 4, + 停止 = 5, + 开启 = 6, + 立即执行 = 7, + 开始 = 8, + 结束 = 9 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/LinqExpressionType.cs b/Znyc.Cloudcar.Admin.Commons/Enums/LinqExpressionType.cs new file mode 100644 index 0000000..50f8a44 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/LinqExpressionType.cs @@ -0,0 +1,15 @@ +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + public enum LinqExpressionType + { + Equal = 0, //= + NotEqual = 1, //!= + GreaterThan, //> + LessThan, //< + ThanOrEqual, //>= + LessThanOrEqual, //<= + In, + Contains, //Contains + NotContains //NotContains + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/MsgType.cs b/Znyc.Cloudcar.Admin.Commons/Enums/MsgType.cs new file mode 100644 index 0000000..ef8bfad --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/MsgType.cs @@ -0,0 +1,23 @@ +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 通知操作类型 + /// + public enum MsgType + { + /// + /// 不通知 + /// + No = 0, + + /// + /// 异常通知 + /// + Error = 1, + + /// + /// 通知所有 + /// + All = 2 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/PlatformTypeEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/PlatformTypeEnum.cs new file mode 100644 index 0000000..8779131 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/PlatformTypeEnum.cs @@ -0,0 +1,25 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 来源平台 + /// + public enum PlatformTypeEnum + { + /// + /// 人才招聘 + /// + [Description("人才招聘")] Cloudcar = 1, + + /// + /// 派工调度 + /// + [Description("派工调度")] Dispatching = 2, + + /// + /// 后台管理系统 + /// + [Description("后台管理系统")] Management = 3 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/ProductStatusEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/ProductStatusEnum.cs new file mode 100644 index 0000000..c83d837 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/ProductStatusEnum.cs @@ -0,0 +1,41 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// + public enum ProductStatusEnum + { + /// + /// 未通过 + /// + [Description("未通过")] + Fail = 0, + + /// + /// 审核中 + /// + [Description("审核中")] + Review = 10, + + /// + /// 出售中 + /// + [Description("出售中")] + Sell = 20, + + + /// + /// 已成交 + /// + [Description("已成交")] + Deal = 30, + + + /// + /// 已下架 + /// + [Description("已下架")] + Cancel = 99, + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/ProductTypeEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/ProductTypeEnum.cs new file mode 100644 index 0000000..c462155 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/ProductTypeEnum.cs @@ -0,0 +1,20 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 产品类型枚举 + /// + public enum ProductTypeEnum + { + /// + /// 求职 + /// + [Description("求职")] ApplyJob = 1, + + /// + /// 招聘 + /// + [Description("招聘")] Cloudcar = 2 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/QueryOrderBy.cs b/Znyc.Cloudcar.Admin.Commons/Enums/QueryOrderBy.cs new file mode 100644 index 0000000..cb7146a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/QueryOrderBy.cs @@ -0,0 +1,8 @@ +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + public enum QueryOrderBy + { + Desc = 1, + Asc = 2 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/UserCertificationEnum.cs b/Znyc.Cloudcar.Admin.Commons/Enums/UserCertificationEnum.cs new file mode 100644 index 0000000..9628b49 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/UserCertificationEnum.cs @@ -0,0 +1,30 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 用户实名状态枚举 + /// + public enum UserCertificationEnum + { + /// + /// 实名审核中 + /// + [Description("实名审核中")] Review = 0, + + /// + /// 实名通过 + /// + [Description("实名通过")] Pass = 1, + + /// + /// 实名失败 + /// + [Description("实名失败")] Fail = 2, + + /// + /// 未实名 + /// + [Description("未实名")] None = 3 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Enums/UserType.cs b/Znyc.Cloudcar.Admin.Commons/Enums/UserType.cs new file mode 100644 index 0000000..8e8e448 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Enums/UserType.cs @@ -0,0 +1,23 @@ +namespace Znyc.Cloudcar.Admin.Commons.Enums +{ + /// + /// 用户类型 + /// + public enum UserType + { + /// + /// 会员 + /// + Member = 0, + + /// + /// 租户 + /// + Tenant, + + /// + /// 管理员 + /// + Manager + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extend/ExtDate.cs b/Znyc.Cloudcar.Admin.Commons/Extend/ExtDate.cs new file mode 100644 index 0000000..487141b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extend/ExtDate.cs @@ -0,0 +1,281 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Extend +{ + /// + /// 日期扩展方法 + /// + public static class ExtDate + { + /// + /// 格式:刚刚、几分钟前、几小时前、几天前、yyyy/MM/dd + /// + /// + /// + public static string ToEasyString(this DateTime value) + { + DateTime now = DateTime.Now; + if (now < value) + { + return value.ToString("yyyy/MM/dd"); + } + + TimeSpan dep = now - value; + if (dep.TotalMinutes < 30) + { + return "刚刚"; + } + + if (dep.TotalMinutes >= 30 && dep.TotalMinutes < 60) + { + return (int)dep.TotalMinutes + " 分钟前"; + } + + if (dep.TotalHours < 24) + { + return (int)dep.TotalHours + " 小时前"; + } + + if (dep.TotalDays <= 7) + { + return (int)dep.TotalDays + " 天前"; + } + + if (dep.TotalDays > 7 && dep.TotalDays <= 14) + { + int defautlWeek = 0; + defautlWeek = (int)dep.TotalDays / 7; + if ((int)dep.TotalDays % 7 > 0) + { + defautlWeek++; + } + + return defautlWeek + " 周前"; + } + + if (dep.TotalDays > 14 && dep.TotalDays < 365) + { + return value.Month.ToString().PadLeft(2, '0') + "-" + + value.Day.ToString().PadLeft(2, '0') + " " + value.Hour + ":" + value.Minute; + } + + return now.Year - value.Year + " 年前"; + } + + /// + /// 格式:即将、几分钟后、几小时后、几天后、yyyy/MM/dd + /// + /// + /// + public static string ToEasyStringDQ(this DateTime value) + { + DateTime now = DateTime.Now; + if (value < now) + { + return "已过期"; + } + + TimeSpan dep = value - now; + + if (dep.TotalMinutes < 60) + { + return (int)dep.TotalMinutes + " 分钟后"; + } + + if (dep.TotalHours < 24) + { + return (int)dep.TotalHours + " 小时后"; + } + + if (dep.TotalDays <= 30) + { + return (int)dep.TotalDays + " 天后"; + } + + if (dep.TotalDays > 30 && dep.TotalDays <= 90) + { + int defautlWeek = 0; + defautlWeek = (int)dep.TotalDays / 30; + if ((int)dep.TotalDays % 30 > 0) + { + defautlWeek++; + } + + return defautlWeek + " 个月后"; + } + + if (dep.TotalDays > 90 && dep.TotalDays < 365) + { + return value.Month.ToString().PadLeft(2, '0') + "-" + + value.Day.ToString().PadLeft(2, '0') + " " + value.Hour + ":" + value.Minute; + } + + return " 长期"; + } + + /// + /// 格式:几秒、几分钟几秒、几小时几分钟几秒 + /// + /// + /// + public static string ToBrowseTime(this int value) + { + if (value > 0) + { + TimeSpan ts = new TimeSpan(0, 0, value); + if (ts.Days > 0) + { + if (ts.Hours > 0) + { + return ts.Days + "天" + ts.Hours + "小时" + ts.Minutes + "分钟" + ts.Seconds + "秒"; + } + + return ts.Hours + "小时" + ts.Minutes + "分钟"; + } + + if (ts.Hours > 0) + { + if (ts.Seconds > 0) + { + return ts.Hours + "小时" + ts.Minutes + "分钟" + ts.Seconds + "秒"; + } + + return ts.Hours + "小时" + ts.Minutes + "分钟"; + } + + if (ts.Minutes > 0) + { + return ts.Minutes + "分钟" + ts.Seconds + "秒"; + } + + return ts.Seconds + "秒"; + } + + return "1秒"; + } + + /// + /// + /// + /// + public static string ToEasyString(this DateTime? value) + { + if (value.HasValue) + { + return value.Value.ToEasyString(); + } + + return string.Empty; + } + + /// + /// + /// + /// + public static string ToEasyStringDQ(this DateTime? value) + { + if (value.HasValue) + { + return value.Value.ToEasyStringDQ(); + } + + return string.Empty; + } + + /// + /// 计算日期间隔 + /// + /// 要参与计算的其中一个日期 + /// 要参与计算的另一个日期 + /// 决定返回值形式的枚举 + /// 一个代表年月日的int数组,具体数组长度与枚举参数drf有关 + public static int[] ToDiffResult(DateTime d1, DateTime d2, DiffResultFormat drf) + { + #region 数据初始化 + + DateTime max; + DateTime min; + int year; + int month; + int tempYear, tempMonth; + if (d1 > d2) + { + max = d1; + min = d2; + } + else + { + max = d2; + min = d1; + } + + tempYear = max.Year; + tempMonth = max.Month; + if (max.Month < min.Month) + { + tempYear--; + tempMonth = tempMonth + 12; + } + + year = tempYear - min.Year; + month = tempMonth - min.Month; + + #endregion 数据初始化 + + #region 按条件计算 + + if (drf == DiffResultFormat.dd) + { + TimeSpan ts = max - min; + return new[] { ts.Days }; + } + + if (drf == DiffResultFormat.mm) + { + return new[] { month + year * 12 }; + } + + if (drf == DiffResultFormat.yy) + { + return new[] { year }; + } + + return new[] { year, month }; + + #endregion 按条件计算 + } + } + + /// + /// 关于返回值形式的枚举 + /// + public enum DiffResultFormat + { + /// + /// 年数和月数 + /// + yymm, + + /// + /// 年数 + /// + yy, + + /// + /// 月数 + /// + mm, + + /// + /// 天数 + /// + dd + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extend/ExtIEnumerable.cs b/Znyc.Cloudcar.Admin.Commons/Extend/ExtIEnumerable.cs new file mode 100644 index 0000000..da0238a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extend/ExtIEnumerable.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Znyc.Cloudcar.Admin.Commons.Extend +{ + /// + /// IEnumerable��չ�� + /// + [DebuggerStepThrough] + public static class ExtIEnumerable + { + /// + /// ѭ��IEnumerable + /// + /// + /// + /// + /// + public static IEnumerable Each(this IEnumerable source, Action fun) + { + foreach (T item in source) + { + fun(item); + } + + return source; + } + + /// + /// IEnumerableתList + /// + /// + /// + /// + /// + /// + public static List ToList(this IEnumerable source, Func fun) + { + List result = new List(); + source.Each(m => result.Add(fun(m))); + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extend/ExtInt.cs b/Znyc.Cloudcar.Admin.Commons/Extend/ExtInt.cs new file mode 100644 index 0000000..e0e2411 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extend/ExtInt.cs @@ -0,0 +1,33 @@ +namespace Znyc.Cloudcar.Admin.Commons.Extend +{ + /// + /// ļССļ + /// + public static class ExtInt + { + /// + /// ʾļСX Bytex KbxMxG + /// + /// + /// + public static string ToDisplayFileSize(this int value) + { + if (value < 1000) + { + return string.Format("{0} Byte", value); + } + + if (value >= 1000 && value < 1000000) + { + return string.Format("{0:F2} Kb", (double)value / 1024); + } + + if (value >= 1000 && value < 1000000000) + { + return string.Format("{0:F2} M", (double)value / 1048576); + } + + return string.Format("{0:F2} G", (double)value / 1073741824); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extend/ExtQueryable.cs b/Znyc.Cloudcar.Admin.Commons/Extend/ExtQueryable.cs new file mode 100644 index 0000000..d844786 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extend/ExtQueryable.cs @@ -0,0 +1,46 @@ +using System.Linq; +using System.Linq.Expressions; + +namespace Znyc.Cloudcar.Admin.Commons.Extend +{ + /// + /// + public static class ExtQueryable + { + /// + /// + /// + /// + /// + /// + public static IQueryable OrderBy(this IQueryable source, string ordering) + { + System.Type type = typeof(T); + System.Reflection.PropertyInfo property = type.GetProperty(ordering); + ParameterExpression parameter = Expression.Parameter(type, "p"); + MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, property); + LambdaExpression orderByExp = Expression.Lambda(propertyAccess, parameter); + MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new[] { type, property.PropertyType }, + source.Expression, Expression.Quote(orderByExp)); + return source.Provider.CreateQuery(resultExp); + } + + /// + /// + /// + /// + /// + /// + public static IQueryable OrderByDescending(this IQueryable source, string ordering) + { + System.Type type = typeof(T); + System.Reflection.PropertyInfo property = type.GetProperty(ordering); + ParameterExpression parameter = Expression.Parameter(type, "p"); + MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, property); + LambdaExpression orderByExp = Expression.Lambda(propertyAccess, parameter); + MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderByDescending", + new[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp)); + return source.Provider.CreateQuery(resultExp); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extend/ExtString.cs b/Znyc.Cloudcar.Admin.Commons/Extend/ExtString.cs new file mode 100644 index 0000000..3539edb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extend/ExtString.cs @@ -0,0 +1,566 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.IO; +using System.Net; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; + +namespace Znyc.Cloudcar.Admin.Commons.Extend +{ + /// + /// ַ + /// + public static class ExtString + { + /// + /// email֤ + /// + private static readonly Regex emailExpression = + new(@"^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$", + RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.Compiled); + + /// + /// url֤ + /// + private static readonly Regex webUrlExpression = new(@"(http|https)://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", + RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.Compiled); + + /// + /// + private static readonly Regex stripHTMLExpression = new("<\\S[^><]*>", + RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.CultureInvariant | + RegexOptions.Compiled); + + /// + /// htmlʽ + /// + /// + /// + public static string NoHTML(this string Htmlstring) + { + Htmlstring = Regex.Replace(Htmlstring, @"", "", RegexOptions.IgnoreCase); + Htmlstring = Regex.Replace(Htmlstring, @"", "", RegexOptions.IgnoreCase); + Htmlstring = Regex.Replace(Htmlstring, @"", "", RegexOptions.IgnoreCase); + Htmlstring = Regex.Replace(Htmlstring, @"<.*?>", "", RegexOptions.IgnoreCase); + Htmlstring = Regex.Replace(Htmlstring, @"<(.[^>]*)>", " ", RegexOptions.IgnoreCase); + Htmlstring = Regex.Replace(Htmlstring, @"([\r\n])[\s]+", " ", RegexOptions.IgnoreCase); + Htmlstring = Regex.Replace(Htmlstring, @"-->", " ", RegexOptions.IgnoreCase); + Htmlstring = Regex.Replace(Htmlstring, @" UserService, IUserRepository --> UserRepository. + /// + /// + /// 服务集合 + /// 服务集合 + public static IServiceCollection AddAutoScanInjection(this IServiceCollection services) + { + RuntimeHelper.GetAllZnycAssemblies().ToList().ForEach(a => + { + a.GetTypes().Where(t => typeof(IPrivateDependency).IsAssignableFrom(t) && t.IsClass).ToList().ForEach( + t => + { + Type serviceType = t.GetInterface($"I{t.Name}"); + if ((serviceType ?? t).GetInterface(typeof(ISingletonDependency).Name) != null) + { + if (serviceType != null) + { + services.AddSingleton(serviceType, t); + } + else + { + services.AddSingleton(t); + } + } + else if ((serviceType ?? t).GetInterface(typeof(IScopedDependency).Name) != null) + { + if (serviceType != null) + { + services.AddScoped(serviceType, t); + } + else + { + services.AddScoped(t); + } + } + else if ((serviceType ?? t).GetInterface(typeof(ITransientDependency).Name) != null) + { + if (serviceType != null) + { + services.AddTransient(serviceType, t); + } + else + { + services.AddTransient(t); + } + } + else + { + if (serviceType != null) + { + services.AddTransient(serviceType, t); + } + else + { + services.AddTransient(t); + } + } + }); + }); + return services; + } + + #region 用DI批量注入接口程序集中对应的实现类,接口和实现类在一个程序集中。 + + /// + /// 用DI批量注入接口程序集中对应的实现类。 + /// 针对每一次服务提供请求,IServiceProvider对象总是创建一个新的服务实例 + /// + /// 需要注意的是,这里有如下约定: + /// IUserService --> UserService, IUserRepository --> UserRepository. + /// + /// + /// + /// 接口程序集的名称(不包含文件扩展名) + /// + public static IServiceCollection AddTransientAssembly(this IServiceCollection service, + string interfaceAssemblyName) + { + if (service == null) + { + throw new ArgumentNullException(nameof(service)); + } + + if (string.IsNullOrEmpty(interfaceAssemblyName)) + { + throw new ArgumentNullException(nameof(interfaceAssemblyName)); + } + + Assembly assembly = RuntimeHelper.GetAssembly(interfaceAssemblyName); + if (assembly == null) + { + throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found"); + } + + //过滤掉非接口及泛型接口 + System.Collections.Generic.IEnumerable types = assembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); + + foreach (Type type in types) + { + string implementTypeName = type.Name.Substring(1); + Type implementType = RuntimeHelper.GetImplementType(implementTypeName, type); + if (implementType != null) + { + service.AddTransient(type, implementType); + } + } + + return service; + } + + /// + /// 用DI批量注入接口程序集中对应的实现类。 + /// 在同一个作用域内只初始化一个实例 ,可以理解为每一个请求只创建一个实例,同一个请求会在一个作用域内。在Scooped的生存周期内,如果容器释放 它也就被释放了 + /// + /// 需要注意的是,这里有如下约定: + /// IUserService --> UserService, IUserRepository --> UserRepository. + /// + /// + /// + /// 接口程序集的名称(不包含文件扩展名) + /// + public static IServiceCollection AddScopedAssembly(this IServiceCollection service, + string interfaceAssemblyName) + { + if (service == null) + { + throw new ArgumentNullException(nameof(service)); + } + + if (string.IsNullOrEmpty(interfaceAssemblyName)) + { + throw new ArgumentNullException(nameof(interfaceAssemblyName)); + } + + Assembly assembly = RuntimeHelper.GetAssembly(interfaceAssemblyName); + if (assembly == null) + { + throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found"); + } + + //过滤掉非接口及泛型接口 + System.Collections.Generic.IEnumerable types = assembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); + + foreach (Type type in types) + { + string implementTypeName = type.Name.Substring(1); + Type implementType = RuntimeHelper.GetImplementType(implementTypeName, type); + if (implementType != null) + { + service.AddScoped(type, implementType); + } + } + + return service; + } + + /// + /// 用DI批量注入接口程序集中对应的实现类。 + /// 整个应用程序生命周期以内只创建一个实例,后续每个请求都使用相同的实例。如果应用程序需要单例行为,建议让服务容器管理服务的生命周期,而不是在自己的类中实现单例模式。 + /// + /// 需要注意的是,这里有如下约定: + /// IUserService --> UserService, IUserRepository --> UserRepository. + /// + /// + /// + /// 接口程序集的名称(不包含文件扩展名) + /// + public static IServiceCollection AddSingletonAssembly(this IServiceCollection service, + string interfaceAssemblyName) + { + if (service == null) + { + throw new ArgumentNullException(nameof(service)); + } + + if (string.IsNullOrEmpty(interfaceAssemblyName)) + { + throw new ArgumentNullException(nameof(interfaceAssemblyName)); + } + + Assembly assembly = RuntimeHelper.GetAssembly(interfaceAssemblyName); + if (assembly == null) + { + throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found"); + } + + //过滤掉非接口及泛型接口 + System.Collections.Generic.IEnumerable types = assembly.GetTypes().Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); + + foreach (Type type in types) + { + string implementTypeName = type.Name.Substring(1); + Type implementType = RuntimeHelper.GetImplementType(implementTypeName, type); + if (implementType != null) + { + service.AddSingleton(type, implementType); + } + } + + return service; + } + + #endregion 用DI批量注入接口程序集中对应的实现类,接口和实现类在一个程序集中。 + + #region 用DI批量注入接口程序集中对应的实现类,接口和实现类在独立的程序集中。 + + /// + /// 用DI批量注入接口程序集中对应的实现类。 + /// + /// + /// 接口程序集的名称(不包含文件扩展名) + /// 实现程序集的名称(不包含文件扩展名) + /// + public static IServiceCollection AddScopedAssembly(this IServiceCollection service, + string interfaceAssemblyName, string implementAssemblyName) + { + if (service == null) + { + throw new ArgumentNullException(nameof(service)); + } + + if (string.IsNullOrEmpty(interfaceAssemblyName)) + { + throw new ArgumentNullException(nameof(interfaceAssemblyName)); + } + + if (string.IsNullOrEmpty(implementAssemblyName)) + { + throw new ArgumentNullException(nameof(implementAssemblyName)); + } + + Assembly interfaceAssembly = RuntimeHelper.GetAssembly(interfaceAssemblyName); + if (interfaceAssembly == null) + { + throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found"); + } + + Assembly implementAssembly = RuntimeHelper.GetAssembly(implementAssemblyName); + if (implementAssembly == null) + { + throw new DllNotFoundException($"the dll \"{implementAssemblyName}\" not be found"); + } + + //过滤掉非接口及泛型接口 + System.Collections.Generic.IEnumerable types = interfaceAssembly.GetTypes() + .Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); + + foreach (Type type in types) + { + //过滤掉抽象类、泛型类以及非class + TypeInfo implementType = implementAssembly.DefinedTypes + .FirstOrDefault(t => t.IsClass && !t.IsAbstract && !t.IsGenericType && + t.GetInterfaces().Any(b => b.Name == type.Name)); + if (implementType != null) + { + service.AddScoped(type, implementType.AsType()); + } + } + + return service; + } + + /// + /// 用DI批量注入接口程序集中对应的实现类。 + /// + /// + /// 接口程序集的名称(不包含文件扩展名) + /// 实现程序集的名称(不包含文件扩展名) + /// + public static IServiceCollection AddTransientAssembly(this IServiceCollection service, + string interfaceAssemblyName, string implementAssemblyName) + { + if (service == null) + { + throw new ArgumentNullException(nameof(service)); + } + + if (string.IsNullOrEmpty(interfaceAssemblyName)) + { + throw new ArgumentNullException(nameof(interfaceAssemblyName)); + } + + if (string.IsNullOrEmpty(implementAssemblyName)) + { + throw new ArgumentNullException(nameof(implementAssemblyName)); + } + + Assembly interfaceAssembly = RuntimeHelper.GetAssembly(interfaceAssemblyName); + if (interfaceAssembly == null) + { + throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found"); + } + + Assembly implementAssembly = RuntimeHelper.GetAssembly(implementAssemblyName); + if (implementAssembly == null) + { + throw new DllNotFoundException($"the dll \"{implementAssemblyName}\" not be found"); + } + + //过滤掉非接口及泛型接口 + System.Collections.Generic.IEnumerable types = interfaceAssembly.GetTypes() + .Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); + + foreach (Type type in types) + { + //过滤掉抽象类、泛型类以及非class + TypeInfo implementType = implementAssembly.DefinedTypes + .FirstOrDefault(t => t.IsClass && !t.IsAbstract && !t.IsGenericType && + t.GetInterfaces().Any(b => b.Name == type.Name)); + if (implementType != null) + { + service.AddTransient(type, implementType.AsType()); + } + } + + return service; + } + + /// + /// 用DI批量注入接口程序集中对应的实现类。 + /// + /// + /// 接口程序集的名称(不包含文件扩展名) + /// 实现程序集的名称(不包含文件扩展名) + /// + public static IServiceCollection AddSingletonAssembly(this IServiceCollection service, + string interfaceAssemblyName, string implementAssemblyName) + { + if (service == null) + { + throw new ArgumentNullException(nameof(service)); + } + + if (string.IsNullOrEmpty(interfaceAssemblyName)) + { + throw new ArgumentNullException(nameof(interfaceAssemblyName)); + } + + if (string.IsNullOrEmpty(implementAssemblyName)) + { + throw new ArgumentNullException(nameof(implementAssemblyName)); + } + + Assembly interfaceAssembly = RuntimeHelper.GetAssembly(interfaceAssemblyName); + if (interfaceAssembly == null) + { + throw new DllNotFoundException($"the dll \"{interfaceAssemblyName}\" not be found"); + } + + Assembly implementAssembly = RuntimeHelper.GetAssembly(implementAssemblyName); + if (implementAssembly == null) + { + throw new DllNotFoundException($"the dll \"{implementAssemblyName}\" not be found"); + } + + //过滤掉非接口及泛型接口 + System.Collections.Generic.IEnumerable types = interfaceAssembly.GetTypes() + .Where(t => t.GetTypeInfo().IsInterface && !t.GetTypeInfo().IsGenericType); + + foreach (Type type in types) + { + //过滤掉抽象类、泛型类以及非class + TypeInfo implementType = implementAssembly.DefinedTypes + .FirstOrDefault(t => t.IsClass && !t.IsAbstract && !t.IsGenericType && + t.GetInterfaces().Any(b => b.Name == type.Name)); + if (implementType != null) + { + service.AddSingleton(type, implementType.AsType()); + } + } + + return service; + } + + #endregion 用DI批量注入接口程序集中对应的实现类,接口和实现类在独立的程序集中。 + + #region 数据库上下文相关服务注入 + + /// + /// 注册数据库上下文工厂 + /// + /// + /// + /// + public static IServiceCollection AddDbContextFactory(this IServiceCollection services, + Action action) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + DbContextFactory factory = DbContextFactory.Instance; + factory.ServiceCollection = services; + action?.Invoke(factory); + return factory.ServiceCollection; + } + + /// + /// 注入数据库上下文 + /// + /// + /// + /// + /// 数据库上下文配置参数 + /// + public static IServiceCollection AddDbContext(this IServiceCollection services, DbContextOption option) + where IT : IDbContextCore where T : BaseDbContext, IT + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (option == null) + { + throw new ArgumentNullException(nameof(option)); + } + + services.AddSingleton(option); + return services.AddDbContext(option); + } + + /// + /// 注入数据库上下文 + /// + /// + /// + /// + /// + public static IServiceCollection AddDbContext(this IServiceCollection services) + where IT : IDbContextCore where T : BaseDbContext, IT + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + return services.AddDbContext(); + } + + /// + /// 获取数据库上下文 + /// + /// + /// 上下文标签名称 + /// + /// + public static object GetDbContext(this IServiceProvider provider, string dbContextTagName, Type serviceType) + { + if (provider == null) + { + throw new ArgumentNullException(nameof(provider)); + } + + object implService = provider.GetRequiredService(serviceType); + DbContextOption option = provider.GetServices() + .FirstOrDefault(m => m.dbConfigName == dbContextTagName); + + object context = Activator.CreateInstance(implService.GetType(), option); + + return context; + } + + #endregion 数据库上下文相关服务注入 + + #region 注册仓储Repositories + + /// + /// 注册仓储Repositories + /// + /// + /// + /// + public static IServiceCollection RegisterDefaultRepositories(this IServiceCollection services) + where T : DbContext, new() + { + Assembly assembly = Assembly.GetExecutingAssembly(); + System.Collections.Generic.List list = assembly.GetTypes().Where(t => t.GetCustomAttributes() + .Any(a => a.ContextType == typeof(T)) + && !t.GetCustomAttributes().Any() && + !t.FullName.Contains("Migrations")).ToList(); + if (list.Any()) + { + foreach (Type type in list) + { + Type pkType = GetPrimaryKeyType(type); + Type implType = GetRepositoryType(type, pkType); + if (pkType != null) + { + services.TryAddScoped(typeof(IRepository<,>).MakeGenericType(type, pkType), implType); + } + } + } + + return services; + } + + /// + /// 获取继承仓储BaseRepository的所有仓储类型 + /// + /// + /// + /// + private static Type GetRepositoryType(Type entityType, Type primaryKeyType) + { + return typeof(BaseRepository<,>).MakeGenericType(entityType, primaryKeyType); + } + + /// + /// 获取继承Entity的所有实体类型主键类型 + /// + /// + /// + private static Type GetPrimaryKeyType(Type entityType) + { + foreach (Type interfaceType in entityType.GetTypeInfo().GetInterfaces()) + { + if (interfaceType.GetTypeInfo().IsGenericType && + interfaceType.GetGenericTypeDefinition() == typeof(Entity)) + { + return interfaceType.GenericTypeArguments[0]; + } + } + + return null; + } + + #endregion 注册仓储Repositories + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/CollectionExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/CollectionExtensions.cs new file mode 100644 index 0000000..0b7d9c8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/CollectionExtensions.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Data; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// 集合扩展方法 + /// + public static class CollectionExtensions + { + /// + /// 如果条件成立,添加项 + /// + public static void AddIf(this ICollection collection, T value, bool flag) + { + Check.NotNull(collection, nameof(collection)); + if (flag) + { + collection.Add(value); + } + } + + /// + /// 如果条件成立,添加项 + /// + public static void AddIf(this ICollection collection, T value, Func func) + { + Check.NotNull(collection, nameof(collection)); + if (func()) + { + collection.Add(value); + } + } + + /// + /// 如果不存在,添加项 + /// + public static void AddIfNotExist(this ICollection collection, T value, Func existFunc = null) + { + Check.NotNull(collection, nameof(collection)); + bool exists = existFunc == null ? collection.Contains(value) : existFunc(value); + if (!exists) + { + collection.Add(value); + } + } + + /// + /// 如果不为空,添加项 + /// + public static void AddIfNotNull(this ICollection collection, T value) where T : class + { + Check.NotNull(collection, nameof(collection)); + if (value != null) + { + collection.Add(value); + } + } + + /// + /// 获取对象,不存在对使用委托添加对象 + /// + public static T GetOrAdd(this ICollection collection, Func selector, Func factory) + { + Check.NotNull(collection, nameof(collection)); + T item = collection.FirstOrDefault(selector); + if (item == null) + { + item = factory(); + collection.Add(item); + } + + return item; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/DateTimeExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/DateTimeExtensions.cs new file mode 100644 index 0000000..70a12db --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/DateTimeExtensions.cs @@ -0,0 +1,308 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// 日期时间扩展 + /// + public static class DateTimeExtensions + { + // Number of 100ns ticks per time unit + private const long TicksPerMillisecond = 10000; + + private const long TicksPerSecond = TicksPerMillisecond * 1000; + private const long TicksPerMinute = TicksPerSecond * 60; + private const long TicksPerHour = TicksPerMinute * 60; + + private const long TicksPerDay = TicksPerHour * 24; + + // Number of milliseconds per time unit + private const int MillisPerSecond = 1000; + + private const int MillisPerMinute = MillisPerSecond * 60; + private const int MillisPerHour = MillisPerMinute * 60; + + private const int MillisPerDay = MillisPerHour * 24; + + // Number of days in a non-leap year + private const int DaysPerYear = 365; + + // Number of days in 4 years + private const int DaysPer4Years = DaysPerYear * 4 + 1; // 1461 + + // Number of days in 100 years + private const int DaysPer100Years = DaysPer4Years * 25 - 1; // 36524 + + // Number of days in 400 years + private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097 + + // Number of days from 1/1/0001 to 12/31/1600 + private const int DaysTo1601 = DaysPer400Years * 4; // 584388 + + // Number of days from 1/1/0001 to 12/30/1899 + private const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367; + + // Number of days from 1/1/0001 to 12/31/1969 + internal const int + DaysTo1970 = DaysPer400Years * 4 + DaysPer100Years * 3 + DaysPer4Years * 17 + DaysPerYear; // 719,162 + + // Number of days from 1/1/0001 to 12/31/9999 + private const int DaysTo10000 = DaysPer400Years * 25 - 366; // 3652059 + + internal const long MinTicks = 0; + internal const long MaxTicks = DaysTo10000 * TicksPerDay - 1; + private const long MaxMillis = (long)DaysTo10000 * MillisPerDay; + + private const long DoubleDateOffset = DaysTo1899 * TicksPerDay; + + // All OA dates must be greater than (not >=) OADateMinAsDouble + private const double OADateMinAsDouble = -657435.0; + + // All OA dates must be less than (not <=) OADateMaxAsDouble + private const double OADateMaxAsDouble = 2958466.0; + + /// + /// + public static readonly DateTime BeginOfEpoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// Converts a nullable date/time value to UTC. + /// + /// The nullable date/time + /// The nullable date/time in UTC + public static DateTime? ToUniversalTime(this DateTime? dateTime) + { + return dateTime.HasValue ? dateTime.Value.ToUniversalTime() : null; + } + + /// + /// Converts a nullable UTC date/time value to local time. + /// + /// The nullable UTC date/time + /// The nullable UTC date/time as local time + public static DateTime? ToLocalTime(this DateTime? dateTime) + { + return dateTime.HasValue ? dateTime.Value.ToLocalTime() : null; + } + + /// + /// Returns a date that is rounded to the next even hour above the given + /// date. + ///

+ /// For example an input date with a time of 08:13:54 would result in a date + /// with the time of 09:00:00. If the date's time is in the 23rd hour, the + /// date's 'day' will be promoted, and the time will be set to 00:00:00. + ///

+ ///
+ /// + /// the Date to round, if the current time will + /// be used + /// + /// the new rounded date + public static DateTime GetEvenHourDate(this DateTime? dateTime) + { + if (!dateTime.HasValue) + { + dateTime = DateTime.UtcNow; + } + + DateTime d = dateTime.Value.AddHours(1); + return new DateTime(d.Year, d.Month, d.Day, d.Hour, 0, 0); + } + + /// + /// Returns a date that is rounded to the next even minute above the given + /// date. + ///

+ /// For example an input date with a time of 08:13:54 would result in a date + /// with the time of 08:14:00. If the date's time is in the 59th minute, + /// then the hour (and possibly the day) will be promoted. + ///

+ ///
+ /// The Date to round, if the current time will be used + /// The new rounded date + public static DateTime GetEvenMinuteDate(this DateTime? dateTime) + { + if (!dateTime.HasValue) + { + dateTime = DateTime.UtcNow; + } + + DateTime d = dateTime.Value; + d = d.AddMinutes(1); + return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, 0); + } + + /// + /// Returns a date that is rounded to the previous even minute below the + /// given date. + ///

+ /// For example an input date with a time of 08:13:54 would result in a date + /// with the time of 08:13:00. + ///

+ ///
+ /// + /// the Date to round, if the current time will + /// be used + /// + /// the new rounded date + public static DateTime GetEvenMinuteDateBefore(this DateTime? dateTime) + { + if (!dateTime.HasValue) + { + dateTime = DateTime.UtcNow; + } + + DateTime d = dateTime.Value; + return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, 0); + } + + /// + /// + /// + /// + public static long ToJavaScriptTicks(this DateTime dateTime) + { + DateTimeOffset utcDateTime = dateTime.ToUniversalTime(); + long javaScriptTicks = (utcDateTime.Ticks - BeginOfEpoch.Ticks) / 10000; + return javaScriptTicks; + } + + /// + /// Get the first day of the month for + /// any full date submitted + /// + /// + /// + public static DateTime GetFirstDayOfMonth(this DateTime date) + { + DateTime dtFrom = date; + dtFrom = dtFrom.AddDays(-(dtFrom.Day - 1)); + return dtFrom; + } + + /// + /// Get the last day of the month for any + /// full date + /// + /// + /// + public static DateTime GetLastDayOfMonth(this DateTime date) + { + DateTime dtTo = date; + dtTo = dtTo.AddMonths(1); + dtTo = dtTo.AddDays(-dtTo.Day); + return dtTo; + } + + /// + /// + /// + /// + public static DateTime ToEndOfTheDay(this DateTime dt) + { + if (dt != null) + { + return new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59); + } + + return dt; + } + + /// + /// + /// + /// + public static DateTime? ToEndOfTheDay(this DateTime? dt) + { + return dt.HasValue ? dt.Value.ToEndOfTheDay() : dt; + } + + /// Epoch time. Number of seconds since midnight (UTC) on 1st January 1970. + public static long ToUnixTime(this DateTime date) + { + return Convert.ToInt64((date.ToUniversalTime() - BeginOfEpoch).TotalSeconds); + } + + /// UTC date based on number of seconds since midnight (UTC) on 1st January 1970. + public static DateTime FromUnixTime(this long unixTime) + { + return BeginOfEpoch.AddSeconds(unixTime); + } + + // Creates a DateTime from an OLE Automation Date. + // + public static DateTime FromOADate(this double d) + { + return new(DoubleDateToTicks(d), DateTimeKind.Unspecified); + } + + // Converts an OLE Date to a tick count. + // This function is duplicated in COMDateTime.cpp + internal static long DoubleDateToTicks(double value) + { + // The check done this way will take care of NaN + if (!(value < OADateMaxAsDouble) || !(value > OADateMinAsDouble)) + { + throw new ArgumentException("Arg_OleAutDateInvalid"); + } + + // Conversion to long will not cause an overflow here, as at this point the "value" is in between OADateMinAsDouble and OADateMaxAsDouble + long millis = (long)(value * MillisPerDay + (value >= 0 ? 0.5 : -0.5)); + // The interesting thing here is when you have a value like 12.5 it all positive 12 days and 12 hours from 01/01/1899 + // However if you a value of -12.25 it is minus 12 days but still positive 6 hours, almost as though you meant -11.75 all negative + // This line below fixes up the millis in the negative case + if (millis < 0) + { + millis -= millis % MillisPerDay * 2; + } + + millis += DoubleDateOffset / TicksPerMillisecond; + + if (millis < 0 || millis >= MaxMillis) + { + throw new ArgumentException("Arg_OleAutDateScale"); + } + + return millis * TicksPerMillisecond; + } + + #region 时间对象与时间戳相互转换 + + /// + /// 将 DateTime 转换为 Unix 时间戳 + /// + /// 需要转换的时间 + /// Unix 时间戳 + public static long DateTimeToUnixTime(this DateTime dateTime) + { + return (long)(dateTime - TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1, 0, 0, 0), TimeZoneInfo.Local)) + .TotalSeconds; + } + + /// + /// 将 Unix 时间戳转换为 DateTime + /// + /// Unix 时间戳 + /// 需要转换的时间 + public static DateTime UnixTimeToDateTime(this long timestamp) + { + if (timestamp < 0) + { + throw new ArgumentOutOfRangeException("timestamp is out of range"); + } + + return TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1, 0, 0, 0), TimeZoneInfo.Local) + .AddSeconds(timestamp); + } + + #endregion 时间对象与时间戳相互转换 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/EntityFrameworkCoreExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/EntityFrameworkCoreExtensions.cs new file mode 100644 index 0000000..2d837cc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/EntityFrameworkCoreExtensions.cs @@ -0,0 +1,246 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.IDbContext; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + public static class EntityFrameworkCoreExtensions + { + public static DataTable GetCurrentDatabaseAllTables(this IDbContextCore context) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade db = context.GetDatabase(); + string sql = string.Empty; + if (db.IsSqlServer()) + { + sql = "select * from (SELECT (case when a.colorder=1 then d.name else '' end) as TableName," + + "(case when a.colorder=1 then isnull(f.value,'') else '' end) as TableComment" + + " FROM syscolumns a" + + " inner join sysobjects d on a.id=d.id and d.xtype='U' and d.name<>'dtproperties'" + + " left join sys.extended_properties f on d.id=f.major_id and f.minor_id=0) t" + + " where t.TableName!=''"; + } + else if (db.IsMySql()) + { + sql = + "SELECT TABLE_NAME as TableName," + + " Table_Comment as TableComment" + + " FROM INFORMATION_SCHEMA.TABLES" + + $" where TABLE_SCHEMA = '{db.GetDbConnection().Database}'"; + } + else if (db.IsNpgsql()) + { + sql = + "select relname as TableName," + + " cast(obj_description(relfilenode,'pg_class') as varchar) as TableComment" + + " from pg_class c" + + " where relkind = 'r' and relname not like 'pg_%' and relname not like 'sql_%'" + + " order by relname"; + } + else if (db.IsOracle()) + { + sql = + "select \"a\".TABLE_NAME as \"TableName\",\"b\".COMMENTS as \"TableComment\" from USER_TABLES \"a\" JOIN user_tab_comments \"b\" on \"b\".TABLE_NAME=\"a\".TABLE_NAME"; + } + else + { + throw new NotImplementedException("This method does not support current database yet."); + } + + return context.GetDataTable(sql); + } + + public static DataTable GetTableColumns(this IDbContextCore context, params string[] tableNames) + { + if (tableNames == null || tableNames.Length == 0) + { + return null; + } + + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade db = context.GetDatabase(); + string sql = string.Empty; + if (db.IsSqlServer()) + { + sql = "SELECT d.name as TableName,a.name as ColName," + + "CONVERT(bit,(case when COLUMNPROPERTY(a.id,a.name,'IsIdentity')=1 then 1 else 0 end)) as IsIdentity, " + + "CONVERT(bit,(case when (SELECT count(*) FROM sysobjects WHERE (name in (SELECT name FROM sysindexes WHERE (id = a.id) AND (indid in (SELECT indid FROM sysindexkeys WHERE (id = a.id) AND (colid in (SELECT colid FROM syscolumns WHERE (id = a.id) AND (name = a.name))))))) AND (xtype = 'PK'))>0 then 1 else 0 end)) as IsPrimaryKey," + + "b.name as ColumnType," + + "COLUMNPROPERTY(a.id,a.name,'PRECISION') as ColumnLength," + + "CONVERT(bit,(case when a.isnullable=1 then 1 else 0 end)) as IsNullable, " + + "isnull(e.text,'') as DefaultValue," + + "isnull(g.[value], ' ') AS Comments " + + "FROM syscolumns a left join systypes b on a.xtype=b.xusertype inner join sysobjects d on a.id=d.id and d.xtype='U' and d.name<>'dtproperties' left join syscomments e on a.cdefault=e.id left join sys.extended_properties g on a.id=g.major_id AND a.colid=g.minor_id left join sys.extended_properties f on d.id=f.class and f.minor_id=0 " + + $"where b.name is not null and d.name in ({tableNames.Select(m => $"'{m}'").Join(",")}) order by a.id,a.colorder"; + } + else if (db.IsMySql()) + { + sql = + "select table_name as TableName,column_name as ColName, " + + " column_default as DefaultValue," + + " IF(extra = 'auto_increment','TRUE','FALSE') as IsIdentity," + + " IF(is_nullable = 'YES','TRUE','FALSE') as IsNullable," + + " DATA_TYPE as ColumnType," + + " CHARACTER_MAXIMUM_LENGTH as ColumnLength," + + " IF(COLUMN_KEY = 'PRI','TRUE','FALSE') as IsPrimaryKey," + + " COLUMN_COMMENT as Comments " + + $" from information_schema.columns where table_schema = '{db.GetDbConnection().Database}' and table_name in ({tableNames.Select(m => $"'{m}'").Join(",")})"; + } + else if (db.IsNpgsql()) + { + sql = + "select table_name as TableName,column_name as ColName," + + "data_type as ColumnType," + + "coalesce(character_maximum_length, numeric_precision, -1) as ColumnLength," + + "CAST((case is_nullable when 'NO' then 0 else 1 end) as bool) as IsNullable," + + "column_default as DefaultValue," + + "CAST((case when position('nextval' in column_default)> 0 then 1 else 0 end) as bool) as IsIdentity, " + + "CAST((case when b.pk_name is null then 0 else 1 end) as bool) as IsPrimaryKey," + + "c.DeText as Comments" + + " from information_schema.columns" + + " left join " + + " (select pg_attr.attname as colname,pg_constraint.conname as pk_name from pg_constraint " + + " inner join pg_class on pg_constraint.conrelid = pg_class.oid" + + " inner join pg_attribute pg_attr on pg_attr.attrelid = pg_class.oid and pg_attr.attnum = pg_constraint.conkey[1]" + + $" inner join pg_type on pg_type.oid = pg_attr.atttypid where pg_class.relname in ({tableNames.Select(m => $"'{m}'").Join(",")}) and pg_constraint.contype = 'p') b on b.colname = information_schema.columns.column_name " + + " left join " + + " (select attname, description as DeText from pg_class " + + " left join pg_attribute pg_attr on pg_attr.attrelid = pg_class.oid" + + " left join pg_description pg_desc on pg_desc.objoid = pg_attr.attrelid and pg_desc.objsubid = pg_attr.attnum " + + $" where pg_attr.attnum > 0 and pg_attr.attrelid = pg_class.oid and pg_class.relname in ({tableNames.Select(m => $"'{m}'").Join(",")})) c on c.attname = information_schema.columns.column_name" + + $" where table_schema = 'public' and table_name in ({tableNames.Select(m => $"'{m}'").Join(",")}) order by ordinal_position asc"; + } + else if (db.IsOracle()) + { + sql = "select a.Table_Name as TableName," + + "a.DATA_LENGTH as ColumnLength," + + "a.COLUMN_NAME as ColName," + + "a.DATA_PRECISION as DataPrecision," + + "a.DATA_SCALE as DataScale," + + "a.DATA_TYPE as ColumnType," + + "decode(a.NULLABLE, 'Y', 'TRUE', 'N', 'FALSE') as IsNullable," + + "case when d.COLUMN_NAME is null then 'FALSE' else 'TRUE' end as IsPrimaryKey," + + "decode(a.IDENTITY_COLUMN, 'YES', 'TRUE', 'NO', 'FALSE') as IsIdentity," + + "b.COMMENTS as Comments " + + "from user_tab_columns a " + + "left join user_tab_comments b on b.TABLE_NAME = a.COLUMN_NAME " + + "left join user_constraints c on c.TABLE_NAME = a.TABLE_NAME and c.CONSTRAINT_TYPE = 'P' " + + "left join user_cons_columns d on d.CONSTRAINT_NAME = c.CONSTRAINT_NAME and d.COLUMN_NAME = a.COLUMN_NAME " + + $"where a.Table_Name in ({tableNames.Select(m => $"'{m.ToUpper()}'").Join(",")})"; + } + else + { + throw new NotImplementedException("This method does not support current database yet."); + } + + return context.GetDataTable(sql); + } + + /// + /// 执行SQL返回受影响的行数 + /// + public static int ExecuteSqlNoQuery(this IDbContextCore context, string sql, DbParameter[] sqlParams = null) + { + return ExecuteNoQuery(context, sql, sqlParams); + } + + /// + /// 执行存储过程返回IEnumerable数据集 + /// + public static IEnumerable ExecuteStoredProcedure(this IDbContextCore context, string sql, + DbParameter[] sqlParams = null) where T : new() + { + return Execute(context, sql, CommandType.StoredProcedure, sqlParams); + } + + /// + /// 执行sql返回IEnumerable数据集 + /// + public static IEnumerable ExecuteSqlReader(this IDbContextCore context, string sql, + DbParameter[] sqlParams = null) where T : new() + { + return Execute(context, sql, CommandType.Text, sqlParams); + } + + private static int ExecuteNoQuery(this IDbContextCore context, string sql, DbParameter[] sqlParams) + { + Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade db = context.GetDatabase(); + DbConnection connection = db.GetDbConnection(); + DbCommand cmd = connection.CreateCommand(); + if (connection.State == ConnectionState.Closed) + { + connection.Open(); + } + + cmd.CommandText = sql; + cmd.CommandType = CommandType.Text; + if (sqlParams != null) + { + cmd.Parameters.AddRange(sqlParams); + } + + int result = cmd.ExecuteNonQuery(); + connection.Close(); + return result; + } + + private static IEnumerable Execute(this IDbContextCore context, string sql, CommandType type, + params DbParameter[] sqlParams) where T : new() + { + Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade db = context.GetDatabase(); + DbConnection connection = db.GetDbConnection(); + DbCommand cmd = connection.CreateCommand(); + if (connection.State == ConnectionState.Closed) + { + connection.Open(); + } + + cmd.CommandText = sql; + cmd.CommandType = type; + if (sqlParams != null) + { + cmd.Parameters.AddRange(sqlParams); + } + + DbDataReader reader = cmd.ExecuteReader(); + IEnumerable result = reader.ToList(); + connection.Close(); + return result; + } + + public static object ExecuteScalar(this IDbContextCore context, string sql, params DbParameter[] sqlParams) + { + Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade db = context.GetDatabase(); + DbConnection connection = db.GetDbConnection(); + DbCommand cmd = connection.CreateCommand(); + if (connection.State == ConnectionState.Closed) + { + connection.Open(); + } + + cmd.CommandText = sql; + cmd.CommandType = CommandType.Text; + if (sqlParams != null) + { + cmd.Parameters.AddRange(sqlParams); + } + + object result = cmd.ExecuteScalar(); + connection.Close(); + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/EnumExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/EnumExtensions.cs new file mode 100644 index 0000000..38cb934 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/EnumExtensions.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// 枚举类型的扩展 + /// + public static class EnumExtensions + { + /// + /// + /// + /// + public static string ToDescription(this Enum item) + { + string name = item.ToString(); + DescriptionAttribute desc = item.GetType().GetField(name)?.GetCustomAttribute(); + return desc?.Description ?? name; + } + + /// + /// + /// + /// + public static long ToInt64(this Enum item) + { + return Convert.ToInt64(item); + } + + /// + /// 根据枚举的value获取枚举 + /// + /// 枚举的类型,示例:typeof(enum1) + /// 可能的枚举值 + /// 枚举,示例:enum1.en1 + public static Enum ParseEnum(Type enumType, string value) + { + return Enum.Parse(enumType, value) as Enum; + } + + + /// + /// 根据 value 值获取Description + /// + /// + /// + /// + public static string GetDescription(this Type enumType, int value) + { + object Key = GetNameAndValue(enumType).FirstOrDefault(p => p.Value.Equals(value)).Key; + if (Key==null) + { + return null; + } + + return Key.ToString(); + } + /// + /// 获取枚举名以及对应的Value + /// + /// 枚举类型typeof(T) + /// 返回Dictionary ,Key为描述名, Value为枚举对应的值 + public static Dictionary GetNameAndValue(this Type type) + { + if (type.IsEnum) + { + Dictionary dic = new Dictionary(); + Array enumValues = Enum.GetValues(type); + foreach (Enum value in enumValues) + { + dic.Add(GetDescription(value), value.GetHashCode()); + } + + return dic; + } + + return null; + } + + /// + /// 从枚举中获取Description + /// + /// 需要获取枚举描述的枚举 + /// 描述内容 + public static string GetDescription(this Enum enumName) + { + string description = string.Empty; + FieldInfo fieldInfo = enumName.GetType().GetField(enumName.ToString()); + DescriptionAttribute[] attributes = GetDescriptAttr(fieldInfo); + if (attributes != null && attributes.Length > 0) + { + description = attributes[0].Description; + } + else + { + description = enumName.ToString(); + } + + return description; + } + /// + /// 获取字段Description + /// + /// FieldInfo + /// DescriptionAttribute[] + private static DescriptionAttribute[] GetDescriptAttr(FieldInfo fieldInfo) + { + if (fieldInfo != null) + { + return (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); + } + + return null; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/ExpressionExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/ExpressionExtensions.cs new file mode 100644 index 0000000..6998455 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/ExpressionExtensions.cs @@ -0,0 +1,293 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace Zxw.Framework.NetCore.Extensions +{ + /// + /// 表达式树常用扩展方法 + /// + public static class ExpressionExtensions + { + /// + /// 取的 Expression + /// > predicate 表达式对应的属性名称 + /// 例如:c=>c.Value.Year 侧返回:Value.Year + /// + /// + /// + /// + /// + public static string GetPropertyName(this Expression> predicate) + { + MemberExpression expression = predicate.Body as MemberExpression; + //return expression.Member.Name; //该属性只返回最后一个属性,因此采用下面方法返回。 + return expression.ToString().Substring(2); + } + + public static ParameterExpression CreateLambdaParam(string name) + { + return Expression.Parameter(typeof(T), name); + } + + /// + /// 创建linq表达示的body部分 + /// + public static Expression GenerateBody(this ParameterExpression param, Filter filterObj) + { + System.Reflection.PropertyInfo property = typeof(T).GetProperty(filterObj.Key); + + //组装左边 + Expression left = Expression.Property(param, property); + //组装右边 + Expression right = null; + + if (property.PropertyType == typeof(int)) + { + right = Expression.Constant(int.Parse(filterObj.Value)); + } + else if (property.PropertyType == typeof(DateTime)) + { + right = Expression.Constant(DateTime.Parse(filterObj.Value)); + } + else if (property.PropertyType == typeof(string)) + { + right = Expression.Constant(filterObj.Value); + } + else if (property.PropertyType == typeof(decimal)) + { + right = Expression.Constant(decimal.Parse(filterObj.Value)); + } + else if (property.PropertyType == typeof(Guid)) + { + right = Expression.Constant(Guid.Parse(filterObj.Value)); + } + else if (property.PropertyType == typeof(bool)) + { + right = Expression.Constant(filterObj.Value.Equals("1")); + } + else if (property.PropertyType == typeof(Guid?)) + { + left = Expression.Property(left, "Value"); + right = Expression.Constant(Guid.Parse(filterObj.Value)); + } + else + { + throw new Exception("暂不能解析该Key的类型"); + } + + //c.XXX=="XXX" + Expression filter = Expression.Equal(left, right); + switch (filterObj.Contrast) + { + case "<=": + filter = Expression.LessThanOrEqual(left, right); + break; + + case "<": + filter = Expression.LessThan(left, right); + break; + + case ">": + filter = Expression.GreaterThan(left, right); + break; + + case ">=": + filter = Expression.GreaterThanOrEqual(left, right); + break; + + case "!=": + filter = Expression.NotEqual(left, right); + break; + + case "like": + filter = Expression.Call(left, typeof(string).GetMethod("Contains", new[] { typeof(string) }), + Expression.Constant(filterObj.Value)); + break; + + case "not in": + ConstantExpression listExpression = Expression.Constant(filterObj.Value.Split(',').ToList()); //数组 + System.Reflection.MethodInfo method = typeof(List).GetMethod("Contains", new[] { typeof(string) }); //Contains语句 + filter = Expression.Not(Expression.Call(listExpression, method, left)); + break; + + case "in": + ConstantExpression lExp = Expression.Constant(filterObj.Value.Split(',').ToList()); //数组 + System.Reflection.MethodInfo methodInfo = + typeof(List).GetMethod("Contains", new[] { typeof(string) }); //Contains语句 + filter = Expression.Call(lExp, methodInfo, left); + break; + } + + return filter; + } + + public static Expression> GenerateTypeBody(this ParameterExpression param, Filter filterObj) + { + return (Expression>)param.GenerateBody(filterObj); + } + + /// + /// 创建完整的lambda + /// + public static LambdaExpression GenerateLambda(this ParameterExpression param, Expression body) + { + //c=>c.XXX=="XXX" + return Expression.Lambda(body, param); + } + + public static Expression> GenerateTypeLambda(this ParameterExpression param, Expression body) + { + return (Expression>)param.GenerateLambda(body); + } + + public static Expression AndAlso(this Expression expression, Expression expressionRight) + { + return Expression.AndAlso(expression, expressionRight); + } + + public static Expression Or(this Expression expression, Expression expressionRight) + { + return Expression.Or(expression, expressionRight); + } + + public static Expression And(this Expression expression, Expression expressionRight) + { + return Expression.And(expression, expressionRight); + } + + //系统已经有该函数的实现 + //public static IQueryable Where(this IQueryable query, Expression expression) + //{ + // Expression expr = Expression.Call(typeof(Queryable), "Where", new[] { typeof(T) }, + // Expression.Constant(query), expression); + // //生成动态查询 + // IQueryable result = query.Provider.CreateQuery(expr); + // return result; + //} + + public static IQueryable GenerateFilter(this IQueryable query, string filterjson) + { + if (!string.IsNullOrEmpty(filterjson)) + { + IEnumerable filters = JsonConvert.DeserializeObject>(filterjson); + ParameterExpression param = CreateLambdaParam("c"); + + Expression result = Expression.Constant(true); + foreach (Filter filter in filters) + { + result = result.AndAlso(param.GenerateBody(filter)); + } + + query = query.Where(param.GenerateTypeLambda(result)); + } + + return query; + } + + /// + /// 以特定的条件运行组合两个Expression表达式 + /// + /// 表达式的主实体类型 + /// 第一个Expression表达式 + /// 要组合的Expression表达式 + /// 组合条件运算方式 + /// 组合后的表达式 + public static Expression Compose(this Expression first, Expression second, + Func merge) + { + // build parameter map (from parameters of second to parameters of first) + Dictionary map = + first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); + + // replace parameters in the second lambda expression with parameters from the first + Expression secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); + + // apply composition of lambda expression bodies to parameters from the first expression + return Expression.Lambda(merge(first.Body, secondBody), first.Parameters); + } + + /// + /// 以 Expression.AndAlso 组合两个Expression表达式 + /// + /// 表达式的主实体类型 + /// 第一个Expression表达式 + /// 要组合的Expression表达式 + /// 组合后的表达式 + public static Expression> And(this Expression> first, + Expression> second) + { + return first.Compose(second, Expression.AndAlso); + } + + /// + /// 以 Expression.OrElse 组合两个Expression表达式 + /// + /// 表达式的主实体类型 + /// 第一个Expression表达式 + /// 要组合的Expression表达式 + /// 组合后的表达式 + public static Expression> Or(this Expression> first, + Expression> second) + { + return first.Compose(second, Expression.OrElse); + } + + /// + /// 参数重新绑定 + /// + /// + private class ParameterRebinder : ExpressionVisitor + { + private readonly Dictionary _map; + + /// + /// Initializes a new instance of the class. + /// + /// The map. + private ParameterRebinder(Dictionary map) + { + _map = map ?? new Dictionary(); + } + + /// + /// Replaces the parameters. + /// + /// The map. + /// The exp. + /// + public static Expression ReplaceParameters(Dictionary map, + Expression exp) + { + return new ParameterRebinder(map).Visit(exp); + } + + /// + /// 访问 。 + /// + /// 要访问的表达式。 + /// + /// 如果修改了该表达式或任何子表达式,则为修改后的表达式;否则返回原始表达式。 + /// + protected override Expression VisitParameter(ParameterExpression node) + { + if (_map.TryGetValue(node, out ParameterExpression replacement)) + { + node = replacement; + } + + return base.VisitParameter(node); + } + } + } + + public class Filter + { + public string Key { get; set; } + public string Value { get; set; } + public string Contrast { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/HttpContextExtentions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/HttpContextExtentions.cs new file mode 100644 index 0000000..65cd42d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/HttpContextExtentions.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Znyc.Cloudcar.Admin.Commons.Helpers; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// HttpContext 扩展 + /// + public static class HttpContextExtentions + { + public static IApplicationBuilder UseStaticHttpContextAccessor(this IApplicationBuilder app) + { + IHttpContextAccessor httpContextAccessor = app.ApplicationServices.GetRequiredService(); + HttpContextHelper.Configure(httpContextAccessor); + return app; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/ObjectExtension.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/ObjectExtension.cs new file mode 100644 index 0000000..017b57d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/ObjectExtension.cs @@ -0,0 +1,1508 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +using System.Xml; +using System.Xml.Linq; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// 对象自定义扩展类 + /// + public static class ObjectExtension + { + private static readonly Regex BoolRegex = + new("(?(true|false))", RegexOptions.IgnoreCase | RegexOptions.Singleline); + + private static readonly Regex IntRegex = + new("(?-?\\d+)", RegexOptions.IgnoreCase | RegexOptions.Singleline); + + private static readonly Regex DecimalRegex = + new("(?-?\\d+(\\.\\d+)?)", RegexOptions.IgnoreCase | RegexOptions.Singleline); + + private static readonly Regex DateTimeRegex = new( + "(?(((\\d+)[/年-](0?[13578]|1[02])[/月-](3[01]|[12]\\d|0?\\d)[日]?)|((\\d+)[/年-](0?[469]|11)[/月-](30|[12]\\d|0?\\d)[日]?)|((\\d+)[/年-]0?2[/月-](2[0-8]|1\\d|0?\\d)[日]?))(\\s((2[0-3]|[0-1]\\d)):[0-5]\\d:[0-5]\\d)?)" + , + RegexOptions.IgnoreCase | RegexOptions.Singleline); + + private static readonly Regex TimeSpanRegex = + new( + "(?-?(\\d+\\.(([0-1]\\d)|(2[0-3])):[0-5]\\d:[0-5]\\d)|((([0-1]\\d)|(2[0-3])):[0-5]\\d:[0-5]\\d)|(\\d+))" + , + RegexOptions.IgnoreCase | RegexOptions.Singleline); + + private static readonly Regex GuidRegex = + new( + "(?\\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\\}{0,1})" + , + RegexOptions.IgnoreCase | RegexOptions.Singleline); + + private static readonly Regex MobileRegex = new("^1[3|4|5|7|8][0-9]\\d{4,8}$"); + + private static readonly Regex EmailRegex = + new("^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\\.[a-zA-Z0-9_-]{2,3}){1,2})$"); + + /// + /// 将集合转换为数据集。 + /// + /// 转换的元素类型。 + /// 集合。 + /// 是否生成泛型数据集。 + /// 数据集。 + public static DataSet ToDataSet(this IEnumerable list, bool generic = true) + { + return ListToDataSet(list, generic); + } + + /// + /// 将集合转换为数据集。 + /// + /// 集合。 + /// 是否生成泛型数据集。 + /// 数据集。 + public static DataSet ToDataSet(this IEnumerable list, bool generic = true) + { + return ListToDataSet(list, generic); + } + + /// + /// 将集合转换为数据集。 + /// + /// 转换的元素类型。 + /// 集合。 + /// 是否生成泛型数据集。 + /// 数据集。 + public static DataSet ToDataSet(this IEnumerable list, bool generic = true) + { + return ListToDataSet(list, typeof(T), generic); + } + + /// + /// 将实例转换为集合数据集。 + /// + /// 实例类型。 + /// 实例。 + /// 是否生成泛型数据集。 + /// 数据集。 + public static DataSet ToListSet(this T o, bool generic = true) + { + if (o is IEnumerable) + { + return ListToDataSet(o as IEnumerable, generic); + } + + return ListToDataSet(new[] { o }, generic); + } + + /// + /// 将可序列化实例转换为XmlDocument。 + /// + /// 实例类型。 + /// 实例。 + /// XmlDocument。 + public static XmlDocument ToXmlDocument(this T o) + { + XmlDocument xmlDocument = new XmlDocument + { + InnerXml = o.ToListSet().GetXml() + }; + return xmlDocument; + } + + public static object ChangeType(this object convertibleValue, Type type) + { + if (null == convertibleValue) + { + return null; + } + + try + { + if (type == typeof(Guid) || type == typeof(Guid?)) + { + string value = convertibleValue.ToString(); + if (value == "") + { + return null; + } + + return Guid.Parse(value); + } + + if (!type.IsGenericType) + { + return Convert.ChangeType(convertibleValue, type); + } + + if (type.ToString() == "System.Nullable`1[System.Boolean]" || type.ToString() == "System.Boolean") + { + if (convertibleValue.ToString() == "0") + { + return false; + } + + return true; + } + + Type genericTypeDefinition = type.GetGenericTypeDefinition(); + if (genericTypeDefinition == typeof(Nullable<>)) + { + return Convert.ChangeType(convertibleValue, Nullable.GetUnderlyingType(type)); + } + } + catch + { + return null; + } + + return null; + } + + /// + /// 获取对象里指定成员名称 + /// + /// + /// 格式 Expression> exp = x => new { x.字段1, x.字段2 };或x=>x.Name + /// + public static string[] GetExpressionProperty(this Expression> properties) + { + if (properties == null) + { + return new string[] { }; + } + + if (properties.Body is NewExpression) + { + return ((NewExpression)properties.Body).Members.Select(x => x.Name).ToArray(); + } + + if (properties.Body is MemberExpression) + { + return new[] { ((MemberExpression)properties.Body).Member.Name }; + } + + if (properties.Body is UnaryExpression) + { + return new[] { ((properties.Body as UnaryExpression).Operand as MemberExpression).Member.Name }; + } + + throw new Exception("未实现的表达式"); + } + + /// + /// 将集合转换为数据集。 + /// + /// 集合。 + /// 转换的元素类型。 + /// 是否生成泛型数据集。 + /// 转换后的数据集。 + private static DataSet ListToDataSet(IEnumerable list, Type t, bool generic) + { + DataSet ds = new DataSet("Data"); + if (t == null) + { + if (list != null) + { + foreach (object i in list) + { + if (i == null) + { + continue; + } + + t = i.GetType(); + break; + } + } + + if (t == null) + { + return ds; + } + } + + ds.Tables.Add(t.Name); + //如果集合中元素为DataSet扩展涉及到的基本类型时,进行特殊转换。 + if (t.IsValueType || t == typeof(string)) + { + ds.Tables[0].TableName = "Info"; + ds.Tables[0].Columns.Add(t.Name); + if (list != null) + { + foreach (object i in list) + { + DataRow addRow = ds.Tables[0].NewRow(); + addRow[t.Name] = i; + ds.Tables[0].Rows.Add(addRow); + } + } + + return ds; + } + + //处理模型的字段和属性。 + FieldInfo[] fields = t.GetFields(); + PropertyInfo[] properties = t.GetProperties(); + foreach (FieldInfo j in fields) + { + if (!ds.Tables[0].Columns.Contains(j.Name)) + { + if (generic) + { + ds.Tables[0].Columns.Add(j.Name, j.FieldType); + } + else + { + ds.Tables[0].Columns.Add(j.Name); + } + } + } + + foreach (PropertyInfo j in properties) + { + if (!ds.Tables[0].Columns.Contains(j.Name)) + { + if (generic) + { + ds.Tables[0].Columns.Add(j.Name, j.PropertyType); + } + else + { + ds.Tables[0].Columns.Add(j.Name); + } + } + } + + if (list == null) + { + return ds; + } + //读取list中元素的值。 + foreach (object i in list) + { + if (i == null) + { + continue; + } + + DataRow addRow = ds.Tables[0].NewRow(); + foreach (FieldInfo j in fields) + { + MemberExpression field = Expression.Field(Expression.Constant(i), j.Name); + LambdaExpression lambda = Expression.Lambda(field); + Delegate func = lambda.Compile(); + object value = func.DynamicInvoke(); + addRow[j.Name] = value; + } + + foreach (PropertyInfo j in properties) + { + MemberExpression property = Expression.Property(Expression.Constant(i), j); + LambdaExpression lambda = Expression.Lambda(property); + Delegate func = lambda.Compile(); + object value = func.DynamicInvoke(); + addRow[j.Name] = value; + } + + ds.Tables[0].Rows.Add(addRow); + } + + return ds; + } + + /// + /// 将集合转换为数据集。 + /// + /// 转换的元素类型。 + /// 集合。 + /// 是否生成泛型数据集。 + /// 数据集。 + private static DataSet ListToDataSet(IEnumerable list, bool generic) + { + return ListToDataSet(list, typeof(T), generic); + } + + /// + /// 将集合转换为数据集。 + /// + /// 集合。 + /// 是否转换为字符串形式。 + /// 转换后的数据集。 + private static DataSet ListToDataSet(IEnumerable list, bool generic) + { + return ListToDataSet(list, null, generic); + } + + /// + /// 获取DataSet第一表,第一行,第一列的值。 + /// + /// DataSet数据集。 + /// 值。 + public static object GetData(this DataSet ds) + { + if ( + ds == null + || ds.Tables.Count == 0 + ) + { + return string.Empty; + } + + return ds.Tables[0].GetData(); + } + + /// + /// 获取DataTable第一行,第一列的值。 + /// + /// DataTable数据集表。 + /// 值。 + public static object GetData(this DataTable dt) + { + if ( + dt.Columns.Count == 0 + || dt.Rows.Count == 0 + ) + { + return string.Empty; + } + + return dt.Rows[0][0]; + } + + /// + /// 获取DataSet第一个匹配columnName的值。 + /// + /// 数据集。 + /// 列名。 + /// 值。 + public static object GetData(this DataSet ds, string columnName) + { + if ( + ds == null + || ds.Tables.Count == 0 + ) + { + return string.Empty; + } + + foreach (DataTable dt in ds.Tables) + { + object o = dt.GetData(columnName); + if (!string.IsNullOrEmpty(o.ToString())) + { + return o; + } + } + + return string.Empty; + } + + /// + /// 获取DataTable第一个匹配columnName的值。 + /// + /// 数据表。 + /// 列名。 + /// 值。 + public static object GetData(this DataTable dt, string columnName) + { + if (string.IsNullOrEmpty(columnName)) + { + return GetData(dt); + } + + if ( + dt.Columns.Count == 0 + || dt.Columns.IndexOf(columnName) == -1 + || dt.Rows.Count == 0 + ) + { + return string.Empty; + } + + return dt.Rows[0][columnName]; + } + + /// + /// 将object转换为string类型信息。 + /// + /// object。 + /// 默认值。 + /// string。 + public static string ToString(this object o, string t) + { + string info = string.Empty; + if (o == null) + { + info = t; + } + else + { + info = o.ToString(); + } + + return info; + } + + /// + /// 将DateTime?转换为string类型信息。 + /// + /// DateTime?。 + /// 标准或自定义日期和时间格式的字符串。 + /// 默认值。 + /// string。 + public static string ToString(this DateTime? o, string format, string t) + { + string info = string.Empty; + if (o == null) + { + info = t; + } + else + { + info = o.Value.ToString(format); + } + + return info; + } + + /// + /// 将TimeSpan?转换为string类型信息。 + /// + /// TimeSpan?。 + /// 标准或自定义时间格式的字符串。 + /// 默认值。 + /// string。 + public static string ToString(this TimeSpan? o, string format, string t) + { + string info = string.Empty; + if (o == null) + { + info = t; + } + else + { + info = o.Value.ToString(format); + } + + return info; + } + + /// + /// 将object转换为截取后的string类型信息。 + /// + /// object。 + /// 此实例中子字符串的起始字符位置(从零开始)。 + /// 子字符串中的字符数。 + /// 后缀。如果没有截取则不添加。 + /// 截取后的string类型信息。 + public static string ToSubString(this object o, int startIndex, int length, string suffix = null) + { + string inputString = o.ToString(string.Empty); + startIndex = Math.Max(startIndex, 0); + startIndex = Math.Min(startIndex, inputString.Length - 1); + length = Math.Max(length, 1); + if (startIndex + length > inputString.Length) + { + length = inputString.Length - startIndex; + } + + if (inputString.Length == startIndex + length) + { + return inputString; + } + + return inputString.Substring(startIndex, length) + suffix; + } + + /// + /// 将object转换为byte类型信息。 + /// + /// object。 + /// 默认值。 + /// byte。 + public static byte ToByte(this object o, byte t = default) + { + if (!byte.TryParse(o.ToString(string.Empty), out byte info)) + { + info = t; + } + + return info; + } + + /// + /// + /// + /// + public static byte[] ToBytes(this object obj) + { + if (obj == null) + { + return null; + } + + BinaryFormatter bf = new BinaryFormatter(); + using (MemoryStream ms = new MemoryStream()) + { + bf.Serialize(ms, obj); + return ms.ToArray(); + } + } + + /// + /// + /// + /// + public static object ToObject(this byte[] source) + { + using (MemoryStream memStream = new MemoryStream()) + { + BinaryFormatter bf = new BinaryFormatter(); + memStream.Write(source, 0, source.Length); + memStream.Seek(0, SeekOrigin.Begin); + object obj = bf.Deserialize(memStream); + return obj; + } + } + + /// + /// 将object转换为char类型信息。 + /// + /// object。 + /// 默认值。 + /// char。 + public static char ToChar(this object o, char t = default) + { + if (!char.TryParse(o.ToString(string.Empty), out char info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为int类型信息。 + /// + /// object。 + /// 默认值。 + /// int。 + public static int ToInt(this object o, int t = default) + { + if (!int.TryParse(o.ToString(string.Empty), out int info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为double类型信息。 + /// + /// object。 + /// 默认值。 + /// double。 + public static double ToDouble(this object o, double t = default) + { + if (!double.TryParse(o.ToString(string.Empty), out double info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为decimal类型信息。 + /// + /// object。 + /// 默认值。 + /// decimal。 + public static decimal ToDecimal(this object o, decimal t = default) + { + if (!decimal.TryParse(o.ToString(string.Empty), out decimal info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为float类型信息。 + /// + /// object。 + /// 默认值。 + /// float。 + public static float ToFloat(this object o, float t = default) + { + if (!float.TryParse(o.ToString(string.Empty), out float info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为long类型信息。 + /// + /// object。 + /// 默认值。 + /// long。 + public static long ToLong(this object o, long t = default) + { + if (!long.TryParse(o.ToString(string.Empty), out long info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为bool类型信息。 + /// + /// object。 + /// 默认值。 + /// bool。 + public static bool ToBool(this object o, bool t = default) + { + if (!bool.TryParse(o.ToString(string.Empty), out bool info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为sbyte类型信息。 + /// + /// object。 + /// 默认值。 + /// sbyte。 + public static sbyte ToSbyte(this object o, sbyte t = default) + { + if (!sbyte.TryParse(o.ToString(string.Empty), out sbyte info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为short类型信息。 + /// + /// object。 + /// 默认值。 + /// short。 + public static short ToShort(this object o, short t = default) + { + if (!short.TryParse(o.ToString(string.Empty), out short info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为ushort类型信息。 + /// + /// object。 + /// 默认值。 + /// ushort。 + public static ushort ToUShort(this object o, ushort t = default) + { + if (!ushort.TryParse(o.ToString(string.Empty), out ushort info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为ulong类型信息。 + /// + /// object。 + /// 默认值。 + /// ulong。 + public static ulong ToULong(this object o, ulong t = default) + { + if (!ulong.TryParse(o.ToString(string.Empty), out ulong info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为Enum[T]类型信息。 + /// + /// object。 + /// 默认值。 + /// Enum[T]。 + public static T ToEnum(this object o, T t = default) + where T : struct + { + if (!Enum.TryParse(o.ToString(string.Empty), out T info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为DateTime类型信息。 + /// + /// object。 + /// 默认值。 + /// DateTime。 + public static DateTime ToDateTime(this object o, DateTime t = default) + { + if (t == default) + { + t = new DateTime(1753, 1, 1); + } + + if (!DateTime.TryParse(o.ToString(string.Empty), out DateTime info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为TimeSpan类型信息。 + /// + /// object。 + /// 默认值。 + /// TimeSpan。 + public static TimeSpan ToTimeSpan(this object o, TimeSpan t = default) + { + if (t == default) + { + t = new TimeSpan(0, 0, 0); + } + + if (!TimeSpan.TryParse(o.ToString(string.Empty), out TimeSpan info)) + { + info = t; + } + + return info; + } + + /// + /// 将object转换为Guid类型信息。 + /// + /// object。 + /// 默认值。 + /// Guid。 + public static Guid ToGuid(this object o, Guid t = default) + { + if (!Guid.TryParse(o.ToString(string.Empty), out Guid info)) + { + info = t; + } + + return info; + } + + /// + /// 从object中获取bool类型信息。 + /// + /// object。 + /// bool。 + public static bool? GetBool(this object o) + { + if (!bool.TryParse(BoolRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out bool info)) + { + return null; + } + + return info; + } + + /// + /// 从object中获取int类型信息。 + /// + /// object。 + /// int。 + public static int? GetInt(this object o) + { + if (!int.TryParse(IntRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out int info)) + { + return null; + } + + return info; + } + + /// + /// 从object中获取decimal类型信息。 + /// + /// object。 + /// decimal。 + public static decimal? GetDecimal(this object o) + { + if (!decimal.TryParse(DecimalRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out decimal info)) + { + return null; + } + + return info; + } + + /// + /// 从object中获取double类型信息。 + /// + /// object。 + /// double。 + public static double? GetDouble(this object o) + { + if (!double.TryParse(DecimalRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out double info)) + { + return null; + } + + return info; + } + + /// + /// 从object中获取正数信息。 + /// + /// object。 + /// decimal。 + public static decimal? GetPositiveNumber(this object o) + { + if (!decimal.TryParse(DecimalRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out decimal info)) + { + return null; + } + + return Math.Abs(info); + } + + /// + /// 从object中获取DateTime?类型信息。 + /// + /// object。 + /// DateTime?。 + public static DateTime? GetDateTime(this object o) + { + if (!DateTime.TryParse( + DateTimeRegex.Match(o.ToString(string.Empty)).Groups["info"].Value.Replace("年", "-").Replace("月", "-") + .Replace("/", "-").Replace("日", ""), out DateTime info)) + { + return null; + } + + return info; + } + + /// + /// 从object中获取TimeSpan?类型信息。 + /// + /// object。 + /// TimeSpan?。 + public static TimeSpan? GetTimeSpan(this object o) + { + if (!TimeSpan.TryParse(TimeSpanRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out TimeSpan info)) + { + return null; + } + + return info; + } + + /// + /// 从object中获取Guid?类型信息。 + /// + /// object。 + /// Guid?。 + public static Guid? GetGuid(this object o) + { + if (!Guid.TryParse(GuidRegex.Match(o.ToString(string.Empty)).Groups["info"].Value, out Guid info)) + { + return null; + } + + return info; + } + + /// + /// 将object转换为SqlServer中的DateTime?类型信息。 + /// + /// object。 + /// 默认值。 + /// DateTime?。 + public static DateTime? GetSqlDateTime(this object o, DateTime t = default) + { + if (!DateTime.TryParse(o.ToString(string.Empty), out DateTime info)) + { + info = t; + } + + if (info < new DateTime(1753, 1, 1) || info > new DateTime(9999, 12, 31)) + { + return null; + } + + return info; + } + + /// + /// 读取XElement节点的文本内容。 + /// + /// XElement节点。 + /// 默认值。 + /// 文本内容。 + public static string Value(this XElement xElement, string t = default) + { + if (xElement == null) + { + return t; + } + + return xElement.Value; + } + + /// + /// 获取与指定键相关的值。 + /// + /// 键类型。 + /// 值类型。 + /// 表示键/值对象的泛型集合。 + /// 键。 + /// 默认值。 + /// 值。 + public static TValue GetValue(this IDictionary dictionary, TKey key, + TValue t = default) + { + if (dictionary == null || key == null) + { + return t; + } + + if (!dictionary.TryGetValue(key, out TValue value)) + { + value = t; + } + + return value; + } + + /// + /// 获取与指定键相关或者第一个的值。 + /// + /// 键类型。 + /// 值类型。 + /// 表示键/值对象的泛型集合。 + /// 键。 + /// 默认值。 + /// 值。 + public static TValue GetFirstOrDefaultValue(this IDictionary dictionary, TKey key, + TValue t = default) + { + if (dictionary == null || key == null) + { + return t; + } + + if (!dictionary.TryGetValue(key, out TValue value)) + { + if (dictionary.Count() == 0) + { + value = t; + } + else + { + value = dictionary.FirstOrDefault().Value; + } + } + + return value; + } + + /// + /// 获取具有指定 System.Xml.Linq.XName 的第一个(按文档顺序)子元素。 + /// + /// XContainer。 + /// 要匹配的 System.Xml.Linq.XName。 + /// 是否返回同名默认值。 + /// 与指定 System.Xml.Linq.XName 匹配的 System.Xml.Linq.XElement,或者为 null。 + public static XElement Element(this XContainer xContainer, XName xName, bool t) + { + XElement info; + if (xContainer == null) + { + info = null; + } + else + { + info = xContainer.Element(xName); + } + + if (t && info == null) + { + info = new XElement(xName); + } + + return info; + } + + /// + /// 按文档顺序返回此元素或文档的子元素集合。 + /// + /// XContainer。 + /// 是否返回非空默认值。 + /// System.Xml.Linq.XElement 的按文档顺序包含此System.Xml.Linq.XContainer 的子元素,或者非空默认值。 + public static IEnumerable Elements(this XContainer xContainer, bool t) + { + IEnumerable info; + if (xContainer == null) + { + info = null; + } + else + { + info = xContainer.Elements(); + } + + if (t && info == null) + { + info = new List(); + } + + return info; + } + + /// + /// 按文档顺序返回此元素或文档的经过筛选的子元素集合。集合中只包括具有匹配 System.Xml.Linq.XName 的元素。 + /// + /// XContainer。 + /// 要匹配的 System.Xml.Linq.XName。 + /// 是否返回非空默认值。 + /// System.Xml.Linq.XElement 的按文档顺序包含具有匹配System.Xml.Linq.XName 的 System.Xml.Linq.XContainer 的子级,或者非空默认值。 + public static IEnumerable Elements(this XContainer xContainer, XName xName, bool t) + { + IEnumerable info; + if (xContainer == null) + { + info = null; + } + else + { + info = xContainer.Elements(xName); + } + + if (t && info == null) + { + info = new List(); + } + + return info; + } + + /// + /// 删除html标签。 + /// + /// 输入的字符串。 + /// 没有html标签的字符串。 + public static string RemoveHTMLTags(this string html) + { + return Regex + .Replace( + Regex.Replace( + Regex.Replace( + (html ?? string.Empty).Replace(" ", " ").Replace("\r\n", " ").Replace("\n", " ") + .Replace("\r", " ").Replace("\t", " "), "<\\/?[^>]+>", "\r\n"), "(\r\n)+", "\r\n"), + "(\\s)+", " ").Trim(); + } + + /// + /// 字符串转换为文件名。 + /// + /// 字符串。 + /// 文件名。 + public static string ToFileName(this string s) + { + return Regex.Replace(s.ToString(string.Empty), @"[\\/:*?<>|]", "_").Replace("\t", " ").Replace("\r\n", " ") + .Replace("\"", " "); + } + + /// + /// 获取星期一的日期。 + /// + /// 日期。 + /// 星期一的日期。 + public static DateTime? GetMonday(this DateTime dateTime) + { + return dateTime.AddDays(-1 * (int)dateTime.AddDays(-1).DayOfWeek).ToString("yyyy-MM-dd").GetDateTime(); + } + + /// + /// 获取默认非空字符串。 + /// + /// 首选默认非空字符串。 + /// 依次非空字符串可选项。 + /// 默认非空字符串。若无可选项则返回string.Empty。 + public static string DefaultStringIfEmpty(this string s, params string[] args) + { + if (string.IsNullOrEmpty(s)) + { + foreach (string i in args) + { + if (!string.IsNullOrEmpty(i) && !string.IsNullOrEmpty(i.Trim())) + { + return i; + } + } + } + + return s ?? string.Empty; + } + + /// + /// 对 URL 字符串进行编码。 + /// + /// 要编码的文本。 + /// 匹配要编码的文本。 + /// 指定编码方案的 System.Text.Encoding 对象。 + /// 一个已编码的字符串。 + public static string ToUrlEncodeString(this string s, Regex regex = default, Encoding encoding = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + + if (regex == null) + { + return HttpUtility.UrlEncode(s, encoding); + } + + List l = new List(); + foreach (char i in s) + { + string t = i.ToString(); + l.Add(regex.IsMatch(t) ? HttpUtility.UrlEncode(t, encoding) : t); + } + + return string.Join(string.Empty, l); + } + + /// + /// 对 URL 字符串进行编码。 + /// + /// 要编码的文本。 + /// 匹配要编码的文本。 + /// 指定编码方案的 System.Text.Encoding 对象。 + /// 一个已编码的字符串。 + public static string ToUrlEncodeString(this string s, string regex, Encoding encoding = null) + { + return ToUrlEncodeString(s, new Regex(regex), encoding); + } + + /// + /// 将日期转换为UNIX时间戳字符串 + /// + /// + /// + public static string ToUnixTimeStamp(this DateTime date) + { + DateTime startTime = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1)); + string timeStamp = date.Subtract(startTime).Ticks.ToString(); + return timeStamp.Substring(0, timeStamp.Length - 7); + } + + public static string Join(this IEnumerable source, string separator) + { + return string.Join(separator, source); + } + + /// + /// 判断当前字符串是否是移动电话号码 + /// + /// + /// + public static bool IsMobile(this string mobile) + { + return MobileRegex.IsMatch(mobile); + } + + /// + /// 判断当前字符串是否为邮箱 + /// + /// + /// + public static bool IsEmail(this string email) + { + return EmailRegex.IsMatch(email); + } + + /// + /// 把对象类型转换为指定类型 + /// + /// + /// + /// + public static object CastTo(this object value, Type conversionType) + { + if (value == null) + { + return null; + } + + if (conversionType.IsNullableType()) + { + conversionType = conversionType.GetUnNullableType(); + } + + if (conversionType.IsEnum) + { + return Enum.Parse(conversionType, value.ToString()); + } + + if (conversionType == typeof(Guid)) + { + return Guid.Parse(value.ToString()); + } + + return Convert.ChangeType(value, conversionType); + } + + /// + /// 把对象类型转化为指定类型 + /// + /// 动态类型 + /// 要转化的源对象 + /// 转化后的指定类型的对象,转化失败引发异常。 + public static T CastTo(this object value) + { + if (value == null && default(T) == null) + { + return default; + } + + if (value.GetType() == typeof(T)) + { + return (T)value; + } + + object result = CastTo(value, typeof(T)); + return (T)result; + } + + /// + /// 把对象类型转化为指定类型,转化失败时返回指定的默认值 + /// + /// 动态类型 + /// 要转化的源对象 + /// 转化失败返回的指定默认值 + /// 转化后的指定类型对象,转化失败时返回指定的默认值 + public static T CastTo(this object value, T defaultValue) + { + try + { + return CastTo(value); + } + catch (Exception) + { + return defaultValue; + } + } + + /// + /// 将对象保存为csv + /// + /// + /// + /// 文件名称 + /// 分隔符,默认逗号 + public static void SaveToCsv(this IEnumerable source, string csvFullName, string separator = ",") + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (string.IsNullOrEmpty(separator)) + { + separator = ","; + } + + string csv = string.Join(separator, source); + using (StreamWriter sw = new StreamWriter(csvFullName, false)) + { + sw.Write(csv); + sw.Close(); + } + } + + public static bool IsImplement(this Type entityType, Type interfaceType) + { + return /*entityType.IsClass && !entityType.IsAbstract &&*/ entityType.GetTypeInfo().GetInterfaces().Any(t => + t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition() == interfaceType); + } + + /// + /// 将对象转为DataTable + /// + /// + /// + /// + public static DataTable ToDataTable(this IEnumerable source) + { + DataTable dtReturn = new DataTable(); + + if (source == null) + { + return dtReturn; + } + // column names + PropertyInfo[] oProps = null; + + foreach (T rec in source) + { + // Use reflection to get property names, to create table, Only first time, others will follow + if (oProps == null) + { + oProps = rec.GetType().GetProperties(); + foreach (PropertyInfo pi in oProps) + { + Type colType = pi.PropertyType; + + if (colType.IsNullableType()) + { + colType = colType.GetGenericArguments()[0]; + } + + if (colType == typeof(bool)) + { + colType = typeof(int); + } + + dtReturn.Columns.Add(new DataColumn(pi.Name, colType)); + } + } + + DataRow dr = dtReturn.NewRow(); + + foreach (PropertyInfo pi in oProps) + { + object value = pi.GetValue(rec, null) ?? DBNull.Value; + if (value is bool) + { + dr[pi.Name] = (bool)value ? 1 : 0; + } + else + { + dr[pi.Name] = value; + } + } + + dtReturn.Rows.Add(dr); + } + + return dtReturn; + } + } + + /// + /// 结果。 + /// + /// 结果返回值类型。 + public class Result + { + /// + /// 标记。 + /// + public Flag Flag { get; set; } + + /// + /// 返回值。 + /// + public T Return { get; set; } + + /// + /// 消息。 + /// + public string Message { get; set; } + + /// + /// 异常。 + /// + public Exception Exception { get; set; } + + /// + /// 时间。 + /// + public DateTime DateTime { get; set; } + + /// + /// 整型数据。 + /// + public int Int { get; set; } + + /// + /// 浮点数据。 + /// + public decimal Decimal { get; set; } + + /// + /// 布尔数据。 + /// + public bool Bool { get; set; } + + /// + /// 对象。 + /// + public object Object { get; set; } + } + + /// + /// 标记。 + /// + public enum Flag + { + /// + /// 默认。 + /// + Default, + + /// + /// 真。 + /// + True, + + /// + /// 假。 + /// + False + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/ParameterCheckExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/ParameterCheckExtensions.cs new file mode 100644 index 0000000..031254c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/ParameterCheckExtensions.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Properties; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// 用于参数检查的扩展方法 + /// + public static class ParameterCheckExtensions + { + /// + /// 验证指定值的断言是否为真,如果不为真,抛出指定消息的指定类型 + /// 异常 + /// + /// 异常类型 + /// 要验证的断言。 + /// 异常消息。 + private static void Require(bool assertion, string message) where TException : Exception + { + if (assertion) + { + return; + } + + if (string.IsNullOrEmpty(message)) + { + throw new ArgumentNullException("message"); + } + + TException exception = (TException)Activator.CreateInstance(typeof(TException), message); + throw exception; + } + + /// + /// 验证指定值的断言表达式是否为真,不为值抛出异常 + /// + /// + /// 要验证的断言表达式 + /// 异常消息 + public static void Required(this T value, Func assertionFunc, string message) + { + if (assertionFunc == null) + { + throw new ArgumentNullException("assertionFunc"); + } + + Require(assertionFunc(value), message); + } + + /// + /// 验证指定值的断言表达式是否为真,不为真抛出异常 + /// + /// 要判断的值的类型 + /// 抛出的异常类型 + /// 要判断的值 + /// 要验证的断言表达式 + /// 异常消息 + public static void Required(this T value, Func assertionFunc, string message) + where TException : Exception + { + if (assertionFunc == null) + { + throw new ArgumentNullException("assertionFunc"); + } + + Require(assertionFunc(value), message); + } + + /// + /// 检查参数不能为空引用,否则抛出异常。 + /// + /// + /// 参数名称 + /// + public static void CheckNotNull(this T value, string paramName) where T : class + { + Require(value != null, string.Format(Resources.ParameterCheck_NotNull, paramName)); + } + + /// + /// 检查字符串不能为空引用或空字符串,否则抛出异常或异常。 + /// + /// + /// 参数名称。 + /// + /// + public static void CheckNotNullOrEmpty(this string value, string paramName) + { + value.CheckNotNull(paramName); + Require(value.Length > 0, + string.Format(Resources.ParameterCheck_NotNullOrEmpty_String, paramName)); + } + + /// + /// 检查Guid值不能为Guid.Empty,否则抛出异常。 + /// + /// + /// 参数名称。 + /// + public static void CheckNotEmpty(this Guid value, string paramName) + { + Require(value != Guid.Empty, + string.Format(Resources.ParameterCheck_NotEmpty_Guid, paramName)); + } + + /// + /// 检查集合不能为空引用或空集合,否则抛出异常或异常。 + /// + /// 集合项的类型。 + /// + /// 参数名称。 + /// + /// + public static void CheckNotNullOrEmpty(this IEnumerable collection, string paramName) + { + collection.CheckNotNull(paramName); + Require(collection.Any(), + string.Format(Resources.ParameterCheck_NotNullOrEmpty_Collection, paramName)); + } + + /// + /// 检查参数必须小于[或可等于,参数canEqual]指定值,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 要比较的值。 + /// 是否可等于。 + /// + public static void CheckLessThan(this T value, string paramName, T target, bool canEqual = false) + where T : IComparable + { + bool flag = canEqual ? value.CompareTo(target) <= 0 : value.CompareTo(target) < 0; + string format = canEqual ? Resources.ParameterCheck_NotLessThanOrEqual : Resources.ParameterCheck_NotLessThan; + Require(flag, string.Format(format, paramName, target)); + } + + /// + /// 检查参数必须大于[或可等于,参数canEqual]指定值,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 要比较的值。 + /// 是否可等于。 + /// + public static void CheckGreaterThan(this T value, string paramName, T target, bool canEqual = false) + where T : IComparable + { + bool flag = canEqual ? value.CompareTo(target) >= 0 : value.CompareTo(target) > 0; + string format = canEqual + ? Resources.ParameterCheck_NotGreaterThanOrEqual + : Resources.ParameterCheck_NotGreaterThan; + Require(flag, string.Format(format, paramName, target)); + } + + /// + /// 检查参数必须在指定范围之间,否则抛出异常。 + /// + /// 参数类型。 + /// + /// 参数名称。 + /// 比较范围的起始值。 + /// 比较范围的结束值。 + /// 是否可等于起始值 + /// 是否可等于结束值 + /// + public static void CheckBetween(this T value, string paramName, T start, T end, bool startEqual = false, + bool endEqual = false) + where T : IComparable + { + bool flag = startEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0; + string message = startEqual + ? string.Format(Resources.ParameterCheck_Between, paramName, start, end) + : string.Format(Resources.ParameterCheck_BetweenNotEqual, paramName, start, end, start); + Require(flag, message); + + flag = endEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0; + message = endEqual + ? string.Format(Resources.ParameterCheck_Between, paramName, start, end) + : string.Format(Resources.ParameterCheck_BetweenNotEqual, paramName, start, end, end); + Require(flag, message); + } + + /// + /// 检查指定路径的文件夹必须存在,否则抛出异常。 + /// + /// + /// 参数名称。 + /// + /// + public static void CheckDirectoryExists(this string directory, string paramName = null) + { + CheckNotNull(directory, paramName); + Require(Directory.Exists(directory), + string.Format(Resources.ParameterCheck_DirectoryNotExists, directory)); + } + + /// + /// 检查指定路径的文件必须存在,否则抛出异常。 + /// + /// + /// 参数名称。 + /// 当文件路径为null时 + /// 当文件路径不存在时 + public static void CheckFileExists(this string filename, string paramName = null) + { + CheckNotNull(filename, paramName); + Require(File.Exists(filename), + string.Format(Resources.ParameterCheck_FileNotExists, filename)); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/SessionExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/SessionExtensions.cs new file mode 100644 index 0000000..dd07f32 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/SessionExtensions.cs @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using Microsoft.AspNetCore.Http; +using Newtonsoft.Json; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// Session 扩展函数,直接将实体类序列化成json存储和读取 + /// + public static class SessionExtensions + { + /// + /// 设置session值 + /// + /// + /// + /// + public static void Set(this ISession session, string key, object value) + { + session.SetString(key, JsonConvert.SerializeObject(value)); + } + + /// + /// 获取session + /// + /// + /// + /// + /// + public static T Get(this ISession session, string key) + { + string value = session.GetString(key); + + return value == null ? default : JsonConvert.DeserializeObject(value); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/SqlMapperExtensions.Async.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/SqlMapperExtensions.Async.cs new file mode 100644 index 0000000..b67196f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/SqlMapperExtensions.Async.cs @@ -0,0 +1,789 @@ +using Dapper; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Dapper.Contrib.Extensions +{ + /// + /// 修改mysql新增数据时返回影响记录数 + /// + public static partial class SqlMapperExtensions + { + /// + /// Returns a single entity by a single id from table "Ts" asynchronously using Task. T must be of interface type. + /// Id must be marked with [Key] attribute. + /// Created entity is tracked/intercepted for changes and used by the Update() extension. + /// + /// Interface type to create and populate + /// Open SqlConnection + /// Id of the entity to get, must be marked with [Key] attribute + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// Entity of T + public static async Task GetAsync(this IDbConnection connection, dynamic id, + IDbTransaction transaction = null, int? commandTimeout = null) where T : class + { + Type type = typeof(T); + if (!GetQueries.TryGetValue(type.TypeHandle, out string sql)) + { + PropertyInfo key = GetSingleKey(nameof(GetAsync)); + string name = GetTableName(type); + sql = $"SELECT * FROM {name} WHERE {key.Name} = @keyName"; + GetQueries[type.TypeHandle] = sql; + } + + DynamicParameters dynParms = new DynamicParameters(); + dynParms.Add("@keyName", id); + + if (!type.IsInterface) + { + return (await connection.QueryAsync(sql, dynParms, transaction, commandTimeout) + .ConfigureAwait(false)).FirstOrDefault(); + } + + IDictionary res = + (await connection.QueryAsync(sql, dynParms).ConfigureAwait(false)).FirstOrDefault() as + IDictionary; + + if (res == null) + { + return null; + } + + T obj = ProxyGenerator.GetInterfaceProxy(); + + foreach (PropertyInfo property in TypePropertiesCache(type)) + { + object val = res[property.Name]; + if (val == null) + { + continue; + } + + if (property.PropertyType.IsGenericType && + property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + Type genericType = Nullable.GetUnderlyingType(property.PropertyType); + if (genericType != null) + { + property.SetValue(obj, Convert.ChangeType(val, genericType), null); + } + } + else + { + property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null); + } + } + + ((IProxy)obj).IsDirty = false; //reset change tracking and return + + return obj; + } + + /// + /// Returns a list of entites from table "Ts". + /// Id of T must be marked with [Key] attribute. + /// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension + /// for optimal performance. + /// + /// Interface or type to create and populate + /// Open SqlConnection + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// Entity of T + public static Task> GetAllAsync(this IDbConnection connection, + IDbTransaction transaction = null, int? commandTimeout = null) where T : class + { + Type type = typeof(T); + Type cacheType = typeof(List); + + if (!GetQueries.TryGetValue(cacheType.TypeHandle, out string sql)) + { + GetSingleKey(nameof(GetAll)); + string name = GetTableName(type); + + sql = "SELECT * FROM " + name; + GetQueries[cacheType.TypeHandle] = sql; + } + + if (!type.IsInterface) + { + return connection.QueryAsync(sql, null, transaction, commandTimeout); + } + + return GetAllAsyncImpl(connection, transaction, commandTimeout, sql, type); + } + + private static async Task> GetAllAsyncImpl(IDbConnection connection, + IDbTransaction transaction, int? commandTimeout, string sql, Type type) where T : class + { + IEnumerable result = await connection.QueryAsync(sql).ConfigureAwait(false); + List list = new List(); + foreach (IDictionary res in result) + { + T obj = ProxyGenerator.GetInterfaceProxy(); + foreach (PropertyInfo property in TypePropertiesCache(type)) + { + object val = res[property.Name]; + if (val == null) + { + continue; + } + + if (property.PropertyType.IsGenericType && + property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + Type genericType = Nullable.GetUnderlyingType(property.PropertyType); + if (genericType != null) + { + property.SetValue(obj, Convert.ChangeType(val, genericType), null); + } + } + else + { + property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null); + } + } + + ((IProxy)obj).IsDirty = false; //reset change tracking and return + list.Add(obj); + } + + return list; + } + + /// + /// Inserts an entity into table "Ts" asynchronously using Task and returns identity id. + /// + /// The type being inserted. + /// Open SqlConnection + /// Entity to insert + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// The specific ISqlAdapter to use, auto-detected based on connection if null + /// Identity of inserted entity + public static async Task InsertAsync(this IDbConnection connection, T entityToInsert, + IDbTransaction transaction = null, + int? commandTimeout = null, ISqlAdapter sqlAdapter = null) where T : class + { + Type type = typeof(T); + sqlAdapter = sqlAdapter ?? GetFormatter(connection); + + bool isList = false; + if (type.IsArray) + { + isList = true; + type = type.GetElementType(); + } + else if (type.IsGenericType) + { + TypeInfo typeInfo = type.GetTypeInfo(); + bool implementsGenericIEnumerableOrIsGenericIEnumerable = + typeInfo.ImplementedInterfaces.Any(ti => + ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); + + if (implementsGenericIEnumerableOrIsGenericIEnumerable) + { + isList = true; + type = type.GetGenericArguments()[0]; + } + } + + string name = GetTableName(type); + StringBuilder sbColumnList = new StringBuilder(null); + List allProperties = TypePropertiesCache(type); + List keyProperties = KeyPropertiesCache(type).ToList(); + List computedProperties = ComputedPropertiesCache(type); + List allPropertiesExceptKeyAndComputed = + allProperties.ToList(); //.Except(keyProperties.Union(computedProperties)).ToList(); + + for (int i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) + { + PropertyInfo property = allPropertiesExceptKeyAndComputed[i]; + sqlAdapter.AppendColumnName(sbColumnList, property.Name); + if (i < allPropertiesExceptKeyAndComputed.Count - 1) + { + sbColumnList.Append(", "); + } + } + + StringBuilder sbParameterList = new StringBuilder(null); + for (int i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) + { + PropertyInfo property = allPropertiesExceptKeyAndComputed[i]; + sbParameterList.AppendFormat("@{0}", property.Name); + if (i < allPropertiesExceptKeyAndComputed.Count - 1) + { + sbParameterList.Append(", "); + } + } + + int returnVal = 0; + bool wasClosed = connection.State == ConnectionState.Closed; + if (wasClosed) + { + connection.Open(); + } + + if (!isList) //single entity + { + returnVal = await sqlAdapter.InsertAsync(connection, transaction, commandTimeout, name, + sbColumnList.ToString(), + sbParameterList.ToString(), keyProperties, entityToInsert); + } + else + { + //insert list of entities + string cmd = $"insert into {name} ({sbColumnList}) values ({sbParameterList})"; + returnVal = await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout); + } + + if (wasClosed) + { + connection.Close(); + } + + return returnVal; + } + + /// + /// Inserts an entity into table "Ts" asynchronously using Task and returns identity id. + /// + /// The type being inserted. + /// Open SqlConnection + /// Entity to insert + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// The specific ISqlAdapter to use, auto-detected based on connection if null + /// Identity of inserted entity + public static async Task InsertReturnPrimaryKeyAsync(this IDbConnection connection, T entityToInsert, + IDbTransaction transaction = null, + int? commandTimeout = null, ISqlAdapter sqlAdapter = null) where T : class + { + Type type = typeof(T); + sqlAdapter = sqlAdapter ?? GetFormatter(connection); + if (type.IsArray) + { + type = type.GetElementType(); + } + else if (type.IsGenericType) + { + TypeInfo typeInfo = type.GetTypeInfo(); + bool implementsGenericIEnumerableOrIsGenericIEnumerable = + typeInfo.ImplementedInterfaces.Any(ti => + ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); + + if (implementsGenericIEnumerableOrIsGenericIEnumerable) + { + type = type.GetGenericArguments()[0]; + } + } + + string name = GetTableName(type); + StringBuilder sbColumnList = new StringBuilder(null); + List allProperties = TypePropertiesCache(type); + List keyProperties = KeyPropertiesCache(type).ToList(); + List computedProperties = ComputedPropertiesCache(type); + List allPropertiesExceptKeyAndComputed = + allProperties.ToList(); //.Except(keyProperties.Union(computedProperties)).ToList(); + + for (int i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) + { + PropertyInfo property = allPropertiesExceptKeyAndComputed[i]; + sqlAdapter.AppendColumnName(sbColumnList, property.Name); + if (i < allPropertiesExceptKeyAndComputed.Count - 1) + { + sbColumnList.Append(", "); + } + } + + StringBuilder sbParameterList = new StringBuilder(null); + for (int i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) + { + PropertyInfo property = allPropertiesExceptKeyAndComputed[i]; + sbParameterList.AppendFormat("@{0}", property.Name); + if (i < allPropertiesExceptKeyAndComputed.Count - 1) + { + sbParameterList.Append(", "); + } + } + + long returnVal = 0; + bool wasClosed = connection.State == ConnectionState.Closed; + if (wasClosed) + { + connection.Open(); + } + + //if (!isList) //single entity + //{ + // returnVal = await sqlAdapter.(connection, transaction, commandTimeout, name, + // sbColumnList.ToString(), + // sbParameterList.ToString(), keyProperties, entityToInsert); + //} + //else + //{ + //insert list of entities + string cmd = $"insert into {name} ({sbColumnList}) values ({sbParameterList});SELECT LAST_INSERT_ID();"; + returnVal = await connection.ExecuteScalarAsync(cmd, entityToInsert, transaction, commandTimeout); + // } + + if (wasClosed) + { + connection.Close(); + } + + return returnVal; + } + + /// + /// Updates entity in table "Ts" asynchronously using Task, checks if the entity is modified if the entity is tracked + /// by the Get() extension. + /// + /// Type to be updated + /// Open SqlConnection + /// Entity to be updated + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// true if updated, false if not found or not modified (tracked entities) + public static async Task UpdateAsync(this IDbConnection connection, T entityToUpdate, + IDbTransaction transaction = null, int? commandTimeout = null) where T : class + { + if (entityToUpdate is IProxy proxy && !proxy.IsDirty) + { + return false; + } + + Type type = typeof(T); + + if (type.IsArray) + { + type = type.GetElementType(); + } + else if (type.IsGenericType) + { + TypeInfo typeInfo = type.GetTypeInfo(); + bool implementsGenericIEnumerableOrIsGenericIEnumerable = + typeInfo.ImplementedInterfaces.Any(ti => + ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); + + if (implementsGenericIEnumerableOrIsGenericIEnumerable) + { + type = type.GetGenericArguments()[0]; + } + } + + List keyProperties = KeyPropertiesCache(type).ToList(); + List explicitKeyProperties = ExplicitKeyPropertiesCache(type); + if (keyProperties.Count == 0 && explicitKeyProperties.Count == 0) + { + throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); + } + + string name = GetTableName(type); + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("update {0} set ", name); + + List allProperties = TypePropertiesCache(type); + keyProperties.AddRange(explicitKeyProperties); + List computedProperties = ComputedPropertiesCache(type); + List nonIdProps = allProperties.Except(keyProperties.Union(computedProperties)).ToList(); + + ISqlAdapter adapter = GetFormatter(connection); + + for (int i = 0; i < nonIdProps.Count; i++) + { + PropertyInfo property = nonIdProps[i]; + adapter.AppendColumnNameEqualsValue(sb, property.Name); + if (i < nonIdProps.Count - 1) + { + sb.Append(", "); + } + } + + sb.Append(" where "); + for (int i = 0; i < keyProperties.Count; i++) + { + PropertyInfo property = keyProperties[i]; + adapter.AppendColumnNameEqualsValue(sb, property.Name); + if (i < keyProperties.Count - 1) + { + sb.Append(" and "); + } + } + + int updated = await connection + .ExecuteAsync(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: transaction) + .ConfigureAwait(false); + return updated > 0; + } + + /// + /// Delete entity in table "Ts" asynchronously using Task. + /// + /// Type of entity + /// Open SqlConnection + /// Entity to delete + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// true if deleted, false if not found + public static async Task DeleteAsync(this IDbConnection connection, T entityToDelete, + IDbTransaction transaction = null, int? commandTimeout = null) where T : class + { + if (entityToDelete == null) + { + throw new ArgumentException("Cannot Delete null Object", nameof(entityToDelete)); + } + + Type type = typeof(T); + + if (type.IsArray) + { + type = type.GetElementType(); + } + else if (type.IsGenericType) + { + TypeInfo typeInfo = type.GetTypeInfo(); + bool implementsGenericIEnumerableOrIsGenericIEnumerable = + typeInfo.ImplementedInterfaces.Any(ti => + ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); + + if (implementsGenericIEnumerableOrIsGenericIEnumerable) + { + type = type.GetGenericArguments()[0]; + } + } + + List keyProperties = KeyPropertiesCache(type); + List explicitKeyProperties = ExplicitKeyPropertiesCache(type); + if (keyProperties.Count == 0 && explicitKeyProperties.Count == 0) + { + throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); + } + + string name = GetTableName(type); + keyProperties.AddRange(explicitKeyProperties); + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("DELETE FROM {0} WHERE ", name); + + ISqlAdapter adapter = GetFormatter(connection); + + for (int i = 0; i < keyProperties.Count; i++) + { + PropertyInfo property = keyProperties[i]; + adapter.AppendColumnNameEqualsValue(sb, property.Name); + if (i < keyProperties.Count - 1) + { + sb.Append(" AND "); + } + } + + int deleted = await connection.ExecuteAsync(sb.ToString(), entityToDelete, transaction, commandTimeout) + .ConfigureAwait(false); + return deleted > 0; + } + + /// + /// Delete all entities in the table related to the type T asynchronously using Task. + /// + /// Type of entity + /// Open SqlConnection + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// true if deleted, false if none found + public static async Task DeleteAllAsync(this IDbConnection connection, + IDbTransaction transaction = null, int? commandTimeout = null) where T : class + { + Type type = typeof(T); + string statement = "DELETE FROM " + GetTableName(type); + int deleted = await connection.ExecuteAsync(statement, null, transaction, commandTimeout) + .ConfigureAwait(false); + return deleted > 0; + } + } +} + +public partial interface ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert); +} + +public partial class SqlServerAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, + string tableName, string columnList, string parameterList, IEnumerable keyProperties, + object entityToInsert) + { + string cmd = $"INSERT INTO `{tableName}` ({columnList}) values ({parameterList}); select @@ROWCOUNT num"; + SqlMapper.GridReader multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout) + .ConfigureAwait(false); + + dynamic first = multi.Read().FirstOrDefault(); + if (first == null || first.num == null) + { + return 0; + } + + int num = (int)first.num; + + return num; + } +} + +public partial class SqlCeServerAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, + string tableName, string columnList, string parameterList, IEnumerable keyProperties, + object entityToInsert) + { + string cmd = $"INSERT INTO `{tableName}` ({columnList}) values ({parameterList}); select @@ROWCOUNT num"; + SqlMapper.GridReader multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout) + .ConfigureAwait(false); + + dynamic first = multi.Read().FirstOrDefault(); + if (first == null || first.num == null) + { + return 0; + } + + int num = (int)first.num; + + return num; + } +} + +public partial class MySqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, + string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + string cmd = $"INSERT INTO `{tableName}` ({columnList}) VALUES ({parameterList});select ROW_COUNT() num"; + SqlMapper.GridReader multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout) + .ConfigureAwait(false); + + dynamic first = multi.Read().FirstOrDefault(); + if (first == null || first.num == null) + { + return 0; + } + + int num = (int)first.num; + + return num; + //await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + //var r = await connection.QueryAsync("SELECT LAST_INSERT_ID() id", transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false); + + //var id = r.First().id; + //if (id == null) return 0; + //var pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + //if (pi.Length == 0) return Convert.ToInt32(id); + + //var idp = pi[0]; + //idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + //return Convert.ToInt32(id); + } +} + +public partial class PostgresAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, + string tableName, string columnList, string parameterList, IEnumerable keyProperties, + object entityToInsert) + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2})", tableName, columnList, parameterList); + + // If no primary key then safe to assume a join table with not too much data to return + PropertyInfo[] propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) + { + sb.Append(" RETURNING *"); + } + else + { + sb.Append(" RETURNING "); + bool first = true; + foreach (PropertyInfo property in propertyInfos) + { + if (!first) + { + sb.Append(", "); + } + + first = false; + sb.Append(property.Name); + } + } + + IEnumerable results = await connection.QueryAsync(sb.ToString(), entityToInsert, transaction, commandTimeout) + .ConfigureAwait(false); + + // Return the key by assinging the corresponding property in the object - by product is that it supports compound primary keys + int id = 0; + foreach (PropertyInfo p in propertyInfos) + { + object value = ((IDictionary)results.First())[p.Name.ToLower()]; + p.SetValue(entityToInsert, value, null); + if (id == 0) + { + id = Convert.ToInt32(value); + } + } + + return id; + } +} + +public partial class SQLiteAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, + string tableName, string columnList, string parameterList, IEnumerable keyProperties, + object entityToInsert) + { + string cmd = $"INSERT INTO `{tableName}` ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id"; + SqlMapper.GridReader multi = await connection.QueryMultipleAsync(cmd, entityToInsert, transaction, commandTimeout) + .ConfigureAwait(false); + + int id = (int)multi.Read().First().id; + PropertyInfo[] pi = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (pi.Length == 0) + { + return id; + } + + PropertyInfo idp = pi[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return id; + } +} + +public partial class FbAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public async Task InsertAsync(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, + string tableName, string columnList, string parameterList, IEnumerable keyProperties, + object entityToInsert) + { + string cmd = $"insert into `{tableName}` ({columnList}) values ({parameterList})"; + await connection.ExecuteAsync(cmd, entityToInsert, transaction, commandTimeout).ConfigureAwait(false); + + PropertyInfo[] propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + string keyName = propertyInfos[0].Name; + IEnumerable r = await connection.QueryAsync($"SELECT FIRST 1 {keyName} ID FROM `{tableName}` ORDER BY {keyName} DESC", + transaction: transaction, commandTimeout: commandTimeout).ConfigureAwait(false); + + dynamic id = r.First().ID; + if (id == null) + { + return 0; + } + + if (propertyInfos.Length == 0) + { + return Convert.ToInt32(id); + } + + PropertyInfo idp = propertyInfos[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return Convert.ToInt32(id); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/SqlMapperExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/SqlMapperExtensions.cs new file mode 100644 index 0000000..12ae1a0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/SqlMapperExtensions.cs @@ -0,0 +1,1266 @@ +using Dapper; +using StackExchange.Profiling.Data; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; + +#if NETSTANDARD1_3 +using DataException = System.InvalidOperationException; +#endif + +namespace Dapper.Contrib.Extensions +{ + /// + /// The Dapper.Contrib extensions for Dapper + /// + public static partial class SqlMapperExtensions + { + /// + /// The function to get a database type from the given . + /// + /// The connection to get a database type name from. + public delegate string GetDatabaseTypeDelegate(IDbConnection connection); + + /// + /// The function to get a a table name from a given + /// + /// The to get a table name for. + public delegate string TableNameMapperDelegate(Type type); + + private static readonly ConcurrentDictionary> KeyProperties = + new(); + + private static readonly ConcurrentDictionary> ExplicitKeyProperties + = new(); + + private static readonly ConcurrentDictionary> TypeProperties = + new(); + + private static readonly ConcurrentDictionary> ComputedProperties = + new(); + + private static readonly ConcurrentDictionary GetQueries = + new(); + + private static readonly ConcurrentDictionary TypeTableName = + new(); + + private static readonly ISqlAdapter DefaultAdapter = new SqlServerAdapter(); + + private static readonly Dictionary AdapterDictionary + = new() + { + ["sqlconnection"] = new SqlServerAdapter(), + ["sqlceconnection"] = new SqlCeServerAdapter(), + ["npgsqlconnection"] = new PostgresAdapter(), + ["sqliteconnection"] = new SQLiteAdapter(), + ["mysqlconnection"] = new MySqlAdapter(), + ["fbconnection"] = new FbAdapter() + }; + + /// + /// Specify a custom table name mapper based on the POCO type name + /// + public static TableNameMapperDelegate TableNameMapper; + + /// + /// Specifies a custom callback that detects the database type instead of relying on the default strategy (the name of + /// the connection type object). + /// Please note that this callback is global and will be used by all the calls that require a database specific + /// adapter. + /// + public static GetDatabaseTypeDelegate GetDatabaseType; + + private static List ComputedPropertiesCache(Type type) + { + if (ComputedProperties.TryGetValue(type.TypeHandle, out IEnumerable pi)) + { + return pi.ToList(); + } + + List computedProperties = TypePropertiesCache(type) + .Where(p => p.GetCustomAttributes(true).Any(a => a is ComputedAttribute)).ToList(); + + ComputedProperties[type.TypeHandle] = computedProperties; + return computedProperties; + } + + private static List ExplicitKeyPropertiesCache(Type type) + { + if (ExplicitKeyProperties.TryGetValue(type.TypeHandle, out IEnumerable pi)) + { + return pi.ToList(); + } + + List explicitKeyProperties = TypePropertiesCache(type) + .Where(p => p.GetCustomAttributes(true).Any(a => a is ExplicitKeyAttribute)).ToList(); + + ExplicitKeyProperties[type.TypeHandle] = explicitKeyProperties; + return explicitKeyProperties; + } + + /// + /// 查询主键,属性加了Key标签 + /// + /// + /// + private static List KeyPropertiesCache(Type type) + { + if (KeyProperties.TryGetValue(type.TypeHandle, out IEnumerable pi)) + { + return pi.ToList(); + } + + List allProperties = TypePropertiesCache(type); + List keyProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute)) + .ToList(); + + if (keyProperties.Count == 0) + { + PropertyInfo idProp = allProperties.Find(p => + string.Equals(p.Name, "Id", StringComparison.CurrentCultureIgnoreCase)); + if (idProp != null && !idProp.GetCustomAttributes(true).Any(a => a is ExplicitKeyAttribute)) + { + keyProperties.Add(idProp); + } + } + + KeyProperties[type.TypeHandle] = keyProperties; + return keyProperties; + } + + private static List TypePropertiesCache(Type type) + { + if (TypeProperties.TryGetValue(type.TypeHandle, out IEnumerable pis)) + { + return pis.ToList(); + } + + PropertyInfo[] properties = type.GetProperties().Where(IsWriteable).ToArray(); + TypeProperties[type.TypeHandle] = properties; + return properties.ToList(); + } + + private static bool IsWriteable(PropertyInfo pi) + { + List attributes = pi.GetCustomAttributes(typeof(WriteAttribute), false).AsList(); + if (attributes.Count != 1) + { + return true; + } + + WriteAttribute writeAttribute = (WriteAttribute)attributes[0]; + return writeAttribute.Write; + } + + private static PropertyInfo GetSingleKey(string method) + { + Type type = typeof(T); + List keys = KeyPropertiesCache(type); + //var explicitKeys = ExplicitKeyPropertiesCache(type); + int keyCount = keys.Count; // + explicitKeys.Count; + if (keyCount > 1) + { + throw new DataException( + $"{method} only supports an entity with a single [Key] property. [Key] Count: {keys.Count}"); + } + + if (keyCount == 0) + { + throw new DataException($"{method} only supports an entity with a [Key] property"); + } + + return keys[0]; + } + + /// + /// Returns a single entity by a single id from table "Ts". + /// Id must be marked with [Key] attribute. + /// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension + /// for optimal performance. + /// + /// Interface or type to create and populate + /// Open SqlConnection + /// Id of the entity to get, must be marked with [Key] attribute + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// Entity of T + public static T Get(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, + int? commandTimeout = null) where T : class + { + Type type = typeof(T); + + if (!GetQueries.TryGetValue(type.TypeHandle, out string sql)) + { + PropertyInfo key = GetSingleKey(nameof(Get)); + string name = GetTableName(type); + + sql = $"select * from {name} where {key.Name} = @KeyName"; + GetQueries[type.TypeHandle] = sql; + } + + DynamicParameters dynParms = new DynamicParameters(); + dynParms.Add("@KeyName", id); + + T obj; + + if (type.IsInterface) + { + IDictionary res = connection.Query(sql, dynParms).FirstOrDefault() as IDictionary; + + if (res == null) + { + return null; + } + + obj = ProxyGenerator.GetInterfaceProxy(); + + foreach (PropertyInfo property in TypePropertiesCache(type)) + { + object val = res[property.Name]; + if (val == null) + { + continue; + } + + if (property.PropertyType.IsGenericType && + property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + Type genericType = Nullable.GetUnderlyingType(property.PropertyType); + if (genericType != null) + { + property.SetValue(obj, Convert.ChangeType(val, genericType), null); + } + } + else + { + property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null); + } + } + + ((IProxy)obj).IsDirty = false; //reset change tracking and return + } + else + { + obj = connection.Query(sql, dynParms, transaction, commandTimeout: commandTimeout).FirstOrDefault(); + } + + return obj; + } + + /// + /// Returns a list of entites from table "Ts". + /// Id of T must be marked with [Key] attribute. + /// Entities created from interfaces are tracked/intercepted for changes and used by the Update() extension + /// for optimal performance. + /// + /// Interface or type to create and populate + /// Open SqlConnection + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// Entity of T + public static IEnumerable GetAll(this IDbConnection connection, IDbTransaction transaction = null, + int? commandTimeout = null) where T : class + { + Type type = typeof(T); + Type cacheType = typeof(List); + + if (!GetQueries.TryGetValue(cacheType.TypeHandle, out string sql)) + { + GetSingleKey(nameof(GetAll)); + string name = GetTableName(type); + + sql = "select * from " + name; + GetQueries[cacheType.TypeHandle] = sql; + } + + if (!type.IsInterface) + { + return connection.Query(sql, null, transaction, commandTimeout: commandTimeout); + } + + IEnumerable result = connection.Query(sql); + List list = new List(); + foreach (IDictionary res in result) + { + T obj = ProxyGenerator.GetInterfaceProxy(); + foreach (PropertyInfo property in TypePropertiesCache(type)) + { + object val = res[property.Name]; + if (val == null) + { + continue; + } + + if (property.PropertyType.IsGenericType && + property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + Type genericType = Nullable.GetUnderlyingType(property.PropertyType); + if (genericType != null) + { + property.SetValue(obj, Convert.ChangeType(val, genericType), null); + } + } + else + { + property.SetValue(obj, Convert.ChangeType(val, property.PropertyType), null); + } + } + + ((IProxy)obj).IsDirty = false; //reset change tracking and return + list.Add(obj); + } + + return list; + } + + private static string GetTableName(Type type) + { + if (TypeTableName.TryGetValue(type.TypeHandle, out string name)) + { + return name; + } + + if (TableNameMapper != null) + { + name = TableNameMapper(type); + } + else + { +#if NETSTANDARD1_3 + var info = type.GetTypeInfo(); +#else + Type info = type; +#endif + //NOTE: This as dynamic trick falls back to handle both our own Table-attribute as well as the one in EntityFramework + dynamic tableAttrName = + info.GetCustomAttribute(false)?.Name + ?? (info.GetCustomAttributes(false) + .FirstOrDefault(attr => attr.GetType().Name == "TableAttribute") as dynamic)?.Name; + + if (tableAttrName != null) + { + name = tableAttrName; + } + else + { + name = type.Name + "s"; + if (type.IsInterface && name.StartsWith("I")) + { + name = name.Substring(1); + } + } + } + + TypeTableName[type.TypeHandle] = name; + return name; + } + + /// + /// Inserts an entity into table "Ts" and returns identity id or number of inserted rows if inserting a list. + /// + /// The type to insert. + /// Open SqlConnection + /// Entity to insert, can be list of entities + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// Identity of inserted entity, or number of inserted rows if inserting a list + public static long Insert(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, + int? commandTimeout = null) where T : class + { + bool isList = false; + Type type = typeof(T); + + if (type.IsArray) + { + isList = true; + type = type.GetElementType(); + } + else if (type.IsGenericType) + { + TypeInfo typeInfo = type.GetTypeInfo(); + bool implementsGenericIEnumerableOrIsGenericIEnumerable = + typeInfo.ImplementedInterfaces.Any(ti => + ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); + + if (implementsGenericIEnumerableOrIsGenericIEnumerable) + { + isList = true; + type = type.GetGenericArguments()[0]; + } + } + + string name = GetTableName(type); + StringBuilder sbColumnList = new StringBuilder(null); + List allProperties = TypePropertiesCache(type); + List keyProperties = KeyPropertiesCache(type); + List computedProperties = ComputedPropertiesCache(type); + List allPropertiesExceptKeyAndComputed = + allProperties.ToList(); //.Except(keyProperties.Union(computedProperties)).ToList(); + + ISqlAdapter adapter = GetFormatter(connection); + + for (int i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) + { + PropertyInfo property = allPropertiesExceptKeyAndComputed[i]; + adapter.AppendColumnName(sbColumnList, property.Name); //fix for issue #336 + if (i < allPropertiesExceptKeyAndComputed.Count - 1) + { + sbColumnList.Append(", "); + } + } + + StringBuilder sbParameterList = new StringBuilder(null); + for (int i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++) + { + PropertyInfo property = allPropertiesExceptKeyAndComputed[i]; + sbParameterList.AppendFormat("@{0}", property.Name); + if (i < allPropertiesExceptKeyAndComputed.Count - 1) + { + sbParameterList.Append(", "); + } + } + + int returnVal; + bool wasClosed = connection.State == ConnectionState.Closed; + if (wasClosed) + { + connection.Open(); + } + + if (!isList) //single entity + { + returnVal = adapter.Insert(connection, transaction, commandTimeout, name, sbColumnList.ToString(), + sbParameterList.ToString(), keyProperties, entityToInsert); + } + else + { + //insert list of entities + string cmd = $"insert into {name} ({sbColumnList}) values ({sbParameterList})"; + returnVal = connection.Execute(cmd, entityToInsert, transaction, commandTimeout); + } + + if (wasClosed) + { + connection.Close(); + } + + return returnVal; + } + + /// + /// Updates entity in table "Ts", checks if the entity is modified if the entity is tracked by the Get() extension. + /// + /// Type to be updated + /// Open SqlConnection + /// Entity to be updated + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// true if updated, false if not found or not modified (tracked entities) + public static bool Update(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, + int? commandTimeout = null) where T : class + { + if (entityToUpdate is IProxy proxy && !proxy.IsDirty) + { + return false; + } + + Type type = typeof(T); + + if (type.IsArray) + { + type = type.GetElementType(); + } + else if (type.IsGenericType) + { + TypeInfo typeInfo = type.GetTypeInfo(); + bool implementsGenericIEnumerableOrIsGenericIEnumerable = + typeInfo.ImplementedInterfaces.Any(ti => + ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); + + if (implementsGenericIEnumerableOrIsGenericIEnumerable) + { + type = type.GetGenericArguments()[0]; + } + } + + List keyProperties = + KeyPropertiesCache(type).ToList(); //added ToList() due to issue #418, must work on a list copy + List explicitKeyProperties = ExplicitKeyPropertiesCache(type); + if (keyProperties.Count == 0 && explicitKeyProperties.Count == 0) + { + throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); + } + + string name = GetTableName(type); + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("update {0} set ", name); + + List allProperties = TypePropertiesCache(type); + keyProperties.AddRange(explicitKeyProperties); + List computedProperties = ComputedPropertiesCache(type); + List nonIdProps = allProperties.Except(keyProperties.Union(computedProperties)).ToList(); + + ISqlAdapter adapter = GetFormatter(connection); + + for (int i = 0; i < nonIdProps.Count; i++) + { + PropertyInfo property = nonIdProps[i]; + adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336 + if (i < nonIdProps.Count - 1) + { + sb.Append(", "); + } + } + + sb.Append(" where "); + for (int i = 0; i < keyProperties.Count; i++) + { + PropertyInfo property = keyProperties[i]; + adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336 + if (i < keyProperties.Count - 1) + { + sb.Append(" and "); + } + } + + int updated = connection.Execute(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, + transaction: transaction); + return updated > 0; + } + + /// + /// Delete entity in table "Ts". + /// + /// Type of entity + /// Open SqlConnection + /// Entity to delete + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// true if deleted, false if not found + public static bool Delete(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null, + int? commandTimeout = null) where T : class + { + if (entityToDelete == null) + { + throw new ArgumentException("Cannot Delete null Object", nameof(entityToDelete)); + } + + Type type = typeof(T); + + if (type.IsArray) + { + type = type.GetElementType(); + } + else if (type.IsGenericType) + { + TypeInfo typeInfo = type.GetTypeInfo(); + bool implementsGenericIEnumerableOrIsGenericIEnumerable = + typeInfo.ImplementedInterfaces.Any(ti => + ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>)) || + typeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>); + + if (implementsGenericIEnumerableOrIsGenericIEnumerable) + { + type = type.GetGenericArguments()[0]; + } + } + + List keyProperties = + KeyPropertiesCache(type).ToList(); //added ToList() due to issue #418, must work on a list copy + List explicitKeyProperties = ExplicitKeyPropertiesCache(type); + if (keyProperties.Count == 0 && explicitKeyProperties.Count == 0) + { + throw new ArgumentException("Entity must have at least one [Key] or [ExplicitKey] property"); + } + + string name = GetTableName(type); + keyProperties.AddRange(explicitKeyProperties); + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("delete from {0} where ", name); + + ISqlAdapter adapter = GetFormatter(connection); + + for (int i = 0; i < keyProperties.Count; i++) + { + PropertyInfo property = keyProperties[i]; + adapter.AppendColumnNameEqualsValue(sb, property.Name); //fix for issue #336 + if (i < keyProperties.Count - 1) + { + sb.Append(" and "); + } + } + + int deleted = connection.Execute(sb.ToString(), entityToDelete, transaction, commandTimeout); + return deleted > 0; + } + + /// + /// Delete all entities in the table related to the type T. + /// + /// Type of entity + /// Open SqlConnection + /// The transaction to run under, null (the default) if none + /// Number of seconds before command execution timeout + /// true if deleted, false if none found + public static bool DeleteAll(this IDbConnection connection, IDbTransaction transaction = null, + int? commandTimeout = null) where T : class + { + Type type = typeof(T); + string name = GetTableName(type); + string statement = $"delete from {name}"; + int deleted = connection.Execute(statement, null, transaction, commandTimeout); + return deleted > 0; + } + + /// + /// 适配数据类型 + /// 2020-11-09 集成MiniProfiler + /// + /// + /// + private static ISqlAdapter GetFormatter(IDbConnection connection) + { + string name = GetDatabaseType?.Invoke(connection).ToLower() + ?? connection.GetType().Name.ToLower(); + if (name == "profileddbconnection") + { + ProfiledDbConnection pconn = (ProfiledDbConnection)connection; + name = pconn.WrappedConnection.GetType().Name.ToLower(); + } + + return !AdapterDictionary.ContainsKey(name) + ? DefaultAdapter + : AdapterDictionary[name]; + } + + /// + /// Defined a proxy object with a possibly dirty state. + /// + public interface IProxy //must be kept public + { + /// + /// Whether the object has been changed. + /// + bool IsDirty { get; set; } + } + + /// + /// Defines a table name mapper for getting table names from types. + /// + public interface ITableNameMapper + { + /// + /// Gets a table name from a given . + /// + /// The to get a name from. + /// The table name for the given . + string GetTableName(Type type); + } + + private static class ProxyGenerator + { + private static readonly Dictionary TypeCache = new(); + + private static AssemblyBuilder GetAsmBuilder(string name) + { + return AssemblyBuilder.DefineDynamicAssembly(new AssemblyName { Name = name }, AssemblyBuilderAccess.Run); + } + + public static T GetInterfaceProxy() + { + Type typeOfT = typeof(T); + + if (TypeCache.TryGetValue(typeOfT, out Type k)) + { + return (T)Activator.CreateInstance(k); + } + + AssemblyBuilder assemblyBuilder = GetAsmBuilder(typeOfT.Name); + + ModuleBuilder moduleBuilder = + assemblyBuilder.DefineDynamicModule("SqlMapperExtensions." + + typeOfT.Name); //NOTE: to save, add "asdasd.dll" parameter + + Type interfaceType = typeof(IProxy); + TypeBuilder typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "_" + Guid.NewGuid(), + TypeAttributes.Public | TypeAttributes.Class); + typeBuilder.AddInterfaceImplementation(typeOfT); + typeBuilder.AddInterfaceImplementation(interfaceType); + + //create our _isDirty field, which implements IProxy + MethodInfo setIsDirtyMethod = CreateIsDirtyProperty(typeBuilder); + + // Generate a field for each property, which implements the T + foreach (PropertyInfo property in typeof(T).GetProperties()) + { + bool isId = property.GetCustomAttributes(true).Any(a => a is KeyAttribute); + CreateProperty(typeBuilder, property.Name, property.PropertyType, setIsDirtyMethod, isId); + } + +#if NETSTANDARD1_3 || NETSTANDARD2_0 + var generatedType = typeBuilder.CreateTypeInfo().AsType(); +#else + Type generatedType = typeBuilder.CreateType(); +#endif + + TypeCache.Add(typeOfT, generatedType); + return (T)Activator.CreateInstance(generatedType); + } + + private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder) + { + Type propType = typeof(bool); + FieldBuilder field = typeBuilder.DefineField("_" + nameof(IProxy.IsDirty), propType, FieldAttributes.Private); + PropertyBuilder property = typeBuilder.DefineProperty(nameof(IProxy.IsDirty), + PropertyAttributes.None, + propType, + new[] { propType }); + + const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.NewSlot | + MethodAttributes.SpecialName + | MethodAttributes.Final | MethodAttributes.Virtual | + MethodAttributes.HideBySig; + + // Define the "get" and "set" accessor methods + MethodBuilder currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + nameof(IProxy.IsDirty), + getSetAttr, + propType, + Type.EmptyTypes); + ILGenerator currGetIl = currGetPropMthdBldr.GetILGenerator(); + currGetIl.Emit(OpCodes.Ldarg_0); + currGetIl.Emit(OpCodes.Ldfld, field); + currGetIl.Emit(OpCodes.Ret); + MethodBuilder currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + nameof(IProxy.IsDirty), + getSetAttr, + null, + new[] { propType }); + ILGenerator currSetIl = currSetPropMthdBldr.GetILGenerator(); + currSetIl.Emit(OpCodes.Ldarg_0); + currSetIl.Emit(OpCodes.Ldarg_1); + currSetIl.Emit(OpCodes.Stfld, field); + currSetIl.Emit(OpCodes.Ret); + + property.SetGetMethod(currGetPropMthdBldr); + property.SetSetMethod(currSetPropMthdBldr); + MethodInfo getMethod = typeof(IProxy).GetMethod("get_" + nameof(IProxy.IsDirty)); + MethodInfo setMethod = typeof(IProxy).GetMethod("set_" + nameof(IProxy.IsDirty)); + typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod); + typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod); + + return currSetPropMthdBldr; + } + + private static void CreateProperty(TypeBuilder typeBuilder, string propertyName, Type propType, + MethodInfo setIsDirtyMethod, bool isIdentity) + { + //Define the field and the property + FieldBuilder field = typeBuilder.DefineField("_" + propertyName, propType, FieldAttributes.Private); + PropertyBuilder property = typeBuilder.DefineProperty(propertyName, + PropertyAttributes.None, + propType, + new[] { propType }); + + const MethodAttributes getSetAttr = MethodAttributes.Public + | MethodAttributes.Virtual + | MethodAttributes.HideBySig; + + // Define the "get" and "set" accessor methods + MethodBuilder currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName, + getSetAttr, + propType, + Type.EmptyTypes); + + ILGenerator currGetIl = currGetPropMthdBldr.GetILGenerator(); + currGetIl.Emit(OpCodes.Ldarg_0); + currGetIl.Emit(OpCodes.Ldfld, field); + currGetIl.Emit(OpCodes.Ret); + + MethodBuilder currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + propertyName, + getSetAttr, + null, + new[] { propType }); + + //store value in private field and set the isdirty flag + ILGenerator currSetIl = currSetPropMthdBldr.GetILGenerator(); + currSetIl.Emit(OpCodes.Ldarg_0); + currSetIl.Emit(OpCodes.Ldarg_1); + currSetIl.Emit(OpCodes.Stfld, field); + currSetIl.Emit(OpCodes.Ldarg_0); + currSetIl.Emit(OpCodes.Ldc_I4_1); + currSetIl.Emit(OpCodes.Call, setIsDirtyMethod); + currSetIl.Emit(OpCodes.Ret); + + //TODO: Should copy all attributes defined by the interface? + if (isIdentity) + { + Type keyAttribute = typeof(KeyAttribute); + ConstructorInfo myConstructorInfo = keyAttribute.GetConstructor(new Type[] { }); + CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(myConstructorInfo, new object[] { }); + property.SetCustomAttribute(attributeBuilder); + } + + property.SetGetMethod(currGetPropMthdBldr); + property.SetSetMethod(currSetPropMthdBldr); + MethodInfo getMethod = typeof(T).GetMethod("get_" + propertyName); + MethodInfo setMethod = typeof(T).GetMethod("set_" + propertyName); + typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod); + typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod); + } + } + } + + /// + /// Specifies that this field is a explicitly set primary key in the database + /// + [AttributeUsage(AttributeTargets.Property)] + public class ExplicitKeyAttribute : Attribute + { + } + + /// + /// Specifies whether a field is writable in the database. + /// + [AttributeUsage(AttributeTargets.Property)] + public class WriteAttribute : Attribute + { + /// + /// Specifies whether a field is writable in the database. + /// + /// Whether a field is writable in the database. + public WriteAttribute(bool write) + { + Write = write; + } + + /// + /// Whether a field is writable in the database. + /// + public bool Write { get; } + } + + /// + /// Specifies that this is a computed column. + /// + [AttributeUsage(AttributeTargets.Property)] + public class ComputedAttribute : Attribute + { + } +} + +/// +/// The interface for all Dapper.Contrib database operations +/// Implementing this is each provider's model. +/// +public partial interface ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert); + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + void AppendColumnName(StringBuilder sb, string columnName); + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + void AppendColumnNameEqualsValue(StringBuilder sb, string columnName); +} + +/// +/// The SQL Server database adapter. +/// +public partial class SqlServerAdapter : ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + string cmd = $"insert into `{tableName}` ({columnList}) values ({parameterList}); select @@ROWCOUNT num"; + SqlMapper.GridReader multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout); + + dynamic first = multi.Read().FirstOrDefault(); + if (first == null || first.num == null) + { + return 0; + } + + int num = (int)first.num; + return num; + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}]", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}] = @{1}", columnName, columnName); + } +} + +/// +/// The SQL Server Compact Edition database adapter. +/// +public partial class SqlCeServerAdapter : ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + string cmd = $"insert into `{tableName}` ({columnList}) values ({parameterList}); select @@ROWCOUNT num"; + SqlMapper.GridReader multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout); + + dynamic first = multi.Read().FirstOrDefault(); + if (first == null || first.num == null) + { + return 0; + } + + int num = (int)first.num; + return num; + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}]", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("[{0}] = @{1}", columnName, columnName); + } +} + +/// +/// The MySQL database adapter. +/// +public partial class MySqlAdapter : ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// 2020-11-09 影响行数改为Select ROW_COUNT() + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + string cmd = $"insert into `{tableName}` ({columnList}) values ({parameterList}); select ROW_COUNT() num"; + SqlMapper.GridReader multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout); + + dynamic first = multi.Read().FirstOrDefault(); + if (first == null || first.num == null) + { + return 0; + } + + int num = (int)first.num; + return num; + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("`{0}`", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("`{0}` = @{1}", columnName, columnName); + } +} + +/// +/// The Postgres database adapter. +/// +public partial class PostgresAdapter : ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("insert into {0} ({1}) values ({2})", tableName, columnList, parameterList); + + // If no primary key then safe to assume a join table with not too much data to return + PropertyInfo[] propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) + { + sb.Append(" RETURNING *"); + } + else + { + sb.Append(" RETURNING "); + bool first = true; + foreach (PropertyInfo property in propertyInfos) + { + if (!first) + { + sb.Append(", "); + } + + first = false; + sb.Append(property.Name); + } + } + + List results = connection.Query(sb.ToString(), entityToInsert, transaction, commandTimeout: commandTimeout) + .ToList(); + + // Return the key by assinging the corresponding property in the object - by product is that it supports compound primary keys + int id = 0; + foreach (PropertyInfo p in propertyInfos) + { + object value = ((IDictionary)results[0])[p.Name.ToLower()]; + p.SetValue(entityToInsert, value, null); + if (id == 0) + { + id = Convert.ToInt32(value); + } + } + + return id; + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\"", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName); + } +} + +/// +/// The SQLite database adapter. +/// +public partial class SQLiteAdapter : ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + string cmd = $"INSERT INTO `{tableName}` ({columnList}) VALUES ({parameterList}); SELECT last_insert_rowid() id"; + SqlMapper.GridReader multi = connection.QueryMultiple(cmd, entityToInsert, transaction, commandTimeout); + + int id = (int)multi.Read().First().id; + PropertyInfo[] propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + if (propertyInfos.Length == 0) + { + return id; + } + + PropertyInfo idProperty = propertyInfos[0]; + idProperty.SetValue(entityToInsert, Convert.ChangeType(id, idProperty.PropertyType), null); + + return id; + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\"", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("\"{0}\" = @{1}", columnName, columnName); + } +} + +/// +/// The Firebase SQL adapeter. +/// +public partial class FbAdapter : ISqlAdapter +{ + /// + /// Inserts into the database, returning the Id of the row created. + /// + /// The connection to use. + /// The transaction to use. + /// The command timeout to use. + /// The table to insert into. + /// The columns to set with this insert. + /// The parameters to set for this insert. + /// The key columns in this table. + /// The entity to insert. + /// The Id of the row created. + public int Insert(IDbConnection connection, IDbTransaction transaction, int? commandTimeout, string tableName, + string columnList, string parameterList, IEnumerable keyProperties, object entityToInsert) + { + string cmd = $"insert into `{tableName}` ({columnList}) values ({parameterList})"; + connection.Execute(cmd, entityToInsert, transaction, commandTimeout); + + PropertyInfo[] propertyInfos = keyProperties as PropertyInfo[] ?? keyProperties.ToArray(); + string keyName = propertyInfos[0].Name; + IEnumerable r = connection.Query($"SELECT FIRST 1 {keyName} ID FROM `{tableName}` ORDER BY {keyName} DESC", + transaction: transaction, commandTimeout: commandTimeout); + + dynamic id = r.First().ID; + if (id == null) + { + return 0; + } + + if (propertyInfos.Length == 0) + { + return Convert.ToInt32(id); + } + + PropertyInfo idp = propertyInfos[0]; + idp.SetValue(entityToInsert, Convert.ChangeType(id, idp.PropertyType), null); + + return Convert.ToInt32(id); + } + + /// + /// Adds the name of a column. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnName(StringBuilder sb, string columnName) + { + sb.AppendFormat("{0}", columnName); + } + + /// + /// Adds a column equality to a parameter. + /// + /// The string builder to append to. + /// The column name. + public void AppendColumnNameEqualsValue(StringBuilder sb, string columnName) + { + sb.AppendFormat("{0} = @{1}", columnName, columnName); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/TypeExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/TypeExtensions.cs new file mode 100644 index 0000000..f7f6c28 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/TypeExtensions.cs @@ -0,0 +1,424 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Data; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// 类型辅助扩展方法类 + /// + public static class TypeExtensions + { + /// + /// 判断当前类型是否可由指定类型派生 + /// + public static bool IsDeriveClassFrom(this Type type, bool canAbstract = false) + { + return IsDeriveClassFrom(type, typeof(TBaseType), canAbstract); + } + + /// + /// 判断当前类型是否可由指定类型派生 + /// + public static bool IsDeriveClassFrom(this Type type, Type baseType, bool canAbstract = false) + { + Check.NotNull(type, nameof(type)); + Check.NotNull(baseType, nameof(baseType)); + + return type.IsClass && !canAbstract && !type.IsAbstract && type.IsBaseOn(baseType); + } + + /// + /// 判断类型是否为Nullable类型 + /// + /// 要处理的类型 + /// 是返回True,不是返回False + public static bool IsNullableType(this Type type) + { + return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + /// + /// 由类型的Nullable类型返回实际类型 + /// + /// 要处理的类型对象 + /// + public static Type GetNonNullableType(this Type type) + { + if (IsNullableType(type)) + { + return type.GetGenericArguments()[0]; + } + + return type; + } + + /// + /// 通过类型转换器获取Nullable类型的基础类型 + /// + /// 要处理的类型对象 + /// + public static Type GetUnNullableType(this Type type) + { + if (IsNullableType(type)) + { + NullableConverter nullableConverter = new NullableConverter(type); + return nullableConverter.UnderlyingType; + } + + return type; + } + + /// + /// 获取类型的Description特性描述信息 + /// + /// 类型对象 + /// 是否搜索类型的继承链以查找描述特性 + /// 返回Description特性描述信息,如不存在则返回类型的全名 + public static string GetDescription(this Type type, bool inherit = true) + { + DescriptionAttribute desc = type.GetAttribute(inherit); + return desc == null ? type.FullName : desc.Description; + } + + /// + /// 获取成员元数据的Description特性描述信息 + /// + /// 成员元数据对象 + /// 是否搜索成员的继承链以查找描述特性 + /// 返回Description特性描述信息,如不存在则返回成员的名称 + public static string GetDescription(this MemberInfo member, bool inherit = true) + { + DescriptionAttribute desc = member.GetAttribute(inherit); + if (desc != null) + { + return desc.Description; + } + + DisplayNameAttribute displayName = member.GetAttribute(inherit); + if (displayName != null) + { + return displayName.DisplayName; + } + + DisplayAttribute display = member.GetAttribute(inherit); + if (display != null) + { + return display.Name; + } + + return member.Name; + } + + /// + /// 检查指定指定类型成员中是否存在指定的Attribute特性 + /// + /// 要检查的Attribute特性类型 + /// 要检查的类型成员 + /// 是否从继承中查找 + /// 是否存在 + public static bool HasAttribute(this MemberInfo memberInfo, bool inherit = true) where T : Attribute + { + return memberInfo.IsDefined(typeof(T), inherit); + } + + /// + /// 从类型成员获取指定Attribute特性 + /// + /// Attribute特性类型 + /// 类型类型成员 + /// 是否从继承中查找 + /// 存在返回第一个,不存在返回null + public static T GetAttribute(this MemberInfo memberInfo, bool inherit = true) where T : Attribute + { + object[] attributes = memberInfo.GetCustomAttributes(typeof(T), inherit); + return attributes.FirstOrDefault() as T; + } + + /// + /// 从类型成员获取指定Attribute特性 + /// + /// Attribute特性类型 + /// 类型类型成员 + /// 是否从继承中查找 + /// 返回所有指定Attribute特性的数组 + public static T[] GetAttributes(this MemberInfo memberInfo, bool inherit = true) where T : Attribute + { + return memberInfo.GetCustomAttributes(typeof(T), inherit).Cast().ToArray(); + } + + /// + /// 判断类型是否为集合类型 + /// + /// 要处理的类型 + /// 是返回True,不是返回False + public static bool IsEnumerable(this Type type) + { + if (type == typeof(string)) + { + return false; + } + + return typeof(IEnumerable).IsAssignableFrom(type); + } + + /// + /// 判断当前泛型类型是否可由指定类型的实例填充 + /// + /// 泛型类型 + /// 指定类型 + /// + public static bool IsGenericAssignableFrom(this Type genericType, Type type) + { + genericType.CheckNotNull("genericType"); + type.CheckNotNull("type"); + if (!genericType.IsGenericType) + { + throw new ArgumentException("该功能只支持泛型类型的调用,非泛型类型可使用 IsAssignableFrom 方法。"); + } + + List allOthers = new List { type }; + if (genericType.IsInterface) + { + allOthers.AddRange(type.GetInterfaces()); + } + + foreach (Type other in allOthers) + { + Type cur = other; + while (cur != null) + { + if (cur.IsGenericType) + { + cur = cur.GetGenericTypeDefinition(); + } + + if (cur.IsSubclassOf(genericType) || cur == genericType) + { + return true; + } + + cur = cur.BaseType; + } + } + + return false; + } + + /// + /// 方法是否是异步 + /// + public static bool IsAsync(this MethodInfo method) + { + return method.ReturnType == typeof(Task) + || method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>); + } + + /// + /// 返回当前类型是否是指定基类的派生类 + /// + /// 当前类型 + /// 要判断的基类型 + /// + public static bool IsBaseOn(this Type type, Type baseType) + { + if (baseType.IsGenericTypeDefinition) + { + return baseType.IsGenericAssignableFrom(type); + } + + return baseType.IsAssignableFrom(type); + } + + /// + /// 返回当前类型是否是指定基类的派生类 + /// + /// 要判断的基类型 + /// 当前类型 + /// + public static bool IsBaseOn(this Type type) + { + Type baseType = typeof(TBaseType); + return type.IsBaseOn(baseType); + } + + /// + /// 获取类型的全名,附带所在类库 + /// + public static string GetFullNameWithModule(this Type type) + { + return $"{type.FullName},{type.Module.Name.Replace(".dll", "").Replace(".exe", "")}"; + } + + /// + /// 获取类型的显示短名称 + /// + public static string ShortDisplayName(this Type type) + { + return type.DisplayName(false); + } + + /// + /// 获取类型的显示名称 + /// + public static string DisplayName([NotNull] this Type type, bool fullName = true) + { + StringBuilder sb = new StringBuilder(); + ProcessType(sb, type, fullName); + return sb.ToString(); + } + + /// + /// 获取主键字段 + /// + /// + /// + public static PropertyInfo GetKeyProperty(this Type entity) + { + return entity.GetProperties().GetKeyProperty(); + } + + /// + /// + /// + /// + public static PropertyInfo GetKeyProperty(this PropertyInfo[] properties) + { + return properties.Where(c => c.IsKey()).FirstOrDefault(); + } + + /// + /// + /// + /// + public static bool IsKey(this PropertyInfo propertyInfo) + { + object[] keyAttributes = propertyInfo.GetCustomAttributes(typeof(KeyAttribute), false); + if (keyAttributes.Length > 0) + { + return true; + } + + return false; + } + + #region 私有方法 + + private static readonly Dictionary _builtInTypeNames = new() + { + { typeof(bool), "bool" }, + { typeof(byte), "byte" }, + { typeof(char), "char" }, + { typeof(decimal), "decimal" }, + { typeof(double), "double" }, + { typeof(float), "float" }, + { typeof(int), "int" }, + { typeof(long), "long" }, + { typeof(object), "object" }, + { typeof(sbyte), "sbyte" }, + { typeof(short), "short" }, + { typeof(string), "string" }, + { typeof(uint), "uint" }, + { typeof(ulong), "ulong" }, + { typeof(ushort), "ushort" }, + { typeof(void), "void" } + }; + + private static void ProcessType(StringBuilder builder, Type type, bool fullName) + { + if (type.IsGenericType) + { + Type[] genericArguments = type.GetGenericArguments(); + ProcessGenericType(builder, type, genericArguments, genericArguments.Length, fullName); + } + else if (type.IsArray) + { + ProcessArrayType(builder, type, fullName); + } + else if (_builtInTypeNames.TryGetValue(type, out string builtInName)) + { + builder.Append(builtInName); + } + else if (!type.IsGenericParameter) + { + builder.Append(fullName ? type.FullName : type.Name); + } + } + + private static void ProcessArrayType(StringBuilder builder, Type type, bool fullName) + { + Type innerType = type; + while (innerType.IsArray) + { + innerType = innerType.GetElementType(); + } + + ProcessType(builder, innerType, fullName); + + while (type.IsArray) + { + builder.Append('['); + builder.Append(',', type.GetArrayRank() - 1); + builder.Append(']'); + type = type.GetElementType(); + } + } + + private static void ProcessGenericType(StringBuilder builder, Type type, Type[] genericArguments, int length, + bool fullName) + { + int offset = type.IsNested ? type.DeclaringType.GetGenericArguments().Length : 0; + + if (fullName) + { + if (type.IsNested) + { + ProcessGenericType(builder, type.DeclaringType, genericArguments, offset, fullName); + builder.Append('+'); + } + else + { + builder.Append(type.Namespace); + builder.Append('.'); + } + } + + int genericPartIndex = type.Name.IndexOf('`'); + if (genericPartIndex <= 0) + { + builder.Append(type.Name); + return; + } + + builder.Append(type.Name, 0, genericPartIndex); + builder.Append('<'); + + for (int i = offset; i < length; i++) + { + ProcessType(builder, genericArguments[i], fullName); + if (i + 1 == length) + { + continue; + } + + builder.Append(','); + if (!genericArguments[i + 1].IsGenericParameter) + { + builder.Append(' '); + } + } + + builder.Append('>'); + } + + #endregion 私有方法 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Extensions/YuebonClaimTypes.cs b/Znyc.Cloudcar.Admin.Commons/Extensions/YuebonClaimTypes.cs new file mode 100644 index 0000000..17f00ad --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Extensions/YuebonClaimTypes.cs @@ -0,0 +1,59 @@ +using System.Security.Claims; + +namespace Znyc.Cloudcar.Admin.Commons.Extensions +{ + /// + /// + public static class ZnycClaimTypes + { + /// + /// Default: + /// + public static string UserName { get; set; } = ClaimTypes.Name; + + /// + /// Default: + /// + public static string UserId { get; set; } = ClaimTypes.NameIdentifier; + + /// + /// Default: + /// + public static string Role { get; set; } = ClaimTypes.Role; + + /// + /// Default: + /// + public static string Email { get; set; } = ClaimTypes.Email; + + /// + /// Default: "email_verified". + /// + public static string EmailVerified { get; set; } = "email_verified"; + + /// + /// Default: "phone_number". + /// + public static string PhoneNumber { get; set; } = "phone_number"; + + /// + /// Default: "phone_number_verified". + /// + public static string PhoneNumberVerified { get; set; } = "phone_number_verified"; + + /// + /// Default: "tenantid". + /// + public static string TenantId { get; set; } = "tenantid"; + + /// + /// Default: "editionid". + /// + public static string EditionId { get; set; } = "editionid"; + + /// + /// Default: "client_id". + /// + public static string ClientId { get; set; } = "client_id"; + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/AppVersionHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/AppVersionHelper.cs new file mode 100644 index 0000000..d09bbd3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/AppVersionHelper.cs @@ -0,0 +1,28 @@ +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 应用版本号、软件厂商等信息 + /// + public class AppVersionHelper + { + /// + /// 版本号 + /// + public const string Version = "3.0"; + + /// + /// 软件厂商 + /// + public const string Manufacturer = "上海越邦网络科技有限公司"; + + /// + /// 网站地址 + /// + public const string WebSite = "http://www.Znyc.Cloudcar.Admin.com"; + + /// + /// 更新地址 + /// + public const string UpdateUrl = "http://netcore.Znyc.Cloudcar.Admin.com/update"; + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/BooleanJsonConverter.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/BooleanJsonConverter.cs new file mode 100644 index 0000000..ffa49bc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/BooleanJsonConverter.cs @@ -0,0 +1,37 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// + public class BooleanJsonConverter : JsonConverter + { + /// + /// + /// + /// + /// + /// + public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.True || reader.TokenType == JsonTokenType.False) + { + return reader.GetBoolean(); + } + + return bool.Parse(reader.GetString()); + } + + /// + /// + /// + /// + /// + public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options) + { + writer.WriteBooleanValue(value); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/ByteConvertHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/ByteConvertHelper.cs new file mode 100644 index 0000000..03db0f5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/ByteConvertHelper.cs @@ -0,0 +1,45 @@ +using Newtonsoft.Json; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// byte转换类 + /// + public class ByteConvertHelper + { + /// + /// 将对象转换为byte数组 + /// + /// 被转换对象 + /// 转换后byte数组 + public static byte[] Object2Bytes(object obj) + { + string json = JsonConvert.SerializeObject(obj); + byte[] serializedResult = Encoding.UTF8.GetBytes(json); + return serializedResult; + } + + /// + /// 将byte数组转换成对象 + /// + /// 被转换byte数组 + /// 转换完成后的对象 + public static object Bytes2Object(byte[] buff) + { + string json = Encoding.UTF8.GetString(buff); + return JsonConvert.DeserializeObject(json); + } + + /// + /// 将byte数组转换成对象 + /// + /// 被转换byte数组 + /// 转换完成后的对象 + public static T Bytes2Object(byte[] buff) + { + string json = Encoding.UTF8.GetString(buff); + return JsonConvert.DeserializeObject(json); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/ConvertHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/ConvertHelper.cs new file mode 100644 index 0000000..9fe5ec8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/ConvertHelper.cs @@ -0,0 +1,868 @@ +using System; +using System.Text; +using System.Threading; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 处理数据类型转换,数制转换、编码转换相关的类 + /// + public sealed class ConvertHelper + { + #region 将byte[]转换成int + + /// + /// 将byte[]转换成int + /// + /// 需要转换成整数的byte数组 + public static int BytesToInt32(byte[] data) + { + //如果传入的字节数组长度小于4,则返回0 + if (data.Length < 4) + { + return 0; + } + + //定义要返回的整数 + int num = 0; + + //如果传入的字节数组长度大于4,需要进行处理 + if (data.Length >= 4) + { + //创建一个临时缓冲区 + byte[] tempBuffer = new byte[4]; + + //将传入的字节数组的前4个字节复制到临时缓冲区 + Buffer.BlockCopy(data, 0, tempBuffer, 0, 4); + + //将临时缓冲区的值转换成整数,并赋给num + num = BitConverter.ToInt32(tempBuffer, 0); + } + + //返回整数 + return num; + } + + #endregion 将byte[]转换成int + + #region 各进制数间转换 + + /// + /// 实现各进制数间的转换。ConvertBase("15",10,16)表示将十进制数15转换为16进制的数。 + /// + /// 要转换的值,即原值 + /// 原值的进制,只能是2,8,10,16四个值。 + /// 要转换到的目标进制,只能是2,8,10,16四个值。 + public static string ConvertBase(string value, int from, int to) + { + if (!isBaseNumber(from)) + { + throw new ArgumentException("参数from只能是2,8,10,16四个值。"); + } + + if (!isBaseNumber(to)) + { + throw new ArgumentException("参数to只能是2,8,10,16四个值。"); + } + + int intValue = Convert.ToInt32(value, from); //先转成10进制 + string result = Convert.ToString(intValue, to); //再转成目标进制 + if (to == 2) + { + int resultLength = result.Length; //获取二进制的长度 + switch (resultLength) + { + case 7: + result = "0" + result; + break; + + case 6: + result = "00" + result; + break; + + case 5: + result = "000" + result; + break; + + case 4: + result = "0000" + result; + break; + + case 3: + result = "00000" + result; + break; + } + } + + return result; + } + + /// + /// 判断是否是 2 8 10 16 + /// + /// + /// + private static bool isBaseNumber(int baseNumber) + { + if (baseNumber == 2 || baseNumber == 8 || baseNumber == 10 || baseNumber == 16) + { + return true; + } + + return false; + } + + #endregion 各进制数间转换 + + #region 使用指定字符集将string转换成byte[] + + /// + /// 将string转换成byte[] + /// + /// 要转换的字符串 + public static byte[] StringToBytes(string text) + { + return Encoding.Default.GetBytes(text); + } + + /// + /// 使用指定字符集将string转换成byte[] + /// + /// 要转换的字符串 + /// 字符编码 + public static byte[] StringToBytes(string text, Encoding encoding) + { + return encoding.GetBytes(text); + } + + #endregion 使用指定字符集将string转换成byte[] + + #region 使用指定字符集将byte[]转换成string + + /// + /// 将byte[]转换成string + /// + /// 要转换的字节数组 + public static string BytesToString(byte[] bytes) + { + return Encoding.Default.GetString(bytes); + } + + /// + /// 使用指定字符集将byte[]转换成string + /// + /// 要转换的字节数组 + /// 字符编码 + public static string BytesToString(byte[] bytes, Encoding encoding) + { + return encoding.GetString(bytes); + } + + #endregion 使用指定字符集将byte[]转换成string + + #region 将数据转换为整型 + + /// + /// 将数据转换为整型 转换失败返回默认值 + /// + /// 数据类型 + /// 数据 + /// 默认值 + /// + public static int ToInt32(T data, int defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToInt32(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为整型 转换失败返回默认值 + /// + /// 数据 + /// 默认值 + /// + public static int ToInt32(string data, int defValue) + { + //如果为空则返回默认值 + if (string.IsNullOrEmpty(data)) + { + return defValue; + } + + if (int.TryParse(data, out int temp)) + { + return temp; + } + + return defValue; + } + + /// + /// 将数据转换为整型 转换失败返回默认值 + /// + /// 数据 + /// 默认值 + /// + public static int ToInt32(object data, int defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToInt32(data); + } + catch + { + return defValue; + } + } + + #endregion 将数据转换为整型 + + #region 将数据转换为布尔型 + + /// + /// 将数据转换为布尔类型 转换失败返回默认值 + /// + /// 数据类型 + /// 数据 + /// 默认值 + /// + public static bool ToBoolean(T data, bool defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToBoolean(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为布尔类型 转换失败返回 默认值 + /// + /// 数据 + /// 默认值 + /// + public static bool ToBoolean(string data, bool defValue) + { + //如果为空则返回默认值 + if (string.IsNullOrEmpty(data)) + { + return defValue; + } + + if (bool.TryParse(data, out bool temp)) + { + return temp; + } + + return defValue; + } + + /// + /// 将数据转换为布尔类型 转换失败返回 默认值 + /// + /// 数据 + /// 默认值 + /// + public static bool ToBoolean(object data, bool defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToBoolean(data); + } + catch + { + return defValue; + } + } + + #endregion 将数据转换为布尔型 + + #region 将数据转换为单精度浮点型 + + /// + /// 将数据转换为单精度浮点型 转换失败 返回默认值 + /// + /// 数据类型 + /// 数据 + /// 默认值 + /// + public static float ToFloat(T data, float defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToSingle(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为单精度浮点型 转换失败返回默认值 + /// + /// 数据 + /// 默认值 + /// + public static float ToFloat(object data, float defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToSingle(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为单精度浮点型 转换失败返回默认值 + /// + /// 数据 + /// 默认值 + /// + public static float ToFloat(string data, float defValue) + { + //如果为空则返回默认值 + if (string.IsNullOrEmpty(data)) + { + return defValue; + } + + if (float.TryParse(data, out float temp)) + { + return temp; + } + + return defValue; + } + + #endregion 将数据转换为单精度浮点型 + + #region 将数据转换为双精度浮点型 + + /// + /// 将数据转换为双精度浮点型 转换失败返回默认值 + /// + /// 数据的类型 + /// 要转换的数据 + /// 默认值 + /// + public static double ToDouble(T data, double defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToDouble(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为双精度浮点型,并设置小数位 转换失败返回默认值 + /// + /// 数据的类型 + /// 要转换的数据 + /// 小数的位数 + /// 默认值 + /// + public static double ToDouble(T data, int decimals, double defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Math.Round(Convert.ToDouble(data), decimals); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为双精度浮点型 转换失败返回默认值 + /// + /// 要转换的数据 + /// 默认值 + /// + public static double ToDouble(object data, double defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToDouble(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为双精度浮点型 转换失败返回默认值 + /// + /// 要转换的数据 + /// 默认值 + /// + public static double ToDouble(string data, double defValue) + { + //如果为空则返回默认值 + if (string.IsNullOrEmpty(data)) + { + return defValue; + } + + if (double.TryParse(data, out double temp)) + { + return temp; + } + + return defValue; + } + + /// + /// 将数据转换为双精度浮点型,并设置小数位 转换失败返回默认值 + /// + /// 要转换的数据 + /// 小数的位数 + /// 默认值 + /// + public static double ToDouble(object data, int decimals, double defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Math.Round(Convert.ToDouble(data), decimals); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为双精度浮点型,并设置小数位 转换失败返回默认值 + /// + /// 要转换的数据 + /// 小数的位数 + /// 默认值 + /// + public static double ToDouble(string data, int decimals, double defValue) + { + //如果为空则返回默认值 + if (string.IsNullOrEmpty(data)) + { + return defValue; + } + + if (double.TryParse(data, out double temp)) + { + return Math.Round(temp, decimals); + } + + return defValue; + } + + #endregion 将数据转换为双精度浮点型 + + #region 将数据转换为指定类型 + + /// + /// 将数据转换为指定类型 + /// + /// 转换的数据 + /// 转换的目标类型 + public static object ConvertTo(object data, Type targetType) + { + if (data == null || Convert.IsDBNull(data)) + { + return null; + } + + Type type2 = data.GetType(); + if (targetType == type2) + { + return data; + } + + if ((targetType == typeof(Guid) || targetType == typeof(Guid?)) && type2 == typeof(string)) + { + if (string.IsNullOrEmpty(data.ToString())) + { + return null; + } + + return new Guid(data.ToString()); + } + + if (targetType.IsEnum) + { + try + { + return Enum.Parse(targetType, data.ToString(), true); + } + catch + { + return Enum.ToObject(targetType, data); + } + } + + if (targetType.IsGenericType) + { + targetType = targetType.GetGenericArguments()[0]; + } + + return Convert.ChangeType(data, targetType); + } + + /// + /// 将数据转换为指定类型 + /// + /// 转换的目标类型 + /// 转换的数据 + public static T ConvertTo(object data) + { + if (data == null || Convert.IsDBNull(data)) + { + return default; + } + + object obj = ConvertTo(data, typeof(T)); + if (obj == null) + { + return default; + } + + return (T)obj; + } + + #endregion 将数据转换为指定类型 + + #region = ChangeType = + + /// + /// + /// + /// + /// + public static object ChangeType(object obj, Type conversionType) + { + return ChangeType(obj, conversionType, Thread.CurrentThread.CurrentCulture); + } + + /// + /// + /// + /// + /// + /// + public static object ChangeType(object obj, Type conversionType, IFormatProvider provider) + { + #region Nullable + + Type nullableType = Nullable.GetUnderlyingType(conversionType); + if (nullableType != null) + { + if (obj == null) + { + return null; + } + + return Convert.ChangeType(obj, nullableType, provider); + } + + #endregion Nullable + + if (typeof(Enum).IsAssignableFrom(conversionType)) + { + return Enum.Parse(conversionType, obj.ToString()); + } + + return Convert.ChangeType(obj, conversionType, provider); + } + + #endregion = ChangeType = + + #region 将数据转换Decimal + + /// + /// 将数据转换为Decimal 转换失败返回默认值 + /// + /// 数据类型 + /// 数据 + /// 默认值 + /// + public static decimal ToDecimal(T data, decimal defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToDecimal(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为Decimal 转换失败返回 默认值 + /// + /// 数据 + /// 默认值 + /// + public static decimal ToDecimal(object data, decimal defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToDecimal(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为Decimal 转换失败返回 默认值 + /// + /// 数据 + /// 默认值 + /// + public static decimal ToDecimal(string data, decimal defValue) + { + //如果为空则返回默认值 + if (string.IsNullOrEmpty(data)) + { + return defValue; + } + + if (decimal.TryParse(data, out decimal temp)) + { + return temp; + } + + return defValue; + } + + #endregion 将数据转换Decimal + + #region 将数据转换为DateTime + + /// + /// 将数据转换为DateTime 转换失败返回默认值 + /// + /// 数据类型 + /// 数据 + /// 默认值 + /// + public static DateTime ToDateTime(T data, DateTime defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToDateTime(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为DateTime 转换失败返回 默认值 + /// + /// 数据 + /// 默认值 + /// + public static DateTime ToDateTime(object data, DateTime defValue) + { + //如果为空则返回默认值 + if (data == null || Convert.IsDBNull(data)) + { + return defValue; + } + + try + { + return Convert.ToDateTime(data); + } + catch + { + return defValue; + } + } + + /// + /// 将数据转换为DateTime 转换失败返回 默认值 + /// + /// 数据 + /// 默认值 + /// + public static DateTime ToDateTime(string data, DateTime defValue) + { + //如果为空则返回默认值 + if (string.IsNullOrEmpty(data)) + { + return defValue; + } + + DateTime temp = DateTime.Now; + + if (DateTime.TryParse(data, out temp)) + { + return temp; + } + + return defValue; + } + + #endregion 将数据转换为DateTime + + #region 半角全角转换 + + /// + /// 转全角的函数(SBC case) + /// + /// 任意字符串 + /// 全角字符串 + /// + /// 全角空格为12288,半角空格为32 + /// 其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248 + /// + public static string ConvertToSBC(string input) + { + //半角转全角: + char[] c = input.ToCharArray(); + for (int i = 0; i < c.Length; i++) + { + if (c[i] == 32) + { + c[i] = (char)12288; + continue; + } + + if (c[i] < 127) + { + c[i] = (char)(c[i] + 65248); + } + } + + return new string(c); + } + + /// 转半角的函数(DBC case) + /// 任意字符串 + /// 半角字符串 + /// + /// 全角空格为12288,半角空格为32 + /// 其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248 + /// + public static string ConvertToDBC(string input) + { + char[] c = input.ToCharArray(); + for (int i = 0; i < c.Length; i++) + { + if (c[i] == 12288) + { + c[i] = (char)32; + continue; + } + + if (c[i] > 65280 && c[i] < 65375) + { + c[i] = (char)(c[i] - 65248); + } + } + + return new string(c); + } + + #endregion 半角全角转换 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/CookiesHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/CookiesHelper.cs new file mode 100644 index 0000000..68da683 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/CookiesHelper.cs @@ -0,0 +1,129 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Net; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// Cookie操作类 + /// + public static class CookiesHelper + { + /// + /// + public static HttpContext HttpHelper => HttpContextHelper.HttpContext; + + /// + /// Cookie名称 + /// + public static string CookieName { get; set; } = "Znyc_"; + + /// + /// 设置Cookie键 + /// + /// 键 + /// + private static string CookieKey(string cookieName) + { + return CookieName + cookieName; + } + + /// + /// 删除Cookie + /// + /// + /// Coookie名称 + public static void DeleteCookie(HttpContext context, string cookieName) + { + string key = CookieKey(cookieName); + context.Response.Cookies.Delete(key); + } + + /// + /// 写/保存Cookie + /// + /// + /// Coookie名称 + /// Coookie值 + /// 有效月数 + public static void WriteCookie(HttpContext context, string cookieName, string value, int months) + { + WriteCookie(context, cookieName, value, months, 0); + } + + /// + /// 写/保存Cookie + /// + /// Coookie名称 + /// Coookie值 + /// 有效月数 + public static void WriteCookie(string cookieName, string value, int months) + { + WriteCookie(HttpHelper, cookieName, value, months, 0); + } + + /// + /// 写/保存Cookie + /// + /// + /// Coookie名称 + /// Coookie值 + /// 有效月数 + /// 有效天数 + public static void WriteCookie(HttpContext context, string cookieName, string value, int months, int days) + { + string key = CookieKey(cookieName); + if (!context.Request.Cookies.ContainsKey(key)) + { + DateTime expires = DateTime.Today.AddDays(30 * months + days); + DateTimeOffset dateAndOffset = new DateTimeOffset(expires, + TimeZoneInfo.Local.GetUtcOffset(expires)); + + context.Response.Cookies.Append(key, value, + new CookieOptions + { + Expires = expires + }); + } + } + + /// + /// 获取Cookie值 + /// + /// + /// Coookie名称 + /// + public static string ReadCookie(HttpContext context, string cookieName) + { + string key = CookieKey(cookieName); + + try + { + return WebUtility.UrlDecode(context.Request.Cookies[key]); + } + catch + { + return ""; + } + } + + /// + /// 获取Cookie值 + /// + /// Coookie名称 + /// + public static string ReadCookie(string cookieName) + { + string key = CookieKey(cookieName); + + try + { + return WebUtility.UrlDecode(HttpHelper.Request.Cookies[key]); + } + catch + { + return ""; + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/DatetimeJsonConverter.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/DatetimeJsonConverter.cs new file mode 100644 index 0000000..6b13e15 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/DatetimeJsonConverter.cs @@ -0,0 +1,74 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 时间类型格式数据处理 + /// + public class DateTimeJsonConverter : JsonConverter + { + /// + /// 时间格式 + /// + private readonly string _dateFormatString; + + /// + /// + public DateTimeJsonConverter() + { + _dateFormatString = "yyyy-MM-dd HH:mm:ss"; + } + + /// + /// + /// 时间格式 + public DateTimeJsonConverter(string dateFormatString) + { + _dateFormatString = dateFormatString; + } + + /// + /// + /// + /// + /// + /// + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + if (DateTime.TryParse(reader.GetString(), out DateTime date)) + { + return date; + } + } + + return reader.GetDateTime(); + } + + /// + /// + /// + /// + /// + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); + } + } + + public class DateTimeNullableConverter : JsonConverter + { + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return string.IsNullOrEmpty(reader.GetString()) ? default(DateTime?) : DateTime.Parse(reader.GetString()); + } + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + { + writer.WriteStringValue(value?.ToString("yyyy-MM-dd HH:mm:ss")); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/DecimalJsonConverter.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/DecimalJsonConverter.cs new file mode 100644 index 0000000..3cc1ab3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/DecimalJsonConverter.cs @@ -0,0 +1,38 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Znyc.Cloudcar.Admin.Commons.Extensions; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + public class DecimalJsonConverter : JsonConverter + { + /// + /// + /// + /// + /// + /// + public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Number) + { + return reader.GetDecimal(); + } + + return reader.GetString().Equals("") + ? "0.00".ToDecimal() + : reader.GetString().ToDecimal(); + } + + /// + /// + /// + /// + /// + public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options) + { + writer.WriteNumberValue(value); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/EmojiFilterHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/EmojiFilterHelper.cs new file mode 100644 index 0000000..45a196a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/EmojiFilterHelper.cs @@ -0,0 +1,76 @@ +using System; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons +{ + /// + /// 过滤表情符号帮助类 + /// + public class EmojiFilterHelper + { + /// + /// 检测是否有emoji字符 + /// + /// + /// 一旦含有就抛出 + public static Boolean ContainsEmoji(string source) + { + char[] item = source.ToCharArray(); + for (int i = 0; i < source.Length; i++) + { + if (IsEmojiCharacter(item[i])) + return true; //do nothing,判断到了这里表明,确认有表情字符 + } + return false; + } + + private static Boolean IsEmojiCharacter(char codePoint) + { + return (codePoint == 0x0) || + (codePoint == 0x9) || + (codePoint == 0xA) || + (codePoint == 0xD) || + ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) || + ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) || + ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF)); + } + + /// + /// 过滤emoji 或者 其他非文字类型的字符 + /// + /// + /// + public static String FilterEmoji(string source) + { + if (!ContainsEmoji(source)) + return source;//如果不包含,直接返回 + //到这里铁定包含 + StringBuilder buf = null; + char[] item = source.ToCharArray(); + for (int i = 0; i < source.Length; i++) + { + char codePoint = item[i]; + if (IsEmojiCharacter(codePoint)) + { + if (buf == null) + buf = new StringBuilder(source.Length); + buf.Append(codePoint); + } + } + if (buf == null) + return source;//如果没有找到 emoji表情,则返回源字符串 + else + { + if (buf.Length == source.Length) + { + buf = null;//这里的意义在于尽可能少的toString,因为会重新生成字符串 + return source; + } + else + return buf.ToString(); + } + + } + + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/EntityMapper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/EntityMapper.cs new file mode 100644 index 0000000..8577d0a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/EntityMapper.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Reflection; +using System.Reflection.Emit; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 实体类映射,源自SqlSugar(http://www.codeisbug.com/Doc/3/1113) + /// + public static class EntityMapper + { + //用于构造Emit的DataRow中获取字段的方法信息 + private static readonly MethodInfo getValueMethod = + typeof(DataRow).GetMethod("get_Item", new[] { typeof(int) }); + + //用于构造Emit的DataRow中判断是否为空行的方法信息 + private static readonly MethodInfo isDBNullMethod = + typeof(DataRow).GetMethod("IsNull", new[] { typeof(int) }); + + private static readonly ConcurrentDictionary CachedMappers = + new(); + + public static IEnumerable ToList(this DbDataReader dr) + { + // If a mapping function from dr -> T does not exist, create and cache one + if (!CachedMappers.ContainsKey(typeof(T))) + { + // Our method will take in a single parameter, a DbDataReader + Type[] methodArgs = { typeof(DbDataReader) }; + + // The MapDR method will map a DbDataReader row to an instance of type T + DynamicMethod dm = new DynamicMethod("MapDR", typeof(T), methodArgs, + Assembly.GetExecutingAssembly().GetType().Module); + ILGenerator il = dm.GetILGenerator(); + + // We'll have a single local variable, the instance of T we're mapping + il.DeclareLocal(typeof(T)); + + // Create a new instance of T and save it as variable 0 + il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Stloc_0); + + foreach (PropertyInfo pi in typeof(T).GetProperties()) + { + // Load the T instance, SqlDataReader parameter and the field name onto the stack + il.Emit(OpCodes.Ldloc_0); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldstr, pi.Name); + + // Push the column value onto the stack + il.Emit(OpCodes.Callvirt, typeof(DbDataReader).GetMethod("get_Item", new[] { typeof(string) })); + + // Depending on the type of the property, convert the datareader column value to the type + switch (pi.PropertyType.Name) + { + case "Int16": + il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt16", new[] { typeof(object) })); + break; + + case "Int32": + il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new[] { typeof(object) })); + break; + + case "Int64": + il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt64", new[] { typeof(object) })); + break; + + case "Boolean": + il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToBoolean", new[] { typeof(object) })); + break; + + case "String": + il.Emit(OpCodes.Callvirt, typeof(string).GetMethod("ToString", new Type[] { })); + break; + + case "DateTime": + il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToDateTime", new[] { typeof(object) })); + break; + + case "Decimal": + il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToDecimal", new[] { typeof(object) })); + break; + + default: + // Don't set the field value as it's an unsupported type + continue; + } + + // Set the T instances property value + il.Emit(OpCodes.Callvirt, typeof(T).GetMethod("set_" + pi.Name, new[] { pi.PropertyType })); + } + + // Load the T instance onto the stack + il.Emit(OpCodes.Ldloc_0); + + // Return + il.Emit(OpCodes.Ret); + + // Cache the method so we won't have to create it again for the type T + CachedMappers.TryAdd(typeof(T), dm.CreateDelegate(typeof(MapEntity))); + } + + // Get a delegate reference to the dynamic method + MapEntity invokeMapEntity = (MapEntity)CachedMappers[typeof(T)]; + + // For each row, map the row to an instance of T and yield return it + while (dr.Read()) + { + yield return invokeMapEntity(dr); + } + } + + /// + /// 将DataTable转换成泛型对象列表 + /// + /// + /// + /// + public static List ToList(this DataTable dt) + { + List list = new List(); + if (dt == null) + { + return list; + } + + //声明 委托Load的一个实例rowMap + Load rowMap = null; + + //从rowMapMethods查找当前T类对应的转换方法,没有则使用Emit构造一个。 + if (!CachedMappers.ContainsKey(typeof(T))) + { + DynamicMethod method = new DynamicMethod("DynamicCreateEntity_" + typeof(T).Name, typeof(T), + new[] { typeof(DataRow) }, typeof(T), true); + ILGenerator generator = method.GetILGenerator(); + LocalBuilder result = generator.DeclareLocal(typeof(T)); + generator.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); + generator.Emit(OpCodes.Stloc, result); + + for (int index = 0; index < dt.Columns.Count; index++) + { + PropertyInfo propertyInfo = typeof(T).GetProperty(dt.Columns[index].ColumnName); + Label endIfLabel = generator.DefineLabel(); + if (propertyInfo != null && propertyInfo.GetSetMethod() != null) + { + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldc_I4, index); + generator.Emit(OpCodes.Callvirt, isDBNullMethod); + generator.Emit(OpCodes.Brtrue, endIfLabel); + generator.Emit(OpCodes.Ldloc, result); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldc_I4, index); + generator.Emit(OpCodes.Callvirt, getValueMethod); + generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); + generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod()); + generator.MarkLabel(endIfLabel); + } + } + + generator.Emit(OpCodes.Ldloc, result); + generator.Emit(OpCodes.Ret); + + //构造完成以后传给rowMap + rowMap = (Load)method.CreateDelegate(typeof(Load)); + } + else + { + rowMap = (Load)CachedMappers[typeof(T)]; + } + + //遍历Datatable的rows集合,调用rowMap把DataRow转换为对象(T) + foreach (DataRow info in dt.Rows) + { + list.Add(rowMap(info)); + } + + return list; + } + + public static void ClearCachedMapperMethods() + { + CachedMappers.Clear(); + } + + private delegate T MapEntity(DbDataReader dr); + + //把DataRow转换为对象的委托声明 + private delegate T Load(DataRow dataRecord); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/FileHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/FileHelper.cs new file mode 100644 index 0000000..aca87b5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/FileHelper.cs @@ -0,0 +1,250 @@ +using ICSharpCode.SharpZipLib.Checksum; +using ICSharpCode.SharpZipLib.Zip; +using System; +using System.IO; +using System.Text; +using Znyc.Cloudcar.Admin.Commons.Extend; +using Znyc.Cloudcar.Admin.Commons.Log; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 文件处理帮助类 + /// + public class FileHelper + { + /// + /// 制作压缩包(多个文件压缩到一个压缩包,支持加密、注释) + /// + /// 压缩文件目录 + /// 压缩包文件名 + /// 压缩级别 1-9 + /// 密码 + /// 注释 + /// 文件类型 + public static void ZipFiles(string topDirectoryName, string zipedFileName, int compresssionLevel, + string password, string comment, string filetype) + { + using (ZipOutputStream zos = new ZipOutputStream(File.Open(zipedFileName, FileMode.OpenOrCreate))) + { + if (compresssionLevel != 0) + { + zos.SetLevel(compresssionLevel); //设置压缩级别 + } + + if (!string.IsNullOrEmpty(password)) + { + zos.Password = password; //设置zip包加密密码 + } + + if (!string.IsNullOrEmpty(comment)) + { + zos.SetComment(comment); //设置zip包的注释 + } + //循环设置目录下所有的*.jpg文件(支持子目录搜索) + foreach (string file in Directory.GetFiles(topDirectoryName, filetype, SearchOption.AllDirectories)) + { + if (File.Exists(file)) + { + FileInfo item = new FileInfo(file); + FileStream fs = File.OpenRead(item.FullName); + byte[] buffer = new byte[fs.Length]; + fs.Read(buffer, 0, buffer.Length); + ZipEntry entry = new ZipEntry(item.Name); + zos.PutNextEntry(entry); + zos.Write(buffer, 0, buffer.Length); + fs.Close(); + } + } + + zos.Close(); + } + } + + /// + /// 压缩多层目录 + /// + /// 压缩文件目录 + /// 压缩包文件名 + /// 压缩级别 1-9 + /// 密码 + /// 注释 + /// 文件类型 + public static void ZipFileDirectory(string topDirectoryName, string zipedFileName, int compresssionLevel, + string password, string comment, string filetype) + { + using (FileStream ZipFile = File.Open(zipedFileName, FileMode.OpenOrCreate)) + { + using (ZipOutputStream zos = new ZipOutputStream(ZipFile)) + { + if (compresssionLevel != 0) + { + zos.SetLevel(compresssionLevel); //设置压缩级别 + } + + if (!string.IsNullOrEmpty(password)) + { + zos.Password = password; //设置zip包加密密码 + } + + if (!string.IsNullOrEmpty(comment)) + { + zos.SetComment(comment); //设置zip包的注释 + } + + ZipSetp(topDirectoryName, zos, "", filetype); + } + } + } + + /// + /// 递归遍历目录 + /// + /// The directory. + /// The ZipOutputStream Object. + /// The parent path. + private static void ZipSetp(string strDirectory, ZipOutputStream s, string parentPath, string filetype) + { + if (strDirectory[strDirectory.Length - 1] != Path.DirectorySeparatorChar) + { + strDirectory += Path.DirectorySeparatorChar; + } + + Crc32 crc = new Crc32(); + + string[] filenames = Directory.GetFileSystemEntries(strDirectory, filetype); + foreach (string file in filenames) // 遍历所有的文件和目录 + { + if (Directory.Exists(file)) // 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件 + { + string pPath = parentPath; + pPath += file.Substring(file.LastIndexOf("\\") + 1); + pPath += "\\"; + ZipSetp(file, s, pPath, filetype); + } + else // 否则直接压缩文件 + { + //打开压缩文件 + using (FileStream fs = File.OpenRead(file)) + { + byte[] buffer = new byte[fs.Length]; + fs.Read(buffer, 0, buffer.Length); + string fileName = parentPath + file.Substring(file.LastIndexOf("\\") + 1); + ZipEntry entry = new ZipEntry(fileName) + { + DateTime = DateTime.Now, + Size = fs.Length + }; + fs.Close(); + crc.Reset(); + crc.Update(buffer); + entry.Crc = crc.Value; + s.PutNextEntry(entry); + s.Write(buffer, 0, buffer.Length); + } + } + } + } + + /// + /// 读文件 + /// + /// + /// + public static string ReadFile(string path) + { + path = path.ToFilePath(); + if (!File.Exists(path)) + { + return ""; + } + + using (StreamReader stream = new StreamReader(path)) + { + return stream.ReadToEnd(); // 读取文件 + } + } + + /// + /// 写文件 + /// + /// 文件路径 + /// 文件名称 + /// 文件内容 + /// 是否追加到最后 + public static void WriteFile(string path, string fileName, string content, bool appendToLast = false) + { + if (!path.EndsWith("\\")) + { + path = path + "\\"; + } + + path = path.ToFilePath(); + if (!Directory.Exists(path)) //如果不存在就创建file文件夹 + { + Directory.CreateDirectory(path); + } + + using (FileStream stream = File.Open(path + fileName, FileMode.OpenOrCreate, FileAccess.Write)) + { + byte[] by = Encoding.Default.GetBytes(content); + if (appendToLast) + { + stream.Position = stream.Length; + } + else + { + stream.SetLength(0); + } + + stream.Write(by, 0, by.Length); + } + } + + #region 直接删除指定目录下的所有文件及文件夹(保留目录) + + /// + /// 删除指定目录下的所有文件及文件夹(保留目录) + /// + /// 文件目录 + public static void DeleteDirectory(string file) + { + try + { + //判断文件夹是否还存在 + if (Directory.Exists(file)) + { + DirectoryInfo fileInfo = new DirectoryInfo(file) + { + //去除文件夹的只读属性 + Attributes = FileAttributes.Normal & FileAttributes.Directory + }; + foreach (string f in Directory.GetFileSystemEntries(file)) + { + if (File.Exists(f)) + { + //去除文件的只读属性 + File.SetAttributes(file, FileAttributes.Normal); + //如果有子文件删除文件 + File.Delete(f); + } + else + { + //循环递归删除子文件夹 + DeleteDirectory(f); + } + } + + //删除空文件夹 + Directory.Delete(file); + } + } + catch (Exception ex) // 异常处理 + { + Log4NetHelper.Error("代码生成异常", ex); + } + } + + #endregion 直接删除指定目录下的所有文件及文件夹(保留目录) + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/FileQuartz.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/FileQuartz.cs new file mode 100644 index 0000000..a26078f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/FileQuartz.cs @@ -0,0 +1,133 @@ +using Quartz; +using System; +using System.IO; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Extend; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 定时任务日志文件 + /// + public class FileQuartz + { + private static string _rootPath { get; set; } + + private static string _logPath { get; set; } + + /// + /// 根目录 + /// + public static string RootPath => _rootPath; + + /// + /// 日志目录 + /// + public static string LogPath => _logPath; + + /// + /// 创建作业所在根目录及日志文件夹 + /// + /// + public static string CreateQuartzRootPath() + { + if (!string.IsNullOrEmpty(_rootPath)) + { + return _rootPath; + } + + _rootPath = AppDomain.CurrentDomain.BaseDirectory; + _rootPath = _rootPath.ReplacePath(); + if (!Directory.Exists(_rootPath)) + { + Directory.CreateDirectory(_rootPath); + } + + _rootPath = _rootPath + "Logs\\Quartz\\"; + _rootPath = _rootPath.ReplacePath(); + //生成日志文件夹 + if (!Directory.Exists(_rootPath)) + { + Directory.CreateDirectory(_rootPath); + } + + return _rootPath; + } + + /// + /// 初始化任务日志文件路径 + /// + /// 任务名称 + public static void InitTaskJobLogPath(string jobName) + { + if (string.IsNullOrEmpty(_logPath)) + { + CreateQuartzRootPath(); + } + + _logPath = _rootPath + jobName; + _logPath = _logPath.ReplacePath(); + //生成日志文件夹 + if (!Directory.Exists(_logPath)) + { + Directory.CreateDirectory(_logPath); + } + } + + /// + /// 任务启动日志 + /// + /// + public static void WriteStartLog(string content) + { + content = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "," + content; + if (!content.EndsWith("\r\n")) + { + content += "\r\n"; + } + + FileHelper.WriteFile(LogPath, "start.txt", content, true); + } + + /// + /// 任务操作日志 + /// + /// + /// + /// + /// + public static void WriteJobAction(JobAction jobAction, ITrigger trigger, string taskName, string groupName) + { + WriteJobAction(jobAction, taskName, groupName, trigger == null ? "未找到作业" : "OK"); + } + + /// + /// 任务操作日志 + /// + /// + /// + /// + /// + public static void WriteJobAction(JobAction jobAction, string taskName, string groupName, string content = null) + { + content = + $"{jobAction.ToString()} -- {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} --分组:{groupName},作业:{taskName},消息:{content ?? "OK"}\r\n"; + FileHelper.WriteFile(LogPath, "action.txt", content, true); + } + + /// + /// 任务错误日志 + /// + /// + public static void WriteErrorLog(string content) + { + content = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "," + content; + if (!content.EndsWith("\r\n")) + { + content += "\r\n"; + } + + FileHelper.WriteFile(LogPath, "Error.txt", content, true); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/GuidUtils.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/GuidUtils.cs new file mode 100644 index 0000000..b4b9c63 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/GuidUtils.cs @@ -0,0 +1,99 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// Guid工具类 + /// + public class GuidUtils + { + /// + /// 获取一个大写的字符串 + /// + /// + /// + private static string upper(string str) + { + return str.ToUpper(); + } + + /// + /// 获取32位不包含“-”号的GUID字符串 + /// + /// + public static string NewGuidFormatN(bool isUpper = false) + { + string guid = Guid.NewGuid().ToString("N"); + return isUpper ? upper(guid) : guid; + } + + /// + /// 获取32位包含“-”号的GUID字符串 + /// + /// + /// + public static string NewGuidFormatD(bool isUpper = false) + { + string guid = Guid.NewGuid().ToString("D"); + return isUpper ? upper(guid) : guid; + } + + /// + /// 获取32位包含“-”号的GUID被“(”、“)”包括的字符串 + /// + /// + /// + public static string NewGuidFormatP(bool isUpper = false) + { + string guid = Guid.NewGuid().ToString("P"); + return isUpper ? upper(guid) : guid; + } + + /// + /// 获取32位包含“-”号的GUID被“{”、“}”包括的字符串 + /// + /// + /// + public static string NewGuidFormatB(bool isUpper = false) + { + string guid = Guid.NewGuid().ToString("B"); + return isUpper ? upper(guid) : guid; + } + + /// + /// 获取4个被“{”、“}”包括的十六进制数,其中第四个值位8个被“{”、“}”包括的十六进制数字符串 + /// + /// + /// + public static string NewGuidFormatX(bool isUpper = false) + { + string guid = Guid.NewGuid().ToString("X"); + return isUpper ? upper(guid) : guid; + } + + #region 自动生成编号 + + /// + /// 表示全局唯一标识符 (GUID)。 + /// + /// + public static string GuId() + { + return Guid.NewGuid().ToString(); + } + + /// + /// 自动生成编号/唯一订单号生成,时间戳+随机数,时间戳精确到毫秒,形如2020052113254137177350 + /// + /// + public static string CreateNo() + { + Random random = new Random(); + string strRandom = random.Next(1000, 10000).ToString(); //生成随机编号 + string code = DateTime.Now.ToString("yyyyMMddHHmmssffff") + strRandom; //形如2020052113254137177350 + return code; + } + + #endregion 自动生成编号 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/HttpContextHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/HttpContextHelper.cs new file mode 100644 index 0000000..2314d99 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/HttpContextHelper.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Http; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// HttpContext帮助类 + /// + public static class HttpContextHelper + { + /// + /// + private static IHttpContextAccessor httpContextAccessor; + + /// + /// + public static HttpContext HttpContext => httpContextAccessor.HttpContext; + + /// + /// 注入 + /// + /// + public static void Configure(IHttpContextAccessor _httpContextAccessor) + { + httpContextAccessor = _httpContextAccessor; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/HttpRequestHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/HttpRequestHelper.cs new file mode 100644 index 0000000..fbe164e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/HttpRequestHelper.cs @@ -0,0 +1,220 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// http请求类 + /// + public static class HttpRequestHelper + { + /// + /// + /// + /// + public static void FillFormDataStream(this Dictionary formData, Stream stream) + { + string dataString = GetQueryString(formData); + byte[] formDataBytes = formData == null ? new byte[0] : Encoding.UTF8.GetBytes(dataString); + stream.Write(formDataBytes, 0, formDataBytes.Length); + stream.Seek(0, SeekOrigin.Begin); //设置指针读取位置 + } + + /// + /// 组装QueryString的方法 + /// 参数之间用&连接,首位没有符号,如:a=1&b=2&c=3 + /// + /// + /// + public static string GetQueryString(this Dictionary formData) + { + if (formData == null || formData.Count == 0) + { + return ""; + } + + StringBuilder sb = new StringBuilder(); + int i = 0; + foreach (KeyValuePair kv in formData) + { + i++; + sb.AppendFormat("{0}={1}", kv.Key, kv.Value); + if (i < formData.Count) + { + sb.Append("&"); + } + } + + return sb.ToString(); + } + + #region 同步方法 + + /// + /// 使用Get方法获取字符串结果 + /// + /// + /// + /// + /// + public static string HttpGet(string url, Encoding encoding = null, int timeOut = 60000) + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.Method = "GET"; + request.Timeout = timeOut; + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + using (Stream responseStream = response.GetResponseStream()) + { + using (StreamReader myStreamReader = new StreamReader(responseStream, encoding ?? Encoding.GetEncoding("utf-8"))) + { + string retString = myStreamReader.ReadToEnd(); + return retString; + } + } + } + + /// + /// 使用Post方法获取字符串结果,常规提交 + /// + /// + public static string HttpPost(string url, Dictionary formData = null, Encoding encoding = null, + int timeOut = 60000, Dictionary headers = null) + { + MemoryStream ms = new MemoryStream(); + formData.FillFormDataStream(ms); //填充formData + return HttpPost(url, ms, "application/x-www-form-urlencoded", encoding, headers, timeOut); + } + + /// + /// 发送HttpPost请求,使用JSON格式传输数据 + /// + /// + /// + /// + /// + /// + public static string HttpPost(string url, string postData, Encoding encoding = null, + Dictionary headers = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + + if (string.IsNullOrWhiteSpace(postData)) + { + throw new ArgumentNullException("postData"); + } + + byte[] data = encoding.GetBytes(postData); + MemoryStream stream = new MemoryStream(); + byte[] formDataBytes = postData == null ? new byte[0] : Encoding.UTF8.GetBytes(postData); + stream.Write(formDataBytes, 0, formDataBytes.Length); + stream.Seek(0, SeekOrigin.Begin); //设置指针读取位置 + return HttpPost(url, stream, "application/json", encoding, headers); + } + + /// + /// 使用POST请求数据,使用JSON传输数据 + /// + /// + /// 传输对象,转换为JSON传输 + /// + /// + public static string HttpPost(string url, object dataObj, Encoding encoding = null, + Dictionary headers = null) + { + if (encoding == null) + { + encoding = Encoding.UTF8; + } + + if (dataObj == null) + { + throw new ArgumentNullException("dataObj"); + } + + string postData = JsonConvert.SerializeObject(dataObj, + new JsonSerializerSettings { DateFormatString = "yyyy-MM-dd HH:mm:ss" }); + byte[] data = encoding.GetBytes(postData); + MemoryStream stream = new MemoryStream(); + byte[] formDataBytes = postData == null ? new byte[0] : Encoding.UTF8.GetBytes(postData); + stream.Write(formDataBytes, 0, formDataBytes.Length); + stream.Seek(0, SeekOrigin.Begin); //设置指针读取位置 + return HttpPost(url, stream, "application/json", encoding, headers); + } + + /// + /// 使用Post方法获取字符串结果 + /// + /// + /// + /// + /// + /// + /// + /// + public static string HttpPost(string url, Stream postStream = null, + string contentType = "application/x-www-form-urlencoded", Encoding encoding = null, + Dictionary headers = null, int timeOut = 60000) + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.Method = "POST"; + request.Timeout = timeOut; + + request.ContentLength = postStream != null ? postStream.Length : 0; + request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"; + request.KeepAlive = false; + + request.UserAgent = + "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.87 Safari/537.36 QQBrowser/9.2.5748.400"; + request.ContentType = contentType; + + if (headers != null) + { + foreach (KeyValuePair header in headers) + { + request.Headers.Add(header.Key, header.Value); + } + } + + #region 输入二进制流 + + if (postStream != null) + { + postStream.Position = 0; + + //直接写入流 + Stream requestStream = request.GetRequestStream(); + + byte[] buffer = new byte[1024]; + int bytesRead = 0; + while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0) + { + requestStream.Write(buffer, 0, bytesRead); + } + + postStream.Close(); //关闭文件访问 + } + + #endregion 输入二进制流 + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + + using (Stream responseStream = response.GetResponseStream()) + { + using (StreamReader myStreamReader = new StreamReader(responseStream, encoding ?? Encoding.GetEncoding("utf-8"))) + { + string retString = myStreamReader.ReadToEnd(); + return retString; + } + } + } + + #endregion 同步方法 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/ImgHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/ImgHelper.cs new file mode 100644 index 0000000..504ca30 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/ImgHelper.cs @@ -0,0 +1,158 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Net; +using Znyc.Cloudcar.Admin.Commons.Log; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 图片处理 + /// + public class ImgHelper + { + /// + /// 生成缩略图 + /// + /// 源文件 + /// 缩略图 + /// 宽 + /// 高 + /// + public static void MakeThumbnail(string originalImagePath, + string thumbnailPath, + int width = 120, int height = 90, string mode = "H") + { + Image image = Image.FromFile(originalImagePath); + if (image.Width <= width && image.Height <= height) + { + File.Copy(originalImagePath, thumbnailPath, true); + image.Dispose(); + } + else + { + int width2 = image.Width; + int height2 = image.Height; + float num = height / (float)height2; + if (width / (float)width2 < num) + { + num = width / (float)width2; + } + + width = (int)(width2 * num); + height = (int)(height2 * num); + Image image2 = new Bitmap(width, height); + Graphics graphics = Graphics.FromImage(image2); + graphics.Clear(Color.White); + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.DrawImage(image, new Rectangle(0, 0, width, height), new Rectangle(0, 0, width2, height2), + GraphicsUnit.Pixel); + EncoderParameters encoderParameters = new EncoderParameters(); + EncoderParameter encoderParameter = new EncoderParameter(Encoder.Quality, 100L); + encoderParameters.Param[0] = encoderParameter; + ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders(); + ImageCodecInfo encoder = null; + int num2 = 0; + while (num2 < imageEncoders.Length) + { + if (!imageEncoders[num2].FormatDescription.Equals("JPEG")) + { + num2++; + continue; + } + + encoder = imageEncoders[num2]; + break; + } + + image2.Save(thumbnailPath, encoder, encoderParameters); + encoderParameters.Dispose(); + encoderParameter.Dispose(); + image.Dispose(); + image2.Dispose(); + graphics.Dispose(); + } + } + + /// + /// 获取网络图片 + /// + /// + /// + public static Bitmap GetNetImg(string imgUrl) + { + try + { + Random random = new Random(); + imgUrl = !imgUrl.Contains("?") + ? imgUrl + "?aid=" + random.NextDouble() + : imgUrl + "&aid=" + random.NextDouble(); + WebRequest webRequest = WebRequest.Create(imgUrl); + WebResponse response = webRequest.GetResponse(); + Stream responseStream = response.GetResponseStream(); + Image image = Image.FromStream(responseStream); + responseStream.Close(); + responseStream.Dispose(); + webRequest = null; + response = null; + return (Bitmap)image; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取网络图片错误", ex); + return new Bitmap(100, 100); + } + } + + /// + /// 将图片裁剪成圆形 + /// + /// + /// + /// + /// + /// + public static Image CutEllipse(Image img, Rectangle rec, Size size, string imgSavePath) + { + Bitmap bitmap = new Bitmap(size.Width, size.Height); + using (Graphics g = Graphics.FromImage(bitmap)) + { + using (TextureBrush br = new TextureBrush(img, WrapMode.Clamp, rec)) + { + br.ScaleTransform(bitmap.Width / (float)rec.Width, bitmap.Height / (float)rec.Height); + g.SmoothingMode = SmoothingMode.AntiAlias; + g.FillEllipse(br, new Rectangle(Point.Empty, size)); + } + } + + bitmap.Save(imgSavePath, ImageFormat.Png); + return bitmap; + } + + /// + /// 将图片裁剪成圆形 + /// + /// + /// + /// + /// + public static Bitmap CutEllipse(Image img, Rectangle rec, Size size) + { + Bitmap bitmap = new Bitmap(size.Width, size.Height); + using (Graphics g = Graphics.FromImage(bitmap)) + { + using (TextureBrush br = new TextureBrush(img, WrapMode.Clamp, rec)) + { + br.ScaleTransform(bitmap.Width / (float)rec.Width, bitmap.Height / (float)rec.Height); + g.SmoothingMode = SmoothingMode.AntiAlias; + g.FillEllipse(br, new Rectangle(Point.Empty, size)); + } + } + + return bitmap; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/IntJsonConverter.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/IntJsonConverter.cs new file mode 100644 index 0000000..a6ae45e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/IntJsonConverter.cs @@ -0,0 +1,38 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Znyc.Cloudcar.Admin.Commons.Extensions; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// + public class IntJsonConverter : JsonConverter + { + /// + /// + /// + /// + /// + /// + public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Number) + { + return reader.GetInt32(); + } + + return reader.GetString().ToInt(); + } + + /// + /// + /// + /// + /// + public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) + { + writer.WriteNumberValue(value); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/NPOIHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/NPOIHelper.cs new file mode 100644 index 0000000..2d01456 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/NPOIHelper.cs @@ -0,0 +1,628 @@ +using NPOI.HPSF; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NPOI.SS.Util; +using NPOI.XSSF.UserModel; +using System; +using System.Data; +using System.IO; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// office 导入导出 + /// + public class NPOIHelper + { + /// + /// DataTable 导出到 Excel 的 MemoryStream + /// + /// 源 DataTable + /// 表头文本 空值未不要表头标题 + /// + public static MemoryStream ExportExcel(DataTable dtSource, string strHeaderText) + { + HSSFWorkbook workbook = new HSSFWorkbook(); + ISheet sheet = workbook.CreateSheet(); + + #region 文件属性 + + DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation(); + dsi.Company = "Znyc.Cloudcar.Admin.com"; + workbook.DocumentSummaryInformation = dsi; + SummaryInformation si = PropertySetFactory.CreateSummaryInformation(); + si.Author = "Znyc.Cloudcar.Admin.com"; + si.ApplicationName = "Znyc.Cloudcar.Admin.com"; + si.LastAuthor = "Znyc.Cloudcar.Admin.com"; + si.Comments = ""; + si.Title = ""; + si.Subject = ""; + si.CreateDateTime = DateTime.Now; + workbook.SummaryInformation = si; + + #endregion 文件属性 + + ICellStyle dateStyle = workbook.CreateCellStyle(); + IDataFormat format = workbook.CreateDataFormat(); + dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd"); + int[] arrColWidth = new int[dtSource.Columns.Count]; + foreach (DataColumn item in dtSource.Columns) + { + arrColWidth[item.Ordinal] = Encoding.GetEncoding("gb2312").GetBytes(item.ColumnName).Length; + } + + for (int i = 0; i < dtSource.Rows.Count; i++) + { + for (int j = 0; j < dtSource.Columns.Count; j++) + { + int intTemp = Encoding.GetEncoding("gb2312").GetBytes(dtSource.Rows[i][j].ToString()).Length; + if (intTemp > arrColWidth[j]) + { + arrColWidth[j] = intTemp; + } + } + } + + int rowIndex = 0; + int intTop = 0; + foreach (DataRow row in dtSource.Rows) + { + #region 新建表、填充表头、填充列头,样式 + + if (rowIndex == 65535 || rowIndex == 0) + { + if (rowIndex != 0) + { + sheet = workbook.CreateSheet(); + } + + intTop = 0; + + #region 表头及样式 + + { + if (strHeaderText.Length > 0) + { + IRow headerRow = sheet.CreateRow(intTop); + intTop += 1; + headerRow.HeightInPoints = 25; + headerRow.CreateCell(0).SetCellValue(strHeaderText); + ICellStyle headStyle = workbook.CreateCellStyle(); + headStyle.Alignment = HorizontalAlignment.Center; + IFont font = workbook.CreateFont(); + font.FontHeightInPoints = 20; + font.Boldweight = 700; + headStyle.SetFont(font); + headerRow.GetCell(0).CellStyle = headStyle; + sheet.AddMergedRegion( + new CellRangeAddress(0, 0, 0, dtSource.Columns.Count - 1)); + } + } + + #endregion 表头及样式 + + #region 列头及样式 + + { + IRow headerRow = sheet.CreateRow(intTop); + intTop += 1; + ICellStyle headStyle = workbook.CreateCellStyle(); + headStyle.Alignment = HorizontalAlignment.Center; + IFont font = workbook.CreateFont(); + font.Boldweight = 700; + headStyle.SetFont(font); + foreach (DataColumn column in dtSource.Columns) + { + headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName); + headerRow.GetCell(column.Ordinal).CellStyle = headStyle; + //设置列宽 + sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256); + } + } + + #endregion 列头及样式 + + rowIndex = intTop; + } + + #endregion 新建表、填充表头、填充列头,样式 + + #region 填充内容 + + IRow dataRow = sheet.CreateRow(rowIndex); + foreach (DataColumn column in dtSource.Columns) + { + ICell newCell = dataRow.CreateCell(column.Ordinal); + string drValue = row[column].ToString(); + switch (column.DataType.ToString()) + { + case "System.String": //字符串类型 + newCell.SetCellValue(drValue); + break; + + case "System.DateTime": //日期类型 + DateTime dateV; + DateTime.TryParse(drValue, out dateV); + newCell.SetCellValue(dateV); + newCell.CellStyle = dateStyle; //格式化显示 + break; + + case "System.Boolean": //布尔型 + bool boolV = false; + bool.TryParse(drValue, out boolV); + newCell.SetCellValue(boolV); + break; + + case "System.Int16": + case "System.Int32": + case "System.Int64": + case "System.Byte": + int intV = 0; + int.TryParse(drValue, out intV); + newCell.SetCellValue(intV); + break; + + case "System.Decimal": + case "System.Double": + double doubV = 0; + double.TryParse(drValue, out doubV); + newCell.SetCellValue(doubV); + break; + + case "System.DBNull": //空值处理 + newCell.SetCellValue(""); + break; + + default: + newCell.SetCellValue(""); + break; + } + } + + #endregion 填充内容 + + rowIndex++; + } + + using (MemoryStream ms = new MemoryStream()) + { + workbook.Write(ms); + ms.Flush(); + ms.Position = 0; + return ms; + } + } + + /// + /// DaataTable 导出到 Excel 文件 + /// + /// 源 DataaTable + /// 表头文本 + /// 保存位置(文件名及路径) + public static void ExportExcel(DataTable dtSource, string strHeaderText, string strFileName) + { + using (MemoryStream ms = ExportExcel(dtSource, strHeaderText)) + { + using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write)) + { + byte[] data = ms.ToArray(); + fs.Write(data, 0, data.Length); + fs.Flush(); + } + } + } + + /// + /// 读取 excel + /// 默认第一行为标头 + /// + /// excel 文档路径 + /// + public static DataTable ImportExcel(string strFileName) + { + DataTable dt = new DataTable(); + HSSFWorkbook hssfworkbook; + using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read)) + { + hssfworkbook = new HSSFWorkbook(file); + } + + ISheet sheet = hssfworkbook.GetSheetAt(0); + System.Collections.IEnumerator rows = sheet.GetRowEnumerator(); + IRow headerRow = sheet.GetRow(0); + int cellCount = headerRow.LastCellNum; + for (int j = 0; j < cellCount; j++) + { + ICell cell = headerRow.GetCell(j); + dt.Columns.Add(cell.ToString()); + } + + for (int i = sheet.FirstRowNum + 1; i <= sheet.LastRowNum; i++) + { + IRow row = sheet.GetRow(i); + if (row.GetCell(row.FirstCellNum) != null && row.GetCell(row.FirstCellNum).ToString().Length > 0) + { + DataRow dataRow = dt.NewRow(); + for (int j = row.FirstCellNum; j < cellCount; j++) + { + if (row.GetCell(j) != null) + { + dataRow[j] = row.GetCell(j).ToString(); + } + } + + dt.Rows.Add(dataRow); + } + } + + return dt; + } + + /// + /// DataSet 导出到 Excel 的 MemoryStream + /// + /// 源 DataSet + /// 表头文本 空值未不要表头标题(多个表对应多个表头以英文逗号(,)分开,个数应与表相同) + /// + public static MemoryStream ExportExcel(DataSet dsSource, string strHeaderText) + { + HSSFWorkbook workbook = new HSSFWorkbook(); + + #region 文件属性 + + DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation(); + dsi.Company = "Znyc.Cloudcar.Admin.com"; + workbook.DocumentSummaryInformation = dsi; + SummaryInformation si = PropertySetFactory.CreateSummaryInformation(); + si.Author = "Znyc.Cloudcar.Admin.com"; + si.ApplicationName = "Znyc.Cloudcar.Admin.com"; + si.LastAuthor = "Znyc.Cloudcar.Admin.com"; + si.Comments = ""; + si.Title = ""; + si.Subject = ""; + si.CreateDateTime = DateTime.Now; + workbook.SummaryInformation = si; + + #endregion 文件属性 + + #region 注释 + + //ICellStyle dateStyle = workbook.CreateCellStyle(); + //IDataFormat format = workbook.CreateDataFormat(); + //dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd"); + + //ISheet sheet = workbook.CreateSheet(); + //int[] arrColWidth = new int[dtSource.Columns.Count]; + //foreach (DataColumn item in dtSource.Columns) + //{ + // arrColWidth[item.Ordinal] = Encoding.GetEncoding("gb2312").GetBytes(item.ColumnName.ToString()).Length; + //} + //for (int i = 0; i < dtSource.Rows.Count; i++) + //{ + // for (int j = 0; j < dtSource.Columns.Count; j++) + // { + // int intTemp = Encoding.GetEncoding("gb2312").GetBytes(dtSource.Rows[i][j].ToString()).Length; + // if (intTemp > arrColWidth[j]) + // { + // arrColWidth[j] = intTemp; + // } + // } + //} + //int rowIndex = 0; + //int intTop = 0; + //foreach (DataRow row in dtSource.Rows) + //{ + // #region 新建表、填充表头、填充列头,样式 + // if (rowIndex == 65535 || rowIndex == 0) + // { + // if (rowIndex != 0) + // { + // sheet = workbook.CreateSheet(); + // } + // intTop = 0; + // #region 表头及样式 + // { + // if (strHeaderText.Length > 0) + // { + // IRow headerRow = sheet.CreateRow(intTop); + // intTop += 1; + // headerRow.HeightInPoints = 25; + // headerRow.CreateCell(0).SetCellValue(strHeaderText); + // ICellStyle headStyle = workbook.CreateCellStyle(); + // headStyle.Alignment = HorizontalAlignment.CENTER; + // IFont font = workbook.CreateFont(); + // font.FontHeightInPoints = 20; + // font.Boldweight = 700; + // headStyle.SetFont(font); + // headerRow.GetCell(0).CellStyle = headStyle; + // sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, dtSource.Columns.Count - 1)); + + // } + // } + // #endregion + // #region 列头及样式 + // { + // IRow headerRow = sheet.CreateRow(intTop); + // intTop += 1; + // ICellStyle headStyle = workbook.CreateCellStyle(); + // headStyle.Alignment = HorizontalAlignment.CENTER; + // IFont font = workbook.CreateFont(); + // font.Boldweight = 700; + // headStyle.SetFont(font); + // foreach (DataColumn column in dtSource.Columns) + // { + // headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName); + // headerRow.GetCell(column.Ordinal).CellStyle = headStyle; + // //设置列宽 + // sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256); + // } + + // } + // #endregion + // rowIndex = intTop; + // } + // #endregion + // #region 填充内容 + // IRow dataRow = sheet.CreateRow(rowIndex); + // foreach (DataColumn column in dtSource.Columns) + // { + // ICell newCell = dataRow.CreateCell(column.Ordinal); + // string drValue = row[column].ToString(); + // switch (column.DataType.ToString()) + // { + // case "System.String"://字符串类型 + // newCell.SetCellValue(drValue); + // break; + // case "System.DateTime"://日期类型 + // DateTime dateV; + // DateTime.TryParse(drValue, out dateV); + // newCell.SetCellValue(dateV); + // newCell.CellStyle = dateStyle;//格式化显示 + // break; + // case "System.Boolean"://布尔型 + // bool boolV = false; + // bool.TryParse(drValue, out boolV); + // newCell.SetCellValue(boolV); + // break; + // case "System.Int16": + // case "System.Int32": + // case "System.Int64": + // case "System.Byte": + // int intV = 0; + // int.TryParse(drValue, out intV); + // newCell.SetCellValue(intV); + // break; + // case "System.Decimal": + // case "System.Double": + // double doubV = 0; + // double.TryParse(drValue, out doubV); + // newCell.SetCellValue(doubV); + // break; + // case "System.DBNull"://空值处理 + // newCell.SetCellValue(""); + // break; + // default: + // newCell.SetCellValue(""); + // break; + // } + // } + // #endregion + // rowIndex++; + //} + + #endregion 注释 + + string[] strNewText = strHeaderText.Split(Convert.ToChar(",")); + if (dsSource.Tables.Count == strNewText.Length) + { + for (int i = 0; i < dsSource.Tables.Count; i++) + { + ExportFromDSExcel(workbook, dsSource.Tables[i], strNewText[i]); + } + } + + using (MemoryStream ms = new MemoryStream()) + { + workbook.Write(ms); + ms.Flush(); + ms.Position = 0; + return ms; + } + } + + /// + /// DataTable 导出到 Excel 的 MemoryStream + /// + /// 源 workbook + /// 源 DataTable + /// 表头文本 空值未不要表头标题(多个表对应多个表头以英文逗号(,)分开,个数应与表相同) + /// + public static void ExportFromDSExcel(HSSFWorkbook workbook, DataTable dtSource, string strHeaderText) + { + ICellStyle dateStyle = workbook.CreateCellStyle(); + IDataFormat format = workbook.CreateDataFormat(); + dateStyle.DataFormat = format.GetFormat("yyyy-MM-dd HH:mm:ss"); + ISheet sheet = workbook.CreateSheet(strHeaderText); + + int[] arrColWidth = new int[dtSource.Columns.Count]; + foreach (DataColumn item in dtSource.Columns) + { + arrColWidth[item.Ordinal] = Encoding.GetEncoding("gb2312").GetBytes(item.ColumnName).Length; + } + + for (int i = 0; i < dtSource.Rows.Count; i++) + { + for (int j = 0; j < dtSource.Columns.Count; j++) + { + int intTemp = Encoding.GetEncoding("gb2312").GetBytes(dtSource.Rows[i][j].ToString()).Length; + if (intTemp > arrColWidth[j]) + { + arrColWidth[j] = intTemp; + } + } + } + + int rowIndex = 0; + int intTop = 0; + foreach (DataRow row in dtSource.Rows) + { + #region 新建表、填充表头、填充列头,样式 + + if (rowIndex == 65535 || rowIndex == 0) + { + if (rowIndex != 0) + { + sheet = workbook.CreateSheet(); + } + + intTop = 0; + + #region 表头及样式 + + { + if (strHeaderText.Length > 0) + { + IRow headerRow = sheet.CreateRow(intTop); + intTop += 1; + headerRow.HeightInPoints = 25; + headerRow.CreateCell(0).SetCellValue(strHeaderText); + ICellStyle headStyle = workbook.CreateCellStyle(); + headStyle.Alignment = HorizontalAlignment.Center; + IFont font = workbook.CreateFont(); + font.FontHeightInPoints = 20; + font.Boldweight = 700; + headStyle.SetFont(font); + headerRow.GetCell(0).CellStyle = headStyle; + sheet.AddMergedRegion( + new CellRangeAddress(0, 0, 0, dtSource.Columns.Count - 1)); + } + } + + #endregion 表头及样式 + + #region 列头及样式 + + { + IRow headerRow = sheet.CreateRow(intTop); + intTop += 1; + ICellStyle headStyle = workbook.CreateCellStyle(); + headStyle.Alignment = HorizontalAlignment.Center; + IFont font = workbook.CreateFont(); + font.Boldweight = 700; + headStyle.SetFont(font); + foreach (DataColumn column in dtSource.Columns) + { + headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName); + headerRow.GetCell(column.Ordinal).CellStyle = headStyle; + //设置列宽 + // sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal] + 1) * 256); // 设置设置列宽 太长会报错 修改2014 年9月22日 + int dd = (arrColWidth[column.Ordinal] + 1) * 256; + + if (dd > 200 * 256) + { + dd = 100 * 256; + } + + sheet.SetColumnWidth(column.Ordinal, dd); + } + } + + #endregion 列头及样式 + + rowIndex = intTop; + } + + #endregion 新建表、填充表头、填充列头,样式 + + #region 填充内容 + + IRow dataRow = sheet.CreateRow(rowIndex); + foreach (DataColumn column in dtSource.Columns) + { + ICell newCell = dataRow.CreateCell(column.Ordinal); + string drValue = row[column].ToString(); + switch (column.DataType.ToString()) + { + case "System.String": //字符串类型 + newCell.SetCellValue(drValue); + break; + + case "System.DateTime": //日期类型 + if (drValue.Length > 0) + { + DateTime.TryParse(drValue, out DateTime dateV); + newCell.SetCellValue(dateV); + newCell.CellStyle = dateStyle; //格式化显示 + } + else + { + newCell.SetCellValue(drValue); + } + + break; + + case "System.Boolean": //布尔型 + bool boolV = false; + bool.TryParse(drValue, out boolV); + newCell.SetCellValue(boolV); + break; + + case "System.Int16": + case "System.Int32": + case "System.Int64": + case "System.Byte": + int intV = 0; + int.TryParse(drValue, out intV); + newCell.SetCellValue(intV); + break; + + case "System.Decimal": + case "System.Double": + double doubV = 0; + double.TryParse(drValue, out doubV); + newCell.SetCellValue(doubV); + break; + + case "System.DBNull": //空值处理 + newCell.SetCellValue(""); + break; + + default: + newCell.SetCellValue(""); + break; + } + } + + #endregion 填充内容 + + rowIndex++; + } + } + + /// + /// 按指定长度创建列并带入样式 + /// + /// + /// + /// + /// + public static bool CreateCellsWithLength(XSSFRow hssfrow, int len, XSSFCellStyle cellstyle) + { + try + { + for (int i = 0; i < len; i++) + { + hssfrow.CreateCell(i); + hssfrow.Cells[i].CellStyle = cellstyle; + } + + return true; + } + catch (Exception ce) + { + throw new Exception("CreateCellsWithLength:" + ce.Message); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/ObjectReplaceHtmlHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/ObjectReplaceHtmlHelper.cs new file mode 100644 index 0000000..3b4836d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/ObjectReplaceHtmlHelper.cs @@ -0,0 +1,61 @@ +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 用对象属性及属性值替换预设字符串 + /// 主要应用于模板打印,导出 + /// + public class ObjectReplaceHtmlHelper + { + /// + /// 用实体属性替换相关的字符串,主要应用于打印和导出 + /// 方法将日期时间型属性值截取为日期型,格式“YYYY-MM-DD”, + /// 将布尔型属性值调整为是或否 + /// + /// 实体对象 + /// 要替换的原字符串 + /// 变量前缀 + /// + public static string ObjectReplaceString(object objInfo, string strReplace, string prefix = "") + { + string result = string.Empty; + string nowReplace = strReplace; + System.Type type = objInfo.GetType(); //获得该类的Type + foreach (System.Reflection.PropertyInfo pi in type.GetProperties()) + { + string name = pi.Name; //获得属性的名字,后面就可以根据名字判断来进行些自己想要的操作 + object value = pi.GetValue(objInfo, null); //用pi.GetValue获得值 + System.Type propertyType = value?.GetType() ?? typeof(object); //获得属性的类型 + string replaceOld = "$" + prefix + name; + string newStrValue = ""; + if (value != null) + { + //将日期时间型和布尔型数据进行处理,其他枚举数据提前处理 + if (propertyType.Name == "DateTime") //如果是时间型取日期 + { + newStrValue = value.ToString().Substring(0, 10); + } + else if (propertyType.Name == "Boolean") //布尔型转为是或否 + { + if (bool.TryParse(value.ToString(), out bool blvalue)) + { + newStrValue = "是"; + } + else + { + newStrValue = "否"; + } + } + else + { + newStrValue = value.ToString(); + } + } + + nowReplace = nowReplace.Replace(replaceOld, newStrValue); + } + + result += nowReplace; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/RuntimeHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/RuntimeHelper.cs new file mode 100644 index 0000000..00dc757 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/RuntimeHelper.cs @@ -0,0 +1,137 @@ +using Microsoft.Extensions.DependencyModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using Znyc.Cloudcar.Admin.Commons.Options; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// + public class RuntimeHelper + { + /// + /// 获取项目程序集,排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包 + /// + /// + public static IList GetAllAssemblies() + { + List list = new List(); + DependencyContext deps = DependencyContext.Default; + //排除所有的系统程序集、Nuget下载包 + IEnumerable libs = deps.CompileLibraries.Where(lib => lib.Type == AssembleTypeConsts.Project); //只获取本项目用到的包 + foreach (CompilationLibrary lib in libs) + { + try + { + Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name)); + list.Add(assembly); + } + catch (Exception) + { + // ignored + } + } + + return list; + } + + /// + /// 获取项目程序集,排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包和Znyc.Cloudcar.Admin.Commons.dll + /// 获取所有关于Znyc的程序集 + /// + /// + public static IList GetAllZnycAssemblies() + { + List list = new List(); + DependencyContext deps = DependencyContext.Default; + //排除所有的系统程序集、Nuget下载包 + IEnumerable libs = deps.CompileLibraries.Where(lib => + lib.Type == AssembleTypeConsts.Project || lib.Name.StartsWith("Znyc")); //只获取本项目用到的包 + foreach (CompilationLibrary lib in libs) + { + try + { + if (lib.Name != "Znyc.Cloudcar.Admin.Commons") + { + Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name)); + list.Add(assembly); + } + } + catch (Exception) + { + // ignored + } + } + + return list; + } + + /// + /// + /// + /// + public static Assembly GetAssembly(string assemblyName) + { + return GetAllZnycAssemblies().FirstOrDefault(assembly => assembly.FullName.Contains(assemblyName)); + } + + /// + /// + /// + public static IList GetAllTypes() + { + List list = new List(); + foreach (Assembly assembly in GetAllAssemblies()) + { + IEnumerable typeInfos = assembly.DefinedTypes; + foreach (TypeInfo typeInfo in typeInfos) + { + list.Add(typeInfo.AsType()); + } + } + + return list; + } + + /// + /// + /// + /// + public static IList GetTypesByAssembly(string assemblyName) + { + List list = new List(); + Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName)); + IEnumerable typeInfos = assembly.DefinedTypes; + foreach (TypeInfo typeInfo in typeInfos) + { + list.Add(typeInfo.AsType()); + } + + return list; + } + + /// + /// 获取实现类 + /// + /// + /// + /// + public static Type GetImplementType(string typeName, Type baseInterfaceType) + { + return GetAllTypes().FirstOrDefault(t => + { + if (t.Name == typeName && + t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name)) + { + TypeInfo typeInfo = t.GetTypeInfo(); + return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType; + } + + return false; + }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/SessionHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/SessionHelper.cs new file mode 100644 index 0000000..496063b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/SessionHelper.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Http; +using Znyc.Cloudcar.Admin.Commons.Extensions; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// Session帮助类,可在非controler中读取或保存session + /// + public static class SessionHelper + { + /// + /// + public static HttpContext HttpHelper => HttpContextHelper.HttpContext; + + /// + /// 设置 Session + /// + /// + /// + public static void SetSession(string key, object value) + { + HttpHelper.Session.Set(key, value); + } + + /// + /// 获取 Session + /// + /// + /// + /// + public static T GetSession(string key) + { + return HttpHelper.Session.Get(key); + } + + /// + /// 获取 Session + /// + /// + /// + public static string GetString(string key) + { + return HttpHelper.Session.GetString(key); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/SignHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/SignHelper.cs new file mode 100644 index 0000000..0a8c29b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/SignHelper.cs @@ -0,0 +1,193 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Encrypt; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Options; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 签名验证自定义类 + /// + public class SignHelper + { + /// + /// 全局过滤器验证签名 + /// + /// + /// + public static CommonResult CheckSign(HttpContext httpContext) + { + CommonResult result = new CommonResult(); + //从http请求的头里面获取参数 + HttpRequest request = httpContext.Request; + string appId = ""; //客户端应用唯一标识 + string nonce = ""; //随机字符串 + string signature = ""; //参数签名,去除空参数,按字母倒序排序进行Md5签名 为了提高传参过程中,防止参数被恶意修改,在请求接口的时候加上sign可以有效防止参数被篡改 + long timeStamp; //时间戳, 校验5分钟内有效 + try + { + appId = request.Headers["appId"].SingleOrDefault(); + nonce = request.Headers["nonce"].SingleOrDefault(); + timeStamp = Convert.ToInt64(request.Headers["timeStamp"].SingleOrDefault()); + signature = request.Headers["signature"].SingleOrDefault(); + } + catch (Exception ex) + { + result.ErrCode = "40004"; + result.ErrMsg = "签名参数异常:" + ex.Message; + return result; + } + + //appId是否为可用的AllowCacheApp allowCacheApp = VerifyAppId(appId); + //if (allowCacheApp == null) + //{ + // result.ErrCode = "40004"; + // result.ErrMsg = "AppId不被允许访问:" + appId; + // return result; + //} + + //判断timespan是否有效,请求是否超时 + DateTime tonow = timeStamp.UnixTimeToDateTime(); + int expires_minute = tonow.Minute - DateTime.Now.Minute; + if (expires_minute > 5 || expires_minute < -5) + { + result.ErrCode = "40004"; + result.ErrMsg = "接口请求超时"; + return result; + } + + //根据请求类型拼接参数 + NameValueCollection form = HttpUtility.ParseQueryString(request.QueryString.ToString()); + string data = string.Empty; + if (form.Count > 0) + { + data = GetQueryString(form); + } + else + { + //request.EnableBuffering(); + request.Body.Seek(0, SeekOrigin.Begin); + Stream stream = request.Body; + StreamReader streamReader = new StreamReader(stream); + data = streamReader.ReadToEndAsync().Result; + request.Body.Seek(0, SeekOrigin.Begin); + } + + CacheHelper cacheHelper = new CacheHelper(); + object reqtimeStampCache = cacheHelper.Get("request_" + timeStamp + nonce); + if (reqtimeStampCache != null) + { + result.ErrCode = "40004"; + result.ErrMsg = "无效签名"; + return result; + } + + TimeSpan expiresSliding = DateTime.Now.AddMinutes(120) - DateTime.Now; + cacheHelper.Add("request_" + timeStamp + nonce, timeStamp + nonce, expiresSliding); + //bool blValidate = Validate(timeStamp.ToString(), nonce, allowCacheApp.AppSecret, data, signature); + //if (!blValidate) + //{ + // result.ErrCode = "40004"; + // result.ErrMsg = "无效签名"; + // return result; + //} + //else + //{ + result.ErrCode = "0"; + result.Success = true; + return result; + //} + } + + /// + /// get请求查询参数, url上直接接参数时,通过此方法获取 + /// + /// 请求参数 + /// + public static string GetQueryString(NameValueCollection form) + { + //第一步:取出所有get参数 + Dictionary parames = new Dictionary(); + for (int f = 0; f < form.Count; f++) + { + string key = form.Keys[f]; + if (key != null) + { + parames.Add(key, form[key]); + } + } + + // 第二步:把字典按Key的字母顺序排序 + IDictionary sortedParams = new SortedDictionary(parames); + IEnumerator> dem = sortedParams.GetEnumerator(); + + // 第三步:把所有参数名和参数值串在一起 + StringBuilder query = new StringBuilder(""); //签名字符串 + if (parames == null || parames.Count == 0) + { + return query.ToString(); + } + + while (dem.MoveNext()) + { + string key = dem.Current.Key; + string value = dem.Current.Value; + if (!string.IsNullOrEmpty(key)) + { + query.Append(key).Append(value); + } + } + + return query.ToString(); + } + + /// + /// 签名验证 + /// + /// 时间戳 + /// 随机字符串 + /// 客户端应用密钥 + /// 接口参数内容 + /// 当前请求内容的数字签名 + /// + public static bool Validate(string timeStamp, string nonce, string appSecret, string data, string signature) + { + string signStr = timeStamp + nonce + data + appSecret; + string signMd5 = MD5Util.GetMD5_32(signStr); + return signMd5 == signature; + } + + /// + /// 验证appId是否被允许 + /// + /// + /// + private static AllowCacheApp VerifyAppId(string appId) + { + AllowCacheApp allowCacheApp = new AllowCacheApp(); + if (string.IsNullOrEmpty(appId)) + { + return allowCacheApp; + } + + CacheHelper cacheHelper = new CacheHelper(); + List list = cacheHelper.Get("AllowAppId").ToJson().ToList(); + if (list.Count > 0) + { + allowCacheApp = list.Where(s => s.AppId == appId).FirstOrDefault(); + } + + return allowCacheApp; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/StringHelper.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/StringHelper.cs new file mode 100644 index 0000000..9a6e0ea --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/StringHelper.cs @@ -0,0 +1,166 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Text; +using System.Text.RegularExpressions; +using Znyc.Cloudcar.Admin.Commons.Enums; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 字符串帮助类 + /// + public class StringHelper + { + private static readonly char[] _constant = + { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' + }; + + /// + /// 生成随机字符串,默认32位 + /// + /// 随机数长度 + /// + public static string GenerateRandom(int length = 32) + { + StringBuilder newRandom = new StringBuilder(); + Random rd = new Random(); + for (int i = 0; i < length; i++) + { + newRandom.Append(_constant[rd.Next(_constant.Length)]); + } + + return newRandom.ToString(); + } + + /// + /// 生成随机字符串,只包含数字 + /// + /// + /// + public static string GenerateRandomNumber(int length = 6) + { + StringBuilder newRandom = new StringBuilder(); + Random rd = new Random(); + for (int i = 0; i < length; i++) + { + newRandom.Append(_constant[rd.Next(10)]); + } + + return newRandom.ToString(); + } + + /// + /// + /// + /// + /// + public static string Format(string str, object obj) + { + if (string.IsNullOrEmpty(str)) + { + return str; + } + + string s = str; + if (obj.GetType().Name == "JObject") + { + foreach (System.Collections.Generic.KeyValuePair item in (JObject)obj) + { + string k = item.Key; + string v = item.Value.ToString(); + s = Regex.Replace(s, "\\{" + k + "\\}", v, RegexOptions.IgnoreCase); + } + } + else + { + foreach (System.Reflection.PropertyInfo p in obj.GetType().GetProperties()) + { + string xx = p.Name; + string yy = p.GetValue(obj).ToString(); + s = Regex.Replace(s, "\\{" + xx + "\\}", yy, RegexOptions.IgnoreCase); + } + } + + return s; + } + + /// + /// 隐藏手机号 + /// + /// + /// + public static string ConvertPhoneNo(string Phone) + { + return Regex.Replace(Phone, "(\\d{3})\\d{4}(\\d{4})", "$1****$2"); + } + + /// + /// 隐藏身份证号 + /// + /// + /// + public static string ConvertIdCard(string idCard) + { + return Regex.Replace(idCard, "(\\d{6})\\d{8}(\\w{4})", "$1********$2"); + } + + /// + /// 生成流水号 + /// + /// + /// + /// + /// + public static string GetSerialNumber(ProductTypeEnum productType, long IndustryId, long JobId) + { + return DateTime.Now.ToString("yyyyMMddhhmmss"); // + productType.ToInt() + IndustryId + JobId; + } + + /// + /// + /// + /// + public static string ChineseMainlandForPhone(string phone) + { + return string.Format("+86{0}", phone); + } + + /// + /// 计算年龄 + /// + /// + /// + public static int? GetAgeByBirthDate(DateTime? birthDate) + { + int? age = 0; + if (!birthDate.ToString().Equals("0001/1/1 0:00:00")) + { + DateTime now = DateTime.Now; + age = now.Year - birthDate?.Year; + if (now.Month < birthDate?.Month || now.Month == birthDate?.Month && now.Day < birthDate?.Day) + { + age--; + } + } + + return age < 0 ? 0 : age; + } + + /// + /// 计算百分比 + /// + /// 除数 + /// 被除数 + /// + public static decimal GetPercent(decimal divisor, decimal dividend) + { + if (divisor == 0 || dividend == 0) + { + return Convert.ToDecimal(0); + } + + return Math.Floor(Math.Round(decimal.Parse((divisor / dividend).ToString("0.000")), 2) * 100); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/UpperFirstCaseNamingPolicy.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/UpperFirstCaseNamingPolicy.cs new file mode 100644 index 0000000..a85d6fe --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/UpperFirstCaseNamingPolicy.cs @@ -0,0 +1,20 @@ +using System.Text.Json; +using Znyc.Cloudcar.Admin.Commons.Extend; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// 首字母大写 + /// + public class UpperFirstCaseNamingPolicy : JsonNamingPolicy + { + /// + /// + /// + /// + public override string ConvertName(string name) + { + return name.UpperFirst(); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Helpers/XmlConverter.cs b/Znyc.Cloudcar.Admin.Commons/Helpers/XmlConverter.cs new file mode 100644 index 0000000..36d1d55 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Helpers/XmlConverter.cs @@ -0,0 +1,59 @@ +using System; +using System.IO; +using System.Xml.Linq; +using System.Xml.Serialization; + +namespace Znyc.Cloudcar.Admin.Commons.Helpers +{ + /// + /// XML文件与对象相互转化操作 + /// + public class XmlConverter + { + /// + /// 将对象转换为xml格式 + /// + /// + /// + /// xml文件路径 + /// + public static void Serialize(T obj, string xmlFilePath) + { + FileStream xmlfs = null; + try + { + XmlSerializer serializer = new XmlSerializer(typeof(T)); + xmlfs = new FileStream(xmlFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); + serializer.Serialize(xmlfs, obj); + } + catch (Exception ex) + { + throw ex; + } + finally + { + if (xmlfs != null) + { + xmlfs.Close(); + } + } + } + + /// + /// 将xml格式转为对象 + /// + /// + /// xml文件路径 + /// + public static T Deserialize(string xmlFilePath) + { + XDocument doc = XDocument.Load(xmlFilePath); + XmlSerializer serializer = new XmlSerializer(typeof(T)); + StringReader reader = new StringReader(doc.ToString()); + T result = (T)serializer.Deserialize(reader); + reader.Close(); + reader.Dispose(); + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/IoC/IoCContainer.cs b/Znyc.Cloudcar.Admin.Commons/IoC/IoCContainer.cs new file mode 100644 index 0000000..948dfc6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/IoC/IoCContainer.cs @@ -0,0 +1,23 @@ +using Znyc.Cloudcar.Admin.Commons.Core.App; + +namespace Znyc.Cloudcar.Admin.Commons.IoC +{ + /// + /// IOC 容器 + /// + public class IoCContainer + { + /// + /// 从容器中获取对象 Resolve an instance of the default requested type from the container + /// + /// 该方法即将废弃,请使用App.GetService(); + /// + /// + /// 类型 + /// + public static T Resolve() where T : class + { + return App.GetService(); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Json/JsonHelper.cs b/Znyc.Cloudcar.Admin.Commons/Json/JsonHelper.cs new file mode 100644 index 0000000..3f66b77 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Json/JsonHelper.cs @@ -0,0 +1,136 @@ +using System.Collections.Generic; +using System.Data; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Unicode; +using Znyc.Cloudcar.Admin.Commons.Helpers; + +namespace Znyc.Cloudcar.Admin.Commons.Json +{ + /// + /// JSON序列化、反序列化扩展类。 + /// + public static class JsonHelper + { + /// + /// 对象序列化成JSON字符串。 + /// + /// 序列化对象 + /// + public static string ToJson(this object obj) + { + JsonSerializerOptions options = new JsonSerializerOptions + { + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All), + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + AllowTrailingCommas = true + }; + //设置时间格式 + options.Converters.Add(new DateTimeJsonConverter()); + options.Converters.Add(new DateTimeNullableConverter()); + //设置bool获取格式 + options.Converters.Add(new BooleanJsonConverter()); + //设置数字 + options.Converters.Add(new IntJsonConverter()); + options.PropertyNamingPolicy = new UpperFirstCaseNamingPolicy(); + options.PropertyNameCaseInsensitive = true; //忽略大小写 + //JsonSerializerOptions options = new JsonSerializerOptions() + //{ + // WriteIndented = true, //格式化json字符串 + // AllowTrailingCommas = true, //可以结尾有逗号 + // //IgnoreNullValues = true, //可以有空值,转换json去除空值属性 + // IgnoreReadOnlyProperties = true, //忽略只读属性 + // PropertyNameCaseInsensitive = true, //忽略大小写 + // Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) + //}; + return JsonSerializer.Serialize(obj, options); + } + + /// + /// JSON字符串序列化成对象。 + /// + /// 对象类型 + /// JSON字符串 + /// + public static T ToObject(this string json) + { + //JsonSerializerOptions options = new JsonSerializerOptions() + //{ + // WriteIndented = true, //格式化json字符串 + // AllowTrailingCommas = true, //可以结尾有逗号 + // //IgnoreNullValues = true, //可以有空值,转换json去除空值属性 + // IgnoreReadOnlyProperties = true, //忽略只读属性 + // PropertyNameCaseInsensitive = true, //忽略大小写 + // //PropertyNamingPolicy = JsonNamingPolicy.CamelCase //命名方式是默认还是CamelCase + // Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) + //}; + + JsonSerializerOptions options = new JsonSerializerOptions + { + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All), + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + AllowTrailingCommas = true + }; + //设置时间格式 + options.Converters.Add(new DateTimeJsonConverter()); + options.Converters.Add(new DateTimeNullableConverter()); + //设置bool获取格式 + options.Converters.Add(new BooleanJsonConverter()); + //设置数字 + options.Converters.Add(new IntJsonConverter()); + //options.PropertyNamingPolicy = new UpperFirstCaseNamingPolicy(); + options.PropertyNameCaseInsensitive = true; //忽略大小写 + return json == null ? default : JsonSerializer.Deserialize(json, options); + } + + /// + /// JSON字符串序列化成集合。 + /// + /// 集合类型 + /// JSON字符串 + /// + public static List ToList(this string json) + { + //JsonSerializerOptions options = new JsonSerializerOptions() + //{ + // WriteIndented = true, //格式化json字符串 + // AllowTrailingCommas = true, //可以结尾有逗号 + // //IgnoreNullValues = true, //可以有空值,转换json去除空值属性 + // IgnoreReadOnlyProperties = true, //忽略只读属性 + // PropertyNameCaseInsensitive = true, //忽略大小写 + // //PropertyNamingPolicy = JsonNamingPolicy.CamelCase //命名方式是默认还是CamelCase + // Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) + //}; + + JsonSerializerOptions options = new JsonSerializerOptions + { + Encoder = JavaScriptEncoder.Create(UnicodeRanges.All), + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + AllowTrailingCommas = true + }; + //设置时间格式 + options.Converters.Add(new DateTimeJsonConverter()); + options.Converters.Add(new DateTimeNullableConverter()); + //设置bool获取格式 + options.Converters.Add(new BooleanJsonConverter()); + //设置数字 + options.Converters.Add(new IntJsonConverter()); + //options.PropertyNamingPolicy = new UpperFirstCaseNamingPolicy(); + options.PropertyNameCaseInsensitive = true; //忽略大小写 + return json == null ? null : JsonSerializer.Deserialize>(json, options); + } + + /// + /// JSON字符串序列化成DataTable。 + /// + /// JSON字符串 + /// + public static DataTable ToTable(this string json) + { + return json == null ? null : JsonSerializer.Deserialize(json); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Linq/EnumerableExtentions.cs b/Znyc.Cloudcar.Admin.Commons/Linq/EnumerableExtentions.cs new file mode 100644 index 0000000..5a473fe --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Linq/EnumerableExtentions.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Znyc.Cloudcar.Admin.Commons.Linq +{ + public static class EnumerableExtentions + { + public static T[] AsToArray(this IEnumerable source, bool isNullAsEmpty = false) + { + if (source == null) + { + return isNullAsEmpty ? new T[0] : null; + } + + return source as T[] ?? source.ToArray(); + } + + public static List AsToList(this IEnumerable source, bool isNullAsEmpty = false) + { + if (source == null) + { + return isNullAsEmpty ? new List() : null; + } + + return source as List ?? source.ToList(); + } + + public static void ForEach(this IEnumerable source, Action process) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (process == null) + { + throw new ArgumentNullException(nameof(process)); + } + + foreach (T item in source) + { + process(item); + } + } + + public static void ForEach(this IEnumerable source, Func process) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (process == null) + { + throw new ArgumentNullException(nameof(process)); + } + + foreach (T item in source) + { + process(item); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Log/DbLogType.cs b/Znyc.Cloudcar.Admin.Commons/Log/DbLogType.cs new file mode 100644 index 0000000..0ecd309 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Log/DbLogType.cs @@ -0,0 +1,65 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.Commons.Log +{ + /// + /// 日志类型 + /// + public enum DbLogType + { + /// + /// 其他 + /// + [Description("其他")] Other = 0, + + /// + /// 登录 + /// + [Description("登录")] Login = 1, + + /// + /// 退出 + /// + [Description("退出")] Exit = 2, + + /// + /// 访问 + /// + [Description("访问")] Visit = 3, + + /// + /// 新增 + /// + [Description("新增")] Create = 4, + + /// + /// 删除 + /// + [Description("删除")] Delete = 5, + + /// + /// 修改 + /// + [Description("修改")] Update = 6, + + /// + /// 提交 + /// + [Description("提交")] Submit = 7, + + /// + /// 异常 + /// + [Description("异常")] Exception = 8, + + /// + /// 软删除 + /// + [Description("软删除")] DeleteSoft = 9, + + /// + /// 软删除 + /// + [Description("SQL语句")] SQL = 10 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Log/Log4netHelper.cs b/Znyc.Cloudcar.Admin.Commons/Log/Log4netHelper.cs new file mode 100644 index 0000000..913472b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Log/Log4netHelper.cs @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright © 2017-2020 Znyc.Cloudcar.Admin.Framework 版权所有 + * Author: Znyc + * Description: Znyc快速开发平台 + * Website:http://www.Znyc.Cloudcar.Admin.com +*********************************************************************************/ + +using log4net; +using log4net.Config; +using log4net.Repository; +using System; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.IO; + +namespace Znyc.Cloudcar.Admin.Commons.Log +{ + /// + /// log4net封装类 + /// *********************************使用说明********************************** + /// 1.首先将配置文件(log4net.config或App.config)放置在程序运行目录 + /// 2.调用SetConfig方法,并传入配置文件的全路径 + /// + public class Log4NetHelper + { + /// + /// log4net 仓储库 + /// + private static ILoggerRepository _repository; + + private static readonly ConcurrentDictionary Loggers = new ConcurrentDictionary(); + + /// + /// 读取配置文件,并使其生效。如果未找到配置文件,则抛出异常 + /// + /// + /// 配置文件全路径 + public static void SetConfig(ILoggerRepository repository, string configFilePath) + { + _repository = repository; + FileInfo fileInfo = new FileInfo(configFilePath); + if (!fileInfo.Exists) + { + throw new Exception("未找到配置文件" + configFilePath); + } + + XmlConfigurator.ConfigureAndWatch(_repository, fileInfo); + } + + /// + /// 获取记录器 + /// + /// soruce + /// + private static ILog GetLogger(string source) + { + if (Loggers.ContainsKey(source)) + { + return Loggers[source]; + } + else + { + ILog logger = LogManager.GetLogger(_repository.Name, source); + Loggers.TryAdd(source, logger); + return logger; + } + } + + #region Log a message object + + /// + /// 调试信息日志 + /// + /// 日志信息 + public static void Debug(string msg) + { + ILog logger = GetLogger("Debug"); + if (logger.IsDebugEnabled) + { + StackTrace stackTrace = new StackTrace(); + StackFrame stackFrame = stackTrace.GetFrame(1); + System.Reflection.MethodBase methodBase = stackFrame.GetMethod(); + string message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; + logger.Info(message); + } + } + + /// + /// 错误信息日志 + /// + /// 日志信息 + public static void Error(string msg) + { + ILog logger = GetLogger("Debug"); + if (logger.IsErrorEnabled) + { + StackTrace stackTrace = new StackTrace(); + StackFrame stackFrame = stackTrace.GetFrame(1); + System.Reflection.MethodBase methodBase = stackFrame.GetMethod(); + string message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; + logger.Info(message); + } + } + + /// + /// 异常错误信息日志 + /// + /// 异常抛出信息 + /// 异常信息 + public static void Error(string throwMsg, Exception ex) + { + ILog logger = GetLogger("Error"); + if (logger.IsErrorEnabled) + { + string message = + $"抛出信息:{throwMsg} \r\n异常类型:{ex.GetType().Name} \r\n异常信息:{ex.Message} \r\n堆栈调用:\r\n{ex.StackTrace}"; + logger.Error(message); + } + } + + /// + /// 异常错误信息 + /// + /// source + /// 异常抛出信息 + /// 异常信息 + public static void Error(Type source, object throwMsg, Exception ex) + { + ILog logger = GetLogger("Error"); + if (logger.IsErrorEnabled) + { + string message = + $"抛出信息:{throwMsg} \r\n异常类型:{ex.GetType().Name} \r\n异常信息:{ex.Message} \r\n【堆栈调用】:\r\n{ex.StackTrace}"; + logger.Error(message); + } + } + + /// + /// 关键信息日志 + /// + /// 日志信息 + public static void Info(string msg) + { + ILog logger = GetLogger("Info"); + if (logger.IsInfoEnabled) + { + StackTrace stackTrace = new StackTrace(); + StackFrame stackFrame = stackTrace.GetFrame(1); + System.Reflection.MethodBase methodBase = stackFrame.GetMethod(); + string message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; + logger.Info(message); + } + } + + /// + /// 警告信息日志 + /// + /// 日志信息 + public static void Warn(string msg) + { + ILog logger = GetLogger("Warn"); + if (logger.IsWarnEnabled) + { + StackTrace stackTrace = new StackTrace(); + StackFrame stackFrame = stackTrace.GetFrame(1); + System.Reflection.MethodBase methodBase = stackFrame.GetMethod(); + string message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; + logger.Info(message); + } + } + + /// + /// 失败信息日志 + /// + /// 日志信息 + public static void Fatal(string msg) + { + ILog logger = GetLogger("Fatal"); + if (logger.IsFatalEnabled) + { + StackTrace stackTrace = new StackTrace(); + StackFrame stackFrame = stackTrace.GetFrame(1); + System.Reflection.MethodBase methodBase = stackFrame.GetMethod(); + string message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; + logger.Info(message); + } + } + + #endregion Log a message object + + /// + /// 关键信息日志 + /// + /// 文件路径 + /// 日志信息 + public static void Info(string path, string msg) + { + ILog logger = GetLogger("Info"); + if (logger.IsInfoEnabled) + { + StackTrace stackTrace = new StackTrace(); + StackFrame stackFrame = stackTrace.GetFrame(1); + System.Reflection.MethodBase methodBase = stackFrame.GetMethod(); + string message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; + logger.Info(message); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Mapping/MapperExtensions.cs b/Znyc.Cloudcar.Admin.Commons/Mapping/MapperExtensions.cs new file mode 100644 index 0000000..d4b99cc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Mapping/MapperExtensions.cs @@ -0,0 +1,93 @@ +using AutoMapper; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Properties; + +namespace Znyc.Cloudcar.Admin.Commons.Mapping +{ + /// + /// 对象映射扩展操作 + /// + public static class MapperExtensions + { + private static IMapper _mapper; + + /// + /// 设置对象映射执行者 + /// + /// 映射执行者 + public static void SetMapper(IMapper mapper) + { + mapper.CheckNotNull("mapper"); + _mapper = mapper; + } + + /// + /// 将对象映射为指定类型 + /// + /// 要映射的目标类型 + /// 源对象 + /// 目标类型的对象 + public static TTarget MapTo(this object source) + { + CheckMapper(); + return _mapper.Map(source); + } + + /// + /// 使用源类型的对象更新目标类型的对象 + /// + /// 源类型 + /// 目标类型 + /// 源对象 + /// 待更新的目标对象 + /// 更新后的目标类型对象 + public static TTarget MapTo(this TSource source, TTarget target) + { + CheckMapper(); + return _mapper.Map(source, target); + } + + /// + /// 将数据源映射为指定的集合 + /// + /// + /// + /// + /// + /// + public static IQueryable ToOutput(this IQueryable source, + params Expression>[] membersToExpand) + { + CheckMapper(); + return _mapper.ProjectTo(source, membersToExpand); + } + + /// + /// 集合到集合 + /// + /// + /// + /// + public static List MapTo(this IEnumerable obj) + { + CheckMapper(); + return _mapper.Map>(obj); + } + + /// + /// 验证映射执行者是否为空 + /// + private static void CheckMapper() + { + if (_mapper == null) + { + throw new NullReferenceException(Resources.Map_MapperIsNull); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Net/IIPAddressParser.cs b/Znyc.Cloudcar.Admin.Commons/Net/IIPAddressParser.cs new file mode 100644 index 0000000..d26590a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Net/IIPAddressParser.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Http; +using System.Collections.Generic; +using System.Net; + +namespace Znyc.Cloudcar.Admin.Commons.Net +{ + public interface IIpAddressParser + { + bool ContainsIp(string ipRule, string clientIp); + + bool ContainsIp(List ipRules, string clientIp); + + bool ContainsIp(List ipRules, string clientIp, out string rule); + + IPAddress GetClientIp(HttpContext context); + + IPAddress ParseIp(string ipAddress); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Net/IPAddressRange.cs b/Znyc.Cloudcar.Admin.Commons/Net/IPAddressRange.cs new file mode 100644 index 0000000..5c294b7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Net/IPAddressRange.cs @@ -0,0 +1,143 @@ +using System; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; + +namespace Znyc.Cloudcar.Admin.Commons.Net +{ + /// + /// IP v4 and v6 range helper by jsakamoto + /// Fork from https://github.com/jsakamoto/ipaddressrange + /// + /// + /// "192.168.0.0/24" + /// "fe80::/10" + /// "192.168.0.0/255.255.255.0" + /// "192.168.0.0-192.168.0.255" + /// + public class IpAddressRange + { + public IPAddress Begin { get; set; } + + public IPAddress End { get; set; } + + public IpAddressRange() + { + Begin = new IPAddress(0L); + End = new IPAddress(0L); + } + + public IpAddressRange(string ipRangeString) + { + // remove all spaces. + ipRangeString = ipRangeString.Replace(" ", ""); + + // Pattern 1. CIDR range: "192.168.0.0/24", "fe80::/10" + Match m1 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)/(?\d+)$", RegexOptions.IgnoreCase); + if (m1.Success) + { + byte[] baseAdrBytes = IPAddress.Parse(m1.Groups["adr"].Value).GetAddressBytes(); + byte[] maskBytes = Bits.GetBitMask(baseAdrBytes.Length, int.Parse(m1.Groups["maskLen"].Value)); + baseAdrBytes = Bits.And(baseAdrBytes, maskBytes); + Begin = new IPAddress(baseAdrBytes); + End = new IPAddress(Bits.Or(baseAdrBytes, Bits.Not(maskBytes))); + return; + } + + // Pattern 2. Uni address: "127.0.0.1", ":;1" + Match m2 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)$", RegexOptions.IgnoreCase); + if (m2.Success) + { + Begin = End = IPAddress.Parse(ipRangeString); + return; + } + + // Pattern 3. Begin end range: "169.258.0.0-169.258.0.255" + Match m3 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)-(?[\da-f\.:]+)$", + RegexOptions.IgnoreCase); + if (m3.Success) + { + Begin = IPAddress.Parse(m3.Groups["begin"].Value); + End = IPAddress.Parse(m3.Groups["end"].Value); + return; + } + + // Pattern 4. Bit mask range: "192.168.0.0/255.255.255.0" + Match m4 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)/(?[\da-f\.:]+)$", + RegexOptions.IgnoreCase); + if (m4.Success) + { + byte[] baseAdrBytes = IPAddress.Parse(m4.Groups["adr"].Value).GetAddressBytes(); + byte[] maskBytes = IPAddress.Parse(m4.Groups["bitmask"].Value).GetAddressBytes(); + baseAdrBytes = Bits.And(baseAdrBytes, maskBytes); + Begin = new IPAddress(baseAdrBytes); + End = new IPAddress(Bits.Or(baseAdrBytes, Bits.Not(maskBytes))); + return; + } + + throw new FormatException("Unknown IP range string."); + } + + public bool Contains(IPAddress ipaddress) + { + if (ipaddress.AddressFamily != Begin.AddressFamily) + { + return false; + } + + byte[] adrBytes = ipaddress.GetAddressBytes(); + return Bits.GE(Begin.GetAddressBytes(), adrBytes) && Bits.LE(End.GetAddressBytes(), adrBytes); + } + } + + internal static class Bits + { + internal static byte[] Not(byte[] bytes) + { + return bytes.Select(b => (byte)~b).ToArray(); + } + + internal static byte[] And(byte[] A, byte[] B) + { + return A.Zip(B, (a, b) => (byte)(a & b)).ToArray(); + } + + internal static byte[] Or(byte[] A, byte[] B) + { + return A.Zip(B, (a, b) => (byte)(a | b)).ToArray(); + } + + internal static bool GE(byte[] A, byte[] B) + { + return A.Zip(B, (a, b) => a == b ? 0 : a < b ? 1 : -1) + .SkipWhile(c => c == 0) + .FirstOrDefault() >= 0; + } + + internal static bool LE(byte[] A, byte[] B) + { + return A.Zip(B, (a, b) => a == b ? 0 : a < b ? 1 : -1) + .SkipWhile(c => c == 0) + .FirstOrDefault() <= 0; + } + + internal static byte[] GetBitMask(int sizeOfBuff, int bitLen) + { + byte[] maskBytes = new byte[sizeOfBuff]; + int bytesLen = bitLen / 8; + int bitsLen = bitLen % 8; + for (int i = 0; i < bytesLen; i++) + { + maskBytes[i] = 0xff; + } + + if (bitsLen > 0) + { + maskBytes[bytesLen] = (byte)~Enumerable.Range(1, 8 - bitsLen).Select(n => 1 << (n - 1)) + .Aggregate((a, b) => a | b); + } + + return maskBytes; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Net/IpAddressUtil.cs b/Znyc.Cloudcar.Admin.Commons/Net/IpAddressUtil.cs new file mode 100644 index 0000000..5d2fe89 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Net/IpAddressUtil.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Net.TencentIp; + +namespace Znyc.Cloudcar.Admin.Commons.Net +{ + /// + /// IP地址 + /// + public class IpAddressUtil + { + /// + /// Ip地址段是否包含另外一个IP地址 + /// + /// + /// + /// + public static bool ContainsIp(string rule, string clientIp) + { + IPAddress ip = ParseIp(clientIp); + + IpAddressRange range = new IpAddressRange(rule); + if (range.Contains(ip)) + { + return true; + } + + return false; + } + + /// + /// Ip地址集合是否包含另外一个IP地址 + /// + /// Ip地址集合List + /// + /// + public static bool ContainsIp(List ipRules, string clientIp) + { + IPAddress ip = ParseIp(clientIp); + if (ipRules != null && ipRules.Any()) + { + foreach (string rule in ipRules) + { + IpAddressRange range = new IpAddressRange(rule); + if (range.Contains(ip)) + { + return true; + } + } + } + + return false; + } + + /// + /// Ip地址集合是否包含另外一个IP地址 + /// + /// + /// + /// + /// + public static bool ContainsIp(List ipRules, string clientIp, out string rule) + { + rule = null; + IPAddress ip = ParseIp(clientIp); + if (ipRules != null && ipRules.Any()) + { + foreach (string r in ipRules) + { + IpAddressRange range = new IpAddressRange(r); + if (range.Contains(ip)) + { + rule = r; + return true; + } + } + } + + return false; + } + + /// + /// + /// + /// + /// + public static IPAddress ParseIp(string ipAddress) + { + return IPAddress.Parse(ipAddress); + } + + /// + /// 是否为ip + /// + /// + /// + public static bool IsIP(string ip) + { + return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"); + } + + /// + /// 根据腾讯地图接口查询IP所属地区 + /// + /// + /// + public static string GetCityByIp(string strIP) + { + try + { + string url = "https://apis.map.qq.com/ws/location/v1/ip?ip=" + strIP + + "&key=WANBZ-6C56D-6P34Y-HWNMG-YHAH7-BJFP5"; + string jsonText = HttpRequestHelper.HttpGet(url); + TencentIpResult ipResult = jsonText.ToObject(); + if (ipResult.status == 0) + { + string nation = ipResult.result.ad_info.nation.ToString(); //国家 + string province = ipResult.result.ad_info.province.ToString(); //省份 + string city = ipResult.result.ad_info.city.ToString(); //城市 + string district = ipResult.result.ad_info.district.ToString(); //区/县 + string adcode = ipResult.result.ad_info.adcode.ToString(); //行政区划代码 + string resultStr = ""; + if (nation is { Length: > 0 }) + { + resultStr += nation; + } + + if (province is { Length: > 0 }) + { + resultStr += province; + } + + if (city is { Length: > 0 }) + { + resultStr += city; + } + + if (district is { Length: > 0 }) + { + resultStr += district; + } + + return resultStr; + } + else + { + Log4NetHelper.Error(strIP + "获取地区接口调用异常。" + ipResult.message); + return "未知"; + } + } + catch (Exception ex) + { + Log4NetHelper.Error(strIP + "获取地区异常。" + ex.Message); + return "未知"; + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Net/RemoteIpParser.cs b/Znyc.Cloudcar.Admin.Commons/Net/RemoteIpParser.cs new file mode 100644 index 0000000..2efffe5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Net/RemoteIpParser.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Http; +using System.Collections.Generic; +using System.Net; + +namespace Znyc.Cloudcar.Admin.Commons.Net +{ + public class RemoteIpParser : IIpAddressParser + { + public bool ContainsIp(string ipRule, string clientIp) + { + return IpAddressUtil.ContainsIp(ipRule, clientIp); + } + + public bool ContainsIp(List ipRules, string clientIp) + { + return IpAddressUtil.ContainsIp(ipRules, clientIp); + } + + public bool ContainsIp(List ipRules, string clientIp, out string rule) + { + return IpAddressUtil.ContainsIp(ipRules, clientIp, out rule); + } + + public virtual IPAddress GetClientIp(HttpContext context) + { + return context.Connection.RemoteIpAddress; + } + + public IPAddress ParseIp(string ipAddress) + { + return IpAddressUtil.ParseIp(ipAddress); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Net/ReversProxyIpParser.cs b/Znyc.Cloudcar.Admin.Commons/Net/ReversProxyIpParser.cs new file mode 100644 index 0000000..69f626c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Net/ReversProxyIpParser.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Linq; +using System.Net; + +namespace Znyc.Cloudcar.Admin.Commons.Net +{ + public class ReversProxyIpParser : RemoteIpParser + { + private readonly string _realIpHeader; + + public ReversProxyIpParser(string realIpHeader) + { + _realIpHeader = realIpHeader; + } + + public override IPAddress GetClientIp(HttpContext context) + { + if (context.Request.Headers.Keys.Contains(_realIpHeader, StringComparer.CurrentCultureIgnoreCase)) + { + return ParseIp(context.Request.Headers[_realIpHeader].First()); + } + + return base.GetClientIp(context); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Net/TencentIp.cs b/Znyc.Cloudcar.Admin.Commons/Net/TencentIp.cs new file mode 100644 index 0000000..eee30db --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Net/TencentIp.cs @@ -0,0 +1,97 @@ +namespace Znyc.Cloudcar.Admin.Commons.Net.TencentIp +{ + /// + /// 通过终端设备IP地址获取其当前所在地理位置,精确到市级,常用于显示当地城市天气预报、初始化用户城市等非精确定位场景。 + /// 响应结果 + /// + public class TencentIpResult + { + /// + /// 状态状态码, + /// 0为正常, + /// 310请求参数信息有误, + /// 311Key格式错误, + /// 306请求有护持信息请检查字符串, + /// 110请求来源未被授权 + /// + public int status { get; set; } + + /// + /// 对status的描述 + /// + public string message { get; set; } + + /// + /// IP定位结果 + /// + public IpResult result { get; set; } + } + + /// + /// IP定位结果 + /// + public class IpResult + { + /// + /// 用于定位的IP地址 + /// + public string ip { get; set; } + + /// + /// 定位坐标 + /// + public Location location { get; set; } + + /// + /// 定位行政区划信息 + /// + public Adinfo ad_info { get; set; } + } + + /// + /// 定位坐标 + /// + public class Location + { + /// + /// 纬度 + /// + public decimal lat { get; set; } + + /// + /// 经度 + /// + public decimal lng { get; set; } + } + + /// + /// 定位行政区划信息 + /// + public class Adinfo + { + /// + /// 国家 + /// + public string nation { get; set; } + + /// + /// 省 + /// + public string province { get; set; } + + /// + /// 市 + /// + public string city { get; set; } + + /// + /// 区 + /// + public string district { get; set; } + + /// + /// 行政区划代码 + /// + public int adcode { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Options/AllowCacheApp.cs b/Znyc.Cloudcar.Admin.Commons/Options/AllowCacheApp.cs new file mode 100644 index 0000000..f44c386 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Options/AllowCacheApp.cs @@ -0,0 +1,53 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Commons.Options +{ + /// + /// 缓存中可用的应用 + /// + [Serializable] + public class AllowCacheApp + { + /// + /// 设置或获取 ID + /// + [MaxLength(50)] + public int Id { get; set; } + + /// + /// 设置或获取 应用Id + /// + [MaxLength(50)] + public string AppId { get; set; } + + /// + /// 设置或获取 应用密钥 + /// + [MaxLength(50)] + public string AppSecret { get; set; } + + /// + /// 设置或获取 消息加密密钥 + /// + [MaxLength(256)] + public string EncodingAESKey { get; set; } + + /// + /// 设置或获取 请求url + /// + [MaxLength(256)] + public string RequestUrl { get; set; } + + /// + /// 设置或获取 token + /// + [MaxLength(256)] + public string Token { get; set; } + + /// + /// 设置或获取 是否开启消息加解密 + /// + public bool? IsOpenAEKey { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Options/AppSetting.cs b/Znyc.Cloudcar.Admin.Commons/Options/AppSetting.cs new file mode 100644 index 0000000..ef6d379 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Options/AppSetting.cs @@ -0,0 +1,316 @@ +using System; +using System.Xml.Serialization; + +namespace Znyc.Cloudcar.Admin.Commons.Options +{ + /// + /// 应用设置实体类 + /// + [Serializable] + public class AppSetting + { + #region 系统基本信息 + + /// + /// 系统名称 + /// + [XmlElement("SoftName")] + public string SoftName { get; set; } + + /// + /// 系统简介 + /// + [XmlElement("SoftSummary")] + public string SoftSummary { get; set; } + + /// + /// 访问域名 + /// + [XmlElement("WebUrl")] + public string WebUrl { get; set; } + + /// + /// Logo + /// + [XmlElement("SysLogo")] + public string SysLogo { get; set; } + + /// + /// 公司名称 + /// + [XmlElement("CompanyName")] + public string CompanyName { get; set; } + + /// + /// 地址 + /// + [XmlElement("Address")] + public string Address { get; set; } + + /// + /// 电话 + /// + [XmlElement("Telphone")] + public string Telphone { get; set; } + + /// + /// Email + /// + [XmlElement("Email")] + public string Email { get; set; } + + /// + /// ICP备案号 + /// + [XmlElement("ICPCode")] + public string ICPCode { get; set; } + + /// + /// 公安备案号 + /// + [XmlElement("PublicSecurityCode")] + public string PublicSecurityCode { get; set; } + + /// + /// 分享标题 + /// + [XmlElement("ShareTitle")] + public string ShareTitle { get; set; } + + /// + /// 微信公众号分享图片 + /// + [XmlElement("ShareWeChatImage")] + public string ShareWeChatImage { get; set; } + + /// + /// 微信小程序分享图片 + /// + [XmlElement("ShareWxAppletImage")] + public string ShareWxAppletImage { get; set; } + + /// + /// 微信推广二维码背景图片 + /// + [XmlElement("ShareBackgroundImage")] + public string ShareBackgroundImage { get; set; } + + #endregion 系统基本信息 + + #region 功能权限设置 + + /// + /// URL重写开关 + /// + [XmlElement("Staticstatus")] + public string Staticstatus { get; set; } + + /// + /// 静态URL后缀 + /// + [XmlElement("Staticextension")] + public string Staticextension { get; set; } + + /// + /// 开启会员功能 + /// + [XmlElement("Memberstatus")] + public string Memberstatus { get; set; } + + /// + /// 是否开启网站 + /// + [XmlElement("Webstatus")] + public string Webstatus { get; set; } + + /// + /// 网站关闭原因 + /// + [XmlElement("Webclosereason")] + public string Webclosereason { get; set; } + + /// + /// 网站统计代码 + /// + [XmlElement("Webcountcode")] + public string Webcountcode { get; set; } + + #endregion 功能权限设置 + + #region 文件服务器 + + /// + /// 文件服务器 + /// + [XmlElement("Fileserver")] + public string Fileserver { get; set; } + + /// + /// 本地文件存储物理物理路径 + /// + [XmlElement("LocalPath")] + public string LocalPath { get; set; } + + /// + /// 阿里云KeyId + /// + [XmlElement("Osssecretid")] + public string Osssecretid { get; set; } + + /// + /// 阿里云SecretKey + /// + [XmlElement("Osssecretkey")] + public string Osssecretkey { get; set; } + + /// + /// 阿里云Bucket + /// + [XmlElement("Ossbucket")] + public string Ossbucket { get; set; } + + /// + /// 阿里云EndPoint + /// + [XmlElement("Ossendpoint")] + public string Ossendpoint { get; set; } + + /// + /// 阿里云绑定域名 + /// + [XmlElement("Ossdomain")] + public string Ossdomain { get; set; } + + #endregion 文件服务器 + + #region 文件上传设置 + + /// + /// 文件上传目录 + /// + [XmlElement("Filepath")] + public string Filepath { get; set; } + + /// + /// 文件保存方式 + /// + [XmlElement("Filesave")] + public string Filesave { get; set; } + + /// + /// 编辑器图片 + /// + [XmlElement("Fileremote")] + public string Fileremote { get; set; } + + /// + /// 文件上传类型 + /// + [XmlElement("Fileextension")] + public string Fileextension { get; set; } + + /// + /// 视频上传类型 + /// + [XmlElement("Videoextension")] + public string Videoextension { get; set; } + + /// + /// 附件上传大小 + /// + [XmlElement("Attachsize")] + public string Attachsize { get; set; } + + /// + /// 视频上传大小 + /// + [XmlElement("Videosize")] + public string Videosize { get; set; } + + /// + /// 图片上传大小 + /// + [XmlElement("Imgsize")] + public string Imgsize { get; set; } + + /// + /// 图片最大尺寸 高度 + /// + [XmlElement("Imgmaxheight")] + public string Imgmaxheight { get; set; } + + /// + /// 图片最大尺寸 宽度 + /// + [XmlElement("Imgmaxwidth")] + public string Imgmaxwidth { get; set; } + + /// + /// 缩略图生成尺寸 高度 + /// + [XmlElement("Thumbnailheight")] + public string Thumbnailheight { get; set; } + + /// + /// 缩略图生成尺寸 宽度 + /// + [XmlElement("Thumbnailwidth")] + public string Thumbnailwidth { get; set; } + + /// + /// 缩略图生成方式 + /// + [XmlElement("Thumbnailmode")] + public string Thumbnailmode { get; set; } + + /// + /// 图片水印类型 + /// + [XmlElement("Watermarktype")] + public string Watermarktype { get; set; } + + /// + /// 图片水印位置 + /// + [XmlElement("Watermarkposition")] + public string Watermarkposition { get; set; } + + /// + /// 图片生成质量 + /// + [XmlElement("Watermarkimgquality")] + public string Watermarkimgquality { get; set; } + + /// + /// 图片水印文件 + /// + [XmlElement("Watermarkpic")] + public string Watermarkpic { get; set; } + + /// + /// 水印透明度 + /// + [XmlElement("Watermarktransparency")] + public string Watermarktransparency { get; set; } + + /// + /// 水印文字 + /// + [XmlElement("Watermarktext")] + public string Watermarktext { get; set; } + + /// + /// 文字字体格式 + /// + [XmlElement("Watermarkfont")] + public string Watermarkfont { get; set; } + + /// + /// 文字字体大小 + /// + [XmlElement("Watermarkfontsize")] + public string Watermarkfontsize { get; set; } + + #endregion 文件上传设置 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Options/AssembleTypeConsts.cs b/Znyc.Cloudcar.Admin.Commons/Options/AssembleTypeConsts.cs new file mode 100644 index 0000000..218d6e6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Options/AssembleTypeConsts.cs @@ -0,0 +1,23 @@ +namespace Znyc.Cloudcar.Admin.Commons.Options +{ + /// + /// + /// + public class AssembleTypeConsts + { + /// + /// + /// + public const string Package = "package"; + + /// + /// + /// + public const string ReferenceAssembly = "referenceassembly"; + + /// + /// + /// + public const string Project = "project"; + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Options/CodeGenerateOption.cs b/Znyc.Cloudcar.Admin.Commons/Options/CodeGenerateOption.cs new file mode 100644 index 0000000..2d80ee9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Options/CodeGenerateOption.cs @@ -0,0 +1,58 @@ +namespace Znyc.Cloudcar.Admin.Commons.Options +{ + /// + /// 代码生成器配置 + /// + public class CodeGenerateOption + { + /// + /// 项目命名空间 + /// + public string BaseNamespace { get; set; } + + /// + /// 数据实体命名空间 + /// + public string EntitysNamespace { get; set; } + + /// + /// 输入输出数据实体名称空间 + /// + public string DtosNamespace { get; set; } + + /// + /// 仓储接口命名空间 + /// + public string IRepositoriesNamespace { get; set; } + + /// + /// 仓储实现名称空间 + /// + public string RepositoriesNamespace { get; set; } + + /// + /// 服务接口命名空间 + /// + public string IServicsNamespace { get; set; } + + /// + /// 服务接口实现命名空间 + /// + public string ServicesNamespace { get; set; } + + /// + /// Api控制器命名空间 + /// + public string ApiControllerNamespace { get; set; } + + /// + /// 去掉的表头字符 + /// + public string ReplaceTableNameStr { get; set; } + + /// + /// 要生数据的表,用“,”分割 + /// + public string TableList { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Options/DbContextOption.cs b/Znyc.Cloudcar.Admin.Commons/Options/DbContextOption.cs new file mode 100644 index 0000000..b51a4ad --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Options/DbContextOption.cs @@ -0,0 +1,30 @@ +using Znyc.Cloudcar.Admin.Commons.Enums; + +namespace Znyc.Cloudcar.Admin.Commons.Options +{ + /// + /// 数据库上下文配置 + /// + public class DbContextOption + { + /// + /// 数据库连接字符串 + /// + public string dbConfigName { get; set; } + + /// + /// 实体程序集名称 + /// + public string ModelAssemblyName { get; set; } + + /// + /// 数据库类型 + /// + public DatabaseType DbType { get; set; } = DatabaseType.SqlServer; + + /// + /// 是否输出Sql日志 + /// + public bool IsOutputSql; + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Options/JwtOption.cs b/Znyc.Cloudcar.Admin.Commons/Options/JwtOption.cs new file mode 100644 index 0000000..0429215 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Options/JwtOption.cs @@ -0,0 +1,33 @@ +namespace Znyc.Cloudcar.Admin.Commons.Options +{ + /// + /// JsonWebToken配置模型。 + /// + public class JwtOption + { + /// + /// 签发者。 + /// + public string Issuer { get; set; } + + /// + /// 收发者。 + /// + public string Audience { get; set; } + + /// + /// 密钥。 + /// + public string Secret { get; set; } + + /// + /// Token有效期(单位:分钟)。 + /// + public int Expiration { get; set; } + + /// + /// Token有效刷新时间(单位:分钟)。 + /// + public int refreshJwtTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Options/UIConstants.cs b/Znyc.Cloudcar.Admin.Commons/Options/UIConstants.cs new file mode 100644 index 0000000..00e95b6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Options/UIConstants.cs @@ -0,0 +1,74 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Commons +{ + /// + /// ַ + /// + public static class UIConstants + { + /// + /// ʱ + /// + public static string ApplicationExpiredDate = "12/29/2012"; + + /// + /// 汾 + /// + public static string SoftwareVersion = "3.0"; + + /// + /// Ʒ + /// + public static string SoftwareProductName = "ZnycSoftSystem"; + + /// + /// + /// + public static int SoftwareProbationDay = 20; + + /// + /// 洢Ŀ¼ + /// + public static string IsolatedStorageDirectoryName = "UserNameDir"; + + /// + /// 洢Կ + /// + public static string IsolatedStorageEncryptKey = "12345678"; + + /// + /// עܹԿ + /// + public static string PublicKey = + @"mtDtu679/0quhftVyOc6/cBov/i534Dkh3AB8RwrpC9Vq2RIFB3uvjRUuaAEPR8vMcijQjVzqLZgMM7jFKclzbh21rWTM+YlOeraKz5FPCC7rSLnv6Tfbzia9VI/r5cfM8ogVMuUKCZeU+PTEmVviasCl8nPYyqOQchlf/MftMM=AQAB"; + + /// + /// ȨϢ + /// + public static string CopyRight = + string.Format( + "Copyright © 2017-{0} Znyc Tech.", + DateTime.Now.Year); + + /// + /// Webַ֤ + /// + public static string WebRegisterURL = "http://www.Znyc.Cloudcar.Admin.com/WebRegister.aspx"; + + /// + /// òֵ + /// + /// ʱ + /// 汾 + /// + /// Կַ + public static void SetValue(string expiredDate, string version, string name, string publicKey) + { + ApplicationExpiredDate = expiredDate; + SoftwareVersion = version; + SoftwareProductName = name; + PublicKey = publicKey; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Page/PageIfno.cs b/Znyc.Cloudcar.Admin.Commons/Page/PageIfno.cs new file mode 100644 index 0000000..9a7d8d1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Page/PageIfno.cs @@ -0,0 +1,99 @@ +using System; +using System.Runtime.Serialization; +using System.Xml.Serialization; + +namespace Znyc.Cloudcar.Admin.Commons.Pages +{ + /// + /// + /// + /// + public delegate void PageInfoChanged(PagerInfo info); + + /// + /// 分页实体 + /// + [Serializable] + [DataContract] + public class PagerInfo + { + /// + /// 页面选择事件 + /// + public event PageInfoChanged OnPageInfoChanged; + + /// + /// 当前页码 + /// + private int currenetPageIndex; + + /// + /// 每页显示的记录 + /// + private int pageSize; + + /// + /// 记录总数 + /// + private int recordCount; + + #region 属性变量 + + /// + /// 获取或设置当前页码 + /// + [XmlElement(ElementName = "CurrenetPageIndex")] + [DataMember] + public int CurrenetPageIndex + { + get => currenetPageIndex; + set + { + currenetPageIndex = value; + + if (OnPageInfoChanged != null) + { + OnPageInfoChanged(this); + } + } + } + + /// + /// 获取或设置每页显示的记录 + /// + [XmlElement(ElementName = "PageSize")] + [DataMember] + public int PageSize + { + get => pageSize; + set + { + pageSize = value; + if (OnPageInfoChanged != null) + { + OnPageInfoChanged(this); + } + } + } + + /// + /// 获取或设置记录总数 + /// + [XmlElement(ElementName = "RecordCount")] + [DataMember] + public int RecordCount + { + get => recordCount; + set + { + recordCount = value; + if (OnPageInfoChanged != null) + { + OnPageInfoChanged(this); + } + } + } + + #endregion 属性变量 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Page/PageResult.cs b/Znyc.Cloudcar.Admin.Commons/Page/PageResult.cs new file mode 100644 index 0000000..4a02902 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Page/PageResult.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Commons.Pages +{ + /// + /// 保存分页请求的结果。 + /// + /// 返回结果集中的POCO类型 + public class PageResult : CommonResult + { + public PageResult() + { + } + + public PageResult(bool success, string msg, object rows) + { + Success = success; + ErrMsg = msg; + ResData = rows; + } + + public PageResult(long currentPage, long totalItems, long itemsPerPage) + { + CurrentPage = currentPage; + TotalItems = totalItems; + ItemsPerPage = itemsPerPage; + } + + public PageResult(long currentPage, long totalPages, long totalItems, long itemsPerPage, List items, + object context) : this(currentPage, totalPages, totalItems) + { + ItemsPerPage = itemsPerPage; + Items = items; + Context = context; + } + + /// + /// 当前页码。 + /// + public long CurrentPage { get; set; } + + /// + /// 总页码数。 + /// + public long TotalPages { get; set; } + + /// + /// 记录总数。 + /// + public long TotalItems { get; set; } + + /// + /// 每页数量。 + /// + public long ItemsPerPage { get; set; } + + /// + /// 当前结果集。 + /// + public List Items { get; set; } + + /// + /// 自定义用户属性。 + /// + public object Context { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Page/PagerHelper.cs b/Znyc.Cloudcar.Admin.Commons/Page/PagerHelper.cs new file mode 100644 index 0000000..dbf9313 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Page/PagerHelper.cs @@ -0,0 +1,390 @@ +using System; +using Znyc.Cloudcar.Admin.Commons.Enums; + +namespace Znyc.Cloudcar.Admin.Commons.Pages +{ + /// + /// 根据各种不同数据库生成不同分页语句的辅助类 PagerHelper + /// + public class PagerHelper + { + #region 成员变量 + + private string tableName; //待查询表或自定义查询语句 + private string fieldsToReturn = "*"; //需要返回的列 + private string fieldNameToSort = string.Empty; //排序字段名称 + private int pageSize = 10; //页尺寸,就是一页显示多少条记录 + private int pageIndex = 1; //当前的页码 + private bool isDescending = false; //是否以降序排列 + private string strwhere = string.Empty; //检索条件(注意: 不要加 where) + + #endregion 成员变量 + + #region 属性对象 + + /// + /// 待查询表或自定义查询语句 + /// + public string TableName + { + get => tableName; + set => tableName = value; + } + + /// + /// 需要返回的列 + /// + public string FieldsToReturn + { + get => fieldsToReturn; + set => fieldsToReturn = value; + } + + /// + /// 排序字段名称 + /// + public string FieldNameToSort + { + get => fieldNameToSort; + set => fieldNameToSort = value; + } + + /// + /// 页尺寸,就是一页显示多少条记录 + /// + public int PageSize + { + get => pageSize; + set => pageSize = value; + } + + /// + /// 当前的页码 + /// + public int PageIndex + { + get => pageIndex; + set => pageIndex = value; + } + + /// + /// 是否以降序排列结果 + /// + public bool IsDescending + { + get => isDescending; + set => isDescending = value; + } + + /// + /// 检索条件(注意: 不要加 where) + /// + public string StrWhere + { + get => strwhere; + set => strwhere = value; + } + + /// + /// 表或Sql语句包装属性 + /// + internal string TableOrSqlWrapper + { + get + { + bool isSql = tableName.ToLower().Contains("from"); + if (isSql) + { + return string.Format("({0}) AA ", tableName); //如果是Sql语句,则加括号后再使用 + } + else + { + return tableName; //如果是表名,则直接使用 + } + } + } + + #endregion 属性对象 + + #region 构造函数 + + /// + /// 默认构造函数,其他通过属性设置 + /// + public PagerHelper() + { + } + + /// + /// 完整的构造函数,可以包含条件,返回记录字段等条件 + /// + /// 表名称,可以自定义查询语句 + /// 需要返回的列 + /// 排序字段名称 + /// 每页显示数量 + /// 当前的页码 + /// 是否以降序排列 + /// 检索条件 + public PagerHelper(string tableName, string fieldsToReturn, string fieldNameToSort, + int pageSize, int pageIndex, bool isDescending, string strwhere) + { + this.tableName = tableName; + this.fieldsToReturn = fieldsToReturn; + this.fieldNameToSort = fieldNameToSort; + this.pageSize = pageSize; + this.pageIndex = pageIndex; + this.isDescending = isDescending; + this.strwhere = strwhere; + } + + #endregion 构造函数 + + #region 各种数据库Sql分页查询,不依赖于存储过程 + + /// + /// 不依赖于存储过程的分页(Oracle) + /// + /// 如果isDoCount为True,返回总数统计Sql;否则返回分页语句Sql + /// + private string GetOracleSql(bool isDoCount) + { + string sql = ""; + if (string.IsNullOrEmpty(strwhere)) + { + strwhere = " (1=1) "; + } + + if (isDoCount) //执行总数统计 + { + sql = string.Format("select count(*) as Total from {0} Where {1} ", TableOrSqlWrapper, strwhere); + } + else + { + string strOrder = string.Format(" order by {0} {1}", fieldNameToSort, isDescending ? "DESC" : "ASC"); + + int minRow = pageSize * (pageIndex - 1); + int maxRow = pageSize * pageIndex; + string selectSql = string.Format("select {0} from {1} Where {2} {3}", fieldsToReturn, TableOrSqlWrapper, + strwhere, strOrder); + sql = string.Format(@"select b.* from + (select a.*, rownum as rowIndex from({2}) a) b + where b.rowIndex > {0} and b.rowIndex <= {1}", minRow, maxRow, selectSql); + } + + return sql; + } + + /// + /// 不依赖于存储过程的分页(SqlServer) + /// + /// 如果isDoCount为True,返回总数统计Sql;否则返回分页语句Sql + /// 是否是Sql server2008及低版本,默认为false + /// + private string GetSqlServerSql(bool isDoCount, bool isSql2008 = false) + { + string sql = ""; + if (string.IsNullOrEmpty(strwhere)) + { + strwhere = " (1=1)"; + } + + if (isDoCount) //执行总数统计 + { + sql = string.Format("select count(*) as Total from {0} Where {1} ", TableOrSqlWrapper, strwhere); + } + else + { + string strOrder = string.Format(" order by {0} {1}", fieldNameToSort, isDescending ? "DESC" : "ASC"); + int minRow = pageSize * (pageIndex - 1) + 1; + int maxRow = pageSize * pageIndex; + if (isSql2008) + { + sql = string.Format( + "SELECT * FROM ( SELECT ROW_NUMBER() OVER (order by {0}) AS rows ,{1} FROM {2} where {3}) AS main_temp where rows BETWEEN {4} and {5}", + strOrder, fieldsToReturn, TableOrSqlWrapper, strwhere, minRow, maxRow); + } + else + { + sql = string.Format(@"With Paging AS + ( SELECT ROW_NUMBER() OVER ({0}) as RowNumber, {1} FROM {2} Where {3}) + SELECT * FROM Paging WHERE RowNumber Between {4} and {5}", strOrder, fieldsToReturn, TableOrSqlWrapper, + strwhere, + minRow, maxRow); + } + } + + return sql; + } + + /// + /// 不依赖于存储过程的分页(Access) + /// + /// 如果isDoCount为True,返回总数统计Sql;否则返回分页语句Sql + /// + private string GetAccessSql(bool isDoCount) + { + string sql = ""; + if (string.IsNullOrEmpty(strwhere)) + { + strwhere = " (1=1) "; + } + + if (isDoCount) //执行总数统计 + { + sql = string.Format("select count(*) as Total from {0} Where {1} ", TableOrSqlWrapper, strwhere); + } + else + { + string strTemp = string.Empty; + string strOrder = string.Empty; + if (isDescending) + { + strTemp = "<(select min"; + strOrder = string.Format(" order by [{0}] desc", fieldNameToSort); + } + else + { + strTemp = ">(select max"; + strOrder = string.Format(" order by [{0}] asc", fieldNameToSort); + } + + sql = string.Format("select top {0} {1} from {2} ", pageSize, fieldsToReturn, TableOrSqlWrapper); + + //如果是第一页就执行以上代码,这样会加快执行速度 + if (pageIndex == 1) + { + sql += string.Format(" Where {0} ", strwhere); + sql += strOrder; + } + else + { + sql += string.Format( + " Where [{0}] {1} ([{0}]) from (select top {2} [{0}] from {3} where {5} {4} ) as tblTmp) and {5} {4}", + fieldNameToSort, strTemp, (pageIndex - 1) * pageSize, TableOrSqlWrapper, strOrder, strwhere); + } + } + + return sql; + } + + /// + /// 不依赖于存储过程的分页(MySql) + /// + /// 如果isDoCount为True,返回总数统计Sql;否则返回分页语句Sql + /// + private string GetMySqlSql(bool isDoCount) + { + string sql = ""; + if (string.IsNullOrEmpty(strwhere)) + { + strwhere = " (1=1) "; + } + + if (isDoCount) //执行总数统计 + { + sql = string.Format("select count(Id) as Total from {0} Where IsDeleted=0 and {1}", TableOrSqlWrapper, strwhere); + } + else + { + //SELECT * FROM 表名称 LIMIT M,N + string strOrder = string.Format(" order by {0} {1}", fieldNameToSort, isDescending ? "DESC" : "ASC"); + + int minRow = pageSize * (pageIndex - 1); + int maxRow = pageSize * pageIndex; + sql = string.Format( + "select {0} from {1} where Id IN(select t.Id from (select Id from {1} Where IsDeleted=0 and {2} )as t) {3} limit {4},{5};", + //"select {0} from {1} where Id IN(select t.Id from (select Id from {1} Where IsDeleted=0 and {2} {3} limit {4},{5})as t);", + fieldsToReturn, TableOrSqlWrapper, strwhere, strOrder, minRow, pageSize); + } + + return sql; + } + + /// + /// 不依赖于存储过程的分页(SQLite) + /// + /// 如果isDoCount为True,返回总数统计Sql;否则返回分页语句Sql + /// + private string GetSQLiteSql(bool isDoCount) + { + string sql = ""; + if (string.IsNullOrEmpty(strwhere)) + { + strwhere = " (1=1) "; + } + + if (isDoCount) //执行总数统计 + { + sql = string.Format("select count(*) as Total from {0} Where {1} ", TableOrSqlWrapper, strwhere); + } + else + { + //SELECT * FROM 表名称 LIMIT M,N + string strOrder = string.Format(" order by {0} {1}", fieldNameToSort, isDescending ? "DESC" : "ASC"); + + int minRow = pageSize * (pageIndex - 1); + int maxRow = pageSize * pageIndex; + sql = string.Format("select {0} from {1} Where {2} {3} LIMIT {4},{5}", + fieldsToReturn, TableOrSqlWrapper, strwhere, strOrder, minRow, pageSize); + } + + return sql; + } + + /// + /// 获取对应数据库的分页语句(指定数据库类型) + /// + /// 如果isDoCount为True,返回总数统计Sql;否则返回分页语句Sql + /// 数据库类型枚举 + public string GetPagingSql(bool isDoCount, DatabaseType dbType) + { + string sql = ""; + switch (dbType) + { + case DatabaseType.Access: + sql = GetAccessSql(isDoCount); + break; + + case DatabaseType.SqlServer: + sql = GetSqlServerSql(isDoCount); + break; + + case DatabaseType.Oracle: + sql = GetOracleSql(isDoCount); + break; + + case DatabaseType.MySql: + sql = GetMySqlSql(isDoCount); + break; + + case DatabaseType.SQLite: + sql = GetSQLiteSql(isDoCount); + break; + } + + return sql; + } + + /// + /// 数据库类型 + /// + /// + /// + private DatabaseType GetDataBaseType(string databaseType) + { + DatabaseType returnValue = DatabaseType.SqlServer; + foreach (DatabaseType dbType in Enum.GetValues(typeof(DatabaseType))) + { + if (dbType.ToString().Equals(databaseType, StringComparison.OrdinalIgnoreCase)) + { + returnValue = dbType; + break; + } + } + + return returnValue; + } + + #endregion 各种数据库Sql分页查询,不依赖于存储过程 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Properties/PublishProfiles/FolderProfile.pubxml b/Znyc.Cloudcar.Admin.Commons/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..7c95673 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,14 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.1 + D:\netcorespace\YueGroup\publish\ + false + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Properties/Resources.Designer.cs b/Znyc.Cloudcar.Admin.Commons/Properties/Resources.Designer.cs new file mode 100644 index 0000000..3fd2159 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Properties/Resources.Designer.cs @@ -0,0 +1,378 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Znyc.Cloudcar.Admin.Commons.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Znyc.Cloudcar.Admin.Commons.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 参数中的字符\"{0}\"不是 {1} 进制数的有效字符。 的本地化字符串。 + /// + internal static string AnyRadixConvert_CharacterIsNotValid { + get { + return ResourceManager.GetString("AnyRadixConvert_CharacterIsNotValid", resourceCulture); + } + } + + /// + /// 查找类似 0 的本地化字符串。 + /// + internal static string AnyRadixConvert_Overflow { + get { + return ResourceManager.GetString("AnyRadixConvert_Overflow", resourceCulture); + } + } + + /// + /// 查找类似 缓存功能尚未初始化,未找到可用的 ICacheProvider 实现。 的本地化字符串。 + /// + internal static string Caching_CacheNotInitialized { + get { + return ResourceManager.GetString("Caching_CacheNotInitialized", resourceCulture); + } + } + + /// + /// 查找类似 标识为“{0}”的项重复定义 的本地化字符串。 + /// + internal static string ConfigFile_ItemKeyDefineRepeated { + get { + return ResourceManager.GetString("ConfigFile_ItemKeyDefineRepeated", resourceCulture); + } + } + + /// + /// 查找类似 名称为“{0}”的类型不存在 的本地化字符串。 + /// + internal static string ConfigFile_NameToTypeIsNull { + get { + return ResourceManager.GetString("ConfigFile_NameToTypeIsNull", resourceCulture); + } + } + + /// + /// 查找类似 请先初始化依赖注入服务,再使用OSharpContext.IocRegisterservices属性 的本地化字符串。 + /// + internal static string Context_BuildservicesFirst { + get { + return ResourceManager.GetString("Context_BuildservicesFirst", resourceCulture); + } + } + + /// + /// 查找类似 上下文初始化类型“{0}”不存在 的本地化字符串。 + /// + internal static string DbContextInitializerConfig_InitializerNotExists { + get { + return ResourceManager.GetString("DbContextInitializerConfig_InitializerNotExists", resourceCulture); + } + } + + /// + /// 查找类似 查询条件组中的操作类型错误,只能为And或者Or。 的本地化字符串。 + /// + internal static string Filter_GroupOperateError { + get { + return ResourceManager.GetString("Filter_GroupOperateError", resourceCulture); + } + } + + /// + /// 查找类似 指定的属性“{0}”在类型“{1}”中不存在。 的本地化字符串。 + /// + internal static string Filter_RuleFieldInTypeNotFound { + get { + return ResourceManager.GetString("Filter_RuleFieldInTypeNotFound", resourceCulture); + } + } + + /// + /// 查找类似 无法解析类型“{0}”的构造函数中类型为“{1}”的参数 的本地化字符串。 + /// + internal static string Ioc_CannotResolveservice { + get { + return ResourceManager.GetString("Ioc_CannotResolveservice", resourceCulture); + } + } + + /// + /// 查找类似 OSharp框架尚未初始化,请先初始化 的本地化字符串。 + /// + internal static string Ioc_FrameworkNotInitialized { + get { + return ResourceManager.GetString("Ioc_FrameworkNotInitialized", resourceCulture); + } + } + + /// + /// 查找类似 类型“{0}”的实现类型无法找到 的本地化字符串。 + /// + internal static string Ioc_ImplementationTypeNotFound { + get { + return ResourceManager.GetString("Ioc_ImplementationTypeNotFound", resourceCulture); + } + } + + /// + /// 查找类似 类型“{0}”中找不到合适参数的构造函数 的本地化字符串。 + /// + internal static string Ioc_NoConstructorMatch { + get { + return ResourceManager.GetString("Ioc_NoConstructorMatch", resourceCulture); + } + } + + /// + /// 查找类似 实现类型不能为“{0}”,因为该类型与注册为“{1}”的其他类型无法区分 的本地化字符串。 + /// + internal static string Ioc_TryAddIndistinguishableTypeToEnumerable { + get { + return ResourceManager.GetString("Ioc_TryAddIndistinguishableTypeToEnumerable", resourceCulture); + } + } + + /// + /// 查找类似 类型“{0}”不是仓储接口“IRepository<,>”的派生类。 的本地化字符串。 + /// + internal static string IocInitializerBase_TypeNotIRepositoryType { + get { + return ResourceManager.GetString("IocInitializerBase_TypeNotIRepositoryType", resourceCulture); + } + } + + /// + /// 查找类似 类型“{0}”不是操作单元“IUnitOfWork”的派生类。 的本地化字符串。 + /// + internal static string IocInitializerBase_TypeNotIUnitOfWorkType { + get { + return ResourceManager.GetString("IocInitializerBase_TypeNotIUnitOfWorkType", resourceCulture); + } + } + + /// + /// 查找类似 创建名称为“{0}”的日志实例时“{1}”返回空实例。 的本地化字符串。 + /// + internal static string Logging_CreateLogInstanceReturnNull { + get { + return ResourceManager.GetString("Logging_CreateLogInstanceReturnNull", resourceCulture); + } + } + + /// + /// 查找类似 MapperExtensions.Mapper不能为空,请先设置值 的本地化字符串。 + /// + internal static string Map_MapperIsNull { + get { + return ResourceManager.GetString("Map_MapperIsNull", resourceCulture); + } + } + + /// + /// 查找类似 当前Http上下文中不存在Request有效范围的Mef部件容器。 的本地化字符串。 + /// + internal static string Mef_HttpContextItems_NotFoundRequestContainer { + get { + return ResourceManager.GetString("Mef_HttpContextItems_NotFoundRequestContainer", resourceCulture); + } + } + + /// + /// 查找类似 指定对象中不存在名称为“{0}”的属性。 的本地化字符串。 + /// + internal static string ObjectExtensions_PropertyNameNotExistsInType { + get { + return ResourceManager.GetString("ObjectExtensions_PropertyNameNotExistsInType", resourceCulture); + } + } + + /// + /// 查找类似 指定名称“{0}”的属性类型不是“{1}”。 的本地化字符串。 + /// + internal static string ObjectExtensions_PropertyNameNotFixedType { + get { + return ResourceManager.GetString("ObjectExtensions_PropertyNameNotFixedType", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”的值必须在“{1}”与“{2}”之间。 的本地化字符串。 + /// + internal static string ParameterCheck_Between { + get { + return ResourceManager.GetString("ParameterCheck_Between", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”的值必须在“{1}”与“{2}”之间,且不能等于“{3}”。 的本地化字符串。 + /// + internal static string ParameterCheck_BetweenNotEqual { + get { + return ResourceManager.GetString("ParameterCheck_BetweenNotEqual", resourceCulture); + } + } + + /// + /// 查找类似 指定的目录路径“{0}”不存在。 的本地化字符串。 + /// + internal static string ParameterCheck_DirectoryNotExists { + get { + return ResourceManager.GetString("ParameterCheck_DirectoryNotExists", resourceCulture); + } + } + + /// + /// 查找类似 指定的文件路径“{0}”不存在。 的本地化字符串。 + /// + internal static string ParameterCheck_FileNotExists { + get { + return ResourceManager.GetString("ParameterCheck_FileNotExists", resourceCulture); + } + } + + /// + /// 查找类似 集合“{0}”中不能包含null的项 的本地化字符串。 + /// + internal static string ParameterCheck_NotContainsNull_Collection { + get { + return ResourceManager.GetString("ParameterCheck_NotContainsNull_Collection", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”的值不能为Guid.Empty 的本地化字符串。 + /// + internal static string ParameterCheck_NotEmpty_Guid { + get { + return ResourceManager.GetString("ParameterCheck_NotEmpty_Guid", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”的值必须大于“{1}”。 的本地化字符串。 + /// + internal static string ParameterCheck_NotGreaterThan { + get { + return ResourceManager.GetString("ParameterCheck_NotGreaterThan", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”的值必须大于或等于“{1}”。 的本地化字符串。 + /// + internal static string ParameterCheck_NotGreaterThanOrEqual { + get { + return ResourceManager.GetString("ParameterCheck_NotGreaterThanOrEqual", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”的值必须小于“{1}”。 的本地化字符串。 + /// + internal static string ParameterCheck_NotLessThan { + get { + return ResourceManager.GetString("ParameterCheck_NotLessThan", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”的值必须小于或等于“{1}”。 的本地化字符串。 + /// + internal static string ParameterCheck_NotLessThanOrEqual { + get { + return ResourceManager.GetString("ParameterCheck_NotLessThanOrEqual", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”不能为空引用。 的本地化字符串。 + /// + internal static string ParameterCheck_NotNull { + get { + return ResourceManager.GetString("ParameterCheck_NotNull", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”不能为空引用或空集合。 的本地化字符串。 + /// + internal static string ParameterCheck_NotNullOrEmpty_Collection { + get { + return ResourceManager.GetString("ParameterCheck_NotNullOrEmpty_Collection", resourceCulture); + } + } + + /// + /// 查找类似 参数“{0}”不能为空引用或空字符串。 的本地化字符串。 + /// + internal static string ParameterCheck_NotNullOrEmpty_String { + get { + return ResourceManager.GetString("ParameterCheck_NotNullOrEmpty_String", resourceCulture); + } + } + + /// + /// 查找类似 类型“{0}”不是实体类型 的本地化字符串。 + /// + internal static string QueryCacheExtensions_TypeNotEntityType { + get { + return ResourceManager.GetString("QueryCacheExtensions_TypeNotEntityType", resourceCulture); + } + } + } +} diff --git a/Znyc.Cloudcar.Admin.Commons/Properties/Resources.resx b/Znyc.Cloudcar.Admin.Commons/Properties/Resources.resx new file mode 100644 index 0000000..d73928a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Properties/Resources.resx @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 参数中的字符\"{0}\"不是 {1} 进制数的有效字符。 + + + 0 + + + 缓存功能尚未初始化,未找到可用的 ICacheProvider 实现。 + + + 标识为“{0}”的项重复定义 + + + 名称为“{0}”的类型不存在 + + + 请先初始化依赖注入服务,再使用OSharpContext.IocRegisterservices属性 + + + 上下文初始化类型“{0}”不存在 + + + 查询条件组中的操作类型错误,只能为And或者Or。 + + + 指定的属性“{0}”在类型“{1}”中不存在。 + + + 类型“{0}”不是仓储接口“IRepository<,>”的派生类。 + + + 类型“{0}”不是操作单元“IUnitOfWork”的派生类。 + + + 无法解析类型“{0}”的构造函数中类型为“{1}”的参数 + + + OSharp框架尚未初始化,请先初始化 + + + 类型“{0}”的实现类型无法找到 + {0}=service type + + + 类型“{0}”中找不到合适参数的构造函数 + + + 实现类型不能为“{0}”,因为该类型与注册为“{1}”的其他类型无法区分 + + + 创建名称为“{0}”的日志实例时“{1}”返回空实例。 + + + MapperExtensions.Mapper不能为空,请先设置值 + + + 当前Http上下文中不存在Request有效范围的Mef部件容器。 + + + 指定对象中不存在名称为“{0}”的属性。 + + + 指定名称“{0}”的属性类型不是“{1}”。 + + + 参数“{0}”的值必须在“{1}”与“{2}”之间。 + + + 参数“{0}”的值必须在“{1}”与“{2}”之间,且不能等于“{3}”。 + + + 指定的目录路径“{0}”不存在。 + + + 指定的文件路径“{0}”不存在。 + + + 集合“{0}”中不能包含null的项 + + + 参数“{0}”的值不能为Guid.Empty + + + 参数“{0}”的值必须大于“{1}”。 + + + 参数“{0}”的值必须大于或等于“{1}”。 + + + 参数“{0}”的值必须小于“{1}”。 + + + 参数“{0}”的值必须小于或等于“{1}”。 + + + 参数“{0}”不能为空引用。 + + + 参数“{0}”不能为空引用或空集合。 + + + 参数“{0}”不能为空引用或空字符串。 + + + 类型“{0}”不是实体类型 + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Result/ResultOutPut.cs b/Znyc.Cloudcar.Admin.Commons/Result/ResultOutPut.cs new file mode 100644 index 0000000..cea9ae5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Result/ResultOutPut.cs @@ -0,0 +1,134 @@ +using System; +using System.Runtime.Serialization; + +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// 公共返回结果对象 + /// + [Serializable] + public class CommonResult + { + /// + /// 错误代码 + /// + private string m_ErrCode = "-1"; + + /// + /// 错误描述信息 + /// + private string m_ErrMsg; + + /// + /// 用来传递的object内容 + /// + [DataMember] private object m_ResData; + + /// + /// 成功或失败 + /// + private bool m_Success; + + /// + /// BaseResult构造函数 + /// + public CommonResult() + { + } + + /// + /// BaseResult构造函数 + /// + /// 错误消息 + /// 错误代码 + public CommonResult(string errmsg, string errcode) + { + ErrMsg = errmsg; + ErrCode = errcode; + } + + /// + /// 构造函数 + /// + /// 错误消息 + /// 成功或失败 + /// 错误代码 + public CommonResult(string errmsg, bool success, string errcode) + { + ErrMsg = errmsg; + ErrCode = errcode; + Success = success; + } + + /// + /// 错误代码 + /// + [DataMember] + public string ErrCode + { + get => m_ErrCode; + set + { + m_ErrCode = value; + if (value == "0") + { + Success = m_Success = true; + } + else + { + Success = m_Success = false; + } + } + } + + /// + /// 如果不成功,返回的错误描述信息 + /// + [DataMember] + public string ErrMsg + { + get => m_ErrMsg; + set => m_ErrMsg = value; + } + + /// + /// 成功返回true,失败返回false + /// + [DataMember] + public bool Success + { + get + { + if (ErrCode == "0") + { + m_Success = true; + } + + return m_Success; + } + set => m_Success = value; + } + + /// + /// 用来传递的object内容 + /// + [DataMember] + public object ResData + { + get => m_ResData; + set => m_ResData = value; + } + } + + /// + /// WEBAPI通用返回泛型基类 + /// + /// + public class CommonResult : CommonResult + { + /// + /// 回传的结果 + /// + public T Result { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Result/TokenResult.cs b/Znyc.Cloudcar.Admin.Commons/Result/TokenResult.cs new file mode 100644 index 0000000..e2b127f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Result/TokenResult.cs @@ -0,0 +1,31 @@ +namespace Znyc.Cloudcar.Admin.Commons.Entitys +{ + /// + /// Token返回结果对象 + /// + public class TokenResult + { + /// + /// 获取到的凭证值 + /// + public string AccessToken { get; set; } + + /// + /// 凭证有效时间,单位:分钟 + /// + public int ExpiresIn { get; set; } + } + + public class GrantType + { + /// + /// 密码校验。 + /// + public const string Password = "password"; + + /// + /// ClientCredential。 + /// + public const string ClientCredentials = "client_credential"; + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Tree/JsTree.cs b/Znyc.Cloudcar.Admin.Commons/Tree/JsTree.cs new file mode 100644 index 0000000..55e6991 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Tree/JsTree.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.Json; + +namespace Znyc.Cloudcar.Admin.Commons.Tree +{ + public static class JsTree + { + public static List JsTreeJson(this List data) + { + return JsTreeJson(data, 0, "").ToList(); + } + + private static string JsTreeJson(List data, long ParentId, string blank) + { + List list = new List(); + JsTreeModel jsTreeModel = new JsTreeModel(); + List ChildNodeList = data.FindAll(t => t.parent == ParentId); + string tabline = ""; + if (!string.IsNullOrEmpty(ParentId.ToString())) + { + tabline = ""; + } + + if (ChildNodeList.Count > 0) + { + tabline = tabline + blank; + } + + foreach (JsTreeModel entity in ChildNodeList) + { + jsTreeModel = entity; + jsTreeModel.children = JsTreeJson(data, entity.id, tabline).ToList(); + list.Add(jsTreeModel); + } + + return list.ToJson(); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Tree/JsTreeModel.cs b/Znyc.Cloudcar.Admin.Commons/Tree/JsTreeModel.cs new file mode 100644 index 0000000..777927d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Tree/JsTreeModel.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Commons.Tree +{ + /// + /// JsTree 数据模型实体 + /// { + /// id : "string" // required + /// parent : "string" // required + /// text : "string" // node text + /// icon : "string" // string for custom + /// state : { + /// opened : boolean // is the node open + /// disabled : boolean // is the node disabled + /// selected : boolean // is the node selected + /// }, + /// li_attr : {} // attributes for the generated LI node + /// a_attr : {} // attributes for the generated A node + /// } + /// + public class JsTreeModel + { + public long id { get; set; } + public long parent { get; set; } + public string text { get; set; } + public string icon { get; set; } + public JsTreeStateModel state { get; set; } + public List children { get; set; } + } + + public class JsTreeStateModel + { + public bool opened { get; set; } + public bool disabled { get; set; } + public bool selected { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Tree/TreeSelect.cs b/Znyc.Cloudcar.Admin.Commons/Tree/TreeSelect.cs new file mode 100644 index 0000000..01b91e7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Tree/TreeSelect.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Text; +using Znyc.Cloudcar.Admin.Commons.Json; + +namespace Znyc.Cloudcar.Admin.Commons.Tree +{ + /// + /// + public static class TreeSelect + { + /// + /// + /// + /// + public static string TreeSelectJson(this List data) + { + StringBuilder sb = new StringBuilder(); + sb.Append("["); + sb.Append(TreeSelectJson(data, 0, "")); + sb.Append("]"); + return sb.ToString(); + } + + /// + /// + /// + /// + /// + /// + private static string TreeSelectJson(List data, int ParentId, string blank) + { + StringBuilder sb = new StringBuilder(); + List ChildNodeList = data.FindAll(t => t.ParentId == ParentId); + string tabline = ""; + if (!string.IsNullOrEmpty(ParentId.ToString())) + { + tabline = "  "; + } + + if (ChildNodeList.Count > 0) + { + tabline = tabline + blank; + } + + foreach (TreeSelectModel entity in ChildNodeList) + { + entity.text = tabline + entity.text; + string strJson = entity.ToJson(); + sb.Append(strJson); + sb.Append(TreeSelectJson(data, entity.Id, tabline)); + } + + return sb.ToString().Replace("}{", "},{"); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Tree/TreeSelectModel.cs b/Znyc.Cloudcar.Admin.Commons/Tree/TreeSelectModel.cs new file mode 100644 index 0000000..199d58b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Tree/TreeSelectModel.cs @@ -0,0 +1,27 @@ +namespace Znyc.Cloudcar.Admin.Commons.Tree +{ + /// + /// + public class TreeSelectModel + { + /// + /// + public int Id { get; set; } + + /// + /// + public string text { get; set; } + + /// + /// + public int ParentId { get; set; } + + /// + /// + public int ParentId1 { get; set; } + + /// + /// + public object data { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Tree/TreeView.cs b/Znyc.Cloudcar.Admin.Commons/Tree/TreeView.cs new file mode 100644 index 0000000..fc6d31a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Tree/TreeView.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.Text; + +namespace Znyc.Cloudcar.Admin.Commons.Tree +{ + /// + /// + public static class TreeView + { + /// + /// + /// + /// + /// + public static string TreeViewJson(this List data, int ParentId = 0) + { + StringBuilder strJson = new StringBuilder(); + //List item = data.FindAll(t => t.ParentId == ParentId); + //strJson.Append("["); + //if (item.Count > 0) + //{ + // foreach (TreeViewModel entity in item) + // { + // strJson.Append("{"); + // strJson.Append("\"id\":\"" + entity.id + "\","); + // strJson.Append("\"text\":\"" + entity.text.Replace(" ", "") + "\","); + // strJson.Append("\"value\":\"" + entity.value + "\","); + // if (entity.title != null && !string.IsNullOrEmpty(entity.title.Replace(" ", ""))) + // { + // strJson.Append("\"title\":\"" + entity.title.Replace(" ", "") + "\","); + // } + // if (entity.img != null && !string.IsNullOrEmpty(entity.img.Replace(" ", ""))) + // { + // strJson.Append("\"img\":\"" + entity.img.Replace(" ", "") + "\","); + // } + // if (entity.checkstate != null) + // { + // strJson.Append("\"checkstate\":" + entity.checkstate + ","); + // } + // if (entity.ParentId != null) + // { + // strJson.Append("\"parentnodes\":\"" + entity.ParentId + "\","); + // } + // strJson.Append("\"showcheck\":" + entity.showcheck.ToString().ToLower() + ","); + // strJson.Append("\"isexpand\":" + entity.isexpand.ToString().ToLower() + ","); + // if (entity.complete == true) + // { + // strJson.Append("\"complete\":" + entity.complete.ToString().ToLower() + ","); + // } + // strJson.Append("\"hasChildren\":" + entity.hasChildren.ToString().ToLower() + ","); + // strJson.Append("\"ChildNodes\":" + TreeViewJson(data, entity.id) + ""); + // strJson.Append("},"); + // } + // strJson = strJson.Remove(strJson.Length - 1, 1); + //} + //strJson.Append("]"); + return strJson.ToString(); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Tree/TreeViewModel.cs b/Znyc.Cloudcar.Admin.Commons/Tree/TreeViewModel.cs new file mode 100644 index 0000000..644358f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Tree/TreeViewModel.cs @@ -0,0 +1,114 @@ +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Commons.Tree +{ + /// + /// 树形视图模型 + /// + public class TreeViewModel + { + /// + /// 构造函数 + /// + public TreeViewModel() + { + nodes = new List(); + } + + /// + /// 构造函数 + /// + /// j节点Id + /// 父节点Id + public TreeViewModel(int nodeId, int pId) + { + this.nodeId = nodeId; + pid = pId; + nodes = new List(); + } + + /** + * 生成一个节点 + * @param nodeId + * @param pId + * @param text + * @param icon + * @param href + */ + public TreeViewModel(int nodeId, int pId, string text, string icon, string href) + { + this.nodeId = nodeId; + pid = pId; + this.text = text; + this.icon = icon; + this.href = href; + nodes = new List(); + } + + /// + /// 树的节点Id,区别于数据库中保存的数据Id + /// + public long nodeId { get; set; } + + /// + /// 树的父节点Id + /// + public long pid { get; set; } + + /// + /// 节点名称 + /// + public string text { get; set; } + + /// + /// 节点图标 + /// + public string icon { get; set; } + + /// + /// 点击节点触发的链接 + /// + public string href { get; set; } + + /// + /// 子节点 + /// + public List nodes { get; set; } + + /// + /// 节点标签 + /// + public long tags { get; set; } + + /// + /// 节点状态 + /// + public TreeViewSateModel state { get; set; } + } + + /// + /// 树形视图节点选择状态 + /// + public class TreeViewSateModel + { + /// + /// 选中 + /// + public bool @checked { get; set; } + + /// + /// 显示或隐藏 + /// + public bool? disabled { get; set; } + + /// + /// 展开 + /// + public bool? expanded { get; set; } + + /// + /// 选中 + /// + public bool? selected { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Tree/VueRouterModel.cs b/Znyc.Cloudcar.Admin.Commons/Tree/VueRouterModel.cs new file mode 100644 index 0000000..3976ba4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Tree/VueRouterModel.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Commons.Tree +{ + /// + /// Vuex菜单模型 + /// + [Serializable] + public class VueRouterModel + { + /// + /// 设定路由的名字,一定要填写不然使用keep-alive时会出现各种问题 + /// + public string name { get; set; } + + /// + /// 路由地址,对应当前路由的路径,总是解析为绝对路径 + /// + public string path { get; set; } + + /// + /// 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 + /// + public bool hidden { get; set; } + + /// + /// 命名视图组件,组件地址 + /// + public string component { get; set; } + + /// + /// 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + /// + public string redirect { get; set; } + + /// + /// 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + /// + public bool alwaysShow { get; set; } + + /// + /// 在根路由设置权限,这样它下面所以的子路由都继承了这个权限 + /// + public Meta meta { get; set; } + + /// + /// 子路由,子菜单 + /// + public List children { get; set; } + } + + /// + /// 路由元信息模型 + /// + [Serializable] + public class Meta + { + /// + /// 构造函数 + /// + /// + /// + /// + public Meta(string title, string icon, bool noCache) + { + this.title = title; + this.icon = icon; + this.noCache = noCache; + } + + /// + /// 设置该路由在侧边栏和面包屑中展示的名字 + /// + public string title { get; set; } + + /// + /// 设置该路由的图标 + /// + public string icon { get; set; } + + /// + /// 设置为true,则不会被keep-alive缓存 + /// + public bool noCache { get; set; } + + /// + /// 当路由设置了该属性,则会高亮相对应的侧边栏。 + /// 这在某些场景非常有用,比如:一个文章的列表页路由为:/article/list + /// 点击文章进入文章详情页,这时候路由为/article/1,但你想在侧边栏高亮文章列表的路由,就可以进行如下设置 + /// activeMenu: '/article/list' + /// + public string activeMenu { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Commons/Znyc.Cloudcar.Admin.Commons.csproj b/Znyc.Cloudcar.Admin.Commons/Znyc.Cloudcar.Admin.Commons.csproj new file mode 100644 index 0000000..0e7f8d7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Commons/Znyc.Cloudcar.Admin.Commons.csproj @@ -0,0 +1,174 @@ + + + + net6.0 + Znyc.Admin + + + + + true + + 1.0 + true + + + + + 1.3.1.32 + MIT + + + + bin\Debug\Znyc.Recruitment.Admin.Commons.xml + bin\Debug\ + + + + bin\Release\ + bin\Release\Znyc.Recruitment.Admin.Commons.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Hangfire/HangfireDispose.cs b/Znyc.Cloudcar.Admin.Hangfire/HangfireDispose.cs new file mode 100644 index 0000000..ddcb489 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Hangfire/HangfireDispose.cs @@ -0,0 +1,43 @@ +using Hangfire; + +namespace Znyc.Cloudcar.Admin.Hangfire +{ + public class HangfireDispose + { + public static void HangfireService() + { + //Fire - And - forget(发布 / 订阅) + //这是一个主要的后台任务类型,持久化消息队列会去处理这个任务。当你创建了一个发布 / 订阅任务,该任务会被保存到默认队列里面(默认队列是"Default",但是支持使用多队列)。多个专注的工作者(Worker)会监听这个队列,并且从中获取任务并且完成任务。 + //BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget")); + + //延迟 + //如果想要延迟某些任务的执行,可以是用以下任务。在给定延迟时间后,任务会被排入队列,并且和发布 / 订阅任务一样执行。 + //BackgroundJob.Schedule(() => Console.WriteLine("Delayed"), TimeSpan.FromDays(1)); + + //循环 + //按照周期性(小时,天等)来调用方法,请使用RecurringJob类。在复杂的场景,您可以使用CRON表达式指定计划时间来处理任务。 + //RecurringJob.AddOrUpdate(() => Console.WriteLine("Daily Job"), Cron.Daily); + + //连续 + //连续性允许您通过将多个后台任务链接在一起来定义复杂的工作流。 + //var id = BackgroundJob.Enqueue(() => Console.WriteLine("Hello, ")); + //BackgroundJob.ContinueWith(id, () => Console.WriteLine("world!")); + + //这里呢就是需要触发的方法 "0/10 * * * * ? " 可以自行搜索cron表达式 代表循环的规律很简单 + //CancelOrderJob代表你要触发的类 Execute代表你要触发的方法 + + + //每晚添加统计数据 + //每日23:55:00执行一次 + // RecurringJob.AddOrUpdate(s => s.InsertStatisticalExecute(), "0 55 23 * * ?", TimeZoneInfo.Local); + + //每日修改广告状态 + //每天6点20点各执行一次 + // RecurringJob.AddOrUpdate(s => s.UpdateBannerStatusExecute(), "0 0 6,20 * * ?", TimeZoneInfo.Local); + + //每日修改活动状态 + //每天6点20点各执行一次 + // RecurringJob.AddOrUpdate(s => s.UpdateActivityStatusExecute(), "0 0 6,20 * * ?", TimeZoneInfo.Local); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoActivityJob.cs b/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoActivityJob.cs new file mode 100644 index 0000000..22dfbc5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoActivityJob.cs @@ -0,0 +1,24 @@ +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Hangfire +{ + public class AutoActivityJob + { + private readonly IActivityService _activityService; + + public AutoActivityJob(IActivityService activityService) + { + _activityService = activityService; + } + + /// + /// 修改活动状态 + /// + /// + public async Task UpdateActivityStatusExecute() + { + await _activityService.UpdateStatusAsync(); + } + + } +} diff --git a/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoBannerJob.cs b/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoBannerJob.cs new file mode 100644 index 0000000..d561add --- /dev/null +++ b/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoBannerJob.cs @@ -0,0 +1,24 @@ +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Hangfire +{ + public class AutoBannerJob + { + private readonly IBannerService _bannerService; + + public AutoBannerJob(IBannerService bannerService) + { + _bannerService = bannerService; + } + + /// + /// 修改广告状态 + /// + /// + public async Task UpdateBannerStatusExecute() + { + await _bannerService.UpdateStatusAsync(); + } + + } +} diff --git a/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoStatisticalJob.cs b/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoStatisticalJob.cs new file mode 100644 index 0000000..931cebc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Hangfire/TaskJobs/AutoStatisticalJob.cs @@ -0,0 +1,24 @@ +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Hangfire +{ + public class AutoStatisticalJob + { + private readonly IStatisticalService _statisticalService; + + public AutoStatisticalJob(IStatisticalService statisticalService) + { + _statisticalService = statisticalService; + } + + /// + /// 添加统计数据 + /// + /// + public async Task InsertStatisticalExecute() + { + await _statisticalService.InsertAsync(); + } + + } +} diff --git a/Znyc.Cloudcar.Admin.Hangfire/Znyc.Cloudcar.Admin.Hangfire.csproj b/Znyc.Cloudcar.Admin.Hangfire/Znyc.Cloudcar.Admin.Hangfire.csproj new file mode 100644 index 0000000..a14d5d7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Hangfire/Znyc.Cloudcar.Admin.Hangfire.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/Znyc.Cloudcar.Admin.MongoDb/Collection/GpsRealTime.cs b/Znyc.Cloudcar.Admin.MongoDb/Collection/GpsRealTime.cs new file mode 100644 index 0000000..b75005f --- /dev/null +++ b/Znyc.Cloudcar.Admin.MongoDb/Collection/GpsRealTime.cs @@ -0,0 +1,66 @@ +using MongoDB.Bson.Serialization.Attributes; +using Pursue.Extension.MongoDB; +using System; + +namespace Znyc.Cloudcar.Admin.MongoDb.Core.Collection +{ + public class GpsRealTime : MongoEntityPrimaryKey + { + private int _acc; + + private string _accDurationTime; + public long VehicleId { get; set; } + public string VehicleCode { get; set; } + public string VehiclePlate { get; set; } + + public long VehicleDriver { get; set; } + public string DriverPhone { get; set; } + public int State { get; set; } + public int GpsState { get; set; } + + /// + /// Gps数据产生时间 + /// + [BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)] + public DateTime GpsTime { get; set; } + + /// + /// Gps服务器接收时间 + /// + [BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)] + public DateTime RecTime { get; set; } + + public decimal Longitude { get; set; } + public decimal Latitude { get; set; } + public int Direct { get; set; } + public int Speed { get; set; } + public string DurationTime { get; set; } + + public int Acc + { + get => GpsState == 0 ? 0 : _acc; + set => _acc = value; + } + + public string AccDurationTime + { + get => GpsState == 0 ? DurationTime : _accDurationTime; + set => _accDurationTime = value; + } + + public string Address { get; set; } + public string SimNo { get; set; } + public long CompanyId { get; set; } + + [BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)] + public DateTime ModifiedTime { get; set; } + + [BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)] + public DateTime CreatedTime { get; set; } + + /// + /// 设备号 + /// + public string TerminalNo { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.MongoDb/IRepositorys/IGpsRealTimeRepository.cs b/Znyc.Cloudcar.Admin.MongoDb/IRepositorys/IGpsRealTimeRepository.cs new file mode 100644 index 0000000..522a2bd --- /dev/null +++ b/Znyc.Cloudcar.Admin.MongoDb/IRepositorys/IGpsRealTimeRepository.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.MongoDb.Core.Collection; + +namespace Znyc.Cloudcar.Admin.MongoDb.Core.IRepositorys +{ + public interface IGpsRealTimeRepository + + { + Task InsertGpsRealTime(GpsRealTime gpsRealTime); + + Task GetGpsRealTime(long vehicleId); + + Task UpdateGpsRealTime(GpsRealTime gpsRealTime); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.MongoDb/MongoContext.cs b/Znyc.Cloudcar.Admin.MongoDb/MongoContext.cs new file mode 100644 index 0000000..fabae71 --- /dev/null +++ b/Znyc.Cloudcar.Admin.MongoDb/MongoContext.cs @@ -0,0 +1,22 @@ +using MongoDB.Driver; +using Pursue.Extension.MongoDB; +using Znyc.Cloudcar.Admin.MongoDb.Core.Collection; + +namespace Znyc.Cloudcar.Admin.MongoDb +{ + public class MongoContext : MongoDbContext + { + // 使用默认构造(DI配置) + public MongoContext() + { + } + + // 也可以使用手工配置 + public MongoContext(string Link, string DataBaseName) : base(Link, DataBaseName) + { + } + + // 上下文模式可以注入需要操作的实体对象和EF一样 + public IMongoCollection GpsRealTime => DbSet(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.MongoDb/Repositorys/GpsRealTimeRepository.cs b/Znyc.Cloudcar.Admin.MongoDb/Repositorys/GpsRealTimeRepository.cs new file mode 100644 index 0000000..789a51a --- /dev/null +++ b/Znyc.Cloudcar.Admin.MongoDb/Repositorys/GpsRealTimeRepository.cs @@ -0,0 +1,35 @@ +using Pursue.Extension.MongoDB; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.MongoDb.Core.Collection; +using Znyc.Cloudcar.Admin.MongoDb.Core.IRepositorys; + +namespace Znyc.Cloudcar.Admin.MongoDb.Core.Repositorys +{ + public class GpsRealTimeRepository : IGpsRealTimeRepository + { + private readonly IMongoDbRepository _gpsRealTimemongoDbRepository; + + public GpsRealTimeRepository(IMongoDbService context) + { + _gpsRealTimemongoDbRepository = context.GetRepository(); + } + + public async Task InsertGpsRealTime(GpsRealTime gpsRealTime) + { + await _gpsRealTimemongoDbRepository.AddAsync(gpsRealTime); + return true; + } + + public async Task GetGpsRealTime(long vehicleId) + { + GpsRealTime gpsRealTime = await _gpsRealTimemongoDbRepository.QueryOneAsync(x => x.VehicleId == vehicleId); + return gpsRealTime; + } + + public async Task UpdateGpsRealTime(GpsRealTime gpsRealTime) + { + await _gpsRealTimemongoDbRepository.UpdateAsync(gpsRealTime.Id.ToString(), gpsRealTime); + return true; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.MongoDb/Znyc.Cloudcar.Admin.MongoDb.Core.csproj b/Znyc.Cloudcar.Admin.MongoDb/Znyc.Cloudcar.Admin.MongoDb.Core.csproj new file mode 100644 index 0000000..b32f8d2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.MongoDb/Znyc.Cloudcar.Admin.MongoDb.Core.csproj @@ -0,0 +1,10 @@ + + + + net6.0 + + + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Application/AreaApp.cs b/Znyc.Cloudcar.Admin.Security.Core/Application/AreaApp.cs new file mode 100644 index 0000000..704c850 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Application/AreaApp.cs @@ -0,0 +1,279 @@ +using Newtonsoft.Json; +using System.Collections.Generic; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Tree; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.Repositories; + +namespace Znyc.Cloudcar.Admin.Security.Application +{ + /// + /// 地区 + /// + public class AreaApp + { + private readonly IAreaRepository service = new AreaRepository(); + + #region 适配于管理后端 + + /// + /// 树形展开treeview需要,数据字典管理页面 + /// + /// + public List ItemsTreeViewJson() + { + List list = new List(); + List listFunction = service.GetListWhere("Layers in (0,1,2)").OrderBy(t => t.SortCode).ToList(); + list = TreeViewJson(listFunction, 0); + return list; + } + + //public List AreaTreeViewJson() + //{ + //string where = "1=1 and Layers in(0,1,2)"; + //bool order = orderByDir == "asc" ? false : true; + //if (!string.IsNullOrEmpty(keywords)) + //{ + // where += string.Format(" and (FullName like '%{0}%' or EnCode like '%{0}%')", keywords); + //} + //List list = _service.GetListWhere(where).OrderBy(t => t.SortCode).ToList().MapTo(); + + //return ToJsonContent(list); + + //List list = new List(); + //List listFunction = service.GetListWhere("Layers in (3,4)").OrderBy(t => t.SortCode).ToList(); + //list = TreeViewJson(listFunction, ""); + //return list; + //} + /// + /// + /// + /// + /// + public List TreeViewJson(List data, long ParentId) + { + List list = new List(); + List ChildNodeList = data.FindAll(t => t.ParentId == ParentId).ToList(); + foreach (AreaEntity entity in ChildNodeList) + { + TreeViewModel treeViewModel = new TreeViewModel + { + nodeId = entity.Id, + pid = entity.ParentId, + text = entity.FullName, + nodes = ChildrenTreeViewList(data, entity.Id), + tags = entity.Id + }; + list.Add(treeViewModel); + } + + return list; + } + + /// + /// + /// + /// + /// + public List ChildrenTreeViewList(List data, long ParentId) + { + List listChildren = new List(); + List ChildNodeList = data.FindAll(t => t.ParentId == ParentId).ToList(); + foreach (AreaEntity entity in ChildNodeList) + { + TreeViewModel treeViewModel = new TreeViewModel + { + nodeId = entity.Id, + pid = entity.ParentId, + text = entity.FullName, + nodes = ChildrenTreeViewList(data, entity.Id), + tags = entity.Id + }; + listChildren.Add(treeViewModel); + } + + return listChildren; + } + + #endregion 适配于管理后端 + + #region 用于uniapp下拉选项 + + /// + /// 获取所有可用的地区,用于uniapp下拉选项 + /// + /// + public List GetAllByEnable() + { + List list = new List(); + CacheHelper cacheHelper = new CacheHelper(); + list = JsonConvert.DeserializeObject>(cacheHelper.Get("Area_Enable_Uniapp") + .ToJson()); + if (list == null || list.Count <= 0) + { + List listFunction = service.GetAllByIsNotDeleteAndEnabledMark("Layers in (0,1,2)") + .OrderBy(t => t.SortCode).ToList(); + list = UniappViewJson(listFunction, 0); + cacheHelper.Add("Area_Enable_Uniapp", list); + } + + return list; + } + + /// + /// 获取省、市、县/区三级可用的地区,用于uniapp下拉选项 + /// + /// + public List GetProvinceToAreaByEnable() + { + List list = new List(); + CacheHelper cacheHelper = new CacheHelper(); + list = JsonConvert.DeserializeObject>(cacheHelper + .Get("Area_ProvinceToArea_Enable_Uniapp").ToJson()); + if (list == null || list.Count <= 0) + { + List listFunctionTemp = service.GetAllByIsNotDeleteAndEnabledMark("Layers in (1,2,3)").OrderBy(t => t.Id) + .ToList(); + List listFunction = new List(); + foreach (AreaEntity item in listFunctionTemp) + { + if (item.Layers == 1) + { + item.ParentId = 0; + } + + listFunction.Add(item); + } + + list = UniappViewJson(listFunction, 0); + cacheHelper.Add("Area_ProvinceToArea_Enable_Uniapp", list); + } + + return list; + } + + /// + /// + /// + /// + /// + public List UniappViewJson(List data, long ParentId) + { + List list = new List(); + List ChildNodeList = data.FindAll(t => t.ParentId == ParentId).ToList(); + foreach (AreaEntity entity in ChildNodeList) + { + AreaPickerOutputDto treeViewModel = new AreaPickerOutputDto + { + value = entity.Id, + label = entity.FullName, + children = ChildrenUniappViewList(data, entity.Id) + }; + list.Add(treeViewModel); + } + + return list; + } + + /// + /// + /// + /// + /// + public List ChildrenUniappViewList(List data, long ParentId) + { + List listChildren = new List(); + List ChildNodeList = data.FindAll(t => t.ParentId == ParentId).ToList(); + foreach (AreaEntity entity in ChildNodeList) + { + AreaPickerOutputDto treeViewModel = new AreaPickerOutputDto + { + value = entity.Id, + label = entity.FullName, + children = ChildrenUniappViewList(data, entity.Id) + }; + listChildren.Add(treeViewModel); + } + + return listChildren; + } + + #endregion 用于uniapp下拉选项 + + #region 适用于select2省市县区级联选择 + + /// + /// 获取省可用的地区,用于select2下拉选项 + /// + /// + public List GetProvinceAll() + { + List list = new List(); + CacheHelper cacheHelper = new CacheHelper(); + list = JsonConvert.DeserializeObject>(cacheHelper + .Get("Area_ProvinceToArea_Select2").ToJson()); + if (list == null || list.Count <= 0) + { + list = service.GetAllByIsNotDeleteAndEnabledMark("Layers =1").OrderBy(t => t.Id).ToList() + .MapTo(); + + cacheHelper.Add("Area_ProvinceToArea_Select2", list); + } + + return list; + } + + /// + /// 获取城市,用于select2下拉选项 + /// + /// 省份Id + /// + public List GetCityByProvinceId(long id) + { + List list = new List(); + CacheHelper cacheHelper = new CacheHelper(); + list = JsonConvert.DeserializeObject>(cacheHelper + .Get("Area_CityToArea_Enable_Select2" + id).ToJson()); + if (list == null || list.Count <= 0) + { + string sqlWhere = string.Format("ParentId='{0}'", id); + list = service.GetAllByIsNotDeleteAndEnabledMark(sqlWhere).OrderBy(t => t.Id).ToList() + .MapTo(); + + cacheHelper.Add("Area_CityToArea_Enable_Select2" + id, list); + } + + return list; + } + + /// + /// 获取县区,用于select2下拉选项 + /// + /// 城市Id + /// + public List GetDistrictByCityId(long id) + { + List list = new List(); + CacheHelper cacheHelper = new CacheHelper(); + list = JsonConvert.DeserializeObject>(cacheHelper + .Get("Area_DistrictToArea_Enable_Select2" + id).ToJson()); + if (list == null || list.Count <= 0) + { + string sqlWhere = string.Format("ParentId='{0}'", id); + list = service.GetAllByIsNotDeleteAndEnabledMark(sqlWhere).OrderBy(t => t.Id).ToList() + .MapTo(); + + cacheHelper.Add("Area_DistrictToArea_Enable_Select2" + id, list); + } + + return list; + } + + #endregion 适用于select2省市县区级联选择 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Application/MenuApp.cs b/Znyc.Cloudcar.Admin.Security.Core/Application/MenuApp.cs new file mode 100644 index 0000000..a94329a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Application/MenuApp.cs @@ -0,0 +1,441 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Core.App; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Tree; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Application +{ + /// + /// + public class MenuApp + { + private readonly IMenuService service = App.GetService(); + private readonly IAdminUserService serviceUser = App.GetService(); + private readonly ISystemTypeService systemservice = App.GetService(); + + /// + /// 获取菜单树JsTree模式 + /// + /// + public List MenuFuntionJsTree() + { + List list = new List(); + + List listMenu = service.GetAllByIsNotDeleteAndEnabledMark().OrderBy(t => t.SortCode).ToList(); + foreach (MenuEntity item in listMenu) + { + JsTreeModel jsTreeModel = new JsTreeModel + { + id = item.Id, + text = item.FullName, + icon = item.Icon, + parent = item.ParentId + }; + JsTreeStateModel jsTreeStateModel = new JsTreeStateModel + { + disabled = false, + selected = true, + opened = true + }; + jsTreeModel.state = jsTreeStateModel; + list.Add(jsTreeModel); + } + + return list.JsTreeJson(); + } + + /// + /// + /// + /// + public List GetMenu(long ParentId) + { + List list = new List(); + + return list; + } + + /// + /// 获取菜单树TreeView模式 + /// + /// + public List MenuFuntionTreeViewJson() + { + List list = new List(); + List listMenu = service.GetAll().OrderBy(t => t.SortCode).ToList(); + list = JsTreeJson(listMenu, 0, "").ToList(); + return list; + } + + /// + /// + /// + /// + /// + /// + private static string JsTreeJson(List data, long ParentId, string blank) + { + List list = new List(); + TreeViewModel jsTreeModel = new TreeViewModel(); + List ChildNodeList = data.FindAll(t => t.ParentId == ParentId); + string tabline = ""; + + if (ChildNodeList.Count > 0) + { + tabline = tabline + blank; + } + + foreach (MenuEntity entity in ChildNodeList) + { + jsTreeModel.text = entity.FullName; + jsTreeModel.icon = entity.Icon; + //list.Add(jsTreeModel); + jsTreeModel.nodes = JsTreeJson(data, entity.Id, tabline).ToList(); + list.Add(jsTreeModel); + } + + return list.ToJson(); + } + + /// + /// 根据用户角色获取菜单树VuexMenusTree模式 + /// + /// 角色ID + /// 系统类型代码子系统代码 + /// + public List GetMenuFuntionJson(long roleIds, string systemCode) + { + List list = new List(); + try + { + SystemTypeEntity systemType = systemservice.GetByCode(systemCode); + list = GetMenusByRole(roleIds, systemType.Id.ToString()).OrderBy(t => t.SortCode) + .MapTo(); + } + catch (Exception ex) + { + Log4NetHelper.Error("根据用户角色和子系统代码获取菜单异常", ex); + } + + return list; + } + + /// + /// 根据用户角色获取菜单树VuexMenusTree模式 + /// + /// 系统类型代码子系统代码 + /// + public List GetMenuFuntionJson(string systemCode) + { + List list = new List(); + try + { + SystemTypeEntity systemType = systemservice.GetByCode(systemCode); + List listMenu = GetMenusByRole(systemType.Id).OrderBy(t => t.SortCode).ToList(); + list = listMenu.MapTo(); + } + catch (Exception ex) + { + Log4NetHelper.Error("根据用户角色和子系统代码获取菜单异常", ex); + } + + return list; + } + + /// + /// 构建菜单树 + /// + /// 菜单列表 + /// 父级Id + /// + public List BuildTreeMenus(List menus, long ParentId = 0) + { + List resultList = new List(); + List childNodeList = menus.FindAll(t => t.ParentId == ParentId); + foreach (MenuEntity menu in childNodeList) + { + MenuOutputDto menuOutputDto = new MenuOutputDto(); + menuOutputDto = menu.MapTo(); + List subChildNodeList = menus.FindAll(t => t.ParentId == menu.Id); + if (subChildNodeList.Count > 0) + { + menuOutputDto.SubMenu = BuildTreeMenus(menus, menu.Id); + } + + resultList.Add(menuOutputDto); + } + + return resultList; + } + + /// + /// 根据用户获取功能菜单 + /// + /// 用户角色ID + /// 系统类型ID/子系统ID + /// + public List GetMenusByRole(long roleIds, string systemId) + { + List menuListResult = new List(); + if (roleIds == 0) + { + menuListResult = service.GetFunctions("", systemId, true); + } + else + { + // string roleIDsStr = string.Format("'{0}'", roleIds.Replace(",", "','")); + string roleIDsStr = ""; + menuListResult = service.GetFunctions(roleIDsStr, systemId, true); + } + + return menuListResult; + } + + /// + /// 根据用户获取功能菜单 + /// + /// 系统类型ID/子系统ID + /// + public List GetMenusByRole(long systemId) + { + List menuListResult = service + .GetAllByIsNotDeleteAndEnabledMark("MenuType in ('M','C') and SystemTypeId='" + systemId + "'") + .ToList(); + return menuListResult; + } + + /// + /// 根据用户ID,获取对应的功能列表 + /// + /// 用户ID + /// 系统类别ID + /// + public List GetFunctionsByUser(long userId, string typeID) + { + string roleId = serviceUser.Get(userId).RoleId.ToString(); + List functions = new List(); + string roleIDsStr = string.Format("'{0}'", roleId.Replace(",", "','")); + if (roleIDsStr != "") + { + functions = service.GetFunctions(roleIDsStr, typeID).ToList().MapTo(); + } + + return functions; + } + + /// + /// 根据用户角色IDs,获取对应的功能列表 + /// + /// 用户角色ID + /// 系统类型ID/子系统ID + /// + public List GetFunctionsByRole(string roleIds, string systemId) + { + List functions = new List(); + string roleIDsStr = string.Format("'{0}'", roleIds.Replace(",", "','")); + if (roleIDsStr != "") + { + functions = service.GetFunctions(roleIDsStr, systemId).ToList().MapTo(); + } + + return functions; + } + + /// + /// 根据用户角色IDs,获取对应的功能列表 + /// + /// 系统类型ID/子系统ID + /// + public List GetFunctionsBySystem(string systemId) + { + List functions = new List(); + functions = service.GetFunctions(systemId).ToList().MapTo(); + return functions; + } + + #region 获取 Vue Router + + /// + /// 根据用户角色获取菜单树VueRouter模式 + /// + /// 角色ID + /// 系统类型代码子系统代码 + /// + public List GetVueRouter(long roleIds, string systemCode) + { + List list = new List(); + try + { + SystemTypeEntity systemType = systemservice.GetByCode(systemCode); + List listMenu = GetMenusByRole(roleIds, systemType.Id.ToString()).OrderBy(t => t.SortCode).ToList(); + List listTree = BuildTreeMenus(listMenu); + list = BuildMenus(listTree); + } + catch (Exception ex) + { + Log4NetHelper.Error("根据用户角色和子系统代码获取菜单异常", ex); + } + + return list; + } + + /// + /// 构建前端路由所需要的菜单 + /// + /// 菜单列表 + /// + public List BuildMenus(List menus) + { + List routers = new List(); + foreach (MenuOutputDto menu in menus) + { + VueRouterModel router = new VueRouterModel + { + hidden = menu.IsShow ? false : true, + name = GetRouteName(menu), + path = GetRouterPath(menu), + component = GetComponent(menu) + }; + Meta meta = new Meta(menu.FullName, menu.Icon == null ? "" : menu.Icon, menu.IsCache); + if (!menu.IsShow && menu.MenuType.Contains("M")) + { + meta.activeMenu = menu.ActiveMenu; + } + + router.meta = meta; + List cMenus = menu.SubMenu; + if (cMenus != null && menu.MenuType == "C") + { + router.alwaysShow = true; + router.redirect = "noRedirect"; + router.children = BuildMenus(cMenus); + } + else if (IsMeunDoc(menu)) + { + List childrenList = new List(); + VueRouterModel childrenRouter = new VueRouterModel + { + path = menu.UrlAddress, + component = menu.Component, + name = menu.EnCode, + meta = new Meta(menu.FullName, menu.Icon == null ? "" : menu.Icon, menu.IsCache) + }; + childrenRouter.meta = meta; + childrenList.Add(childrenRouter); + router.children = childrenList; + } + else if (IsMeunFrame(menu) && cMenus != null) + { + if (!menu.IsShow) + { + router.hidden = true; + } + + router.children = BuildMenus(cMenus); + } + + routers.Add(router); + } + + return routers; + } + + /// + /// 获取路由名称 + /// + /// 菜单信息 + /// + public string GetRouteName(MenuOutputDto menu) + { + string routerName = menu.EnCode; + // 非外链并且是一级目录(类型为目录) + if (IsMeunDoc(menu)) + { + routerName = ""; + } + + return routerName; + } + + /// + /// 获取路由地址 + /// + /// 菜单信息 + /// + public string GetRouterPath(MenuOutputDto menu) + { + string routerPath = menu.UrlAddress; + // 非外链并且是一级目录(类型为目录) + if (0 == menu.ParentId && menu.MenuType == "C" && !menu.IsFrame) + { + routerPath = menu.UrlAddress; // "/" + menu.EnCode; + } + // 非外链并且是一级目录(类型为菜单) + else if (IsMeunDoc(menu)) + { + routerPath = "/"; + } + + return routerPath; + } + + /// + /// 获取组件信息 + /// + /// 菜单信息 + /// + public string GetComponent(MenuOutputDto menu) + { + string component = "Layout"; + if (!string.IsNullOrEmpty(menu.Component) && IsMeunFrame(menu) && !IsMeunDoc(menu)) + { + component = menu.Component; + } + else if (string.IsNullOrEmpty(menu.Component) && IsParentView(menu)) + { + component = "ParentView"; + } + + return component; + } + + /// + /// 是否为菜单内部跳转,并且是一级目录 + /// + /// 菜单信息 + /// + public bool IsMeunDoc(MenuOutputDto menu) + { + return menu.ParentId == 0 && menu.MenuType == "M" && !menu.IsFrame; + } + + /// + /// 是否为菜单内部跳转 + /// + /// 菜单信息 + /// + public bool IsMeunFrame(MenuOutputDto menu) + { + return menu.MenuType == "M" && !menu.IsFrame; + } + + /// + /// 是否为parent_view组件 + /// + /// 菜单信息 + /// + public bool IsParentView(MenuOutputDto menu) + { + return menu.ParentId != 0 && menu.MenuType == "C"; + } + + #endregion 获取 Vue Router + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Application/UploadFileApp.cs b/Znyc.Cloudcar.Admin.Security.Core/Application/UploadFileApp.cs new file mode 100644 index 0000000..3a76986 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Application/UploadFileApp.cs @@ -0,0 +1,217 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.IO; +using Znyc.Cloudcar.Admin.Commons.Core.App; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Options; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Application +{ + /// + /// 文件上传 + /// + public class UploadFileApp + { + private readonly string _filePath; + private readonly ILogger _logger; + private readonly IUploadFileService service = App.GetService(); + private string _belongApp; //所属应用 + private string _belongAppId; //所属应用ID + private string _dbFilePath; //数据库中的文件路径 + private string _dbThumbnail; //数据库中的缩略图路径 + + /// + /// + public UploadFileApp() + { + } + + /// + /// + /// + /// + public UploadFileApp(IOptions setOptions, ILogger logger) + { + _logger = logger; + _filePath = setOptions.Value.LocalPath; + if (string.IsNullOrEmpty(_filePath)) + { + _filePath = AppContext.BaseDirectory; + } + } + + /// + /// 根据应用Id和应用标识批量更新数据 + /// + /// 应用Id + /// 更新前旧的应用Id + /// 应用标识 + /// + public bool UpdateByBeLongAppId(string belongAppId, string oldBeLongAppId, string beLongApp = null) + { + return service.UpdateByBeLongAppId(belongAppId, oldBeLongAppId, beLongApp); + } + + /// + /// 新增 + /// + /// + /// + public long Insert(UploadFileEntity info) + { + return service.Insert(info); + } + + /// + /// 同步查询单个实体。 + /// + /// 主键 + /// + public UploadFileEntity Get(long id) + { + return service.Get(id); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 分页实体 + /// 排序字段 + /// 是否降序 + /// 指定对象的集合 + public List FindWithPager(string condition, PagerInfo info, string fieldToSort, bool desc) + { + return service.FindWithPager(condition, info, fieldToSort, desc).MapTo(); + } + + /// + /// 批量上传文件 + /// + /// 文件 + /// 所属应用,如文章article + /// 所属应用ID,如文章id + /// + public List Adds(IFormFileCollection files, string belongApp, string belongAppId) + { + List result = new List(); + foreach (IFormFile file in files) + { + if (file != null) + { + result.Add(Add(file, belongApp, belongAppId)); + } + } + + return result; + } + + /// + /// 单个上传文件 + /// + /// + /// 所属应用,如文章article + /// 所属应用ID,如文章id + /// + public UploadFileResultOuputDto Add(IFormFile file, string belongApp, string belongAppId) + { + _belongApp = belongApp; + _belongAppId = belongAppId; + if (file != null && file.Length > 0 && file.Length < 10485760) + { + using (BinaryReader binaryReader = new BinaryReader(file.OpenReadStream())) + { + string fileName = Path.GetFileName(file.FileName); + byte[] data = binaryReader.ReadBytes((int)file.Length); + UploadFile(fileName, data); + + UploadFileEntity filedb = new UploadFileEntity + { + FilePath = _dbFilePath, + Thumbnail = _dbThumbnail, + FileName = fileName, + FileSize = file.Length.ToInt(), + FileType = Path.GetExtension(fileName), + Extension = Path.GetExtension(fileName), + BelongApp = _belongApp, + BelongAppId = _belongAppId + }; + service.Insert(filedb); + return filedb.MapTo(); + } + } + + Log4NetHelper.Error("文件过大"); + throw new Exception("文件过大"); + } + + /// + /// 实现文件上传到服务器保存,并生成缩略图 + /// + /// 文件名称 + /// 文件字节流 + private void UploadFile(string fileName, byte[] fileBuffers) + { + string folder = DateTime.Now.ToString("yyyyMMdd"); + + //判断文件是否为空 + if (string.IsNullOrEmpty(fileName)) + { + Log4NetHelper.Error("文件名不能为空"); + throw new Exception("文件名不能为空"); + } + + //判断文件是否为空 + if (fileBuffers.Length < 1) + { + Log4NetHelper.Error("文件不能为空"); + throw new Exception("文件不能为空"); + } + + string _tempfilepath = "/upload/" + _belongApp + "/" + folder + "/"; + string uploadPath = _filePath + _tempfilepath; + if (!Directory.Exists(uploadPath)) + { + Directory.CreateDirectory(uploadPath); + } + + string ext = Path.GetExtension(fileName).ToLower(); + string newName = 0 + ext; + + using (FileStream fs = new FileStream(uploadPath + newName, FileMode.Create)) + { + fs.Write(fileBuffers, 0, fileBuffers.Length); + fs.Close(); + //生成缩略图 + if (ext.Contains(".jpg") || ext.Contains(".jpeg") || ext.Contains(".png") || ext.Contains(".bmp") || + ext.Contains(".gif")) + { + string thumbnailName = 0 + ext; + ImgHelper.MakeThumbnail(uploadPath + newName, uploadPath + thumbnailName); + _dbThumbnail = folder + "/" + thumbnailName; + } + + _dbFilePath = _tempfilepath + "/" + newName; + } + } + + /// + /// 统计上传内容数 + /// + /// + public long GetCountTotal() + { + return service.GetCountByWhere("1=1"); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Application/UserApp.cs b/Znyc.Cloudcar.Admin.Security.Core/Application/UserApp.cs new file mode 100644 index 0000000..febc2fd --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Application/UserApp.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Core.App; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Application +{ + /// + /// + public class UserApp + { + private readonly IRoleService roleService = App.GetService(); + private readonly IAdminUserService service = App.GetService(); + private readonly IAdminUserLogOnService userLogOnService = App.GetService(); + + /// + /// 获取所有用户信息 + /// + /// + public IEnumerable GetAll() + { + return service.GetAll(); + } + + /// + /// 根据用户账号查询用户信息 + /// + /// + /// + public async Task GetByUserName(string userName) + { + return await service.GetByUserName(userName); + } + + /// + /// 根据第三方OpenId查询用户信息 + /// + /// 第三方类型 + /// OpenId值 + /// + public UserOutputDto GetUserOutDtoByOpenId(string openIdType, string openId) + { + return service.GetUserByOpenId(openIdType, openId).MapTo(); + } + + /// + /// 根据第三方OpenId查询用户信息 + /// + /// 第三方类型 + /// OpenId值 + /// + public AdminUserEntity GetUserByOpenId(string openIdType, string openId) + { + return service.GetUserByOpenId(openIdType, openId); + } + + /// + /// 更新用户 + /// + /// 用户信息 + /// + public bool UpdateUser(AdminUserEntity user) + { + return service.Update(user, user.Id); + } + + /// + /// 根据用户ID获取头像 + /// + /// 用户ID + /// + public string GetHeadIconById(long userId) + { + AdminUserEntity user = service.Get(userId); + + if (user != null) + { + return user.HeadIcon; + } + + return ""; + } + + /// + /// 查询用户信息 + /// + /// 用户Id + /// + public AdminUserEntity GetUserById(long id) + { + return service.Get(id); + } + + /// + /// 根据用户id和第三方类型查询 + /// + /// + /// + /// + public UserOpenIdsEntity GetUserOpenIdById(long userId, string openIdType) + { + return service.GetUserOpenIdByuserId(openIdType, userId); + } + + /// + /// 根据微信统一ID(UnionID)查询用户 + /// + /// UnionID + /// + public AdminUserEntity GetUserByUnionId(string unionId) + { + return service.GetUserByUnionId(unionId); + } + + /// + /// 统计用户数 + /// + /// + public long GetCountTotal() + { + return service.GetCountByWhere("1=1"); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityAddInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityAddInput.cs new file mode 100644 index 0000000..db85a79 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityAddInput.cs @@ -0,0 +1,45 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 活动入参 + /// + public class ActivityAddInput + { + /// + /// 活动类型Id + /// + public long ActivityId { get; set; } + + /// + /// 活动图标 + /// + public string Icon { get; set; } + + /// + /// 文字描述 + /// + public string TextDesc { get; set; } + + /// + /// 图片URL + /// + public string PicUrl { get; set; } + + /// + /// 活动详情图 + /// + public string DetailPicUrl { get; set; } + + /// + /// 开始时间 + /// + public DateTime StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime EndTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityOutputDto.cs new file mode 100644 index 0000000..2ef695d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityOutputDto.cs @@ -0,0 +1,57 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 活动输出模型 + /// + public class ActivityOutputDto + { + public long Id { get; set; } + + /// + /// 活动类型Id + /// + public long ActivityId { get; set; } + + /// + /// 活动名称 + /// + public string Name { get; set; } + + /// + /// 活动类型 + /// + public string Icon { get; set; } + + /// + /// 文字描述 + /// + public string TextDesc { get; set; } + + /// + /// 图片URL + /// + public string PicUrl { get; set; } + + /// + /// 活动详情图 + /// + public string DetailPicUrl { get; set; } + + /// + /// 开始时间 + /// + public DateTime StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime EndTime { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityUpdateInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityUpdateInput.cs new file mode 100644 index 0000000..3b4933a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/ActivityUpdateInput.cs @@ -0,0 +1,15 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 活动修改模型 + /// + public class ActivityUpdateInput : ActivityAddInput + { + public long Id { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/SearchActivityModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/SearchActivityModel.cs new file mode 100644 index 0000000..46f6696 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Activity/SearchActivityModel.cs @@ -0,0 +1,26 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 活动搜索条件 + /// + public class SearchActivityModel : SearchInputDto + { + /// + /// 开始时间 + /// + public string StartTime { get; set; } + + /// + /// 结束时间 + /// + public string EndTime { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminCurrentUser.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminCurrentUser.cs new file mode 100644 index 0000000..2c3ba23 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminCurrentUser.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.Tree; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 登录成功返回用户信息 + /// + [Serializable] + public class AdminCurrentUser + { + /// + /// 授权token码 + /// + public string AccessToken { get; set; } + + /// + /// appkey + /// + public string AppKey { get; set; } + + /// + /// 用户ID + /// + public long UserId { get; set; } + + /// + /// 用户账号 + /// + public string Account { get; set; } + + /// + /// 用户名 + /// + public string Name { get; set; } + + /// + /// 昵称 + /// + public string UserName { get; set; } + + /// + /// 姓名 + /// + public string RealName { get; set; } + + /// + /// 头像 + /// + public string HeadIcon { get; set; } + + /// + /// 性别 + /// + public int? Gender { get; set; } + + /// + /// 头像 + /// + public long MemberGradeId { get; set; } + + /// + /// 上级推广员 + /// + public long ReferralUserId { get; set; } + + /// + /// 注册时间 + /// + public DateTime CreateTime { get; set; } + + /// + /// 组织主键 + /// + public virtual long OrganizeId { get; set; } + + /// + /// 部门主键 + /// + public virtual long DeptId { get; set; } + + /// + /// 角色编码,多个角色,使用“,”分格 + /// + public string Role { get; set; } + + /// + /// 手机号码 + /// + public string MobilePhone { get; set; } + + /// + /// 其他对象 + /// + public object OtherOpenObj { get; set; } + + /// + /// 微信登录SessionId + /// + public string WxSessionId { get; set; } + + /// + /// 租户TenantId + /// + public long TenantId { get; set; } + + /// + /// 登录IP地址 + /// + public virtual string CurrentLoginIP { get; set; } + + /// + /// 登录IP地址 + /// + public virtual string IPAddressName { get; set; } + + /// + /// 当前访问的系统Id + /// + public long ActiveSystemId { get; set; } + + /// + /// 当前访问的系统名称 + /// + public string ActiveSystem { get; set; } + + /// + /// 当前访问的系统Url + /// + public string ActiveSystemUrl { get; set; } + + /// + /// 可以访问子系统 + /// + public List SubSystemList { get; set; } + + /// + /// 授权访问菜单 + /// + public List MenusList { get; set; } + + /// + /// 授权访问菜单 + /// + public List MenusRouter { get; set; } + + /// + /// 授权使用功能 + /// + public List Modules { get; set; } + + /// + /// 用户设置的软件主题 + /// + public string UserTheme { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminUser/AdminUserInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminUser/AdminUserInputDto.cs new file mode 100644 index 0000000..d669474 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminUser/AdminUserInputDto.cs @@ -0,0 +1,70 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(AdminUserEntity))] + [Serializable] + public class AdminUserInputDto : IInputDto + { + /// + /// 账号 + /// + public string Account { get; set; } + + /// + /// 用户名 + /// + public string UserName { get; set; } + + /// + /// 头像 + /// + public string HeadIcon { get; set; } + + /// + /// 性别 + /// + public int Gender { get; set; } + + /// + /// 手机号 + /// + public string MobilePhone { get; set; } + + /// + /// 组织主键 + /// + //public long OrganizeId { get; set; } + + /// + /// 部门主键 + /// + public long DepartmentId { get; set; } + + /// + /// 角色主键 + /// + public long RoleId { get; set; } + + /// + ///是否管理员 + /// + public bool IsAdministrator { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 主键 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminUser/AdminUserOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminUser/AdminUserOutputDto.cs new file mode 100644 index 0000000..4abe5da --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/AdminUser/AdminUserOutputDto.cs @@ -0,0 +1,83 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class AdminUserOutputDto + { + /// + /// 用户主键 + /// + public virtual long Id { get; set; } + + /// + /// 账户 + /// + public virtual string Account { get; set; } + + /// + /// 姓名 + /// + public virtual string UserName { get; set; } + + /// + /// 头像 + /// + public virtual string HeadIcon { get; set; } + + /// + /// 性别 + /// + public virtual int Gender { get; set; } + + /// + /// 手机 + /// + public virtual string MobilePhone { get; set; } + + /// + /// 组织主键 + /// + public virtual long OrganizeId { get; set; } + + /// + /// 组织名称 + /// + public virtual string OrganizeName { get; set; } + + /// + /// 部门主键 + /// + public virtual long DepartmentId { get; set; } + + /// + /// 部门名称 + /// + public virtual string DepartmentName { get; set; } + + /// + /// 角色主键 + /// + public virtual string RoleId { get; set; } + + /// + /// 角色名称 + /// + public virtual string RoleName { get; set; } + + /// + /// 是否管理员 + /// + public virtual bool? IsAdministrator { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Api/ApiInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Api/ApiInputDto.cs new file mode 100644 index 0000000..11d76c5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Api/ApiInputDto.cs @@ -0,0 +1,16 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + public class ApiInputDto : IInputDto + { + public string ApiUrl { get; set; } + + + public string AuthKey { get; set; } + + + public string AuthValue { get; set; } + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Api/ApiOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Api/ApiOutputDto.cs new file mode 100644 index 0000000..b202c0a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Api/ApiOutputDto.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Znyc.Cloudcar.Admin.Commons.Dtos; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + [Serializable] + public class ApiOutputDto : IOutputDto + { + [MaxLength(50)] public string ApiUrl { get; set; } + + [MaxLength(15)] public string AuthKey { get; set; } + + [MaxLength(155)] public string AuthValue { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/App/AppInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/App/AppInputDto.cs new file mode 100644 index 0000000..90bfff6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/App/AppInputDto.cs @@ -0,0 +1,60 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(APPEntity))] + [Serializable] + public class APPInputDto : IInputDto + { + /// + /// 设置或获取 + /// + public string AppId { get; set; } + + /// + /// 设置或获取 + /// + public string AppSecret { get; set; } + + /// + /// 设置或获取 + /// + public string EncodingAESKey { get; set; } + + /// + /// 设置或获取 + /// + public string RequestUrl { get; set; } + + /// + /// 设置或获取 + /// + public string Token { get; set; } + + /// + /// 设置或获取 + /// + public bool IsOpenAEKey { get; set; } + + /// + /// 设置或获取 + /// + public bool IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/App/AppOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/App/AppOutputDto.cs new file mode 100644 index 0000000..370ad1f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/App/AppOutputDto.cs @@ -0,0 +1,120 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class AppOutputDto : IOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string AppId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string AppSecret { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(256)] + public string EncodingAESKey { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(256)] + public string RequestUrl { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(256)] + public string Token { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsOpenAEKey { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long CompanyId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long DeptId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string DeleteUserId { get; set; } + + /// + /// + public virtual AdminUserEntity UserInfo { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/ApplyJob/ApplyJobInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/ApplyJob/ApplyJobInputDto.cs new file mode 100644 index 0000000..cdfadef --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/ApplyJob/ApplyJobInputDto.cs @@ -0,0 +1,136 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(ApplyJobEntity))] + [Serializable] + public class ApplyJobInputDto : IInputDto + { + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 内容 + /// + /// > + public string Content { get; set; } + + /// + /// 电话 + /// + public string Phone { get; set; } + + /// + /// 行业类型 + /// + public long IndustryId { get; set; } + + /// + /// 岗位类型 + /// + public long JobId { get; set; } + + /// + /// 求职地区省份 + /// + public string ProvinceId { get; set; } + + /// + /// 求职地区市 + /// + public string CityId { get; set; } + + /// + /// 求职地区 + /// + public string AreaId { get; set; } + + /// + /// 状态 + /// + public long State { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 是否有驾驶证 + /// + public bool? IsHaveDriverLicense { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime TopExpireTime { get; set; } + + /// + /// 工资经验Id + /// + public long? ExperienceId { get; set; } + + /// + /// 流水号 + /// + public string SerialNumber { get; set; } + + /// + /// 出生日期 + /// + public DateTime? BirthDate { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + /// + /// 年龄 + /// + public int? Age { get; set; } + + /// + /// 性别 + /// + public int? Gender { get; set; } + + /// + /// 地址明细(冗余,用于首页查询省市区模糊匹配) + /// + public string Address { get; set; } + + /// + /// 发布时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 创建人 + /// + public long CreatedUserId { get; set; } + + /// + /// 更新时间 + /// + public DateTime ModifiedTime { get; set; } + + /// + /// 主键 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/ApplyJob/ApplyJobOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/ApplyJob/ApplyJobOutputDto.cs new file mode 100644 index 0000000..8e1ce80 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/ApplyJob/ApplyJobOutputDto.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class ApplyJobOutputDto + { + public long Id { get; set; } + + public long UserId { get; set; } + + /// + /// 内容 + /// + public string Content { get; set; } + + /// + /// 姓名 + /// + public string UserName { get; set; } + + /// + /// 头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 电话 + /// + public string Phone { get; set; } + + /// + /// 行业类型 + /// + public long IndustryId { get; set; } + + /// + /// 行业类型名称 + /// + public string IndustryName { get; set; } + + /// + /// 岗位类型 + /// + public long JobId { get; set; } + + /// + /// 岗位类型名称 + /// + public string JobName { get; set; } + + /// + /// 求职地区省份 + /// + public string ProvinceId { get; set; } + + /// + /// 求职地区 + /// + public string CityId { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + public string StatusName { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 是否置顶 + /// + public string Top { get; set; } + + /// + /// 是否有驾驶证 + /// + public bool? IsHaveDriverLicense { get; set; } + + /// + /// 是否有驾驶证 + /// + public string DriverLicense { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 是否公开 + /// + public string Public { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime? TopExpireDate { get; set; } + + /// + /// 工资经验Id + /// + public long? ExperienceId { get; set; } + + /// + /// 工资经验 + /// + public string ExperienceName { get; set; } + + /// + /// 更新时间 + /// + public DateTime ModifiedTime { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 流水号 + /// + public string SerialNumber { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + /// + /// 出生日期 + /// + public DateTime? BirthDate { get; set; } + + /// + /// 年龄 + /// + public int? Age { get; set; } + + /// + /// 性别 + /// + public int? Gender { get; set; } + + /// + /// 地址明细(冗余,用于首页查询省市区模糊匹配) + /// + public string Address { get; set; } + + /// + /// 失败原因 + /// + public string Note { get; set; } + + /// + /// 浏览量 + /// + public int PageView { get; set; } + + /// + /// 微信昵称 + /// + public string NickName { get; set; } + + /// + /// 微信头像 + /// + public string WxAvatarUrl { get; set; } + + /// + /// 通话评价反馈 + /// + public List CallFeedbacks { get; set; } + + /// + /// 通话评价反馈是否已读 + /// + public bool IsReadForCallFeedback { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaInputDto.cs new file mode 100644 index 0000000..bf6d506 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaInputDto.cs @@ -0,0 +1,70 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(AreaEntity))] + [Serializable] + public class AreaInputDto : IInputDto + { + /// + /// 设置或获取 + /// + public long ParentId { get; set; } + + /// + /// 设置或获取 + /// + public long? Layers { get; set; } + + /// + /// 设置或获取 + /// + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + public string SimpleSpelling { get; set; } + + /// + /// 设置或获取 + /// + public string FullIdPath { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsLast { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaOutputDto.cs new file mode 100644 index 0000000..33d0fa4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaOutputDto.cs @@ -0,0 +1,112 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class AreaOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long ParentId { get; set; } + + /// + /// 设置或获取 + /// + public long? Layers { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(400)] + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(200)] + public string SimpleSpelling { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(600)] + public string FullIdPath { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsLast { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string DeleteUserId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaPickerOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaPickerOutputDto.cs new file mode 100644 index 0000000..f9307ad --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaPickerOutputDto.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// uniapp 地区选择 + /// + [Serializable] + public class AreaPickerOutputDto + { + /// + /// 值 + /// + public long value { get; set; } + + /// + /// 显示内容 + /// + public string label { get; set; } + + /// + /// + public List children { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaSelect2OutDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaSelect2OutDto.cs new file mode 100644 index 0000000..6a92ea0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Area/AreaSelect2OutDto.cs @@ -0,0 +1,21 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// select2 地区选择 + /// + [Serializable] + public class AreaSelect2OutDto + { + /// + /// 值 + /// + public long Id { get; set; } + + /// + /// 显示内容 + /// + public string text { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Audit/AuditInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Audit/AuditInputDto.cs new file mode 100644 index 0000000..77f3bf0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Audit/AuditInputDto.cs @@ -0,0 +1,39 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(AuditEntity))] + [Serializable] + public class AuditInputDto : IInputDto + { + /// + /// 产品ID + /// + public long EquipmentId { get; set; } + + + /// + /// 审核人 + /// + public long AuditUserId { get; set; } + + /// + /// 审核状态 + /// + /// + //public long HandleStatus { get; set; } + + /// + /// 审核结果 + /// + public string Note { get; set; } + + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Audit/AuditOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Audit/AuditOutputDto.cs new file mode 100644 index 0000000..ded24dc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Audit/AuditOutputDto.cs @@ -0,0 +1,42 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class AuditOutputDto + { + /// + /// 产品ID + /// + public long ProductId { get; set; } + + /// + /// 产品类型 + /// + public long ProductType { get; set; } + + /// + /// 产品标题 + /// + public string ProductTitle { get; set; } + + /// + /// 审核人 + /// + public long AuditUserId { get; set; } + + /// + /// 审核状态 + /// + /// + public long HandleStatus { get; set; } + + /// + /// 审核结果 + /// + public string Note { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerInput.cs new file mode 100644 index 0000000..a69dce4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerInput.cs @@ -0,0 +1,75 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// Banner入参 + /// + public class BannerInput + { + + /// + /// 图片描述 + /// + + public string Name { get; set; } + + /// + /// 图片URL + /// + public string PicUrl { get; set; } + + /// + /// 类型0未关联,1电话,2链接 + /// + [Required] + + public int Type { get; set; } + + /// + /// 电话 + /// + public string Phone { get; set; } + + /// + /// 跳转页面 + /// + public string PageUrl { get; set; } + + + /// + /// 开始时间 + /// + [Required] + public DateTime StartTime { get; set; } + + /// + /// 结束时间 + /// + [Required] + public DateTime EndTime { get; set; } + + /// + /// 是否主图:0.非主图1.主图 + /// + // public bool IsMaster { get; set; } + + /// + /// 排序 + /// + // public int Sort { get; set; } + + /// + /// 状态 0-起开始/1-进行中/2-已结束 + /// + // public int State { get; set; } + + /// + /// 文字描述 + /// + // public string TextDesc { get; set; } + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerOutputDto.cs new file mode 100644 index 0000000..7622e62 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerOutputDto.cs @@ -0,0 +1,58 @@ +using System; +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 云币列表Dto + /// + [Serializable] + public class BannerOutputDto + { + + public long Id { get; set; } + /// + /// 图片描述 + /// + public string Name { get; set; } + + /// + /// 图片URL + /// + public string PicUrl { get; set; } + + /// + /// 状态 0-起开始/1-进行中/2-已结束 + /// + public int State { get; set; } + + /// + /// 开始时间 + /// + public DateTime StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime EndTime { get; set; } + + /// + /// 类型0未关联,1电话,2链接 + /// + public int Type { get; set; } + + /// + /// 类型0未关联,1电话,2链接 + /// + public string TypeName { get; set; } + + /// + /// 电话 + /// + public string Phone { get; set; } + + /// + /// 跳转页面 + /// + public string PageUrl { get; set; } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerUpdateInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerUpdateInput.cs new file mode 100644 index 0000000..e0903a0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/BannerUpdateInput.cs @@ -0,0 +1,13 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// Banner入参 + /// + public class BannerUpdateInput : BannerInput + { + /// + /// + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/SearchBannerModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/SearchBannerModel.cs new file mode 100644 index 0000000..c034deb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Banner/SearchBannerModel.cs @@ -0,0 +1,13 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// Banner搜索条件 + /// + public class SearchBannerModel : SearchInputDto + { + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/CallFeedbackInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/CallFeedbackInput.cs new file mode 100644 index 0000000..070438e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/CallFeedbackInput.cs @@ -0,0 +1,23 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// CallFeedback入参 + /// + public class CallFeedbackInput + { + /// + /// 产品类型 + /// + public int ProductType { get; set; } + + /// + /// 产品Id + /// + public long ProductId { get; set; } + + /// + /// 评价状态 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/CallFeedbackOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/CallFeedbackOutputDto.cs new file mode 100644 index 0000000..3e9c1d0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/CallFeedbackOutputDto.cs @@ -0,0 +1,49 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 通话评论输出模型 + /// + public class CallFeedbackOutputDto + { + /// + /// 昵称 + /// + public string NickName { get; set; } + + /// + /// 联系电话 + /// + public string Phone { get; set; } + + /// + /// 头像 + /// + public string WxAvatarUrl { get; set; } + + public long Id { get; set; } + + public long UserId { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 反馈内容 + /// + public string Content { get; set; } + + /// + /// 时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 是否已读 + /// + public bool IsRead { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/SearchCallFeedbackModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/SearchCallFeedbackModel.cs new file mode 100644 index 0000000..bfb38b8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CallFeedback/SearchCallFeedbackModel.cs @@ -0,0 +1,18 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + public class SearchCallFeedbackModel : SearchInputDto + { + /// + /// 开始时间 + /// + public string StartTime { get; set; } + + /// + /// 结束时间 + /// + public string EndTime { get; set; } + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Certification/CertificationOutput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Certification/CertificationOutput.cs new file mode 100644 index 0000000..978fc5e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Certification/CertificationOutput.cs @@ -0,0 +1,41 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class CertificationOutput + { + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 用户姓名 + /// + public string Name { get; set; } + + /// + /// 证件号 + /// + public string IdCard { get; set; } + + /// + /// 身份证正面照片 + /// + public string PositivePhoto { get; set; } + + /// + /// 身份证反面照片 + /// + public string ReversePhoto { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Currency/CurrencyInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Currency/CurrencyInput.cs new file mode 100644 index 0000000..802f249 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Currency/CurrencyInput.cs @@ -0,0 +1,22 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + public class CurrencyInput + { + public long Id { get; set; } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 总云币 + /// + public decimal TotalCredits { get; set; } + + /// + /// 可用云币 + /// + public decimal AvailableCredits { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Currency/CurrencyOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Currency/CurrencyOutputDto.cs new file mode 100644 index 0000000..9e95cec --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Currency/CurrencyOutputDto.cs @@ -0,0 +1,22 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + public class CurrencyOutputDto + { + public long Id { get; set; } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 总云币 + /// + public decimal TotalCredits { get; set; } + + /// + /// 可用云币 + /// + public decimal AvailableCredits { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/CurrencyRecordInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/CurrencyRecordInput.cs new file mode 100644 index 0000000..ac5f4a0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/CurrencyRecordInput.cs @@ -0,0 +1,22 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + public class CurrencyRecordInput + { + public long Id { get; set; } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 总云币 + /// + public decimal TotalCredits { get; set; } + + /// + /// 可用云币 + /// + public decimal AvailableCredits { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/CurrencyRecordOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/CurrencyRecordOutputDto.cs new file mode 100644 index 0000000..890a463 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/CurrencyRecordOutputDto.cs @@ -0,0 +1,73 @@ +using System; +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 云币列表Dto + /// + [Serializable] + public class CurrencyRecordOutputDto + { + /// + /// 积分Id + /// + public long Id { get; set; } + + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 用户Id + /// + public string UserName { get; set; } + + /// + /// 用户头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 用户手机号 + /// + public string Phone { get; set; } + + + /// + /// 收支类型 + /// + public int OperatingType { get; set; } + + /// + /// 收支类型 + /// + public string OperatingTypeName { get; set; } + + /// + /// 云币数量 + /// + public decimal OperatingCurrency { get; set; } + + /// + /// 收支途径 + /// + public int CurrencyType { get; set; } + + + /// + /// 收支途径 + /// + public string CurrencyTypeName { get; set; } + + /// + /// 收支时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 云币来源(求职/招聘/用户Id) + /// + public long CurrencySoureObjectId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/SearchCurrencyRecordModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/SearchCurrencyRecordModel.cs new file mode 100644 index 0000000..2b89cb4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/CurrencyRecord/SearchCurrencyRecordModel.cs @@ -0,0 +1,34 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 云币搜索条件 + /// + public class SearchCurrencyRecordModel : SearchInputDto + { + /// + /// 开始时间 + /// + public string StartTime { get; set; } + + /// + /// 结束时间 + /// + public string EndTime { get; set; } + + /// + /// 收支途经 + /// + public int CurrencyType { get; set; } + + /// + /// 收支类型(1=收入/2=支出) + /// + public int OperatingType { get; set; } + + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/DashboardOutModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/DashboardOutModel.cs new file mode 100644 index 0000000..5127269 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/DashboardOutModel.cs @@ -0,0 +1,146 @@ +using System; + +namespace Znyc.Cloudcar.Admin.WebApi.Areas.Security.Entitys +{ + /// + /// 控制台首页显示内容 + /// + [Serializable] + public class DashboardOutModel + { + /// + /// 许可使用公司名称 + /// + public string CertificatedCompany { get; set; } + + /// + /// 系统访问Url + /// + public string WebUrl { get; set; } + + /// + /// 服务器名称 + /// + public string MachineName { get; set; } + + /// + /// 操作系统 + /// + public string OSName { get; set; } + + /// + /// 正在其上运行应用的操作系统。 + /// + public string OSDescription { get; set; } + + /// + /// 获取正在其上运行应用的 .NET 安装的名称。 + /// + public string FrameworkDescription { get; set; } + + /// + /// 获取正在其上运行当前应用的平台体系结构。 + /// + public string OSArchitecture { get; set; } + + /// + /// 获取当前正在运行的应用的进程架构。 + /// + public string ProcessArchitecture { get; set; } + + /// + /// 获取当前计算机上的处理器数。 + /// + public long ProcessorCount { get; set; } + + /// + /// 获取操作系统的内存页的字节数。 + /// + public long SystemPageSize { get; set; } + + /// + /// 获取映射到进程上下文的物理内存量。 + /// + public long WorkingSet { get; set; } + + /// + /// 获取系统启动后经过的毫秒数。 + /// + public long TickCount { get; set; } + + /// + /// 运行时长 + /// + public string RunTimeLength { get; set; } + + /// + /// 部署目录 + /// + public string Directory { get; set; } + + /// + /// 系统版本 + /// + public string SystemVersion { get; set; } + + /// + /// 系统版本 + /// + public string Version { get; set; } + + /// + /// 软件厂商 + /// + public string Manufacturer { get; set; } + + /// + /// 网址 + /// + public string WebSite { get; set; } + + /// + /// 更新地址 + /// + public string UpdateUrl { get; set; } + + /// + /// 服务器IP地址 + /// + public string IPAdress { get; set; } + + /// + /// 服务器端口 + /// + public string Port { get; set; } + + /// + /// 系统名称 + /// + public string Title { get; set; } + + /// + /// 总用户数 + /// + public long TotalUser { get; set; } + + /// + /// 总模块数 + /// + public long TotalModule { get; set; } + + /// + /// 总上传文件数 + /// + public long TotalUploadFile { get; set; } + + /// + /// 定时任务 + /// + public long TotalTask { get; set; } + + /// + /// 总岗位角色数 + /// + public long TotalRole { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryInputDto.cs new file mode 100644 index 0000000..66ea7c1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryInputDto.cs @@ -0,0 +1,55 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(DictionaryEntity))] + [Serializable] + public class DictionaryInputDto : IInputDto + { + /// + /// 字典父级 + /// + public long ParentId { get; set; } + + /// + /// 字典编码 + /// + public string Code { get; set; } + + /// + /// 字典值 + /// + public string Value { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 字典名称 + /// + public string Name { get; set; } + + /// + /// 启用 + /// + public bool IsEnabled { get; set; } = true; + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryListOutput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryListOutput.cs new file mode 100644 index 0000000..544b4ed --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryListOutput.cs @@ -0,0 +1,29 @@ + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 与小程序缓存保持一致 + /// + public class DictionaryListOutput + { + /// + /// 主键Id + /// + public long Id { get; set; } + + /// + /// 父级Id + /// + public long ParentId { get; set; } + + /// + /// 字典编码 + /// + public string Code { get; set; } + + /// + /// 字典值 + /// + public string Value { get; set; } + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryOutputDto.cs new file mode 100644 index 0000000..5992a7e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Dictionary/DictionaryOutputDto.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class DictionaryOutputDto + { + /// + /// 设置或获取 + /// + public long Id { get; set; } + + /// + /// 字典父级 + /// + public long ParentId { get; set; } + + /// + /// 字典编码 + /// + public string Code { get; set; } + + /// + /// 字典值 + /// + public string Value { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 字典名称 + /// + public string Name { get; set; } + + /// + /// 启用 + /// + public bool IsEnabled { get; set; } = true; + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 子集 + /// + public List Children { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Document/ImageOutput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Document/ImageOutput.cs new file mode 100644 index 0000000..2a2b095 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Document/ImageOutput.cs @@ -0,0 +1,24 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos.Document +{ + public class ImageOutput + { + public Credentials Credentials { get; set; } + + public string Expiration { get; set; } + + public int ExpiredTime { get; set; } + + public string RequestId { get; set; } + + public int StartTime { get; set; } + } + + public class Credentials + { + public string TmpSecretId { get; set; } + + public string TmpSecretKey { get; set; } + + public string Token { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentAddInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentAddInput.cs new file mode 100644 index 0000000..af84feb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentAddInput.cs @@ -0,0 +1,120 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// + /// + public class EquipmentAddInput + { + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 标题 + /// + public string Title { get; set; } + + /// + /// 设备编号 + /// + public long EquipmentNumber { get; set; } + + /// + /// 设备类型 + /// + public long EquipmentType { get; set; } + + /// + /// 设备品牌 + /// + public long EquipmentBrand { get; set; } + + /// + /// 汽车底盘 + /// + public long AutomobileChassis { get; set; } + + /// + /// 装载方量 + /// + public long ReprintVolume { get; set; } + + /// + /// 设备型号 + /// + public string EquipmentModel { get; set; } + + /// + /// 设备吨位 + /// + public int EquipmentTonnage { get; set; } + + /// + /// 斗容 + /// + public int Capacity { get; set; } + + /// + /// 设备介绍 + /// + public string Introduction { get; set; } + + /// + /// 出厂日期 + /// + public int AppearanceDate { get; set; } + + /// + /// 出售价格 + /// + public decimal SellingPrice { get; set; } + + /// + /// 车辆位置 + /// + public string AutomobileLocation { get; set; } + + /// + /// 联系人 + /// + public string Contact { get; set; } + + /// + /// 联系人电话 + /// + public string ContactPhone { get; set; } + + /// + /// 状态,10=出售中,11=审核中,30=未通过,40=已成交,99=未通过 + /// + public int State { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime TopExpireDate { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 浏览量 + /// + public int PageView { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentOutputDto.cs new file mode 100644 index 0000000..ba56597 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentOutputDto.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 活动输出模型 + /// + public class EquipmentOutputDto + { + + public long Id { get; set; } + /// + /// 编号 + /// + public long EquipmentNumber { get; set; } + + /// + /// 姓名 + /// + public string UserName { get; set; } + + /// + /// 头像 + /// + public string Avatar { get; set; } + + /// + /// 微信昵称 + /// + public string NickName { get; set; } + + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 标题 + /// + public string Title { get; set; } + + + /// + /// 联系人 + /// + public string Contact { get; set; } + + /// + /// 联系人电话 + /// + public string ContactPhone { get; set; } + + + /// + /// 车辆位置 + /// + public string AutomobileLocation { get; set; } + + /// + /// 设备类型 + /// + public long EquipmentType { get; set; } + + /// + /// 设备类型 + /// + public string EquipmentTypeName { get; set; } + + /// + /// 设备品牌 + /// + public long EquipmentBrand { get; set; } + + /// + /// 设备品牌 + /// + public string EquipmentBrandName { get; set; } + + /// + /// + /// + public int State { get; set; } + + + /// + /// + /// + public string StateName { get; set; } + + + /// + /// 浏览量 + /// + public int PageView { get; set; } + + + /// + /// 设备图片 + /// + public List EquipmentPictures { get; set; } + + + /// + /// 行驶证 + /// + public List DrivingPictures { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime TopExpireDate { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + + /// + /// 创建时间 + /// + public DateTime CreatedTime { get; set; } + + + + ///// + ///// 设备型号 + ///// + //public string EquipmentModel { get; set; } + + /// + /// 汽车底盘 + /// + public long AutomobileChassis { get; set; } + + + /// + /// 汽车底盘 + /// + public string AutomobileChassisName { get; set; } + + ///// + ///// 装载方量 + ///// + //public long ReprintVolume { get; set; } + + + ///// + ///// 设备吨位 + ///// + //public int EquipmentTonnage { get; set; } + + ///// + ///// 斗容 + ///// + //public int Capacity { get; set; } + + /// + /// 设备介绍 + /// + public string Introduction { get; set; } + + ///// + ///// 出厂日期 + ///// + //public DateTime AppearanceDate { get; set; } + + ///// + ///// 出售价格 + ///// + //public decimal SellingPrice { get; set; } + + + + ///// + ///// 是否公开 + ///// + //public bool IsPublic { get; set; } + + + /// + /// 臂架长度 + /// + public long BoomLength { get; set; } + + + /// + /// 臂架长度 + /// + public string BoomLengthName { get; set; } + + + /// + /// + /// + public int PromoteType { get; set; } + + + /// + /// + /// + public bool IsPromote { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentUpdateInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentUpdateInput.cs new file mode 100644 index 0000000..116279f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/EquipmentUpdateInput.cs @@ -0,0 +1,120 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 活动修改模型 + /// + public class EquipmentUpdateInput : EquipmentAddInput + { + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 标题 + /// + public string Title { get; set; } + + /// + /// 设备编号 + /// + public long EquipmentNumber { get; set; } + + /// + /// 设备类型 + /// + public long EquipmentType { get; set; } + + /// + /// 设备品牌 + /// + public long EquipmentBrand { get; set; } + + /// + /// 汽车底盘 + /// + public long AutomobileChassis { get; set; } + + /// + /// 装载方量 + /// + public long ReprintVolume { get; set; } + + /// + /// 设备型号 + /// + public string EquipmentModel { get; set; } + + /// + /// 设备吨位 + /// + public int EquipmentTonnage { get; set; } + + /// + /// 斗容 + /// + public int Capacity { get; set; } + + /// + /// 设备介绍 + /// + public string Introduction { get; set; } + + /// + /// 出厂日期 + /// + public int AppearanceDate { get; set; } + + /// + /// 出售价格 + /// + public decimal SellingPrice { get; set; } + + /// + /// 车辆位置 + /// + public string AutomobileLocation { get; set; } + + /// + /// 联系人 + /// + public string Contact { get; set; } + + /// + /// 联系人电话 + /// + public string ContactPhone { get; set; } + + /// + /// 状态,10=出售中,11=审核中,30=未通过,40=已成交,99=未通过 + /// + public int State { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime TopExpireDate { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 浏览量 + /// + public int PageView { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/SearchEquipmentModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/SearchEquipmentModel.cs new file mode 100644 index 0000000..3f25600 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Equipment/SearchEquipmentModel.cs @@ -0,0 +1,26 @@ +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 活动搜索条件 + /// + public class SearchEquipmentModel : SearchInputDto + { + /// + /// 注册或添加时间 开始 + /// + public string StartTime { get; set; } + + /// + /// 注册或添加时间 结束 + /// + public string EndTime { get; set; } + + + public int State { get; set; } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/ExceptionsLogs/ExceptionsLogsInPutDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/ExceptionsLogs/ExceptionsLogsInPutDto.cs new file mode 100644 index 0000000..808bb3d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/ExceptionsLogs/ExceptionsLogsInPutDto.cs @@ -0,0 +1,60 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(ExceptionsLogsEntity))] + [Serializable] + public class ExceptionsLogsInPutDto : IInputDto + { + /// + /// 访问域名 + /// + public string AppDomainName { get; set; } + + /// + /// 错误页面 + /// + public string ErrorPage { get; set; } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 用户Ip + /// + public string IP { get; set; } + + /// + /// 错误类型 + /// + public string ExceptionType { get; set; } + + /// + /// 异常描述信息 + /// + public string Message { get; set; } + + /// + /// 堆栈信息 + /// + public string StackTrace { get; set; } + + /// + /// 异常时间 + /// + public DateTime ExceptionTime { get; set; } + + /// + /// 主键Id + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/ExceptionsLogs/ExceptionsLogsOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/ExceptionsLogs/ExceptionsLogsOutputDto.cs new file mode 100644 index 0000000..257c3bc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/ExceptionsLogs/ExceptionsLogsOutputDto.cs @@ -0,0 +1,56 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class ExceptionsLogsOutputDto + { + /// + /// 主键Id + /// + public long Id { get; set; } + + /// + /// 访问域名 + /// + public string AppDomainName { get; set; } + + /// + /// 错误页面 + /// + public string ErrorPage { get; set; } + + /// + /// 用户Id + /// + public string UserName { get; set; } + + /// + /// 用户Ip + /// + public string IP { get; set; } + + /// + /// 错误类型 + /// + public string ExceptionType { get; set; } + + /// + /// 异常描述信息 + /// + public string Message { get; set; } + + /// + /// 堆栈信息 + /// + public string StackTrace { get; set; } + + /// + /// 异常时间 + /// + public DateTime ExceptionTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackInput.cs new file mode 100644 index 0000000..745575d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackInput.cs @@ -0,0 +1,10 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// Feedback入参 + /// + public class FeedbackInput + { + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackOutputDto.cs new file mode 100644 index 0000000..73be37e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackOutputDto.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 意见反馈输出模型 + /// + public class FeedbackOutputDto + { + /// + /// 用户名 + /// + public string UserName { get; set; } + + /// + /// 联系电话 + /// + public string Phone { get; set; } + + /// + /// 头像 + /// + public string AvatarUrl { get; set; } + + public long Id { get; set; } + + public long UserId { get; set; } + + /// + /// 反馈内容 + /// + public string Content { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 图片 + /// + public List FeedbackPic { get; set; } + + /// + /// 提交时间 + /// + public DateTime CreatedTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackPicOutput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackPicOutput.cs new file mode 100644 index 0000000..a98e26d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/FeedbackPicOutput.cs @@ -0,0 +1,23 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 意见反馈图片输出模型 + /// + public class FeedbackPicOutput + { + /// + /// 图片URL + /// + public string PicUrl { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 图片是否有效 + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/SearchFeedbackModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/SearchFeedbackModel.cs new file mode 100644 index 0000000..38d2529 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Feedback/SearchFeedbackModel.cs @@ -0,0 +1,23 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + public class SearchFeedbackModel : SearchInputDto + { + /// + /// 开始时间 + /// + public string StartTime { get; set; } + + /// + /// 结束时间 + /// + public string EndTime { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Function/FunctionTreeTableOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Function/FunctionTreeTableOutputDto.cs new file mode 100644 index 0000000..9f432b4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Function/FunctionTreeTableOutputDto.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// vue树形表 + /// + [Serializable] + public class FunctionTreeTableOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string SystemTypeId { get; set; } + + /// + /// + public string SystemTypeName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long ParentId { get; set; } + + /// + /// 设置或获取 + /// + public long? Layers { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Icon { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string UrlAddress { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Target { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsMenu { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsExpand { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsPublic { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowEdit { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowDelete { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string DeleteUserId { get; set; } + + /// + /// 子菜单 + /// + public List Children { get; set; } + + /// + /// 系统标记 + /// + public bool SystemTag { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Function/ModuleFunctionOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Function/ModuleFunctionOutputDto.cs new file mode 100644 index 0000000..cd0002a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Function/ModuleFunctionOutputDto.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 模块功能 + /// + [Serializable] + public class ModuleFunctionOutputDto + { + /// + /// 功能Id + /// + public long Id { get; set; } + + /// + /// 设置或获取 功能名称 + /// + public string FullName { get; set; } + + /// + /// 设置或获取 功能标识 0-子系统 1-标识菜单/模块,2标识按钮功能 + /// + public long FunctionTag { get; set; } + + /// + /// 设置或获取 是否禁止选择 + /// + public bool IsShow { get; set; } + + /// + /// 设置或获取 功能标识 M-标识菜单,F标识功能 + /// + public List listFunction { get; set; } + + /// + /// 子菜单 + /// + public List Children { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsInputDto.cs new file mode 100644 index 0000000..a8d9dab --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsInputDto.cs @@ -0,0 +1,36 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 行业岗位输出对象模型 + /// + [Serializable] + public class IndustryJobsInputDto + { + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 父级id + /// + public long ParentId { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 排序 + /// + public long Sort { get; set; } + + /// + /// 是否启用 + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsOutputDto.cs new file mode 100644 index 0000000..5b1d76a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsOutputDto.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 行业岗位输出对象模型 + /// + [Serializable] + public class IndustryJobsListOutputDto + { + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 父级id + /// + public long ParentId { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// + /// + public List Childers { get; set; } + } + + public class IndustryJobsOutputDto + { + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 父级id + /// + public long ParentId { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsTreeTableDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsTreeTableDto.cs new file mode 100644 index 0000000..72ebfd7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/IndustryJobs/IndustryJobsTreeTableDto.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 行业岗位输出对象模型 + /// + [Serializable] + public class IndustryJobsTreeTableDto + { + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 父级id + /// + public long ParentId { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 是否启用 + /// + public bool IsEnabled { get; set; } + + public List Childers { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/LoginLogsInPutDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/LoginLogsInPutDto.cs new file mode 100644 index 0000000..427a208 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/LoginLogsInPutDto.cs @@ -0,0 +1,114 @@ +using AutoMapper; +using System; +using System.ComponentModel.DataAnnotations; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(LoginLogsEntity))] + [Serializable] + public class LoginLogsInPutDto : IInputDto + { + /// + /// 设置或获取 + /// + public DateTime? Date { get; set; } + + /// + /// 设置或获取 + /// + public string Account { get; set; } + + /// + /// 设置或获取 + /// + public string UserName { get; set; } + + /// + /// 设置或获取 + /// + public long OrganizeId { get; set; } + + /// + /// 设置或获取 + /// + public string Type { get; set; } + + /// + /// 设置或获取 + /// + public string IPAddress { get; set; } + + /// + /// 设置或获取 + /// + public string IPAddressName { get; set; } + + /// + /// 设置或获取 + /// + public string ModuleId { get; set; } + + /// + /// 设置或获取 + /// + public string ModuleName { get; set; } + + /// + /// 设置或获取 + /// + public bool? Result { get; set; } + + /// + /// 设置或获取 + /// + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string DeleteUserId { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/LoginLogsOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/LoginLogsOutputDto.cs new file mode 100644 index 0000000..25d3fb7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/LoginLogsOutputDto.cs @@ -0,0 +1,56 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class LoginLogsOutputDto + { + /// + /// 用户名 + /// + public string UserName { get; set; } + + /// + /// 来源平台 + /// + public long PlatformType { get; set; } + + /// + /// 登录时间 + /// + public DateTime LoginTime { get; set; } + + /// + /// IP + /// + public string IP { get; set; } + + /// + /// 主机 + /// + public string OS { get; set; } + + /// + /// 客户端 + /// + public string Browser { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 登陆结果 + /// + public string Result { get; set; } + + /// + /// 操作系统 + /// + public string UserAgent { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/SearchLoginLogsModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/SearchLoginLogsModel.cs new file mode 100644 index 0000000..9289335 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/LoginLogs/SearchLoginLogsModel.cs @@ -0,0 +1,26 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 日志搜索条件 + /// + public class SearchLoginLogsModel : SearchInputDto + { + /// + /// 添加开始时间 + /// + public string StartTime { get; set; } + + /// + /// 添加结束时间 + /// + public string EndTime { get; set; } + + /// + /// 来源平台 + /// + public int PlatformType { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuInputDto.cs new file mode 100644 index 0000000..fcf5703 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuInputDto.cs @@ -0,0 +1,131 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(MenuEntity))] + [Serializable] + public class MenuInputDto : IInputDto + { + /// + /// 设置或获取 + /// + public long SystemTypeId { get; set; } + + /// + /// 设置或获取 + /// + public long ParentId { get; set; } + + /// + /// 设置或获取 + /// + public long Layers { get; set; } + + /// + /// 设置或获取 + /// + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + public string Icon { get; set; } + + /// + /// 设置或获取路由 + /// + public virtual string UrlAddress { get; set; } + + /// + /// 设置或获取目标打开方式 + /// + public virtual string Target { get; set; } + + /// + /// 设置或获取菜单类型(C目录 M菜单 F按钮) + /// + public virtual string MenuType { get; set; } + + /// + /// 设置或获取组件路径 + /// + public virtual string Component { get; set; } + + /// + /// 设置当前选中菜单,用于新增、编辑、查看操作为单独的路由时指定选中菜单路由 + /// 同时设置为隐藏时才有效 + /// + public virtual string ActiveMenu { get; set; } + + /// + /// 设置或获取 + /// + public bool IsExpand { get; set; } + + /// + /// 设置或获取 是否显示 + /// + public bool IsShow { get; set; } + + /// + /// 设置或获取是否缓存 + /// + public bool IsCache { get; set; } + + /// + /// 设置或获取 是否外链 + /// + public bool IsFrame { get; set; } + + /// + /// 设置或获取 批量添加 + /// + public bool IsBatch { get; set; } + + /// + /// 设置或获取 + /// + public bool IsPublic { get; set; } + + /// + /// 设置或获取 + /// + public int SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + public string Description { get; set; } + + /// + /// 创建日期 + /// + public virtual DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + public string SystemTypeName { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuOutputDto.cs new file mode 100644 index 0000000..2268253 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuOutputDto.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class MenuOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string SystemTypeId { get; set; } + + public string SystemTypeName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long ParentId { get; set; } + + /// + /// 设置或获取 + /// + public long? Layers { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Icon { get; set; } + + /// + /// 设置或获取路由 + /// + public virtual string UrlAddress { get; set; } + + /// + /// 设置或获取目标打开方式 + /// + public virtual string Target { get; set; } + + /// + /// 设置或获取菜单类型(C目录 M菜单 F按钮) + /// + public virtual string MenuType { get; set; } + + /// + /// 设置或获取组件路径 + /// + public virtual string Component { get; set; } + + /// + /// 设置当前选中菜单,用于新增、编辑、查看操作为单独的路由时指定选中菜单路由 + /// 同时设置为隐藏时才有效 + /// + public virtual string ActiveMenu { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsExpand { get; set; } + + /// + /// 设置或获取 是否显示 + /// + public bool IsShow { get; set; } + + /// + /// 设置或获取 是否外链 + /// + public bool IsFrame { get; set; } + + /// + /// 设置或获取是否缓存 + /// + public bool IsCache { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsPublic { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowEdit { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowDelete { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public bool IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string DeleteUserId { get; set; } + + /// + /// 子菜单集合 + /// + public List SubMenu { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuTreeTableOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuTreeTableOutputDto.cs new file mode 100644 index 0000000..8555f6b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Menu/MenuTreeTableOutputDto.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// vue树形表 + /// + public class MenuTreeTableOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string SystemTypeId { get; set; } + + /// + /// + public string SystemTypeName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long ParentId { get; set; } + + /// + /// 设置或获取 + /// + public long? Layers { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Icon { get; set; } + + /// + /// 设置或获取路由 + /// + public virtual string UrlAddress { get; set; } + + /// + /// 设置或获取目标打开方式 + /// + public virtual string Target { get; set; } + + /// + /// 设置或获取菜单类型(C目录 M菜单 F按钮) + /// + public virtual string MenuType { get; set; } + + /// + /// 设置或获取组件路径 + /// + public virtual string Component { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsExpand { get; set; } + + /// + /// 设置或获取 是否显示 + /// + public bool? IsShow { get; set; } + + /// + /// 设置或获取 是否外链 + /// + public bool? IsFrame { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsPublic { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowEdit { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowDelete { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string DeleteUserId { get; set; } + + /// + /// 子菜单 + /// + public List Children { get; set; } + + /// + /// 系统标记 + /// + public bool SystemTag { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageInputDto.cs new file mode 100644 index 0000000..eb700f7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageInputDto.cs @@ -0,0 +1,48 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(MessageEntity))] + [Serializable] + public class MessageInputDto : IInputDto + { + /// + /// 消息内容 + /// + public string Content { get; set; } + + /// + /// 产品Id + /// + public long EquipmentId { get; set; } + + /// + /// 标题 + /// + public string EquipmentTitle { get; set; } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 消息标题 + /// + public string MessageTitle { get; set; } + + + /// + /// 创建人 + /// + public long CreatedUserId { get; set; } + + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageLogsInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageLogsInputDto.cs new file mode 100644 index 0000000..a69720e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageLogsInputDto.cs @@ -0,0 +1,32 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(MessageLogsEntity))] + [Serializable] + public class MessageLogsInputDto : IInputDto + { + /// + /// 接收者Id + /// + public long ReceiverId { get; set; } + + /// + /// 消息Id + /// + public long MessageId { get; set; } + + /// + /// 状态 + /// + public long State { get; set; } + + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageLogsOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageLogsOutputDto.cs new file mode 100644 index 0000000..4cc00e2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageLogsOutputDto.cs @@ -0,0 +1,26 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class MessageLogsOutputDto + { + /// + /// 接收者Id + /// + public long ReceiverId { get; set; } + + /// + /// 消息Id + /// + public long MessageId { get; set; } + + /// + /// 状态 + /// + public long State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageOutputDto.cs new file mode 100644 index 0000000..3c9132f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Message/MessageOutputDto.cs @@ -0,0 +1,46 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class MessageOutputDto + { + /// + /// 发送者Id + /// + public long SendId { get; set; } + + /// + /// 发送类型 + /// + public long Type { get; set; } + + /// + /// 组Id(不涉及组消息可不用) + /// + public long GroupId { get; set; } + + /// + /// 消息内容 + /// + public string Content { get; set; } + + /// + /// 发送时间 + /// + public DateTime SendTime { get; set; } + + /// + /// 产品Id + /// + public long ProductId { get; set; } + + /// + /// 标题 + /// + public string Title { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/OperationLogsInPutDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/OperationLogsInPutDto.cs new file mode 100644 index 0000000..de95d50 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/OperationLogsInPutDto.cs @@ -0,0 +1,70 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(OperationLogsEntity))] + [Serializable] + public class OperationLogsInPutDto : IInputDto + { + /// + /// 操作类型 + /// + public string CRUD { get; set; } + + /// + /// 操作用户 + /// + public string UserName { get; set; } + + /// + /// 操作时间 + /// + public DateTime OperationTime { get; set; } + + /// + /// IP + /// + public string IP { get; set; } + + /// + /// 主机 + /// + public string OS { get; set; } + + /// + /// 浏览器 + /// + public string Browser { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 操作系统 + /// + public string UserAgent { get; set; } + + /// + /// 请求明细 + /// + public string RequertData { get; set; } + + /// + /// 请求url + /// + public string RequestUrl { get; set; } + + /// + /// 主键 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/OperationLogsOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/OperationLogsOutputDto.cs new file mode 100644 index 0000000..a42b171 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/OperationLogsOutputDto.cs @@ -0,0 +1,114 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class OperationLogsOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? Date { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Account { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string UserName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long OrganizeId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Type { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string IPAddress { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string IPAddressName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModuleId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModuleName { get; set; } + + /// + /// 设置或获取 + /// + public bool? Result { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(2147483647)] + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public bool IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public bool IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/SearchOperationLogsModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/SearchOperationLogsModel.cs new file mode 100644 index 0000000..0bd0ffc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/OperationLogs/SearchOperationLogsModel.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 操作日志搜索条件 + /// + public class SearchOperationLogsModel : SearchInputDto + { + /// + /// 添加开始时间 + /// + public string StartTime { get; set; } + + /// + /// 添加结束时间 + /// + public string EndTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Order/OrderOutput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Order/OrderOutput.cs new file mode 100644 index 0000000..5fb021e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Order/OrderOutput.cs @@ -0,0 +1,107 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 订单输出模型 + /// + public class OrderOutput + { + public long Id { get; set; } + + /// + /// 订单编号 + /// + public string OrderSn { get; set; } + + /// + /// 下单人ID + /// + public long UserId { get; set; } + + /// + /// 收货人姓名 + /// + public string ShippingUser { get; set; } + + /// + /// 收货人所在省 + /// + public long Province { get; set; } + + /// + /// 收货人所在市 + /// + public long City { get; set; } + + /// + /// 收货人所在区 + /// + public long Area { get; set; } + + /// + /// 收货人详细地址 + /// + public string Address { get; set; } + + /// + /// 支付方式:1现金,2余额,3网银,4支付宝,5微信.6云币 + /// + public int PaymentMethod { get; set; } + + /// + /// 订单金额 + /// + public decimal OrderMoney { get; set; } + + /// + /// 优惠金额 + /// + public decimal DistrictMoney { get; set; } + + /// + /// 支付金额 + /// + public decimal PaymentMoney { get; set; } + + /// + /// 快递公司名称 + /// + public string ShippingCompName { get; set; } + + /// + /// 快递单号 + /// + public string ShippingSn { get; set; } + + /// + /// 发货时间 + /// + public DateTime? ShippingTime { get; set; } + + /// + /// 支付时间 + /// + public DateTime PayTime { get; set; } + + /// + /// 收货时间 + /// + public DateTime? ReceiveTime { get; set; } + + /// + /// 订单状态:0-已取消-10-未付款,20-已付款,40-已发货,50-交易成功,60-交易关闭 + /// + public int OrderStatus { get; set; } + + /// + /// 订单积分 + /// + public int OrderPoint { get; set; } + + /// + /// 发票抬头 + /// + public string InvoiceTitle { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/OrderDetail/OrderDetailOutput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/OrderDetail/OrderDetailOutput.cs new file mode 100644 index 0000000..9b42044 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/OrderDetail/OrderDetailOutput.cs @@ -0,0 +1,35 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 订单详情输出模型 + /// + public class OrderDetailOutput + { + public long Id { get; set; } + + /// + /// 订单表ID + /// + public long OrderId { get; set; } + + /// + /// 订单商品ID + /// + public long ProductId { get; set; } + + /// + /// 商品名称 + /// + public string ProductName { get; set; } + + /// + /// 购买商品数量 + /// + public int ProductCnt { get; set; } + + /// + /// 购买商品单价 + /// + public decimal ProductPrice { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Organize/OrganizeInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Organize/OrganizeInputDto.cs new file mode 100644 index 0000000..0f07c94 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Organize/OrganizeInputDto.cs @@ -0,0 +1,65 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(OrganizeEntity))] + [Serializable] + public class OrganizeInputDto : IInputDto + { + /// + /// 父级id + /// + public long ParentId { get; set; } + + /// + /// 所属层级 + /// + public int Layers { get; set; } + + /// + /// 功能代码 + /// + public string EnCode { get; set; } + + /// + /// 名称 + /// + public string FullName { get; set; } + + /// + /// 类别Id + /// + public string CategoryName { get; set; } + + /// + /// 上级Id + /// + public string ManagerName { get; set; } + + /// + /// 排序 + /// + public int SortCode { get; set; } + + /// + /// 是否启用 + /// + public bool IsEnabled { get; set; } + + /// + /// 备注 + /// + public string Description { get; set; } + + /// + /// 主键 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Organize/OrganizeOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Organize/OrganizeOutputDto.cs new file mode 100644 index 0000000..b7990cd --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Organize/OrganizeOutputDto.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class OrganizeOutputDto + { + /// + /// 设置或获取 + /// + public long Id { get; set; } + + /// + /// 父级 + /// + public long ParentId { get; set; } + + /// + /// 层次 + /// + public int Layers { get; set; } + + /// + /// 编码 + /// + public string EnCode { get; set; } + + /// + /// 名称 + /// + public string FullName { get; set; } + + /// + /// 负责人 + /// + public string ManagerName { get; set; } + + /// + /// 类型 + /// + public string CategoryName { get; set; } + + /// + /// 排序码 + /// + public int SortCode { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 是否有效 + /// + public bool IsEnabled { get; set; } + + /// + /// 是否删除 + /// + public bool IsDeleted { get; set; } + + /// + /// 子集 + /// + public List Children { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 修改时间 + /// + public DateTime ModifiedTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/PaymentRecordInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/PaymentRecordInput.cs new file mode 100644 index 0000000..482a83f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/PaymentRecordInput.cs @@ -0,0 +1,25 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// + /// + public class PaymentRecordInput + { + public long Id { get; set; } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 总云币 + /// + public decimal TotalCredits { get; set; } + + /// + /// 可用云币 + /// + public decimal AvailableCredits { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/PaymentRecordOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/PaymentRecordOutputDto.cs new file mode 100644 index 0000000..7165085 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/PaymentRecordOutputDto.cs @@ -0,0 +1,57 @@ +using System; +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 充值列表Dto + /// + [Serializable] + public class PaymentRecordOutputDto + { + /// + /// 积分Id + /// + public long Id { get; set; } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 用户Id + /// + public string UserName { get; set; } + + /// + /// 用户头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 用户手机号 + /// + public string Phone { get; set; } + + /// + /// 流水号 + /// + // public string PaySn { get; set; } + + /// + /// 充值金额 + /// + public decimal PaymentMoney { get; set; } + + /// + /// 支付状态:0-已取消-10-未成功,20-已成功 + /// + public int PayStatus { get; set; } + // + + /// + /// 收支时间 + /// + public DateTime CreatedTime { get; set; } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/SearchPaymentRecordModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/SearchPaymentRecordModel.cs new file mode 100644 index 0000000..af9ac45 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/PaymentRecord/SearchPaymentRecordModel.cs @@ -0,0 +1,28 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 充值列表搜索条件 + /// + public class SearchPaymentRecordModel : SearchInputDto + { + /// + /// 开始时间 + /// + public string StartTime { get; set; } + + /// + /// 结束时间 + /// + public string EndTime { get; set; } + + /// + /// 充值金额 + /// + public int PaymentMoney { get; set; } + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeAddInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeAddInput.cs new file mode 100644 index 0000000..2e067ad --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeAddInput.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 充值活动入参 + /// + public class RechargeAddInput + { + /// + /// 活动名称 + /// + public string Name { get; set; } + + public List rechargeIntros { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeOutputDto.cs new file mode 100644 index 0000000..9e50fa8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeOutputDto.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 充值活动输出模型 + /// + public class RechargeOutputDto + { + public long Id { get; set; } + + /// + /// 活动名称 + /// + public string Name { get; set; } + + /// + /// 状态0未开始/1进行中/2已结束 + /// + public int State { get; set; } + + /// + /// 状态名称 + /// + public string StatusName { get; set; } + + /// + /// 详情 + /// + public List rechargeIntros { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeUpdateInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeUpdateInput.cs new file mode 100644 index 0000000..98f6071 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/RechargeUpdateInput.cs @@ -0,0 +1,10 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 充值活动修改模型 + /// + public class RechargeUpdateInput : RechargeAddInput + { + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/SearchRechargeModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/SearchRechargeModel.cs new file mode 100644 index 0000000..4e8dc30 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recharge/SearchRechargeModel.cs @@ -0,0 +1,26 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 充值活动搜索条件 + /// + public class SearchRechargeModel : SearchInputDto + { + /// + /// 开始时间 + /// + public string StartTime { get; set; } + + /// + /// 结束时间 + /// + public string EndTime { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/RechargeIntro/RechargeIntroAddInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/RechargeIntro/RechargeIntroAddInput.cs new file mode 100644 index 0000000..acb5243 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/RechargeIntro/RechargeIntroAddInput.cs @@ -0,0 +1,25 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 充值活动详情入参 + /// + public class RechargeIntroAddInput + { + public long Id { get; set; } + + /// + /// 商品价值 + /// + public int ProductValue { get; set; } + + /// + /// 赠送价值 + /// + public int SendValue { get; set; } + + /// + /// 商品销售价 + /// + public decimal Price { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/RechargeIntro/RechargeIntroOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/RechargeIntro/RechargeIntroOutputDto.cs new file mode 100644 index 0000000..f59827b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/RechargeIntro/RechargeIntroOutputDto.cs @@ -0,0 +1,30 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 充值活动详情输出模型 + /// + public class RechargeIntroOutputDto + { + public long Id { get; set; } + + /// + /// 商品名称 + /// + public string ProductName { get; set; } + + /// + /// 商品价值 + /// + public int ProductValue { get; set; } + + /// + /// 赠送价值 + /// + public int SendValue { get; set; } + + /// + /// 商品销售价 + /// + public decimal Price { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/RecruitmentInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/RecruitmentInputDto.cs new file mode 100644 index 0000000..de6252e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/RecruitmentInputDto.cs @@ -0,0 +1,114 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(CloudcarEntity))] + [Serializable] + public class CloudcarInputDto : IInputDto + { + /// + /// 标题 + /// + public string Title { get; set; } + + public long UserId { get; set; } + + /// + /// 内容 + /// + public string Content { get; set; } + + /// + /// 电话 + /// + public string Phone { get; set; } + + /// + /// 行业类型 + /// + public long IndustryId { get; set; } + + /// + /// 岗位类型 + /// + public long JobId { get; set; } + + /// + /// 工作地区省 + /// + public long ProvinceId { get; set; } + + /// + /// 工作地区市 + /// + public long CityId { get; set; } + + /// + /// 工作地区区 + /// + public long AreaId { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 工资福利 + /// + public string Welfare { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime TopExpireTime { get; set; } + + /// + /// 流水号 + /// + public string SerialNumber { get; set; } + + /// + /// 地址明细(冗余,用于首页查询省市区模糊匹配) + /// + public string Address { get; set; } + + /// + /// 创建人 + /// + public long CreatedUserId { get; set; } + + /// + /// 发布时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 修改时间 + /// + public DateTime ModifiedTime { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/RecruitmentOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/RecruitmentOutputDto.cs new file mode 100644 index 0000000..7534d02 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/RecruitmentOutputDto.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class CloudcarOutputDto + { + /// + /// 主键 + /// + public long Id { get; set; } + + /// + /// 标题 + /// + public string Title { get; set; } + + + public long UserId { get; set; } + + /// + /// 用户姓名 + /// + public string UserName { get; set; } + + /// + /// 头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 内容 + /// + public string Content { get; set; } + + /// + /// 电话 + /// + public string Phone { get; set; } + + /// + /// 行业类型 + /// + public long IndustryId { get; set; } + + /// + /// 行业类型名称 + /// + public string IndustryName { get; set; } + + /// + /// 岗位类型 + /// + public long JobId { get; set; } + + /// + /// 岗位类型名称 + /// + public string JobName { get; set; } + + /// + /// 工作地区省 + /// + public long ProvinceId { get; set; } + + /// + /// 工作地点 + /// + public long CityId { get; set; } + + /// + /// 工作地区区 + /// + public long AreaId { get; set; } + + /// + /// 状态 + /// + public long State { get; set; } + + /// + /// 状态名称 + /// + public string StatusName { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 是否置顶 + /// + public string Top { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 是否公开 + /// + public string Public { get; set; } + + /// + /// 工资福利 + /// + public string Welfare { get; set; } + + /// + /// 工资福利 + /// + public List WelfareList { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime? TopExpireDate { get; set; } + + /// + /// 地址明细(冗余,用于首页查询省市区模糊匹配) + /// + public string Address { get; set; } + + /// + /// 流水号 + /// + public string SerialNumber { get; set; } + + /// + /// 更新时间 + /// + public DateTime ModifiedTime { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + /// + /// 失败原因 + /// + public string Note { get; set; } + + /// + /// 浏览量 + /// + public int PageView { get; set; } + + /// + /// 微信昵称 + /// + public string NickName { get; set; } + + /// + /// 微信头像 + /// + public string WxAvatarUrl { get; set; } + + /// + /// 联系人 + /// + public string Contact { get; set; } + + /// + /// 通话评价反馈 + /// + public List CallFeedbacks { get; set; } + + /// + /// 通话评价反馈是否已读 + /// + public bool IsReadForCallFeedback { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/SearchRecruitmentModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/SearchRecruitmentModel.cs new file mode 100644 index 0000000..7cfcc72 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Recruitment/SearchRecruitmentModel.cs @@ -0,0 +1,41 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 求职搜索条件 + /// + public class SearchCloudcarModel : SearchInputDto + { + /// + /// 注册或添加时间 开始 + /// + public string StartTime { get; set; } + + /// + /// 注册或添加时间 结束 + /// + public string EndTime { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 姓名 + /// + public string UserName { get; set; } + + /// + /// 行业Id + /// + public long industryId { get; set; } + + /// + /// 岗位Id + /// + public long jobId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Region/RegionOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Region/RegionOutputDto.cs new file mode 100644 index 0000000..9d052be --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Region/RegionOutputDto.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 省市区三级输出模型 + /// + [Serializable] + public class RegionOutputDto + { + /// + /// Id + /// + public long RegionId { get; set; } + + /// + /// 父级Id + /// + public long ParentId { get; set; } + + /// + /// 名称 + /// + public string Name { get; set; } + + public List Childers { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeDataInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeDataInputDto.cs new file mode 100644 index 0000000..778cd76 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeDataInputDto.cs @@ -0,0 +1,31 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 角色授权输入模型 + /// + [Serializable] + public class RoleAuthorizeDataInputDto + { + /// + /// 设置角色功能 + /// + public long[] RoleFunctios { get; set; } + + /// + /// 设置角色可访问系统 + /// + public long[] RoleSystem { get; set; } + + /// + /// 设置角色可访问数据 + /// + public string[] RoleData { get; set; } + + /// + /// 设置角色Id + /// + public long RoleId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeInputDto.cs new file mode 100644 index 0000000..fd041f6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeInputDto.cs @@ -0,0 +1,45 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(RoleAuthorizeEntity))] + [Serializable] + public class RoleAuthorizeInputDto : IInputDto + { + /// + /// 设置或获取 + /// + public long? ItemType { get; set; } + + /// + /// 设置或获取 + /// + public string ItemId { get; set; } + + /// + /// 设置或获取 + /// + public long? ObjectType { get; set; } + + /// + /// 设置或获取 + /// + public string ObjectId { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeOutputDto.cs new file mode 100644 index 0000000..03e10e3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleAuthorizeOutputDto.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class RoleAuthorizeOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + public long? ItemType { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ItemId { get; set; } + + /// + /// 设置或获取 + /// + public long? ObjectType { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ObjectId { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + public List Children { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleDataInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleDataInputDto.cs new file mode 100644 index 0000000..5320226 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleDataInputDto.cs @@ -0,0 +1,40 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(RoleDataEntity))] + [Serializable] + public class RoleDataInputDto : IInputDto + { + /// + /// 设置或获取 + /// + public string RoleId { get; set; } + + /// + /// 类型,company-公司,dept-部门,person-个人 + /// + public virtual string DType { get; set; } + + /// + /// 数据数据,部门ID或个人ID + /// + public virtual string AuthorizeData { get; set; } + + /// + /// 设置或获取 + /// + public string Note { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleDataOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleDataOutputDto.cs new file mode 100644 index 0000000..e428162 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleDataOutputDto.cs @@ -0,0 +1,40 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class RoleDataOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string RoleId { get; set; } + + /// + /// 类型,company-公司,dept-部门,person-个人 + /// + public virtual string DType { get; set; } + + /// + /// 数据数据,部门ID或个人ID + /// + public virtual string AuthorizeData { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(1073741823)] + public string Note { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleInputDto.cs new file mode 100644 index 0000000..bbf0a00 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleInputDto.cs @@ -0,0 +1,70 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(RoleEntityEntity))] + [Serializable] + public class RoleInputDto : IInputDto + { + /// + /// 组织id + /// + public long OrganizeId { get; set; } + + /// + /// 类别 + /// + public long Category { get; set; } + + /// + /// 编码 + /// + public string EnCode { get; set; } + + /// + /// 名称 + /// + public string FullName { get; set; } + + /// + /// 类型 + /// + public string Type { get; set; } + + /// + /// 是否可以编辑 + /// + public bool AllowEdit { get; set; } + + /// + /// 是否可以删除 + /// + public bool AllowDelete { get; set; } + + /// + /// 排序 + /// + public long SortCode { get; set; } + + /// + /// 是否可用 + /// + public bool IsEnabled { get; set; } + + /// + /// 详情描述 + /// + public string Description { get; set; } + + /// + /// 主键 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleOutputDto.cs new file mode 100644 index 0000000..97c8c2b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Role/RoleOutputDto.cs @@ -0,0 +1,116 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class RoleOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long OrganizeId { get; set; } + + /// + /// 组织名称 + /// + public virtual string OrganizeName { get; set; } + + /// + /// 设置或获取 + /// + public long? Category { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Type { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowEdit { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowDelete { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string DeleteUserId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/SecurityProfile.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/SecurityProfile.cs new file mode 100644 index 0000000..a94ea2e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/SecurityProfile.cs @@ -0,0 +1,151 @@ +using AutoMapper; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// + public class SecurityProfile : Profile + { + /// + /// / + /// + public SecurityProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(s => s.label, s => s.MapFrom(o => o.FullName)) + .ForMember(s => s.value, s => s.MapFrom(o => o.Id)); + CreateMap() + .ForMember(e => e.text, s => s.MapFrom(o => o.FullName)) + .ForMember(e => e.Id, s => s.MapFrom(o => o.Id)); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap() + .ForMember(s => s.Id, s => s.MapFrom(o => o.Id)) + .ForMember(s => s.FullName, s => s.MapFrom(o => o.FullName)); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap().ReverseMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + + + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + CreateMap(); + + CreateMap(); + + + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalInputDto.cs new file mode 100644 index 0000000..ee5694a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalInputDto.cs @@ -0,0 +1,61 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 控制台首页显示统计数据 + /// + [Serializable] + public class StatisticalInputDto + { + /// + /// 时间 + /// + public string Time { get; set; } + + /// + /// 今日新增用户 + /// + public int UserAddTotal { get; set; } + + /// + /// 用户总数 + /// + public int UserSumTotal { get; set; } + + /// + /// 今日求职发布数 + /// + public int ApplyJobsAddTotal { get; set; } + + /// + /// 今日招聘发布数 + /// + public int CloudcarAddTotal { get; set; } + + /// + /// 本日活跃用户数 + /// + public int ActiveUserTotal { get; set; } + + /// + /// 总收入 + /// + public decimal Income { get; set; } + + /// + /// 日收入 + /// + public decimal TodayIncome { get; set; } + + /// + /// 今日收入百分比 + /// + public decimal TodayIncomePercent { get; set; } + + /// + /// 今日用户增长百分比 + /// + public decimal UserAddTotalPercent { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalListOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalListOutputDto.cs new file mode 100644 index 0000000..ac2415e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalListOutputDto.cs @@ -0,0 +1,61 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 控制台首页显示统计数据 + /// + [Serializable] + public class StatisticalListOutputDto + { + /// + /// 时间 + /// + public string Time { get; set; } + + /// + /// 今日新增用户 + /// + public int UserAddTotal { get; set; } + + /// + /// 用户总数 + /// + public int UserSumTotal { get; set; } + + /// + /// 今日求职发布数 + /// + public int ApplyJobsAddTotal { get; set; } + + /// + /// 今日招聘发布数 + /// + public int CloudcarAddTotal { get; set; } + + /// + /// 本日活跃用户数 + /// + public int ActiveUserTotal { get; set; } + + /// + /// 总收入 + /// + public decimal Income { get; set; } + + /// + /// 日收入 + /// + public decimal TodayIncome { get; set; } + + /// + /// 今日收入百分比 + /// + public decimal TodayIncomePercent { get; set; } + + /// + /// 今日用户增长百分比 + /// + public decimal UserAddTotalPercent { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalOutputDto.cs new file mode 100644 index 0000000..b24dbba --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/Statistical/StatisticalOutputDto.cs @@ -0,0 +1,88 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 控制台首页显示统计数据 + /// + [Serializable] + public class StatisticalOutputDto + { + /// + /// 今日新增用户 + /// + public int UserAddTotal { get; set; } + + /// + /// 用户总数 + /// + public int UserSumTotal { get; set; } + + /// + /// 今日求职发布数 + /// + public int ApplyJobsAddTotal { get; set; } + + /// + /// 今日招聘发布数 + /// + public int CloudcarAddTotal { get; set; } + + /// + /// 本日活跃用户数 + /// + public int ActiveUserTotal { get; set; } + + /// + /// 总收入 + /// + public decimal Income { get; set; } + + /// + /// 日收入 + /// + public decimal TodayIncome { get; set; } + + /// + /// 日增收 + /// + public decimal IncomeIncremental { get; set; } + + /// + /// 今日收入百分比 + /// + public decimal TodayIncomePercent { get; set; } + + /// + /// 用户增长百分比 + /// + public decimal UserAddTotalPercent { get; set; } + + /// + /// 日增长百分比 + /// + public decimal DayAddPercent { get; set; } + + /// + /// 总收入百分比 + /// + public decimal IncomePercent { get; set; } + + /// + /// 求职待审核数 + /// + public int ReviewApplyJobsTotal { get; set; } + + /// + /// 招聘待审核数 + /// + public int ReviewCloudcarTotal { get; set; } + + /// + /// 实名认证待审核数 + /// + public int ReviewCertificationTotal { get; set; } + + public int EquipmentTotal { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/SysSetting/SysSettingOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/SysSetting/SysSettingOutputDto.cs new file mode 100644 index 0000000..209fa07 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/SysSetting/SysSettingOutputDto.cs @@ -0,0 +1,321 @@ +using System; +using System.Xml.Serialization; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出Dto:SysSetting + /// + [Serializable] + public class SysSettingOutputDto + { + /// + /// 版权信息 + /// + public string CopyRight { get; set; } + + #region 系统基本信息 + + /// + /// 系统名称 + /// + [XmlElement("SoftName")] + public string SoftName { get; set; } + + /// + /// 系统简介 + /// + [XmlElement("SoftSummary")] + public string SoftSummary { get; set; } + + /// + /// 访问域名 + /// + [XmlElement("WebUrl")] + public string WebUrl { get; set; } + + /// + /// Logo + /// + [XmlElement("SysLogo")] + public string SysLogo { get; set; } + + /// + /// 公司名称 + /// + [XmlElement("CompanyName")] + public string CompanyName { get; set; } + + /// + /// 地址 + /// + [XmlElement("Address")] + public string Address { get; set; } + + /// + /// 电话 + /// + [XmlElement("Telphone")] + public string Telphone { get; set; } + + /// + /// Email + /// + [XmlElement("Email")] + public string Email { get; set; } + + /// + /// ICP备案号 + /// + [XmlElement("ICPCode")] + public string ICPCode { get; set; } + + /// + /// 公安备案号 + /// + [XmlElement("PublicSecurityCode")] + public string PublicSecurityCode { get; set; } + + /// + /// 分享标题 + /// + [XmlElement("ShareTitle")] + public string ShareTitle { get; set; } + + /// + /// 微信公众号分享图片 + /// + [XmlElement("ShareWeChatImage")] + public string ShareWeChatImage { get; set; } + + /// + /// 微信小程序分享图片 + /// + [XmlElement("ShareWxAppletImage")] + public string ShareWxAppletImage { get; set; } + + /// + /// 微信推广二维码背景图片 + /// + [XmlElement("ShareBackgroundImage")] + public string ShareBackgroundImage { get; set; } + + #endregion 系统基本信息 + + #region 功能权限设置 + + /// + /// URL重写开关 + /// + [XmlElement("Staticstatus")] + public string Staticstatus { get; set; } + + /// + /// 静态URL后缀 + /// + [XmlElement("Staticextension")] + public string Staticextension { get; set; } + + /// + /// 开启会员功能 + /// + [XmlElement("Memberstatus")] + public string Memberstatus { get; set; } + + /// + /// 是否开启网站 + /// + [XmlElement("Webstatus")] + public string Webstatus { get; set; } + + /// + /// 网站关闭原因 + /// + [XmlElement("Webclosereason")] + public string Webclosereason { get; set; } + + /// + /// 网站统计代码 + /// + [XmlElement("Webcountcode")] + public string Webcountcode { get; set; } + + #endregion 功能权限设置 + + #region 文件服务器 + + /// + /// 文件服务器 + /// + [XmlElement("Fileserver")] + public string Fileserver { get; set; } + + /// + /// 本地文件存储物理物理路径 + /// + [XmlElement("LocalPath")] + public string LocalPath { get; set; } + + /// + /// 阿里云KeyId + /// + [XmlElement("Osssecretid")] + public string Osssecretid { get; set; } + + /// + /// 阿里云SecretKey + /// + [XmlElement("Osssecretkey")] + public string Osssecretkey { get; set; } + + /// + /// 阿里云Bucket + /// + [XmlElement("Ossbucket")] + public string Ossbucket { get; set; } + + /// + /// 阿里云EndPoint + /// + [XmlElement("Ossendpoint")] + public string Ossendpoint { get; set; } + + /// + /// 阿里云绑定域名 + /// + [XmlElement("Ossdomain")] + public string Ossdomain { get; set; } + + #endregion 文件服务器 + + #region 文件上传设置 + + /// + /// 文件上传目录 + /// + [XmlElement("Filepath")] + public string Filepath { get; set; } + + /// + /// 文件保存方式 + /// + [XmlElement("Filesave")] + public string Filesave { get; set; } + + /// + /// 编辑器图片 + /// + [XmlElement("Fileremote")] + public string Fileremote { get; set; } + + /// + /// 文件上传类型 + /// + [XmlElement("Fileextension")] + public string Fileextension { get; set; } + + /// + /// 视频上传类型 + /// + [XmlElement("Videoextension")] + public string Videoextension { get; set; } + + /// + /// 附件上传大小 + /// + [XmlElement("Attachsize")] + public string Attachsize { get; set; } + + /// + /// 视频上传大小 + /// + [XmlElement("Videosize")] + public string Videosize { get; set; } + + /// + /// 图片上传大小 + /// + [XmlElement("Imgsize")] + public string Imgsize { get; set; } + + /// + /// 图片最大尺寸 高度 + /// + [XmlElement("Imgmaxheight")] + public string Imgmaxheight { get; set; } + + /// + /// 图片最大尺寸 宽度 + /// + [XmlElement("Imgmaxwidth")] + public string Imgmaxwidth { get; set; } + + /// + /// 缩略图生成尺寸 高度 + /// + [XmlElement("Thumbnailheight")] + public string Thumbnailheight { get; set; } + + /// + /// 缩略图生成尺寸 宽度 + /// + [XmlElement("Thumbnailwidth")] + public string Thumbnailwidth { get; set; } + + /// + /// 缩略图生成方式 + /// + [XmlElement("Thumbnailmode")] + public string Thumbnailmode { get; set; } + + /// + /// 图片水印类型 + /// + [XmlElement("Watermarktype")] + public string Watermarktype { get; set; } + + /// + /// 图片水印位置 + /// + [XmlElement("Watermarkposition")] + public string Watermarkposition { get; set; } + + /// + /// 图片生成质量 + /// + [XmlElement("Watermarkimgquality")] + public string Watermarkimgquality { get; set; } + + /// + /// 图片水印文件 + /// + [XmlElement("Watermarkpic")] + public string Watermarkpic { get; set; } + + /// + /// 水印透明度 + /// + [XmlElement("Watermarktransparency")] + public string Watermarktransparency { get; set; } + + /// + /// 水印文字 + /// + [XmlElement("Watermarktext")] + public string Watermarktext { get; set; } + + /// + /// 文字字体格式 + /// + [XmlElement("Watermarkfont")] + public string Watermarkfont { get; set; } + + /// + /// 文字字体大小 + /// + [XmlElement("Watermarkfontsize")] + public string Watermarkfontsize { get; set; } + + #endregion 文件上传设置 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/SystemType/SystemTypeInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/SystemType/SystemTypeInputDto.cs new file mode 100644 index 0000000..fb09493 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/SystemType/SystemTypeInputDto.cs @@ -0,0 +1,60 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(SystemTypeEntity))] + [Serializable] + public class SystemTypeInputDto : IInputDto + { + /// + /// 设置或获取 + /// + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + public string Url { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowEdit { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowDelete { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/SystemType/SystemTypeOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/SystemType/SystemTypeOutputDto.cs new file mode 100644 index 0000000..2d9fd9e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/SystemType/SystemTypeOutputDto.cs @@ -0,0 +1,100 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class SystemTypeOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string EnCode { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string FullName { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(250)] + public string Url { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowEdit { get; set; } + + /// + /// 设置或获取 + /// + public bool? AllowDelete { get; set; } + + /// + /// 设置或获取 + /// + public long? SortCode { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string DeleteUserId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileInputDto.cs new file mode 100644 index 0000000..fd10717 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileInputDto.cs @@ -0,0 +1,80 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(UploadFileEntity))] + [Serializable] + public class UploadFileInputDto : IInputDto + { + /// + /// 设置或获取 + /// + public string FileName { get; set; } + + /// + /// 设置或获取 + /// + public string FilePath { get; set; } + + /// + /// 设置或获取 + /// + public string Description { get; set; } + + /// + /// 设置或获取 + /// + public string FileType { get; set; } + + /// + /// 设置或获取 + /// + public long? FileSize { get; set; } + + /// + /// 设置或获取 + /// + public string Extension { get; set; } + + /// + /// 设置或获取 + /// + public bool IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + public long SortCode { get; set; } + + /// + /// 设置或获取 + /// + public string CreateUserName { get; set; } + + /// + /// 设置或获取 + /// + public string Thumbnail { get; set; } + + /// + /// 设置或获取 + /// + public string BelongApp { get; set; } + + /// + /// 设置或获取 + /// + public string BelongAppId { get; set; } + + /// + /// 设置或获取 + /// + public long Id { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileOutputDto.cs new file mode 100644 index 0000000..c0c5c10 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileOutputDto.cs @@ -0,0 +1,91 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出Dto:UploadFile + /// + [Serializable] + public class UploadFileOutputDto + { + /// + /// Id + /// + public long Id { get; set; } + + /// + /// 文件名称 + /// + public string FileName { get; set; } + + /// + /// 文件路径 + /// + public string FilePath { get; set; } + + /// + /// 文件路径物理路径 + /// + public string PhysicsFilePath { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 文件类型 + /// + public string FileType { get; set; } + + /// + /// 文件大小 + /// + public long FileSize { get; set; } + + /// + /// 扩展名称 + /// + public string Extension { get; set; } + + /// + /// 排序 + /// + public long SortCode { get; set; } + + /// + /// 删除标志 + /// + public virtual bool? IsDeleted { get; set; } + + /// + /// 有效标志 + /// + public virtual bool IsEnabled { get; set; } + + /// + /// 创建用户主键 + /// + public virtual long CreatedUserId { get; set; } + + /// + /// 上传时间 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 缩略图 + /// + public string Thumbnail { get; set; } + + /// + /// 所属应用 + /// + public string BelongApp { get; set; } + + /// + /// 所属应用ID + /// + public string BelongAppId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileResultOuputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileResultOuputDto.cs new file mode 100644 index 0000000..8a618db --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/UploadFile/UploadFileResultOuputDto.cs @@ -0,0 +1,46 @@ +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 上传结束输出文件对象 + /// + [Serializable] + public class UploadFileResultOuputDto : IOutputDto + { + /// + /// + public long Id { get; set; } + + /// + /// 文件名称 + /// + public string FileName { get; set; } + + /// + /// 文件路径物理路径 + /// + public string PhysicsFilePath { get; set; } + + /// + /// 缩略图 + /// + public string Thumbnail { get; set; } + + /// + /// 文件路径 + /// + public string FilePath { get; set; } + + /// + /// 文件大小 + /// + public long FileSize { get; set; } + + /// + /// 文件类型 + /// + public string FileType { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/SearchUserModel.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/SearchUserModel.cs new file mode 100644 index 0000000..1be3cc8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/SearchUserModel.cs @@ -0,0 +1,36 @@ +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 用户搜索条件 + /// + public class SearchUserModel : SearchInputDto + { + /// + /// 角色Id + /// + public string RoleId { get; set; } + + /// + /// 注册或添加时间 开始 + /// + public string StartTime { get; set; } + + /// + /// 注册或添加时间 结束 + /// + public string EndTime { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 实名状态 + /// + public int CertificationState { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserAllListFocusOutPutDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserAllListFocusOutPutDto.cs new file mode 100644 index 0000000..bbbbed0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserAllListFocusOutPutDto.cs @@ -0,0 +1,227 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// + [Serializable] + [AutoMap(typeof(AdminUserEntity))] + public class UserAllListFocusOutPutDto + { + #region Property Members + + /// + /// 用户主键 + /// + public virtual long id { get; set; } + + /// + /// 账户 + /// + public virtual string Account { get; set; } + + /// + /// 姓名 + /// + public virtual string RealName { get; set; } + + /// + /// 呢称 + /// + public virtual string UserName { get; set; } + + /// + /// 头像 + /// + public virtual string HeadIcon { get; set; } + + /// + /// 性别 + /// + public virtual long? Gender { get; set; } + + /// + /// 生日 + /// + public virtual DateTime? Birthday { get; set; } + + /// + /// 手机 + /// + public virtual string MobilePhone { get; set; } + + /// + /// 密码 + /// + public virtual string UserPassword { get; set; } + + /// + /// 邮箱 + /// + public virtual string Email { get; set; } + + /// + /// 微信 + /// + public virtual string WeChat { get; set; } + + /// + /// 是否会员 + /// + public virtual bool? IsMember { get; set; } + + /// + /// 头像 + /// + public string MemberGradeId { get; set; } + + /// + /// 上级推广员 + /// + public long ReferralUserId { get; set; } + + /// + /// 主管主键 + /// + public virtual string ManagerId { get; set; } + + /// + /// 安全级别 + /// + public virtual long? SecurityLevel { get; set; } + + /// + /// 个性签名 + /// + public virtual string Signature { get; set; } + + /// + /// 组织主键 + /// + public virtual long OrganizeId { get; set; } + + /// + /// 组织名称 + /// + public virtual string OrganizeName { get; set; } + + /// + /// 部门主键 + /// + public virtual string DepartmentId { get; set; } + + /// + /// 部门名称 + /// + public virtual string DepartmentName { get; set; } + + /// + /// 角色主键 + /// + public virtual long RoleId { get; set; } + + /// + /// 角色名称 + /// + public virtual string RoleName { get; set; } + + /// + /// 岗位主键 + /// + public virtual string DutyId { get; set; } + + /// + /// 岗位名称 + /// + public virtual string DutyName { get; set; } + + /// + /// 是否管理员 + /// + public virtual bool? IsAdministrator { get; set; } + + /// + /// 排序码 + /// + public virtual long? SortCode { get; set; } + + /// + /// 描述 + /// + public virtual string Description { get; set; } + + /// + /// 删除标志 + /// + public virtual bool? IsDeleted { get; set; } + + /// + /// 有效标志 + /// + public virtual bool IsEnabled { get; set; } + + /// + /// 创建日期 + /// + public virtual DateTime? CreatedTime { get; set; } + + /// + /// 创建用户主键 + /// + public virtual long CreatedUserId { get; set; } + + /// + /// 最后修改时间 + /// + public virtual DateTime? ModifiedTime { get; set; } + + /// + /// 最后修改用户 + /// + public virtual long ModifiedUserId { get; set; } + + /// + /// 删除时间 + /// + public virtual DateTime? DeleteTime { get; set; } + + /// + /// 删除用户 + /// + public virtual string DeleteUserId { get; set; } + + /// + /// 我是否关注 + /// + public virtual string IfFocus { get; set; } + + /// + /// 总关注人数 + /// + public virtual long TotalFocus { get; set; } + + /// + /// 是否认证 + /// + public virtual string VipGrade { get; set; } + + /// + /// 是否认证 + /// + public virtual bool IsAuthentication { get; set; } + + /// + /// 认证级别 + /// + public virtual long AuthenticationType { get; set; } + + /// + /// 记录总数 + /// + public virtual long RecordCount { get; set; } + + #endregion Property Members + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserExtendInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserExtendInputDto.cs new file mode 100644 index 0000000..73b5933 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserExtendInputDto.cs @@ -0,0 +1,104 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(UserExtendEntity))] + [Serializable] + public class UserExtendInputDto + { + /// + /// 设置或获取 + /// + public long Id { get; set; } + + /// + /// 设置或获取名片内容 + /// + public string CardContent { get; set; } + + /// + /// 设置或获取电话 + /// + public string Telphone { get; set; } + + /// + /// 设置或获取地址 + /// + public string Address { get; set; } + + /// + /// 设置或获取公司名称 + /// + public string CompanyName { get; set; } + + /// + /// 设置或获取职位名称 + /// + public string PositionTitle { get; set; } + + /// + /// 设置或获取个人微信二维码 + /// + public string WechatQrCode { get; set; } + + /// + /// 设置或获取行业 + /// + public string IndustryId { get; set; } + + /// + /// 设置或获取隐私:0-不公开,1-公开;2-部分公开 + /// + public long? OpenType { get; set; } + + /// + /// 设置或获取是否允许他人转发你的名片 + /// + public bool? IsOtherShare { get; set; } + + /// + /// 设置或获取转发标题 + /// + public string ShareTitle { get; set; } + + /// + /// 设置或获取网址 + /// + public string WebUrl { get; set; } + + /// + /// 设置或获取公司简介 + /// + public string CompanyDesc { get; set; } + + /// + /// 设置或获取名片样式 + /// + public string CardTheme { get; set; } + + /// + /// 设置或获取Vip等级 + /// + public string VipGrade { get; set; } + + /// + /// 设置或获取是否认证 + /// + public bool? IsAuthentication { get; set; } + + /// + /// 设置或获取认证类型1-企业;2-个人 + /// + public long? AuthenticationType { get; set; } + + /// + /// 设置或获取 + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserExtendOutPutDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserExtendOutPutDto.cs new file mode 100644 index 0000000..aac94b9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserExtendOutPutDto.cs @@ -0,0 +1,171 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class UserExtendOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取用户Id + /// + [MaxLength(50)] + public long UserId { get; set; } + + /// + /// 设置或获取名片内容 + /// + [MaxLength(2147483647)] + public string CardContent { get; set; } + + /// + /// 设置或获取电话 + /// + [MaxLength(50)] + public string Telphone { get; set; } + + /// + /// 设置或获取地址 + /// + [MaxLength(250)] + public string Address { get; set; } + + /// + /// 设置或获取公司名称 + /// + [MaxLength(250)] + public string CompanyName { get; set; } + + /// + /// 设置或获取职位名称 + /// + [MaxLength(250)] + public string PositionTitle { get; set; } + + /// + /// 设置或获取个人微信二维码 + /// + [MaxLength(250)] + public string WechatQrCode { get; set; } + + /// + /// 设置或获取行业 + /// + [MaxLength(500)] + public string IndustryId { get; set; } + + /// + /// 设置或获取隐私:0-不公开,1-公开;2-部分公开 + /// + public long? OpenType { get; set; } + + /// + /// 设置或获取是否允许他人转发你的名片 + /// + public bool? IsOtherShare { get; set; } + + /// + /// 设置或获取转发标题 + /// + [MaxLength(250)] + public string ShareTitle { get; set; } + + /// + /// 设置或获取网址 + /// + [MaxLength(250)] + public string WebUrl { get; set; } + + /// + /// 设置或获取公司简介 + /// + [MaxLength(2147483647)] + public string CompanyDesc { get; set; } + + /// + /// 设置或获取名片样式 + /// + [MaxLength(250)] + public string CardTheme { get; set; } + + /// + /// 设置或获取Vip等级 + /// + [MaxLength(50)] + public string VipGrade { get; set; } + + /// + /// 设置或获取是否认证 + /// + public bool? IsAuthentication { get; set; } + + /// + /// 设置或获取认证类型1-企业;2-个人 + /// + public long? AuthenticationType { get; set; } + + /// + /// 设置或获取 + /// + public bool IsEnabled { get; set; } + + /// + /// 设置或获取 + /// + public bool? IsDeleted { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? CreatedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string CreatedUserId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long CompanyId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long DeptId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ModifiedTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string ModifiedUserId { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? DeleteTime { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string DeleteUserId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserFocusExtendOutPutDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserFocusExtendOutPutDto.cs new file mode 100644 index 0000000..220a590 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserFocusExtendOutPutDto.cs @@ -0,0 +1,68 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// + [AutoMap(typeof(AdminUserEntity))] + [Serializable] + public class UserFocusExtendOutPutDto : IOutputDto + { + #region Property Members + + /// + /// 用户主键 + /// + public virtual long id { get; set; } + + /// + /// 关注的用户ID + /// + public virtual string FocusUserId { get; set; } + + /// + /// 关注人 + /// + public virtual long CreatedUserId { get; set; } + + /// + /// 关注时间 + /// + public virtual DateTime? CreatedTime { get; set; } + + /// + /// 关注的用户昵称 + /// + public virtual string FUserUserName { get; set; } + + /// + /// 关注的用户头像 + /// + public virtual string FUserHeadIcon { get; set; } + + /// + /// 关注的用户手机 + /// + public virtual string FUserMobilePhone { get; set; } + + /// + /// 关注的用户资料开放程序 + /// + public virtual string FUserOpenType { get; set; } + + /// + /// 记录数 + /// + public virtual long RecordCount { get; set; } + + /// + /// 关注时间 + /// + public virtual string ShowAddTime { get; set; } + + #endregion Property Members + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserInPutDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserInPutDto.cs new file mode 100644 index 0000000..ad1d35e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserInPutDto.cs @@ -0,0 +1,41 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(AdminUserEntity))] + [Serializable] + public class UserInputDto + { + public long Id { get; set; } + + ///// + ///// OpenId + ///// + //public string OpenId { get; set; } + + /// + /// 用户昵称 + /// + public string UserName { get; set; } + + /// + /// 用户头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + ///// + ///// 状态 + ///// + //public long State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserLogOnInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserLogOnInputDto.cs new file mode 100644 index 0000000..9f684cd --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserLogOnInputDto.cs @@ -0,0 +1,109 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(AdminUserLogOnEntity))] + [Serializable] + public class UserLogOnInputDto + { + /// + /// 设置或获取 + /// + public long Id { get; set; } + + /// + /// 设置或获取 + /// + public string UserPassword { get; set; } + + /// + /// 设置或获取 + /// + public string UserSecretkey { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? AllowStartTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? AllowEndTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? LockStartDate { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? LockEndDate { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? FirstVisitTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? PreviousVisitTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? LastVisitTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ChangePasswordDate { get; set; } + + /// + /// 设置或获取 + /// + public bool? MultiUserLogin { get; set; } + + /// + /// 设置或获取 + /// + public long? LogOnCount { get; set; } + + /// + /// 设置或获取 + /// + public bool? UserOnLine { get; set; } + + /// + /// 设置或获取 + /// + public string Question { get; set; } + + /// + /// 设置或获取 + /// + public string AnswerQuestion { get; set; } + + /// + /// 设置或获取 + /// + public bool? CheckIPAddress { get; set; } + + /// + /// 设置或获取 + /// + public string Language { get; set; } + + /// + /// 设置或获取 + /// + public string Theme { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserLogOnOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserLogOnOutputDto.cs new file mode 100644 index 0000000..3161129 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserLogOnOutputDto.cs @@ -0,0 +1,120 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class UserLogOnOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long Id { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long UserId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string UserPassword { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string UserSecretkey { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? AllowStartTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? AllowEndTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? LockStartDate { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? LockEndDate { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? FirstVisitTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? PreviousVisitTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? LastVisitTime { get; set; } + + /// + /// 设置或获取 + /// + public DateTime? ChangePasswordDate { get; set; } + + /// + /// 设置或获取 + /// + public bool? MultiUserLogin { get; set; } + + /// + /// 设置或获取 + /// + public long? LogOnCount { get; set; } + + /// + /// 设置或获取 + /// + public bool? UserOnLine { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Question { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(500)] + public string AnswerQuestion { get; set; } + + /// + /// 设置或获取 + /// + public bool? CheckIPAddress { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Language { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(50)] + public string Theme { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOpenIdsInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOpenIdsInputDto.cs new file mode 100644 index 0000000..220960f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOpenIdsInputDto.cs @@ -0,0 +1,24 @@ +using AutoMapper; +using System; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输入对象模型 + /// + [AutoMap(typeof(UserOpenIdsEntity))] + [Serializable] + public class UserOpenIdsInputDto + { + /// + /// 设置或获取 + /// + public string OpenIdType { get; set; } + + /// + /// 设置或获取 + /// + public string OpenId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOpenIdsOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOpenIdsOutputDto.cs new file mode 100644 index 0000000..8214a21 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOpenIdsOutputDto.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class UserOpenIdsOutputDto + { + /// + /// 设置或获取 + /// + [MaxLength(50)] + public long UserId { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(256)] + public string OpenIdType { get; set; } + + /// + /// 设置或获取 + /// + [MaxLength(128)] + public string OpenId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOutputDto.cs new file mode 100644 index 0000000..cd1218e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserOutputDto.cs @@ -0,0 +1,123 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 输出对象模型 + /// + [Serializable] + public class UserOutputDto + { + /// + /// Id + /// + public long Id { get; set; } + /// + /// OpenId + /// + public string OpenId { get; set; } + + /// + /// UnionId + /// + public string UnionId { get; set; } + + /// + /// 用户昵称 + /// + public string UserName { get; set; } + + /// + /// 用户头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 是否实名认证 + /// + //public bool IsRealAuthentication { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedTime { get; set; } + + /// + /// 更新时间 + /// + public DateTime ModifiedTime { get; set; } + + /// + /// 实名认证Id + /// + public long CertificationId { get; set; } + + /// + /// 姓名 + /// + public string Name { get; set; } + + /// + /// 性别 + /// + + public string Gender { get; set; } + + /// + /// 身份证号码 + /// + + public string IdCard { get; set; } + + /// + /// 签发地址 + /// + public string IssuedAddress { get; set; } + + /// + /// 身份证正面照片 + /// + public string PositivePhoto { get; set; } + + /// + /// 身份证反面照片 + /// + public string ReversePhoto { get; set; } + + /// + /// 实名认证状态 + /// + public int CertificationState { get; set; } + + /// + /// 最后登录时间 + /// + public DateTime? LastLoginTime { get; set; } + + + /// + /// + /// + public bool IsPromote { get; set; } + + /// + /// + /// + public string Contact { get; set; } + + + + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserThemeInputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserThemeInputDto.cs new file mode 100644 index 0000000..d55b4eb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserThemeInputDto.cs @@ -0,0 +1,36 @@ +using System; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 用户自定义主题 + /// + [Serializable] + public class UserThemeInputDto + { + /// + /// 主题颜色 + /// + public string Theme { set; get; } + + /// + /// 主题风格 + /// + public string SideTheme { set; get; } + + /// + /// 是否固定 Header + /// + public bool FixedHeader { set; get; } + + /// + /// 是否开启 Tags-Views + /// + public bool TagsView { set; get; } + + /// + /// 是否显示 Logo + /// + public bool SidebarLogo { set; get; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserWithAccessedCtrls.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserWithAccessedCtrls.cs new file mode 100644 index 0000000..62a2d51 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/User/UserWithAccessedCtrls.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 包括用户及用户可访问的机构/资源/模块/角色 + /// + [Serializable] + public class UserWithAccessedCtrls + { + /// + /// 用户可以访问到的模块(包括所属角色与自己的所有模块) + /// + public List Modules { get; set; } + + /// + /// 用户可以访问的资源 + /// + public List RoleDatas { get; set; } + + /// + /// 用户所属机构 + /// + public List Organizes { get; set; } + + /// + /// 用户所属角色 + /// + public List Roles { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUnifyUser/WxUnifyUserAddInput.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUnifyUser/WxUnifyUserAddInput.cs new file mode 100644 index 0000000..e503af9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUnifyUser/WxUnifyUserAddInput.cs @@ -0,0 +1,53 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 统一平台用户入参 + /// + public class WxUnifyUserAddInput + { + /// + /// UnionId + /// + public string UnionId { get; set; } + + /// + /// 用户昵称 + /// + public string NickName { get; set; } + + /// + /// 用户头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 性别 + /// + public int Gender { get; set; } + + /// + /// 国家 + /// + public string Country { get; set; } + + /// + /// 省份 + /// + public string Province { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 语种 + /// + public string Language { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUnifyUser/WxUnifyUserOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUnifyUser/WxUnifyUserOutputDto.cs new file mode 100644 index 0000000..4ed44f1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUnifyUser/WxUnifyUserOutputDto.cs @@ -0,0 +1,55 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// 云平台统一用户输出模型 + /// + public class WxUnifyUserOutputDto + { + public long Id { get; set; } + + /// + /// UnionId + /// + public string UnionId { get; set; } + + /// + /// 用户昵称 + /// + public string NickName { get; set; } + + /// + /// 用户头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 性别 + /// + public int Gender { get; set; } + + /// + /// 国家 + /// + public string Country { get; set; } + + /// + /// 省份 + /// + public string Province { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 语种 + /// + public string Language { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUserRelation/WxUserRelationOutputDto.cs b/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUserRelation/WxUserRelationOutputDto.cs new file mode 100644 index 0000000..33e95db --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Dtos/WxUserRelation/WxUserRelationOutputDto.cs @@ -0,0 +1,12 @@ +namespace Znyc.Cloudcar.Admin.Security.Dtos +{ + /// + /// + /// + public class WxUserRelationOutputDto + { + public long Id { get; set; } + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/APPEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/APPEntity.cs new file mode 100644 index 0000000..3284d74 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/APPEntity.cs @@ -0,0 +1,45 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 系统应用表,数据实体对象 + /// + [Table("sys_app")] + [Serializable] + public class APPEntity : BaseEntity + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public APPEntity() + { + CreatedTime = DateTime.Now; + ModifiedTime = DateTime.Now; + IsDeleted = false; + } + + /// + /// 应用Id + /// + [MaxLength(50)] + [Description("应用Id")] + public virtual string AppId { get; set; } + + /// + /// 应用密钥 + /// + [MaxLength(256)] + [Description("应用密钥")] + public virtual string AppSecret { get; set; } + + /// + /// 有效标志 + /// + public virtual bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/ActivityEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/ActivityEntity.cs new file mode 100644 index 0000000..d36cd4c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/ActivityEntity.cs @@ -0,0 +1,73 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 活动表 + /// + [Table("activity")] + public class ActivityEntity : BaseEntity + { + /// + /// 活动类型Id + /// + public long ActivityId { get; set; } + + /// + /// 活动图标 + /// + public string Icon { get; set; } + + /// + /// 文字描述 + /// + public string TextDesc { get; set; } + + /// + /// 跳转页面 + /// + public string PageUrl { get; set; } + + /// + /// 图片描述 + /// + public string PicDesc { get; set; } + + /// + /// 图片URL + /// + public string PicUrl { get; set; } + + /// + /// 点击图片跳转页面路径 + /// + public string PicPageUrl { get; set; } + + /// + /// 活动详情图 + /// + public string DetailPicUrl { get; set; } + + /// + /// 开始时间 + /// + public DateTime StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime EndTime { get; set; } + + /// + /// 状态0未开始/1进行中/2已结束 + /// + public int State { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/AdminUserEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/AdminUserEntity.cs new file mode 100644 index 0000000..e35c7f4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/AdminUserEntity.cs @@ -0,0 +1,64 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 用户表,数据实体对象 + /// + [Table("sys_adminuser")] + [Serializable] + public class AdminUserEntity : BaseEntity + { + /// + /// 账户 + /// + public string Account { get; set; } + + /// + /// 姓名 + /// + public string UserName { get; set; } + + /// + /// 头像 + /// + public string HeadIcon { get; set; } + + /// + /// 性别,1=男,0=未知,2=女 + /// + public int Gender { get; set; } + + /// + /// 手机 + /// + public string MobilePhone { get; set; } + + /// + /// 组织主键 + /// + public long OrganizeId { get; set; } + + /// + /// 部门主键 + /// + public long DepartmentId { get; set; } + + /// + /// 角色主键 + /// + public long RoleId { get; set; } + + /// + /// 是否管理员 + /// + public bool IsAdministrator { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/AdminUserLogOnEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/AdminUserLogOnEntity.cs new file mode 100644 index 0000000..d5da764 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/AdminUserLogOnEntity.cs @@ -0,0 +1,59 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 用户登录信息表,数据实体对象 + /// + [Table("sys_adminuser_logon")] + [Serializable] + public class AdminUserLogOnEntity : BaseEntity + { + /// + /// 用户主键 + /// + public virtual long UserId { get; set; } + + /// + /// 用户秘钥 + /// + public virtual string UserPassword { get; set; } + + /// + /// 用户秘钥 + /// + public virtual string UserSecretkey { get; set; } + + /// + /// 最后访问时间 + /// + public virtual DateTime LastVisitTime { get; set; } + + /// + /// 最后修改密码日期 + /// + public virtual DateTime ChangePasswordDate { get; set; } + + /// + /// 登录次数 + /// + public virtual int LogOnCount { get; set; } + + /// + /// 在线状态 + /// + public virtual bool UserOnLine { get; set; } + + /// + /// 系统语言 + /// + public virtual string Language { get; set; } + + /// + /// 系统样式 + /// + public virtual string Theme { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/ApiEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/ApiEntity.cs new file mode 100644 index 0000000..c16d511 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/ApiEntity.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + [Table("sys_api")] + [Serializable] + public class ApiEntity : BaseEntity + { + public string ApiUrl { get; set; } + + public string AuthKey { get; set; } + + public string AuthValue { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/ApplyJobEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/ApplyJobEntity.cs new file mode 100644 index 0000000..1f56ef2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/ApplyJobEntity.cs @@ -0,0 +1,121 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// ApplyJob + /// + [Table("applyjob")] + [Serializable] + public class ApplyJobEntity : BaseEntity + { + /// + /// 流水号 + /// + public string SerialNumber { get; set; } + + public long UserId { get; set; } + + /// + /// 行业类型 + /// + public long IndustryId { get; set; } + + /// + /// 岗位类型 + /// + public long JobId { get; set; } + + /// + /// 求职地区省份 + /// + public string ProvinceId { get; set; } + + /// + /// 求职地区市 + /// + public string CityId { get; set; } + + /// + /// 求职地区区 + /// + public string AreaId { get; set; } + + /// + /// 联系电话 + /// + public string Phone { get; set; } + + /// + /// 工作经验Id + /// + public long? ExperienceId { get; set; } + + /// + /// 是否有驾驶证 + /// + public bool? IsHaveDriverLicense { get; set; } + + /// + /// 性别 + /// + public int? Gender { get; set; } + + /// + /// 出生年月 + /// + public DateTime? BirthDate { get; set; } + + /// + /// 年龄 + /// + public int? Age { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 求职详情 + /// + public string Content { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime TopExpireDate { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + /// + /// 浏览量 + /// + public int PageView { get; set; } + + /// + /// 地址明细(冗余,用于首页查询省市区模糊匹配) + /// + public string Address { get; set; } + + /// + /// 是否实名认证 + /// + public bool IsRealAuthentication { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/AreaEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/AreaEntity.cs new file mode 100644 index 0000000..d109f8e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/AreaEntity.cs @@ -0,0 +1,67 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 行政区域表,数据实体对象 + /// + [Table("sys_area")] + [Serializable] + public class AreaEntity : BaseEntity + { + /// + /// 父级 + /// + [MaxLength(50)] + public long ParentId { get; set; } + + /// + /// 层次 + /// + public int? Layers { get; set; } + + /// + /// 编码 + /// + [MaxLength(50)] + public string EnCode { get; set; } + + /// + /// 名称 + /// + [MaxLength(100)] + public string FullName { get; set; } + + /// + /// 简拼 + /// + [MaxLength(200)] + public string SimpleSpelling { get; set; } + + /// + /// 父级路径 + /// + [MaxLength(600)] + public string FullIdPath { get; set; } + + /// + /// 是否是最后一级 + /// + public bool IsLast { get; set; } + + /// + /// 排序码 + /// + public int SortCode { get; set; } + + /// + /// 有效标志 + /// + public bool IsEnabled { get; set; } + + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/AuditEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/AuditEntity.cs new file mode 100644 index 0000000..d045a2f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/AuditEntity.cs @@ -0,0 +1,50 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 审核记录表 + /// + [Table("audit")] + [Serializable] + public class AuditEntity : BaseEntity + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public AuditEntity() + { + CreatedTime = DateTime.Now; + ModifiedTime = DateTime.Now; + } + + /// + /// 产品ID + /// + public long EquipmentId { get; set; } + + + /// + /// 产品标题 + /// + public string EquipmentTitle { get; set; } + + /// + /// 审核人 + /// + public long AuditUserId { get; set; } + + /// + /// 审核状态 + /// + /// + public int HandleStatus { get; set; } + + /// + /// 审核结果 + /// + public string Note { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/BannerEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/BannerEntity.cs new file mode 100644 index 0000000..30add55 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/BannerEntity.cs @@ -0,0 +1,69 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// banner + /// + [Table("banner")] + public class BannerEntity : BaseEntity + { + /// + /// 图片描述 + /// + public string Name { get; set; } + + /// + /// 图片URL + /// + public string PicUrl { get; set; } + + /// + /// 是否主图:0.非主图1.主图 + /// + public bool IsMaster { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 状态 0-起开始/1-进行中/2-已结束 + /// + public int State { get; set; } + + /// + /// 类型 + /// + public int Type { get; set; } + + /// + /// 电话 + /// + public string Phone { get; set; } + + /// + /// 跳转页面 + /// + public string PageUrl { get; set; } + + /// + /// 文字描述 + /// + public string TextDesc { get; set; } + + /// + /// 开始时间 + /// + public DateTime StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime EndTime { get; set; } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/CallFeedbackEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/CallFeedbackEntity.cs new file mode 100644 index 0000000..6924ff5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/CallFeedbackEntity.cs @@ -0,0 +1,37 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 通话评价表 + /// + [Table("call_feedback")] + public class CallFeedbackEntity : BaseEntity + { + /// + /// UserId + /// + public long UserId { get; set; } + + /// + /// 产品Id + /// + public long ProductId { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 产品类型 + /// + public int ProductType { get; set; } + + /// + /// 是否已读 + /// + public bool IsRead { get; set; } + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/CertificationEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/CertificationEntity.cs new file mode 100644 index 0000000..064e501 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/CertificationEntity.cs @@ -0,0 +1,56 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 用户实名认证表,数据实体对象 + /// + [Table("user_certification")] + [Serializable] + public class CertificationEntity : BaseEntity + { + /// + /// UnionId + /// + public string UnionId { get; set; } + + /// + /// 姓名 + /// + public string Name { get; set; } + + /// + /// 性别 + /// + + public string Gender { get; set; } + + /// + /// 身份证号码 + /// + + public string IdCard { get; set; } + + /// + /// 签发地址 + /// + public string IssuedAddress { get; set; } + + /// + /// 身份证正面照片 + /// + public string PositivePhoto { get; set; } + + /// + /// 身份证反面照片 + /// + public string ReversePhoto { get; set; } + + /// + /// 实名状态 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/CurrencyEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/CurrencyEntity.cs new file mode 100644 index 0000000..c660528 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/CurrencyEntity.cs @@ -0,0 +1,32 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 用户云币表 + /// + [Table("currency")] + public class CurrencyEntity : BaseEntity + { + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 可用云币 + /// + public int AvailableCredits { get; set; } + + /// + /// 正式云币 + /// + public int OfficialCredits { get; set; } + + /// + /// 临时云币 + /// + public int TemporarylCredits { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/CurrencyRecordEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/CurrencyRecordEntity.cs new file mode 100644 index 0000000..ad987a7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/CurrencyRecordEntity.cs @@ -0,0 +1,37 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 云币记录表 + /// + [Table("currency_record")] + public class CurrencyRecordEntity : BaseEntity + { + /// + /// 用户id + /// + public long UserId { get; set; } + + /// + /// 操作云币 + /// + public int OperatingCurrency { get; set; } + + /// + /// 操作类型 + /// + public int OperatingType { get; set; } + + /// + /// 云币类型 + /// + public int CurrencyType { get; set; } + + /// + /// 云币来源Id(12=求职ID)/(12=招聘ID) + /// + public long CurrencySoureObjectId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/DbLogsEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/DbLogsEntity.cs new file mode 100644 index 0000000..2d3be0a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/DbLogsEntity.cs @@ -0,0 +1,41 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 数据库日志表 + /// + [AppDBContext("DefaultDb")] + [Table("db_logs")] + [Serializable] + public class DbLogsEntity : BaseEntity + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public DbLogsEntity() + { + IsDeleted = false; + CreatedTime = DateTime.Now; + } + + /// + /// 所属用户 + /// + public string UserName { get; set; } + + /// + /// SQL语句 + /// + public string SQL { get; set; } + + /// + /// 执行时间 + /// + + public DateTime ExecuteDate { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/DictionaryEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/DictionaryEntity.cs new file mode 100644 index 0000000..4382485 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/DictionaryEntity.cs @@ -0,0 +1,49 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 数据字典选项主表,数据实体对象 + /// + [Table("sys_dictionary")] + [Serializable] + public class DictionaryEntity : BaseEntity + { + /// + /// 字典父级 + /// + public long ParentId { get; set; } + + /// + /// 字典编码 + /// + public string Code { get; set; } + + /// + /// 字典值 + /// + public string Value { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 字典名称 + /// + public string Name { get; set; } + + /// + /// 启用 + /// + public bool IsEnabled { get; set; } = true; + + /// + /// 排序 + /// + public int Sort { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/EquipmentEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/EquipmentEntity.cs new file mode 100644 index 0000000..c3a70cf --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/EquipmentEntity.cs @@ -0,0 +1,134 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 设备表 + /// + [Table("equipment")] + public class EquipmentEntity : BaseEntity + { + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 标题 + /// + public string Title { get; set; } + + /// + /// 设备编号 + /// + public long EquipmentNumber { get; set; } + + /// + /// 设备类型 + /// + public long EquipmentType { get; set; } + + /// + /// 设备品牌 + /// + public long EquipmentBrand { get; set; } + + /// + /// 汽车底盘 + /// + public long AutomobileChassis { get; set; } + + /// + /// 装载方量 + /// + public long ReprintVolume { get; set; } + + /// + /// 设备型号 + /// + public string EquipmentModel { get; set; } + + /// + /// 设备吨位 + /// + public int EquipmentTonnage { get; set; } + + /// + /// 斗容 + /// + public int Capacity { get; set; } + + /// + /// 设备介绍 + /// + public string Introduction { get; set; } + + /// + /// 出厂日期 + /// + public int AppearanceDate { get; set; } + + /// + /// 出售价格 + /// + public decimal SellingPrice { get; set; } + + /// + /// 车辆位置 + /// + public string AutomobileLocation { get; set; } + + /// + /// 联系人 + /// + public string Contact { get; set; } + + /// + /// 联系人电话 + /// + public string ContactPhone { get; set; } + + /// + /// 状态,10=出售中,11=审核中,30=未通过,40=已成交,99=未通过 + /// + public int State { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime TopExpireDate { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 浏览量 + /// + public int PageView { get; set; } + + + /// + /// + /// + public long BoomLength { get; set; } + + /// + /// + /// + public int PromoteType { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/EquipmentPictureEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/EquipmentPictureEntity.cs new file mode 100644 index 0000000..d9e0fc2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/EquipmentPictureEntity.cs @@ -0,0 +1,28 @@ + +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 设备信息图片表 + /// + [Table("equipment_picture")] + [Serializable] + public class EquipmentPictureEntity : BaseEntity + { + public long EquipmentId { get; set; } + + /// + /// 图片类型,10=设备照片,20=行驶证或身份证 + /// + public int PictureType { get; set; } + + /// + /// 图片地址 + /// + public string PictureLink { get; set; } + + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/ExceptionsLogsEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/ExceptionsLogsEntity.cs new file mode 100644 index 0000000..81aa256 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/ExceptionsLogsEntity.cs @@ -0,0 +1,65 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 系统日志,数据实体对象 + /// + [AppDBContext("DefaultDb")] + [Table("exceptions_logs")] + [Serializable] + public class ExceptionsLogsEntity : BaseEntity + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public ExceptionsLogsEntity() + { + IsDeleted = true; + CreatedTime = DateTime.Now; + } + + /// + /// 访问域名 + /// + public string AppDomainName { get; set; } + + /// + /// 错误页面 + /// + public string ErrorPage { get; set; } + + /// + /// 用户名 + /// + public string UserName { get; set; } + + /// + /// 用户Ip + /// + public string IP { get; set; } + + /// + /// 错误类型 + /// + public string ExceptionType { get; set; } + + /// + /// 异常描述信息 + /// + public string Message { get; set; } + + /// + /// 堆栈信息 + /// + public string StackTrace { get; set; } + + /// + /// 异常时间 + /// + public DateTime ExceptionTime { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/FeedbackEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/FeedbackEntity.cs new file mode 100644 index 0000000..176fd64 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/FeedbackEntity.cs @@ -0,0 +1,37 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 意见反馈表 + /// + [Table("feedback")] + [Serializable] + public class FeedbackEntity : BaseEntity + { + public long UserId { get; set; } + + /// + /// 反馈内容 + /// + public string Content { get; set; } + + /// + /// 状态 0未处理/1已处理 + /// + public int State { get; set; } + + /// + /// 处理结果 + /// + public string Result { get; set; } + + /// + /// 备注 + /// + public string Note { get; set; } + + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/FeedbackPicEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/FeedbackPicEntity.cs new file mode 100644 index 0000000..c84b0ff --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/FeedbackPicEntity.cs @@ -0,0 +1,35 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 意见反馈图片表 + /// + [Table("feedback_picture")] + [Serializable] + public class FeedbackPicEntity : BaseEntity + { + /// + /// 意见反馈Id + /// + public long FeedbackId { get; set; } + + /// + /// 图片URL + /// + public string PicUrl { get; set; } + + /// + /// 排序 + /// + public int Sort { get; set; } + + /// + /// 图片是否有效 + /// + public bool IsEnabled { get; set; } + + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/IndustryJobsEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/IndustryJobsEntity.cs new file mode 100644 index 0000000..88c18b0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/IndustryJobsEntity.cs @@ -0,0 +1,34 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 行业岗位表 + /// + [Table("industryjobs")] + public class IndustryJobsEntity : BaseEntity + { + /// + /// 父级Id + /// + public long ParentId { get; set; } + + /// + /// 名称 + /// + [MaxLength(20)] + public string Name { get; set; } + + /// + /// 排序 + /// + public long Sort { get; set; } + + /// + /// 是否启用 + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/LogEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/LogEntity.cs new file mode 100644 index 0000000..77caf95 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/LogEntity.cs @@ -0,0 +1,85 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 系统日志,数据实体对象 + /// + [AppDBContext("DefaultDb")] + [Table("sys_log")] + [Serializable] + public class LogEntity : BaseEntity + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public LogEntity() + { + IsDeleted = true; + CreatedTime = DateTime.Now; + } + + /// + /// 日期 + /// + public DateTime? Date { get; set; } + + /// + /// 用户名 + /// + public string Account { get; set; } + + /// + /// 姓名 + /// + public string UserName { get; set; } + + /// + /// 组织主键 + /// + public long OrganizeId { get; set; } + + /// + /// 类型 + /// + public string Type { get; set; } + + /// + /// IP地址 + /// + public string IPAddress { get; set; } + + /// + /// IP所在城市 + /// + public string IPAddressName { get; set; } + + /// + /// 系统模块Id + /// + public long ModuleId { get; set; } + + /// + /// 系统模块 + /// + public string ModuleName { get; set; } + + /// + /// 结果 + /// + public bool? Result { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 有效标志 + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/LoginLogsEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/LoginLogsEntity.cs new file mode 100644 index 0000000..f37abb8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/LoginLogsEntity.cs @@ -0,0 +1,73 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 系统日志,数据实体对象 + /// + [AppDBContext("DefaultDb")] + [Table("login_logs")] + [Serializable] + public class LoginLogsEntity : BaseEntity + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public LoginLogsEntity() + { + IsDeleted = false; + CreatedTime = DateTime.Now; + ModifiedTime = DateTime.Now; + } + + /// + /// 用户名 + /// + public string UserName { get; set; } + + /// + /// 来源平台 + /// + public int PlatformType { get; set; } + + /// + /// 登录时间 + /// + public DateTime LoginTime { get; set; } + + /// + /// IP + /// + public string IP { get; set; } + + /// + /// 主机 + /// + public string OS { get; set; } + + /// + /// 客户端 + /// + public string Browser { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 登陆结果 + /// + public string Result { get; set; } + + /// + /// 操作系统 + /// + public string UserAgent { get; set; } + + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/MenuEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/MenuEntity.cs new file mode 100644 index 0000000..2797263 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/MenuEntity.cs @@ -0,0 +1,110 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 系统菜单,数据实体对象 + /// + [Table("sys_menu")] + [Serializable] + public class MenuEntity : BaseEntity + { + /// + /// 所属系统主键 + /// + public long SystemTypeId { get; set; } + + /// + /// 父级 + /// + public long ParentId { get; set; } + + /// + /// 层次 + /// + public int Layers { get; set; } + + /// + /// 编码 + /// + public string EnCode { get; set; } + + /// + /// 名称 + /// + public string FullName { get; set; } + + /// + /// 图标 + /// + public string Icon { get; set; } + + /// + /// 路由 + /// + public string UrlAddress { get; set; } + + /// + /// 目标打开方式 + /// + public string Target { get; set; } + + /// + /// 菜单类型(C目录 M菜单 F按钮) + /// + public string MenuType { get; set; } + + /// + /// 组件路径 + /// + public string Component { get; set; } + + /// + /// 设置当前选中菜单,用于新增、编辑、查看操作为单独的路由时指定选中菜单路由 + /// 同时设置为隐藏时才有效 + /// + public string ActiveMenu { get; set; } + + /// + /// 展开 + /// + public bool IsExpand { get; set; } + + /// + /// 设置或获取 是否显示 + /// + public bool IsShow { get; set; } + + /// + /// 设置或获取 是否外链 + /// + public bool IsFrame { get; set; } + + /// + /// 设置或获取是否缓存 + /// + public bool IsCache { get; set; } + + /// + /// 公共 + /// + public bool IsPublic { get; set; } + + /// + /// 排序码 + /// + public long SortCode { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 有效标志 + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/MessageEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/MessageEntity.cs new file mode 100644 index 0000000..a7e5acf --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/MessageEntity.cs @@ -0,0 +1,50 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 站内消息表,数据实体对象 + /// + [Table("message")] + [Serializable] + public class MessageEntity : BaseEntity + { + /// + /// 发送者Id + /// + public long SendId { get; set; } + + /// + /// 设备Id + /// + public long EquipmentId { get; set; } + /// + /// 发送时间 + /// + public DateTime SendTime { get; set; } + + /// + /// + /// + public string EquipmentTitle { get; set; } + + /// + /// 消息标题 + /// + public string MessageTitle { get; set; } + + /// + /// 标题 + /// + public string Content { get; set; } + + + /// + /// + /// + public long GroupId { get; set; } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/MessageLogsEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/MessageLogsEntity.cs new file mode 100644 index 0000000..5e0710a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/MessageLogsEntity.cs @@ -0,0 +1,29 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 消息记录表 + /// + [Table("message_logs")] + [Serializable] + public class MessageLogsEntity : BaseEntity + { + /// + /// 接收者Id + /// + public long ReceiverId { get; set; } + + /// + /// 消息Id + /// + public long MessageId { get; set; } + + /// + /// 状态 + /// + public long State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/OperationLogsEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/OperationLogsEntity.cs new file mode 100644 index 0000000..914d336 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/OperationLogsEntity.cs @@ -0,0 +1,76 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Core.DataManager; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 操作日志表 + /// + [AppDBContext("DefaultDb")] + [Table("operation_logs")] + [Serializable] + public class OperationLogsEntity : BaseEntity + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public OperationLogsEntity() + { + IsDeleted = false; + CreatedTime = DateTime.Now; + ModifiedTime = DateTime.Now; + } + + /// + /// 操作类型 + /// + public string CRUD { get; set; } + + /// + /// 操作用户 + /// + public string UserName { get; set; } + + /// + /// 操作时间 + /// + public DateTime OperationTime { get; set; } + + /// + /// IP + /// + public string IP { get; set; } + + /// + /// 主机 + /// + public string OS { get; set; } + + /// + /// 浏览器 + /// + public string Browser { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 操作系统 + /// + public string UserAgent { get; set; } + + /// + /// 请求明细 + /// + public string RequertData { get; set; } + + /// + /// 请求url + /// + public string RequestUrl { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrderDetailEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrderDetailEntity.cs new file mode 100644 index 0000000..bbd2ef4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrderDetailEntity.cs @@ -0,0 +1,41 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 订单明细表 + /// + [Table("order_detail")] + [Serializable] + public class OrderDetailEntity : BaseEntity + { + /// + /// 订单表ID + /// + public long OrderId { get; set; } + + /// + /// 订单商品ID + /// + public long ProductId { get; set; } + + /// + /// 商品名称 + /// + [MaxLength(25)] + public string ProductName { get; set; } + + /// + /// 购买商品数量 + /// + public int ProductCnt { get; set; } + + /// + /// 购买商品单价 + /// + public decimal ProductPrice { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrderEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrderEntity.cs new file mode 100644 index 0000000..b78301c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrderEntity.cs @@ -0,0 +1,116 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 订单实体 + /// + [Table("`order`")] + [Serializable] + public class OrderEntity : BaseEntity + { + /// + /// 订单编号 + /// + [MaxLength(12)] + public string OrderSn { get; set; } + + /// + /// 下单人ID + /// + public long UserId { get; set; } + + /// + /// 收货人姓名 + /// + [MaxLength(6)] + public string ShippingUser { get; set; } + + /// + /// 收货人所在省 + /// + public long Province { get; set; } + + /// + /// 收货人所在市 + /// + public long City { get; set; } + + /// + /// 收货人所在区 + /// + public long Area { get; set; } + + /// + /// 收货人详细地址 + /// + [MaxLength(55)] + public string Address { get; set; } + + /// + /// 支付方式:1现金,2余额,3网银,4支付宝,5微信.6云币 + /// + public int PaymentMethod { get; set; } + + /// + /// 订单金额 + /// + public decimal OrderMoney { get; set; } + + /// + /// 优惠金额 + /// + public decimal DistrictMoney { get; set; } + + /// + /// 支付金额 + /// + public decimal PaymentMoney { get; set; } + + /// + /// 快递公司名称 + /// + [MaxLength(8)] + public string ShippingCompName { get; set; } + + /// + /// 快递单号 + /// + [MaxLength(15)] + public string ShippingSn { get; set; } + + /// + /// 发货时间 + /// + public DateTime? ShippingTime { get; set; } + + /// + /// 支付时间 + /// + public DateTime PayTime { get; set; } + + /// + /// 收货时间 + /// + public DateTime? ReceiveTime { get; set; } + + /// + /// 订单状态:0-已取消-10-未付款,20-已付款,40-已发货,50-交易成功,60-交易关闭 + /// + public int OrderStatus { get; set; } + + /// + /// 订单积分 + /// + public int OrderPoint { get; set; } + + /// + /// 发票抬头 + /// + [MaxLength(25)] + public string InvoiceTitle { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrganizeEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrganizeEntity.cs new file mode 100644 index 0000000..85967e8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/OrganizeEntity.cs @@ -0,0 +1,56 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 组织表,数据实体对象 + /// + [Table("sys_organize")] + [Serializable] + public class OrganizeEntity : BaseEntity + { + /// + /// 父级 + /// + public long ParentId { get; set; } + + /// + /// 层次 + /// + public int Layers { get; set; } + + /// + /// 编码 + /// + public string EnCode { get; set; } + + /// + /// 名称 + /// + public string FullName { get; set; } + + /// + /// 负责人 + /// + public string ManagerName { get; set; } + + public string CategoryName { get; set; } + + /// + /// 排序码 + /// + public int SortCode { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 是否有效 + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/PaymentRecordEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/PaymentRecordEntity.cs new file mode 100644 index 0000000..e102c6a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/PaymentRecordEntity.cs @@ -0,0 +1,54 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 充值记录 + /// + [Table("payment_record")] + [Serializable] + public class PaymentRecordEntity : BaseEntity + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public PaymentRecordEntity() + { + CreatedTime = DateTime.Now; + ModifiedTime = DateTime.Now; + } + + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 订单ID + /// + public long OrderId { get; set; } + + /// + /// 支付流水号 + /// + public string PaySn { get; set; } + + /// + /// 支付状态:0-已取消-10-未成功,20-已成功 + /// + /// + public int PayStatus { get; set; } + + /// + /// 支付平台:1-Wx,2支付宝 + /// + public int PayPlatform { get; set; } + + /// + /// 支付金额 + /// + public decimal PaymentMoney { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/RechargeEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RechargeEntity.cs new file mode 100644 index 0000000..6aafac9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RechargeEntity.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 充值活动表 + /// + [Table("recharge")] + public class RechargeEntity : BaseEntity + { + /// + /// 活动名称 + /// + public string Name { get; set; } + + /// + /// 状态0未开始/1进行中/2已结束 + /// + public int State { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/RechargeIntroEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RechargeIntroEntity.cs new file mode 100644 index 0000000..3b2eb49 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RechargeIntroEntity.cs @@ -0,0 +1,47 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 充值活动详情表 + /// + [Table("recharge_intro")] + public class RechargeIntroEntity : BaseEntity + { + /// + /// 父级ID + /// + public long ParentId { get; set; } + + /// + /// 商品名称 + /// + public string ProductName { get; set; } + + /// + /// 商品价值 + /// + public int ProductValue { get; set; } + + /// + /// 赠送价值 + /// + public int SendValue { get; set; } + + /// + /// 商品总价值 + /// + public int AllValue { get; set; } + + /// + /// 商品销售价 + /// + public decimal Price { get; set; } + + /// + /// 商品描述 + /// + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/RecruitmentEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RecruitmentEntity.cs new file mode 100644 index 0000000..7f3e173 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RecruitmentEntity.cs @@ -0,0 +1,114 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 系统菜单,数据实体对象 + /// + [Table("Cloudcar")] + [Serializable] + public class CloudcarEntity : BaseEntity + { + /// + /// 用户Id + /// + public long UserId { get; set; } + + /// + /// 流水号 + /// + public string SerialNumber { get; set; } + + /// + /// 招聘标题 + /// + public string Title { get; set; } + + /// + /// 待遇要求 + /// + public string Content { get; set; } + + /// + /// 联系电话 + /// + public string Phone { get; set; } + + /// + /// 行业类型 + /// + public long IndustryId { get; set; } + + /// + /// 岗位类型 + /// + public long JobId { get; set; } + + /// + /// 招聘地区省份 + /// + public long ProvinceId { get; set; } + + /// + /// 招聘地区--市 + /// + public long CityId { get; set; } + + /// + /// 招聘地区--区 + /// + public long AreaId { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 是否置顶 + /// + public bool IsTop { get; set; } + + /// + /// 是否公开 + /// + public bool IsPublic { get; set; } + + /// + /// 工资福利 + /// + public string Welfare { get; set; } + + /// + /// 刷新时间 + /// + public DateTime RefreshDate { get; set; } + + /// + /// 浏览量 + /// + public int PageView { get; set; } + + /// + /// 置顶到期时间 + /// + public DateTime TopExpireDate { get; set; } + + /// + /// 地址明细(冗余,用于首页查询省市区模糊匹配) + /// + public string Address { get; set; } + + /// + /// 是否实名认证 + /// + public bool IsRealAuthentication { get; set; } + + /// + /// 联系人 + /// + public string Contact { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/RegionEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RegionEntity.cs new file mode 100644 index 0000000..a63c161 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RegionEntity.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 省市区表,数据实体对象 + /// + //[Table("Znyc.sys_region")] + [Table("sys_region")] + [Serializable] + public class RegionEntity : BaseEntity + { + /// + /// 父级 + /// + public long ParentId { get; set; } + + /// + /// id + /// + public long RegionId { get; set; } + + /// + /// 名称 + /// + [MaxLength(50)] + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleAuthorizeEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleAuthorizeEntity.cs new file mode 100644 index 0000000..242267d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleAuthorizeEntity.cs @@ -0,0 +1,43 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 角色授权表,数据实体对象 + /// + [Table("sys_role_authorize")] + [Serializable] + public class RoleAuthorizeEntity : BaseEntity + { + #region Property Members + + /// + /// 项目类型功能标识 0-子系统 1-标识菜单/模块,2标识按钮功能 + /// + public virtual long? ItemType { get; set; } + + /// + /// 项目主键 + /// + public virtual long ItemId { get; set; } + + /// + /// 对象分类/类型1-角色,2-部门,3-用户 + /// + public virtual long? ObjectType { get; set; } + + /// + /// 对象主键,对象分类/类型为角色时就是角色ID,部门就是部门ID,用户就是用户ID + /// + public virtual long ObjectId { get; set; } + + /// + /// 排序码 + /// + public virtual long? SortCode { get; set; } + + #endregion Property Members + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleDataEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleDataEntity.cs new file mode 100644 index 0000000..f882f3e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleDataEntity.cs @@ -0,0 +1,27 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 角色的数据权限,数据实体对象 + /// + [Table("sys_role_data")] + public class RoleDataEntity : BaseEntity + { + /// + /// 角色ID + /// + public long RoleId { get; set; } + + /// + /// 类型,company-公司,dept-部门,person-个人 + /// + public string DType { get; set; } + + /// + /// 数据数据,部门ID或个人ID + /// + public string AuthorizeData { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleEntityEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleEntityEntity.cs new file mode 100644 index 0000000..3c29df4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/RoleEntityEntity.cs @@ -0,0 +1,47 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 角色表,数据实体对象 + /// + [Table("sys_role")] + public class RoleEntityEntity : BaseEntity + { + /// + /// 组织主键 + /// + public long OrganizeId { get; set; } + + /// + /// 角色编码 + /// + public string EnCode { get; set; } + + /// + /// 名称 + /// + public string FullName { get; set; } + + /// + /// 类型 + /// + public string Type { get; set; } + + /// + /// 排序码 + /// + public long SortCode { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 有效标志 + /// + public bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/StatisticalEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/StatisticalEntity.cs new file mode 100644 index 0000000..e926555 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/StatisticalEntity.cs @@ -0,0 +1,70 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 统计数据 + /// + [Table("sys_statistical")] + [Serializable] + public class StatisticalEntity : BaseEntity + { + /// + /// 时间 + /// + public string Time { get; set; } + + /// + /// 今日新增用户 + /// + public int UserAddTotal { get; set; } + + /// + /// 用户总数 + /// + public int UserSumTotal { get; set; } + + /// + /// 今日求职发布数 + /// + public int ApplyJobsAddTotal { get; set; } + + /// + /// 今日招聘发布数 + /// + public int CloudcarAddTotal { get; set; } + + /// + /// 本日活跃用户数 + /// + public int ActiveUserTotal { get; set; } + + /// + /// 总收入 + /// + public decimal Income { get; set; } + + /// + /// 日收入 + /// + public decimal TodayIncome { get; set; } + + /// + /// 今日收入百分比 + /// + public decimal TodayIncomePercent { get; set; } + + /// + /// 今日用户增长百分比 + /// + public decimal UserAddTotalPercent { get; set; } + + + /// + /// 未审核设备树 + /// + public int EquipmentAddTotal { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/SysSettingEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/SysSettingEntity.cs new file mode 100644 index 0000000..27a0f80 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/SysSettingEntity.cs @@ -0,0 +1,13 @@ +using System; +using Znyc.Cloudcar.Admin.Commons.Options; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 系统配置 + /// + [Serializable] + public class SysSettingEntity : AppSetting + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/SystemTypeEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/SystemTypeEntity.cs new file mode 100644 index 0000000..903fb1a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/SystemTypeEntity.cs @@ -0,0 +1,44 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 子系统 + /// + [Table("sys_systemtype")] + [Serializable] + public class SystemTypeEntity : BaseEntity + { + /// + /// 编码 + /// + public virtual string EnCode { get; set; } + + /// + /// 系统名称 + /// + public virtual string FullName { get; set; } + + /// + /// 链接 + /// + public virtual string Url { get; set; } + + /// + /// 排序码 + /// + public virtual int SortCode { get; set; } + + /// + /// 描述 + /// + public virtual string Description { get; set; } + + /// + /// 有效标志 + /// + public virtual bool IsEnabled { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/UploadFileEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UploadFileEntity.cs new file mode 100644 index 0000000..0edc63a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UploadFileEntity.cs @@ -0,0 +1,86 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 文件 + /// + [Table("sys_uploadfile")] + public class UploadFileEntity : BaseEntity, ICreationAudited + { + /// + /// + public UploadFileEntity() + { + Id = 0; + FileName = string.Empty; + FilePath = string.Empty; + Description = string.Empty; + FileType = string.Empty; + Extension = string.Empty; + SortCode = 0; + CreatedTime = DateTime.Now; + Thumbnail = string.Empty; + BelongApp = string.Empty; + BelongAppId = string.Empty; + IsDeleted = false; + } + + /// + /// 文件名称 + /// + public string FileName { get; set; } + + /// + /// 文件路径 + /// + public string FilePath { get; set; } + + /// + /// 描述 + /// + public string Description { get; set; } + + /// + /// 文件类型 + /// + public string FileType { get; set; } + + /// + /// 文件大小 + /// + public long FileSize { get; set; } + + /// + /// 扩展名称 + /// + public string Extension { get; set; } + + /// + /// 排序 + /// + public long SortCode { get; set; } + + /// + /// 有效标志 + /// + public virtual bool? IsEnabled { get; set; } + + /// + /// 缩略图 + /// + public string Thumbnail { get; set; } + + /// + /// 所属应用 + /// + public string BelongApp { get; set; } + + /// + /// 所属应用ID + /// + public string BelongAppId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserEntity.cs new file mode 100644 index 0000000..e1e7738 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserEntity.cs @@ -0,0 +1,56 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 用户表,数据实体对象 + /// + [Table("user")] + [Serializable] + public class UserEntity : BaseEntity + { + /// + /// OpenId + /// + public string OpenId { get; set; } + + /// + /// UnionId + /// + public string UnionId { get; set; } + + /// + /// 用户昵称 + /// + public string UserName { get; set; } + + /// + /// 用户头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 状态 + /// + public int State { get; set; } + + /// + /// 是否实名认证 + /// + public bool IsRealAuthentication { get; set; } + + + /// + /// 设置推广账号 + /// + public bool IsPromote { get; set; } + public string Contact { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserExtendEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserExtendEntity.cs new file mode 100644 index 0000000..d315876 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserExtendEntity.cs @@ -0,0 +1,126 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Runtime.Serialization; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 用户表,数据实体对象 + /// + [Table("sys_userextend")] + [Serializable] + public class UserExtendEntity : BaseEntity + { + #region Property Members + + /// + /// 账户 + /// + public virtual long userId { get; set; } + + /// + /// 名片 + /// + public virtual string CardContent { get; set; } + + /// + /// 手机 + /// + public virtual string Telphone { get; set; } + + /// + /// 地址 + /// + public virtual string Address { get; set; } + + /// + /// 公司名称 + /// + public virtual string CompanyName { get; set; } + + /// + /// 职位 + /// + public virtual string PositionTitle { get; set; } + + /// + /// 微信二维码 + /// + public virtual string WeChatQrCode { get; set; } + + /// + /// 地区 + /// + public virtual string IndustryId { get; set; } + + /// + /// 公开情况 + /// + public virtual long OpenType { get; set; } + + /// + /// IsOtherShare + /// + [DataMember] + public virtual bool IsOtherShare { get; set; } + + /// + /// sharetitle + /// + [DataMember] + public virtual string ShareTitle { get; set; } + + /// + /// 主页 + /// + [DataMember] + public virtual string WebUrl { get; set; } + + /// + /// 公司简介 + /// + [DataMember] + public virtual string CompanyDesc { get; set; } + + /// + /// 主题 + /// + public virtual string CardTheme { get; set; } + + /// + /// VIP + /// + public virtual string VipGrade { get; set; } + + /// + /// 是否认证 + /// + public virtual bool IsAuthentication { get; set; } + + /// + /// 认证类型 + /// + public virtual long AuthenticationType { get; set; } + + /// + /// 有效标志 + /// + public virtual bool IsEnabled { get; set; } + + /// + /// 公司id + /// + [MaxLength(50)] + public virtual long CompanyId { get; set; } + + /// + /// 部门id + /// + [MaxLength(50)] + public virtual long DeptId { get; set; } + + #endregion Property Members + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserFocusEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserFocusEntity.cs new file mode 100644 index 0000000..53501a3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserFocusEntity.cs @@ -0,0 +1,31 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 用户表,数据实体对象 + /// + [Table("sys_userfocus")] + [Serializable] + public class UserFocusEntity : BaseEntity, ICreationAudited + { + /// + /// 默认构造函数(需要初始化属性的在此处理) + /// + public UserFocusEntity() + { + Id = 0; + } + + #region Property Members + + /// + /// 关注的用户ID + /// + public virtual string FocusUserId { get; set; } + + #endregion Property Members + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserNameCardViewEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserNameCardViewEntity.cs new file mode 100644 index 0000000..7b9b35f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserNameCardViewEntity.cs @@ -0,0 +1,174 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 用户表,数据实体对象 + /// + [Table("sys_vw_namecard")] + [Serializable] + [NotMapped] + public class UserNameCardViewEntity : BaseEntity + { + #region Property Members + + /// + /// 用户id + /// + public virtual long userId { get; set; } + + /// + /// 名片详情 + /// + public virtual string CardContent { get; set; } + + /// + /// 电话 + /// + public virtual string Telphone { get; set; } + + /// + /// 地址 + /// + public virtual string Address { get; set; } + + /// + /// 公司名称 + /// + public virtual string CompanyName { get; set; } + + /// + /// 职位 + /// + public virtual string PositionTitle { get; set; } + + /// + /// 微信二维码 + /// + public virtual string WeChatQrCode { get; set; } + + /// + /// 行业代码 + /// + public virtual string IndustryId { get; set; } + + /// + /// 公开标识 + /// + public virtual long OpenType { get; set; } + + /// + /// IsOtherShare + /// + public virtual bool? IsOtherShare { get; set; } + + /// + /// ShareTitle + /// + public virtual string ShareTitle { get; set; } + + /// + /// 主页 + /// + public string WebUrl { get; set; } + + /// + /// 公司描述 + /// + public string CompanyDesc { get; set; } + + /// + /// 名片主题 + /// + public virtual string CardTheme { get; set; } + + /// + /// vip等级 + /// + public virtual string VipGrade { get; set; } + + /// + /// 是否认证 + /// + public virtual bool? IsAuthentication { get; set; } + + /// + /// 认证类型 + /// + public virtual long? AuthenticationType { get; set; } + + /// + /// 可以标识 + /// + public virtual bool? IsEnabled { get; set; } + + /// + /// 公司ID + /// + public virtual long CompanyId { get; set; } + + /// + /// 部门ID + /// + public virtual long DeptId { get; set; } + + /// + /// 真实名称 + /// + public virtual string RealName { get; set; } + + /// + /// 昵称 + /// + public virtual string UserName { get; set; } + + /// + /// 头像 + /// + public virtual string HeadIcon { get; set; } + + /// + /// 手机 + /// + public virtual string MobilePhone { get; set; } + + /// + /// Email + /// + public virtual string EMail { get; set; } + + /// + /// 微信 + /// + public virtual string WeChat { get; set; } + + /// + /// 国家 + /// + public virtual string Country { get; set; } + + /// + /// 省份 + /// + public virtual string Province { get; set; } + + /// + /// 城市 + /// + public virtual string City { get; set; } + + /// + /// 性别 + /// + public virtual string Gender { get; set; } + + /// + /// 用户主表id + /// + public virtual string MUserId { get; set; } + + #endregion Property Members + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserOpenIdsEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserOpenIdsEntity.cs new file mode 100644 index 0000000..cf3a29e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/UserOpenIdsEntity.cs @@ -0,0 +1,31 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 第三方登录与用户绑定表,数据实体对象 + /// + [Table("sys_useropenids")] + public class UserOpenIdsEntity : BaseEntity + { + #region Property Members + + /// + /// 用户编号 + /// + public virtual long UserId { get; set; } + + /// + /// 第三方类型 + /// + public virtual string OpenIdType { get; set; } + + /// + /// OpenId + /// + public virtual string OpenId { get; set; } + + #endregion Property Members + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/WxUnifyUserEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/WxUnifyUserEntity.cs new file mode 100644 index 0000000..b7b854e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/WxUnifyUserEntity.cs @@ -0,0 +1,59 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 云平台统一用户表 + /// + [Table("wxunifyuser")] + [Serializable] + public class WxUnifyUserEntity : BaseEntity + { + /// + /// UnionId + /// + public string UnionId { get; set; } + + /// + /// 用户昵称 + /// + public string NickName { get; set; } + + /// + /// 用户头像 + /// + public string AvatarUrl { get; set; } + + /// + /// 手机号 + /// + public string Phone { get; set; } + + /// + /// 性别 + /// + public int Gender { get; set; } + + /// + /// 国家 + /// + public string Country { get; set; } + + /// + /// 省份 + /// + public string Province { get; set; } + + /// + /// 城市 + /// + public string City { get; set; } + + /// + /// 语种 + /// + public string Language { get; set; } + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Entitys/WxUserRelationEntity.cs b/Znyc.Cloudcar.Admin.Security.Core/Entitys/WxUserRelationEntity.cs new file mode 100644 index 0000000..1a388ea --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Entitys/WxUserRelationEntity.cs @@ -0,0 +1,35 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Znyc.Cloudcar.Admin.Commons.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.Entitys +{ + /// + /// 微信用户信息表 + /// + [Table("wxuserrelation")] + [Serializable] + public class WxUserRelationEntity : BaseEntity + { + /// + /// OpenId + /// + public string OpenId { get; set; } + + /// + /// 开放平台Id + /// + public string UnionId { get; set; } + + /// + /// 公众号openid + /// + public string WxOfficialOpenId { get; set; } + + /// + /// 平台类型 + /// + public int PlatformType { get; set; } + + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAPPRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAPPRepository.cs new file mode 100644 index 0000000..50969c4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAPPRepository.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IAPPRepository : IRepository + { + /// + /// ȡapp + /// + /// ӦID + /// ӦԿAppSecret + /// + APPEntity GetAPP(string appid, string secret); + + /// + /// ȡapp + /// + /// ӦID + /// + APPEntity GetAPP(string appid); + + /// + /// + /// + IList SelectApp(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IActivityRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IActivityRepository.cs new file mode 100644 index 0000000..1825753 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IActivityRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// 活动 + /// + public interface IActivityRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAdminUserLogOnRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAdminUserLogOnRepository.cs new file mode 100644 index 0000000..a64fd35 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAdminUserLogOnRepository.cs @@ -0,0 +1,15 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IAdminUserLogOnRepository : IRepository + { + /// + /// ݻԱIDȡû¼Ϣʵ + /// + /// + /// + AdminUserLogOnEntity GetByUserId(long userId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAdminUserRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAdminUserRepository.cs new file mode 100644 index 0000000..688cabc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAdminUserRepository.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IAdminUserRepository : IRepository + { + /// + /// û˺ŲѯûϢ + /// + /// + /// + Task GetByUserName(string userName); + + /// + /// ûֻѯûϢ + /// + /// ֻ + /// + Task GetUserByMobilePhone(string mobilePhone); + + /// + /// AccountֻŲѯûϢ + /// + /// ¼˺ + /// + Task GetUserByLogin(string account); + + /// + /// ݵOpenIdѯûϢ + /// + /// + /// OpenIdֵ + /// + AdminUserEntity GetUserByOpenId(string openIdType, string openId); + + /// + /// ΢UnionIdѯûϢ + /// + /// UnionIdֵ + /// + AdminUserEntity GetUserByUnionId(string unionId); + + /// + /// userIdѯûϢ + /// + /// + /// userId + /// + UserOpenIdsEntity GetUserOpenIdByuserId(string openIdType, long userId); + + /// + /// ûϢ,ƽ̨ + /// + /// + /// + /// + bool UpdateUserByOpenId(AdminUserEntity entity, AdminUserLogOnEntity userLogOnEntity, + UserOpenIdsEntity userOpenIds, + IDbTransaction trans = null); + + /// + /// ûIDõƬϢ + /// + /// + /// + //UserNameCardOutPutDto GetUserNameCardInfo(long userId); + + /// + /// Ƭ + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ////bool SaveNameCard(long userId,string headicon, string UserName, string name, string company, string position, + // string weburl, string mobile, string email, string wx, string wximg, + // string industry, string area, string address, long openflag); + + /// + /// ûϢڹע + /// + /// + /// + /// + /// + IEnumerable GetUserAllListFocusByPage(string currentpage, + string pagesize, long userId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IApiRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IApiRepository.cs new file mode 100644 index 0000000..3c3d734 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IApiRepository.cs @@ -0,0 +1,9 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IApiRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IApplyJobRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IApplyJobRepository.cs new file mode 100644 index 0000000..9ba48a1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IApplyJobRepository.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IApplyJobRepository : IRepository + { + /// + /// UserId޸ְϢǷʵ֤ + /// + /// + /// + Task UpdateIsRealAuthenticationAsync(long userId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAreaRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAreaRepository.cs new file mode 100644 index 0000000..3f0ab99 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAreaRepository.cs @@ -0,0 +1,9 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IAreaRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAuditRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAuditRepository.cs new file mode 100644 index 0000000..8839ecf --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IAuditRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IAuditRepository : IRepository + { + AuditEntity GetProductAuditByProductId(string productId, string productType); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IBannerRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IBannerRepository.cs new file mode 100644 index 0000000..9a5030d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IBannerRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// �ƱҼ�¼�ִ� + /// + public interface IBannerRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICallFeedbackRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICallFeedbackRepository.cs new file mode 100644 index 0000000..4758612 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICallFeedbackRepository.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface ICallFeedbackRepository : IRepository + { + /// + /// ProductId޸ͨ۷ǷѶ + /// + /// + /// + Task UpdateIsReadAsync(long userId, long productId, int productType); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICertificationRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICertificationRepository.cs new file mode 100644 index 0000000..04a78c1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICertificationRepository.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface ICertificationRepository : IRepository + { + /// + /// + /// + /// + Task GetAsync(string UnionId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICurrencyRecordRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICurrencyRecordRepository.cs new file mode 100644 index 0000000..fd29c1f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICurrencyRecordRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// �ƱҼ�¼�ִ� + /// + public interface ICurrencyRecordRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICurrencyRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICurrencyRepository.cs new file mode 100644 index 0000000..99dbf37 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ICurrencyRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// �û��ƱҲִ� + /// + public interface ICurrencyRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IDictionaryRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IDictionaryRepository.cs new file mode 100644 index 0000000..6784eb0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IDictionaryRepository.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IDictionaryRepository : IRepository + { + /// + /// ݱѯֵ + /// + /// + /// + Task GetByEnCodAsynce(string enCode); + + /// + /// ʱжϷǷڣųԼ + /// + /// Id + /// + Task GetByEnCodAsynce(string enCode, long id); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IEquipmentPictureRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IEquipmentPictureRepository.cs new file mode 100644 index 0000000..38bfa0b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IEquipmentPictureRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + /// + public interface IEquipmentPictureRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IEquipmentRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IEquipmentRepository.cs new file mode 100644 index 0000000..6696553 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IEquipmentRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + /// + public interface IEquipmentRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IExceptionsLogsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IExceptionsLogsRepository.cs new file mode 100644 index 0000000..66341de --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IExceptionsLogsRepository.cs @@ -0,0 +1,9 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IExceptionsLogsRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IFeedbackPicRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IFeedbackPicRepository.cs new file mode 100644 index 0000000..0ea2620 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IFeedbackPicRepository.cs @@ -0,0 +1,11 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IFeedbackPicRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IFeedbackRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IFeedbackRepository.cs new file mode 100644 index 0000000..def750c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IFeedbackRepository.cs @@ -0,0 +1,11 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IFeedbackRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IIndustryJobsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IIndustryJobsRepository.cs new file mode 100644 index 0000000..f5a09c0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IIndustryJobsRepository.cs @@ -0,0 +1,9 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IIndustryJobsRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ILoginLogsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ILoginLogsRepository.cs new file mode 100644 index 0000000..6ed05e2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ILoginLogsRepository.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface ILoginLogsRepository : IRepository + { + /// + /// ȡյ¼ + /// + /// + Task GetActiveUserTotal(); + + /// + /// û¼Ϣ + /// + /// + Task> GetLastLoginLogAsync(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMenuRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMenuRepository.cs new file mode 100644 index 0000000..bd0becb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMenuRepository.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IMenuRepository : IRepository + { + /// + /// ݽɫIDַŷֿ)ϵͳIDȡӦIJб + /// + /// ɫID + /// ϵͳID + /// ǷDz˵ + /// + IEnumerable GetFunctions(string roleIds, string typeID, bool isMenu = false); + + /// + /// ϵͳIDȡӦIJб + /// + /// ϵͳID + /// + IEnumerable GetFunctions(string typeID); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMessageLogsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMessageLogsRepository.cs new file mode 100644 index 0000000..66c29f0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMessageLogsRepository.cs @@ -0,0 +1,11 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IMessageLogsRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMessageRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMessageRepository.cs new file mode 100644 index 0000000..4bed1b1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IMessageRepository.cs @@ -0,0 +1,11 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IMessageRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOperationLogsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOperationLogsRepository.cs new file mode 100644 index 0000000..64b9f4d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOperationLogsRepository.cs @@ -0,0 +1,9 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IOperationLogsRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrderDetailRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrderDetailRepository.cs new file mode 100644 index 0000000..ce0c666 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrderDetailRepository.cs @@ -0,0 +1,11 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IOrderDetailRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrderRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrderRepository.cs new file mode 100644 index 0000000..0aa0fb9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrderRepository.cs @@ -0,0 +1,11 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IOrderRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrganizeRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrganizeRepository.cs new file mode 100644 index 0000000..d7c85ea --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IOrganizeRepository.cs @@ -0,0 +1,19 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// ִ֯ӿ + /// õOrganizeҵ + /// + public interface IOrganizeRepository : IRepository + { + /// + /// ȡڵ֯ + /// + /// ֯Id + /// + OrganizeEntity GetRootOrganize(long id); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IPaymentRecordRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IPaymentRecordRepository.cs new file mode 100644 index 0000000..b85390b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IPaymentRecordRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// 充值服务 + /// + public interface IPaymentRecordRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRechargeIntroRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRechargeIntroRepository.cs new file mode 100644 index 0000000..c0e0fc3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRechargeIntroRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// 充值活动详情 + /// + public interface IRechargeIntroRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRechargeRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRechargeRepository.cs new file mode 100644 index 0000000..770f8e4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRechargeRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// 充值活动 + /// + public interface IRechargeRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRecruitmentRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRecruitmentRepository.cs new file mode 100644 index 0000000..33b779c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRecruitmentRepository.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface ICloudcarRepository : IRepository + { + /// + /// UserId޸ƸϢǷʵ֤ + /// + /// + /// + Task UpdateIsRealAuthenticationAsync(long userId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRegionRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRegionRepository.cs new file mode 100644 index 0000000..15f0912 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRegionRepository.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IRegionRepository : IRepository + { + /// + /// areaIdѯ + /// + /// + /// + Task GetRegionNameByAreaId(long areaId, long cityId, long provinceId); + + /// + /// cityIdѯ + /// + /// + /// + Task GetRegionNameByCityId(string cityId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleAuthorizeRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleAuthorizeRepository.cs new file mode 100644 index 0000000..7baacbe --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleAuthorizeRepository.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IRoleAuthorizeRepository : IRepository + { + /// + /// ɫȨ + /// + /// ɫId + /// ɫģ + /// ɫɷ + /// + /// ִгɹtrueΪfalse + Task SaveRoleAuthorize(long roleId, List roleAuthorizesList, + List roleDataList, + IDbTransaction trans = null); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleDataRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleDataRepository.cs new file mode 100644 index 0000000..ecf4811 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleDataRepository.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IRoleDataRepository : IRepository + { + /// + /// ݽɫȨʲ + /// + /// + /// + List GetListDeptByRole(string roleIds); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleRepository.cs new file mode 100644 index 0000000..17d20a2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IRoleRepository.cs @@ -0,0 +1,9 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IRoleRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IStatisticalRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IStatisticalRepository.cs new file mode 100644 index 0000000..8509354 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IStatisticalRepository.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IStatisticalRepository : IRepository + { + Task GetStatisticalAsync(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ISystemTypeRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ISystemTypeRepository.cs new file mode 100644 index 0000000..00919aa --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/ISystemTypeRepository.cs @@ -0,0 +1,15 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface ISystemTypeRepository : IRepository + { + /// + /// 根据系统编码查询系统对象 + /// + /// 系统编码 + /// + SystemTypeEntity GetByCode(string appkey); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IUploadFileRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IUploadFileRepository.cs new file mode 100644 index 0000000..f9f9d5d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IUploadFileRepository.cs @@ -0,0 +1,20 @@ +using System.Data; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + public interface IUploadFileRepository : IRepository + { + /// + /// 根据应用Id和应用标识批量更新数据 + /// + /// 应用Id + /// 更新前旧的应用Id + /// 应用标识 + /// + /// + bool UpdateByBeLongAppId(string beLongAppId, string oldBeLongAppId, string belongApp = null, + IDbTransaction trans = null); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IUserRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IUserRepository.cs new file mode 100644 index 0000000..9607eb5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IUserRepository.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + public interface IUserRepository : IRepository + { + Task GetUserByUnionId(string unionId); + + Task> FindUserWithPagerAsync(SearchUserModel search, PagerInfo info); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IWxUnifyUserRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IWxUnifyUserRepository.cs new file mode 100644 index 0000000..f1158bc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IWxUnifyUserRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// 统一平台用户 + /// + public interface IWxUnifyUserRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IWxUserRelationRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IWxUserRelationRepository.cs new file mode 100644 index 0000000..d90f683 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IRepositories/Recruitment/IWxUserRelationRepository.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IRepositories; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IRepositories +{ + /// + /// + /// + public interface IWxUserRelationRepository : IRepository + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IAPPService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAPPService.cs new file mode 100644 index 0000000..d5d1953 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAPPService.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IAPPService : IService + { + /// + /// ȡapp + /// + /// ӦID + /// ӦԿAppSecret + /// + APPEntity GetAPP(string appid, string secret); + + /// + /// ȡapp + /// + /// ӦID + /// + APPEntity GetAPP(string appid); + + /// + /// + /// + IList SelectApp(); + + /// + /// ¿õӦõ + /// + void UpdateCacheAllowApp(); + + + /// + /// ȡCosToken + /// + /// + CommonResult GetCosToken(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IActivityService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IActivityService.cs new file mode 100644 index 0000000..85b43ca --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IActivityService.cs @@ -0,0 +1,43 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// ӿ + /// + public interface IActivityService : IService + { + /// + /// 첽 + /// + /// + /// + Task InsertAsync(ActivityEntity intput); + + /// + /// ҳѯ + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchActivityModel search); + + + /// + /// ½ӿ + /// + /// + /// + Task UpdateAsync(ActivityEntity input); + + /// + /// ޸Ļӿ + /// + /// + Task UpdateStatusAsync(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IAdminUserLogOnService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAdminUserLogOnService.cs new file mode 100644 index 0000000..79654f5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAdminUserLogOnService.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + public interface IAdminUserLogOnService : IService + { + /// + /// ݻԱIDȡû¼Ϣʵ + /// + /// ûId + /// + AdminUserLogOnEntity GetByUserId(long userId); + + /// + /// ݻԱIDȡû¼Ϣʵ + /// + /// Ϣ + /// ûId + /// + Task SaveUserTheme(UserThemeInputDto info, long userId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IAdminUserService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAdminUserService.cs new file mode 100644 index 0000000..8feddb3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAdminUserService.cs @@ -0,0 +1,109 @@ +using System; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// ûӿ + /// + public interface IAdminUserService : IService + { + /// + /// û½֤ + /// + /// û + /// 루һmd5ܺ + /// ֤ɹûʵ壬֤ʧܷnull|ʾϢ + Task> Validate(string userName, string password); + + /// + /// û½֤ + /// + /// û + /// 루һmd5ܺ + /// û + /// ֤ɹûʵ壬֤ʧܷnull|ʾϢ + Task> Validate(string userName, string password, UserType userType); + + /// + /// û˺ŲѯûϢ + /// + /// + /// + Task GetByUserName(string userName); + + /// + /// ûֻѯûϢ + /// + /// ֻ + /// + Task GetUserByMobilePhone(string mobilePhone); + + /// + /// AccountֻŲѯûϢ + /// + /// ¼˺ + /// + Task GetUserByLogin(string account); + + /// + /// ݵOpenIdѯûϢ + /// + /// + /// OpenIdֵ + /// + AdminUserEntity GetUserByOpenId(string openIdType, string openId); + + /// + /// ΢UnionIdѯûϢ + /// + /// UnionIdֵ + /// + AdminUserEntity GetUserByUnionId(string unionId); + + /// + /// userIdѯûϢ + /// + /// + /// userId + /// + UserOpenIdsEntity GetUserOpenIdByuserId(string openIdType, long userId); + + /// + /// ûϢ,ƽ̨ + /// + /// + /// + /// + bool UpdateUserByOpenId(AdminUserEntity entity, AdminUserLogOnEntity userLogOnEntity, + UserOpenIdsEntity userOpenIds, + IDbTransaction trans = null); + + /// + /// ΢עͨԱû + /// + /// + /// + bool CreateUserByWxOpenId(UserInputDto userInPut); + + /// + /// û + /// + /// + /// + bool UpdateUserByOpenId(UserInputDto userInPut); + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchUserModel search); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IApiService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IApiService.cs new file mode 100644 index 0000000..df9e4fe --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IApiService.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + public interface IApiService : IService + { + Task GetApiAsync(string apiUrl); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IApplyJobService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IApplyJobService.cs new file mode 100644 index 0000000..564f25c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IApplyJobService.cs @@ -0,0 +1,46 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IApplyJobService : IService + { + #region uniappѡ + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchCloudcarModel search); + + Task InsertAsync(ApplyJobEntity intput); + + Task UpdateAsync(ApplyJobEntity intput); + + + + /// + /// IdȡһϢ + /// + /// Id + /// + + Task GetById(long id); + + /// + /// ¼ְϢ + /// + /// + /// + /// + Task RevocationAsync(long id, long userId); + #endregion uniappѡ + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IAreaService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAreaService.cs new file mode 100644 index 0000000..060faf1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAreaService.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IAreaService : IService + { + #region uniappѡ + + /// + /// ȡпõĵuniappѡ + /// + /// + List GetAllByEnable(); + + /// + /// ȡʡС/õĵuniappѡ + /// + /// + List GetProvinceToAreaByEnable(); + + #endregion uniappѡ + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IAuditService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAuditService.cs new file mode 100644 index 0000000..bb50260 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IAuditService.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IAuditService : IService + { + #region uniappѡ + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchUserModel search); + + #endregion uniappѡ + + Task AuditSuccessAsync(AuditEntity info,int PromoteType); + + Task AuditFailAsync(AuditEntity info); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IBannerService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IBannerService.cs new file mode 100644 index 0000000..30c914e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IBannerService.cs @@ -0,0 +1,43 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// Banner + /// + public interface IBannerService : IService + { + + /// + /// б + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchBannerModel search); + + /// + /// 첽 + /// + /// + /// + Task InsertAsync(BannerEntity input); + + /// + /// ½ӿ + /// + /// + /// + Task UpdateAsync(BannerEntity input); + + /// + /// ޸Ĺ״̬ + /// + /// + Task UpdateStatusAsync(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/ICallFeedbackService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/ICallFeedbackService.cs new file mode 100644 index 0000000..c451596 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/ICallFeedbackService.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface ICallFeedbackService : IService + { + /// + /// ͨ۷ҳѯ + /// + /// + /// + Task> FindWithPagerSearchAsync(SearchCallFeedbackModel search); + + /// + /// ޸ͨѶ + /// + /// + /// + /// + Task UpdateIsReadAsync(long userId, long productId, int productType); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/ICertificationService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/ICertificationService.cs new file mode 100644 index 0000000..f1d29fe --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/ICertificationService.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + public interface ICertificationService : IService + { + Task> FindWithPagerSearchAsync(SearchUserModel search); + + Task AuditSuccessAsync(CertificationEntity info); + + Task AuditFailAsync(CertificationEntity info); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/ICurrencyRecordService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/ICurrencyRecordService.cs new file mode 100644 index 0000000..9a81fc1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/ICurrencyRecordService.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// Ʊҷ + /// + public interface ICurrencyRecordService : IService + { + + /// + /// Ʊб + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchCurrencyRecordModel search); + + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/ICurrencyService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/ICurrencyService.cs new file mode 100644 index 0000000..a3ee746 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/ICurrencyService.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// Ʊҷ + /// + public interface ICurrencyService : IService + { + + /// + /// ʵ֤ӻ + /// + /// + /// + /// + Task AddCurrencyForRealName(long userId, long createdUserId); + + + /// + /// ְöƱ + /// + /// + /// 4 + /// + /// + Task TopReturnForApplyJob(long userId, long applyJobId, long createdUserId); + + /// + /// ƸöƱ + /// + /// + /// + /// + /// + Task TopReturnForCloudcar(long userId, long CloudcarId, long createdUserId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IDictionaryService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IDictionaryService.cs new file mode 100644 index 0000000..c65c7bc --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IDictionaryService.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + public interface IDictionaryService : IService + { + /// + /// ȡܲ˵Vue б + /// + /// + Task> GetAllDictionaryTreeTable(); + + /// + /// ݱѯֵ + /// + /// + /// + Task GetByEnCodAsynce(string enCode); + + /// + /// ʱжϷǷڣųԼ + /// + /// Id + /// + Task GetByEnCodAsynce(string enCode, long id); + + /// + /// ѯֵ + /// + /// + /// + Task GetDictionaryById(long id); + + /// + /// ParentIdѯֵб + /// + /// + /// + Task> GetListByPidAsync(long pid); + + /// + /// + /// + /// + /// + /// + Task> GetListByCodeAsync(long pid, string code); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IEquipmentService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IEquipmentService.cs new file mode 100644 index 0000000..675e39b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IEquipmentService.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + /// + public interface IEquipmentService : IService + { + + /// + /// ҳѯ + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchEquipmentModel search); + + /// + /// ¼ + /// + /// + /// + Task CancelAsync(long id); + + Task CompleteAsync(long id); + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IExceptionsLogsService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IExceptionsLogsService.cs new file mode 100644 index 0000000..d78878d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IExceptionsLogsService.cs @@ -0,0 +1,40 @@ +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// ־¼ + /// + public interface IExceptionsLogsService : IService + { + /// + /// ϢдûIJ־¼ + /// Ҫдݿ־ + /// + /// + /// + /// ϸ + /// + bool OnOperationLog(string tableName, string operationType, string note); + + /// + /// ϢдûIJ־¼ + /// Ҫдģ־ + /// + /// ģ + /// + /// ϸ + /// û + /// + bool OnOperationLog(string module, string operationType, string note, AdminCurrentUser AdminCurrentUser); + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + // Task> FindWithPagerSearchAsync(SearchExceptionsLogsModel search); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IFeedbackService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IFeedbackService.cs new file mode 100644 index 0000000..d8421df --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IFeedbackService.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IFeedbackService : IService + { + /// + /// ҳѯ + /// + /// + /// + Task> FindWithPagerSearchAsync(SearchFeedbackModel search); + + /// + /// ༭ + /// + /// + /// + Task UpdateAsync(FeedbackEntity input); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IIndustryJobsService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IIndustryJobsService.cs new file mode 100644 index 0000000..a2be98a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IIndustryJobsService.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// 行业岗位服务 + /// + public interface IIndustryJobsService : IService + { + Task> GetAllIndustryJobsTreeTable(); + + /// + /// 查询行业岗位 + /// + /// + /// + Task> GetListByIdAsync(long id); + + /// + /// 查询行业岗位 + /// + /// + /// + Task GetByIdAsync(long id); + + /// + /// 查询所有行业岗位 + /// + /// + Task> GetAllListAsync(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/ILoginLogsService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/ILoginLogsService.cs new file mode 100644 index 0000000..a4847b2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/ILoginLogsService.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// ½־¼ + /// + public interface ILoginLogsService : IService + { + /// + /// ϢдûIJ־¼ + /// Ҫдݿ־ + /// + /// + /// + /// ϸ + /// + bool OnOperationLog(string tableName, string operationType, string note); + + /// + /// ϢдûIJ־¼ + /// Ҫдģ־ + /// + /// ģ + /// + /// ϸ + /// û + /// + bool OnOperationLog(string module, string operationType, string note, AdminCurrentUser AdminCurrentUser); + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchLoginLogsModel search); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IMenuService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IMenuService.cs new file mode 100644 index 0000000..2c361aa --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IMenuService.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Core.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IMenuService : IService + { + /// + /// ûȡܲ˵ + /// + /// ûID + /// + List GetMenuByUser(long userId); + + /// + /// ȡܲ˵Vue б + /// + /// ϵͳId + /// + Task> GetAllMenuTreeTable(string systemTypeId); + + /// + /// ݽɫIDַŷֿ)ϵͳIDȡӦIJб + /// + /// ɫID + /// ϵͳID + /// ǷDz˵ + /// + List GetFunctions(string roleIds, string typeID, bool isMenu = false); + + /// + /// ϵͳIDȡӦIJб + /// + /// ϵͳID + /// + List GetFunctions(string typeID); + + /// + /// ݸܱѯӼܣҪҳťȨ + /// + /// ˵ܱ + /// + Task> GetListByParentEnCode(string enCode); + + /// + /// ɾ + /// + /// Id + /// + /// + CommonResult DeleteBatchWhere(DeletesInputDto ids, IDbTransaction trans = null); + + /// + /// 첽ɾ + /// + /// Id + /// + /// + Task DeleteBatchWhereAsync(DeletesInputDto ids, IDbTransaction trans = null); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IMessageLogsService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IMessageLogsService.cs new file mode 100644 index 0000000..5fa0124 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IMessageLogsService.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IMessageLogsService : IService + { + Task AddAsync(MessageInputDto input); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IMessageService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IMessageService.cs new file mode 100644 index 0000000..b856707 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IMessageService.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IMessageService : IService + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IOperationLogsService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IOperationLogsService.cs new file mode 100644 index 0000000..ed85b46 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IOperationLogsService.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// ־¼ + /// + public interface IOperationLogsService : IService + { + /// + /// ϢдûIJ־¼ + /// Ҫдݿ־ + /// + /// + /// + /// ϸ + /// + bool OnOperationLog(string tableName, string operationType, string note); + + /// + /// ϢдûIJ־¼ + /// Ҫдģ־ + /// + /// ģ + /// + /// ϸ + /// û + /// + bool OnOperationLog(string module, string operationType, string note, AdminCurrentUser AdminCurrentUser); + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchOperationLogsModel search); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrderDetailService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrderDetailService.cs new file mode 100644 index 0000000..09ccdbd --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrderDetailService.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IOrderDetailService : IService + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrderService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrderService.cs new file mode 100644 index 0000000..f9baba0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrderService.cs @@ -0,0 +1,12 @@ +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IOrderService : IService + { + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrganizeService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrganizeService.cs new file mode 100644 index 0000000..63f3e37 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IOrganizeService.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Core.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// ֯ + /// + public interface IOrganizeService : IService + { + /// + /// ȡ֯Vue б + /// + /// + Task> GetAllOrganizeTreeTable(); + + /// + /// ȡڵ֯ + /// + /// ֯Id + /// + OrganizeEntity GetRootOrganize(long id); + + /// + /// ɾ + /// + /// Id + /// + /// + CommonResult DeleteBatchWhere(DeletesInputDto ids, IDbTransaction trans = null); + + /// + /// 첽ɾ + /// + /// Id + /// + /// + Task DeleteBatchWhereAsync(DeletesInputDto ids, IDbTransaction trans = null); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IPaymentRecordService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IPaymentRecordService.cs new file mode 100644 index 0000000..9a9a83c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IPaymentRecordService.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// ֵ + /// + public interface IPaymentRecordService : IService + { + + /// + /// Ʊб + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchPaymentRecordModel search); + + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IRechargeService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRechargeService.cs new file mode 100644 index 0000000..92c1722 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRechargeService.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// ֵӿ + /// + public interface IRechargeService : IService + { + + /// + /// ҳѯ + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchRechargeModel search); + + /// + /// 첽ֵ + /// + /// + /// + /// + /// + Task InsertRechargeIntroAsync(List input, long parentId, long userId); + + /// + /// 첽 + /// + /// + /// + /// + Task UpdateAsync(RechargeUpdateInput input, long userId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IRecruitmentService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRecruitmentService.cs new file mode 100644 index 0000000..82be21a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRecruitmentService.cs @@ -0,0 +1,51 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface ICloudcarService : IService + { + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchCloudcarModel search); + + /// + /// 첽 + /// + /// + /// + Task InsertAsync(CloudcarEntity intput); + + /// + /// 첽޸ + /// + /// + /// + Task UpdateAsync(CloudcarEntity tinfo); + + + /// + /// + /// + /// + /// + Task GetById(long id); + + /// + /// ¼ƸϢ + /// + /// + /// + /// + Task RevocationAsync(long id, long userId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IRegionService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRegionService.cs new file mode 100644 index 0000000..6eab92e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRegionService.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IRegionService : IService + { + Task> GetAllRegionList(); + + Task> AsyncRegionCache(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleAuthorizeService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleAuthorizeService.cs new file mode 100644 index 0000000..1244516 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleAuthorizeService.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IRoleAuthorizeService : IService + { + /// + /// ݽɫĿͲѯȨ + /// + /// + /// + /// + IEnumerable GetListRoleAuthorizeByRoleId(string roleIds, string itemType); + + /// + /// ȡܲ˵Vue Tree + /// + /// + Task> GetAllFunctionTree(); + + /// + /// ɫȨ + /// + /// ɫId + /// ɫģ + /// ɫɷ + /// + /// ִгɹtrueΪfalse + Task SaveRoleAuthorize(long roleId, List roleAuthorizesList, + List roleDataList, + IDbTransaction trans = null); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleDataService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleDataService.cs new file mode 100644 index 0000000..ec14f4a --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleDataService.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + public interface IRoleDataService : IService + { + /// + /// ݽɫȨʲ + /// + /// + /// + List GetListDeptByRole(string roleIds); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleService.cs new file mode 100644 index 0000000..2a00068 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IRoleService.cs @@ -0,0 +1,32 @@ +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IRoleService : IService + { + /// + /// ݽɫȡɫ + /// + /// + /// + RoleEntityEntity GetRole(string enCode); + + /// + /// ûɫIDȡɫ + /// + /// ɫIDַá,ָ + /// + string GetRoleEnCode(string ids); + + /// + /// ûɫIDȡɫ + /// + /// ɫIDַá,ָ + /// + string GetRoleNameStr(string ids); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IStatisticalService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IStatisticalService.cs new file mode 100644 index 0000000..b460cf4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IStatisticalService.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IStatisticalService : IService + { + Task> FindWithPagerSearchAsync(SearchUserModel search); + + /// + /// 첽 + /// + /// + Task InsertAsync(); + + Task GetStatisticalAsync(); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/ISystemTypeService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/ISystemTypeService.cs new file mode 100644 index 0000000..c134918 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/ISystemTypeService.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// 子系统服务接口 + /// + public interface ISystemTypeService : IService + { + /// + /// 根据系统编码查询系统对象 + /// + /// 系统编码 + /// + SystemTypeEntity GetByCode(string appkey); + + /// + /// 根据角色获取可以访问子系统 + /// + /// 角色Id,用','隔开 + /// + List GetSubSystemList(string roleIds); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IUploadFileService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IUploadFileService.cs new file mode 100644 index 0000000..cd9076b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IUploadFileService.cs @@ -0,0 +1,21 @@ +using System.Data; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + public interface IUploadFileService : IService + { + /// + /// 根据应用Id和应用标识批量更新数据 + /// + /// 应用Id + /// 更新前旧的应用Id + /// 应用标识 + /// + /// + bool UpdateByBeLongAppId(string beLongAppId, string oldBeLongAppId, string belongApp = null, + IDbTransaction trans = null); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IUserService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IUserService.cs new file mode 100644 index 0000000..8ae3ebd --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IUserService.cs @@ -0,0 +1,38 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IUserService : IService + { + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + Task> FindWithPagerSearchAsync(SearchUserModel search); + + /// + /// 첽/û + /// + /// + /// + /// + Task UpdateStatusAsync(long id, int status); + + + /// + /// + /// + /// + /// + Task UpdateIsPromoteAsync(long id); + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/IServices/IWxUserRelationService.cs b/Znyc.Cloudcar.Admin.Security.Core/IServices/IWxUserRelationService.cs new file mode 100644 index 0000000..6c7a149 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/IServices/IWxUserRelationService.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.IServices; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.Security.IServices +{ + /// + /// + public interface IWxUserRelationService : IService + { + /// + /// + /// + /// + /// + /// + Task UpdateAsync(string wxOpenId); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/APPRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/APPRepository.cs new file mode 100644 index 0000000..7c0fa86 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/APPRepository.cs @@ -0,0 +1,59 @@ +using Dapper; +using System.Collections.Generic; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// Ӧòִʵ + /// + public class APPRepository : BaseRepository, IAPPRepository + { + public APPRepository() + { + } + + public APPRepository(IDbContextCore context) : base(context) + { + } + + /// + /// ȡapp + /// + /// ӦID + /// ӦԿAppSecret + /// + public APPEntity GetAPP(string appid, string secret) + { + string sql = @"SELECT * FROM sys_app t WHERE t.AppId = @AppId and AppSecret=@AppSecret and IsDeleted=0"; + return DapperConnRead.QueryFirstOrDefault(sql, new { AppId = appid, AppSecret = secret }); + } + + /// + /// ȡapp + /// + /// ӦID + /// + public APPEntity GetAPP(string appid) + { + string sql = @"SELECT * FROM sys_app t WHERE t.AppId = @AppId and IsDeleted=0"; + return DapperConnRead.QueryFirstOrDefault(sql, new { AppId = appid }); + } + + public IList SelectApp() + { + const string query = + @"select a.*,u.id as Id,u.UserName,u.Account,u.HeadIcon from sys_app a,sys_adminuser u where a.CreatedUserId=u.Id "; + return DapperConnRead.Query(query, (app, user) => + { + app.UserInfo = user; + return app; + }).ToList(); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ActivityRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ActivityRepository.cs new file mode 100644 index 0000000..648db93 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ActivityRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + /// + public class ActivityRepository : BaseRepository, IActivityRepository + { + public ActivityRepository() + { + } + + public ActivityRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AdminUserLogOnRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AdminUserLogOnRepository.cs new file mode 100644 index 0000000..1e21600 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AdminUserLogOnRepository.cs @@ -0,0 +1,30 @@ +using Dapper; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class AdminUserLogOnRepository : BaseRepository, IAdminUserLogOnRepository + { + public AdminUserLogOnRepository() + { + } + + public AdminUserLogOnRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ݻԱIDȡû¼Ϣʵ + /// + /// + /// + public AdminUserLogOnEntity GetByUserId(long userId) + { + string sql = @"SELECT * FROM sys_adminuser_logon t WHERE t.UserId = @UserId"; + return DapperConn.QueryFirstOrDefault(sql, new { UserId = userId }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AdminUserRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AdminUserRepository.cs new file mode 100644 index 0000000..2664d03 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AdminUserRepository.cs @@ -0,0 +1,189 @@ +using Dapper; +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// Ӧòִʵ + /// + public class AdminUserRepository : BaseRepository, IAdminUserRepository + { + public AdminUserRepository() + { + } + + public AdminUserRepository(IDbContextCore context) : base(context) + { + } + + /// + /// û˺ŲѯûϢ + /// + /// + /// + public async Task GetByUserName(string userName) + { + string sql = @"SELECT * FROM sys_adminuser t WHERE t.Account = @UserName"; + return await DapperConn.QueryFirstOrDefaultAsync(sql, new { UserName = userName }); + } + + /// + /// ûֻѯûϢ + /// + /// ֻ + /// + public async Task GetUserByMobilePhone(string mobilephone) + { + string sql = @"SELECT * FROM sys_adminuser t WHERE t.MobilePhone = @MobilePhone"; + return await DapperConn.QueryFirstOrDefaultAsync(sql, new { MobilePhone = mobilephone }); + } + + /// + /// EmailAccountֻŲѯûϢ + /// + /// ¼˺ + /// + public async Task GetUserByLogin(string account) + { + string sql = + @"SELECT * FROM sys_adminuser t WHERE (t.Account = @Account or t.MobilePhone = @Account)"; + return await DapperConn.QueryFirstOrDefaultAsync(sql, new { Account = account }); + } + + /// + /// ΢UnionIdѯûϢ + /// + /// UnionIdֵ + /// + public AdminUserEntity GetUserByUnionId(string unionId) + { + string sql = string.Format("select * from sys_adminuser where UnionId = '{0}'", unionId); + return DapperConn.QueryFirstOrDefault(sql); + } + + /// + /// ݵOpenIdѯûϢ + /// + /// + /// OpenIdֵ + /// + public AdminUserEntity GetUserByOpenId(string openIdType, string openId) + { + string sql = string.Format( + "select * from sys_adminuser as u join sys_adminuserOpenIds as o on u.Id = o.UserId and o.OpenIdType = '{0}' and o.OpenId = '{1}'", + openIdType, openId); + return DapperConn.QueryFirstOrDefault(sql); + } + + /// + /// userIdѯûϢ + /// + /// + /// userId + /// + public UserOpenIdsEntity GetUserOpenIdByuserId(string openIdType, long userId) + { + string sql = string.Format("select * from sys_adminuserOpenIds where OpenIdType = '{0}' and UserId = '{1}'", + openIdType, userId); + return DapperConn.QueryFirstOrDefault(sql); + } + + /// + /// ûϢ,ƽ̨ + /// + /// + /// + /// + public bool UpdateUserByOpenId(AdminUserEntity entity, AdminUserLogOnEntity userLogOnEntity, + UserOpenIdsEntity userOpenIds, + IDbTransaction trans = null) + { + DbContext.GetDbSet().Add(entity); + DbContext.GetDbSet().Add(userOpenIds); + return DbContext.SaveChanges() > 0; + } + + /// + /// ҳõûڹע + /// + /// + /// + /// + /// + public IEnumerable GetUserAllListFocusByPage(string currentpage, + string pagesize, long userId) + { + string sqlRecord = ""; + string sql = ""; + + long countNotIn = (long.Parse(currentpage) - 1) * long.Parse(pagesize); + + sqlRecord = @"select * from sys_adminuser where UserName <> 'ο' and ismember=1 "; + + sql = @"SELECT TOP " + pagesize + + @" +case when t2.Id is null then 'n' +else 'y' end as IfFocus , +IsNull(t3.totalFocus,0) as TotalFocus, +t1.* +from +(select ISNULL(tin2.VipGrade,0) as VipGrade, +ISNULL(tin2.IsAuthentication,0) as IsAuthentication, +ISNULL(tin2.AuthenticationType,0) as AuthenticationType, +tin1.* from sys_adminuser tin1 +left join sys_adminuserExtend tin2 on tin1.Id=tin2.UserId +where UserName <> 'ο' and ismember=1) t1 +left join +(select * from sys_adminuserFocus where CreatedUserId='" + userId + @"') t2 +on t1.id=t2.focususerid +left join +(select top 100 percent focusUserID,count(*) as totalFocus from sys_adminuserFocus group by focusUserID order by totalfocus desc) t3 +on t1.Id=t3.focusUserID + +where t1.Id not in +( +select top " + countNotIn + @" +tt1.Id +from +(select ISNULL(tin2.VipGrade,0) as VipGrade, +ISNULL(tin2.IsAuthentication,0) as IsAuthentication, +ISNULL(tin2.AuthenticationType,0) as AuthenticationType, +tin1.* from sys_adminuser tin1 +left join sys_adminuserExtend tin2 on tin1.Id=tin2.UserId +where UserName <> 'ο' and ismember=1) tt1 +left join +(select * from sys_adminuserFocus where CreatedUserId='" + userId + @"') tt2 +on tt1.id=tt2.focususerid +left join +(select top 100 percent focusUserID,count(*) as totalFocus from sys_adminuserFocus group by focusUserID order by totalfocus desc) tt3 +on tt1.Id=tt3.focusUserID + +order by tt3.totalFocus desc +) + +order by t3.totalFocus desc"; + + List list = new List(); + + IEnumerable infoOutputDto = DapperConn.Query(sql); + + //õܼ¼ + List recordCountList = DapperConn.Query(sqlRecord).AsList(); + + list = infoOutputDto.AsList(); + for (int i = 0; i < list.Count; i++) + { + list[i].RecordCount = recordCountList.Count; + } + + return list; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ApiRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ApiRepository.cs new file mode 100644 index 0000000..ca0182f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ApiRepository.cs @@ -0,0 +1,18 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class ApiRepository : BaseRepository, IApiRepository + { + public ApiRepository() + { + } + + public ApiRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ApplyJobRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ApplyJobRepository.cs new file mode 100644 index 0000000..7464089 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ApplyJobRepository.cs @@ -0,0 +1,34 @@ +using Dapper; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// ְִʵ + /// + public class ApplyJobRepository : BaseRepository, IApplyJobRepository + { + public ApplyJobRepository() + { + } + + public ApplyJobRepository(IDbContextCore context) : base(context) + { + } + + /// + /// UserId޸ְϢǷʵ֤ + /// + /// + /// + public async Task UpdateIsRealAuthenticationAsync(long userId) + { + string sql = @"UPDATE applyjob SET IsRealAuthentication=TRUE WHERE UserId=@UserId"; + return await DapperConn.ExecuteAsync(sql, new { UserId = userId }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AreaRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AreaRepository.cs new file mode 100644 index 0000000..0ff6035 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AreaRepository.cs @@ -0,0 +1,18 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class AreaRepository : BaseRepository, IAreaRepository + { + public AreaRepository() + { + } + + public AreaRepository(IDbContextCore dbContext) : base(dbContext) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AuditRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AuditRepository.cs new file mode 100644 index 0000000..0b78306 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/AuditRepository.cs @@ -0,0 +1,36 @@ +using Dapper; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// Ӧòִʵ + /// + public class AuditRepository : BaseRepository, IAuditRepository + { + public AuditRepository() + { + } + + public AuditRepository(IDbContextCore context) : base(context) + { + } + + /// + /// + /// + /// ƷID + /// Ʒ + /// + public AuditEntity GetProductAuditByProductId(string productId, string productType) + { + string sql = string.Format( + "SELECT * from ProductAudit where ProductId={0} and ProductType={1} and IsDeleted=0", + productId, productType); + return DapperConn.QueryFirstOrDefault(sql); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/BannerRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/BannerRepository.cs new file mode 100644 index 0000000..59082f6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/BannerRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// �ƱҼ�¼�ִ�ʵ�� + /// + public class BannerRepository : BaseRepository, IBannerRepository + { + public BannerRepository() + { + } + + public BannerRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CallFeedbackRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CallFeedbackRepository.cs new file mode 100644 index 0000000..3d4886d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CallFeedbackRepository.cs @@ -0,0 +1,36 @@ +using Dapper; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + public class CallFeedbackRepository : BaseRepository, ICallFeedbackRepository + { + /// + /// + public CallFeedbackRepository() + { + } + + public CallFeedbackRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + + /// + /// ProductId޸ͨ۷ǷѶ + /// + /// + /// + public async Task UpdateIsReadAsync(long userId, long productId, int productType) + { + string sql = @"UPDATE call_feedback SET IsRead=TRUE,ModifiedUserId=@ModifiedUserId,ModifiedTime=NOW() WHERE ProductId=@ProductId AND ProductType=@ProductType;"; + return await DapperConn.ExecuteAsync(sql, new { ModifiedUserId = userId, ProductId = productId, ProductType = productType }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CertificationRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CertificationRepository.cs new file mode 100644 index 0000000..b92fdea --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CertificationRepository.cs @@ -0,0 +1,32 @@ +using Dapper; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class CertificationRepository : BaseRepository, ICertificationRepository + { + public CertificationRepository() + { + } + + public CertificationRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// + /// + /// + public async Task GetAsync(string UnionId) + { + string sql = string.Format( + "SELECT Id,Gender,IdCard,IssuedAddress,PositivePhoto,ReversePhoto,State from user_certification where UnionId='{0}'", + UnionId); + return await DapperConn.QueryFirstOrDefaultAsync(sql); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CurrencyRecordRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CurrencyRecordRepository.cs new file mode 100644 index 0000000..d98ecc7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CurrencyRecordRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// �ƱҼ�¼�ִ�ʵ�� + /// + public class CurrencyRecordRepository : BaseRepository, ICurrencyRecordRepository + { + public CurrencyRecordRepository() + { + } + + public CurrencyRecordRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CurrencyRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CurrencyRepository.cs new file mode 100644 index 0000000..71d70e7 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/CurrencyRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// �û��ƱҲִ�ʵ�� + /// + public class CurrencyRepository : BaseRepository, ICurrencyRepository + { + public CurrencyRepository() + { + } + + public CurrencyRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/DictionaryRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/DictionaryRepository.cs new file mode 100644 index 0000000..56c0d4f --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/DictionaryRepository.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class DictionaryRepository : BaseRepository, IDictionaryRepository + { + public DictionaryRepository() + { + } + + public DictionaryRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ݱѯֵ + /// + /// + /// + public async Task GetByEnCodAsynce(string enCode) + { + //return await DbContext.GetSingleOrDefaultAsync(u => u.Code == enCode); + return await DbContext.GetFirstOrDefaultAsync(u => u.Code == enCode); + } + + /// + /// ʱжϷǷڣųԼ + /// + /// Id + /// + public async Task GetByEnCodAsynce(string enCode, long id) + { + return await DbContext.GetFirstOrDefaultAsync(u => u.Code == enCode && u.Id != id); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/EquipmentPictureRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/EquipmentPictureRepository.cs new file mode 100644 index 0000000..3c907fb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/EquipmentPictureRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + /// + public class EquipmentPictureRepository : BaseRepository, IEquipmentPictureRepository + { + public EquipmentPictureRepository() + { + } + + public EquipmentPictureRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/EquipmentRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/EquipmentRepository.cs new file mode 100644 index 0000000..dcdadd2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/EquipmentRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + /// + public class EquipmentRepository : BaseRepository, IEquipmentRepository + { + public EquipmentRepository() + { + } + + public EquipmentRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ExceptionsLogsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ExceptionsLogsRepository.cs new file mode 100644 index 0000000..6127d25 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/ExceptionsLogsRepository.cs @@ -0,0 +1,26 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// ־ִʵ + /// + public class ExceptionsLogsRepository : BaseRepository, IExceptionsLogsRepository + { + /// + /// + public ExceptionsLogsRepository() + { + } + + /// + /// + /// + public ExceptionsLogsRepository(IDbContextCore dbContext) : base(dbContext) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/FeedbackPicRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/FeedbackPicRepository.cs new file mode 100644 index 0000000..cfd931e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/FeedbackPicRepository.cs @@ -0,0 +1,22 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + public class FeedbackPicRepository : BaseRepository, IFeedbackPicRepository + { + /// + /// + public FeedbackPicRepository() + { + } + + public FeedbackPicRepository(IDbContextCore dbContext) : base(dbContext) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/FeedbackRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/FeedbackRepository.cs new file mode 100644 index 0000000..1dd7035 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/FeedbackRepository.cs @@ -0,0 +1,22 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + public class FeedbackRepository : BaseRepository, IFeedbackRepository + { + /// + /// + public FeedbackRepository() + { + } + + public FeedbackRepository(IDbContextCore dbContext) : base(dbContext) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/IndustryJobsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/IndustryJobsRepository.cs new file mode 100644 index 0000000..9fecb6b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/IndustryJobsRepository.cs @@ -0,0 +1,18 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class IndustryJobsRepository : BaseRepository, IIndustryJobsRepository + { + public IndustryJobsRepository() + { + } + + public IndustryJobsRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/LoginLogsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/LoginLogsRepository.cs new file mode 100644 index 0000000..0815caa --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/LoginLogsRepository.cs @@ -0,0 +1,57 @@ +using Dapper; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// ־ִʵ + /// + public class LoginLogsRepository : BaseRepository, ILoginLogsRepository + { + /// + /// + public LoginLogsRepository() + { + } + + /// + /// + /// + public LoginLogsRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ȡյ¼ + /// + /// + public Task GetActiveUserTotal() + { + string sql = + @"SELECT COUNT(DISTINCT CreatedUserId) FROM login_logs WHERE PlatformType=1 and date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d');"; + return DapperConn.ExecuteScalarAsync(sql); + } + + /// + /// ȡû¼Ϣ + /// + /// + public async Task> GetLastLoginLogAsync() + { + string sql = @"SELECT MAX(max.LoginTime) LoginTime,max.CreatedUserId CreatedUserId + FROM + ( + SELECT * FROM login_logs WHERE PlatformType=1 + + ) max + GROUP BY CreatedUserId"; + return (await DapperConn.QueryAsync(sql)).ToList(); ; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MenuRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MenuRepository.cs new file mode 100644 index 0000000..1c6c5eb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MenuRepository.cs @@ -0,0 +1,66 @@ +using Dapper; +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class MenuRepository : BaseRepository, IMenuRepository + { + public MenuRepository() + { + } + + public MenuRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ݽɫIDַŷֿ)ϵͳIDȡӦIJб + /// + /// ɫID + /// ϵͳID + /// ǷDz˵ + /// + public IEnumerable GetFunctions(string roleIds, string typeID, bool isMenu = false) + { + string sql = + "SELECT DISTINCT b.* FROM sys_menu as b INNER JOIN Sys_RoleAuthorize as a On b.Id = a.ItemId WHERE ObjectId IN (" + + roleIds + ")"; + if (roleIds == "") + { + sql = "SELECT DISTINCT b.* FROM sys_menu as b where 1=1 "; + } + + if (isMenu) + { + sql = sql + "and menutype in('M','C')"; + } + + if (!string.IsNullOrEmpty(typeID)) + { + sql = sql + string.Format(" AND SystemTypeId='{0}' ", typeID); + } + + return DapperConnRead.Query(sql); + } + + /// + /// ϵͳIDȡӦIJб + /// + /// ϵͳID + /// + public IEnumerable GetFunctions(string typeID) + { + string sql = "SELECT DISTINCT b.* FROM sys_menu as b "; + if (!string.IsNullOrEmpty(typeID)) + { + sql = sql + string.Format(" Where SystemTypeId='{0}' ", typeID); + } + + return DapperConnRead.Query(sql); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MessageLogsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MessageLogsRepository.cs new file mode 100644 index 0000000..f814ea9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MessageLogsRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// Ӧ�òִ�ʵ�� + /// + public class MessageLogsRepository : BaseRepository, IMessageLogsRepository + { + public MessageLogsRepository() + { + } + + public MessageLogsRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MessageRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MessageRepository.cs new file mode 100644 index 0000000..b7928fa --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/MessageRepository.cs @@ -0,0 +1,40 @@ +using Dapper; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// Ӧòִʵ + /// + public class MessageRepository : BaseRepository, IMessageRepository + { + public MessageRepository() + { + } + + public MessageRepository(IDbContextCore context) : base(context) + { + } + + ///// + ///// Ϣ + ///// + ///// + //public async Task InsertAsync(MessageEntity entity) + //{ + // string sql = string.Format( + // @"INSERT INTO `message`(`CreatedUserId`, `CreatedTime`, `IsDeleted`, `SendId`, `Type`, `GroupId`, + // `Content`, `SendTime`, `ProductId`, `Title`, `MessageTitle`, `ProductType`) VALUES + // ({0}, now(), 0, {1},{2},{3}, '{4}', now(), {5}, '{6}','{7}', {8}); SELECT LAST_INSERT_ID();", + // entity.SendId, entity.SendId, entity.Type, entity.GroupId, entity.Content, entity.ProductId, + // entity.Title, entity.MessageTitle, entity.ProductType); + // //var input= await DapperConn.QueryFirstOrDefaultAsync(sql); + // long input = await DapperConn.ExecuteScalarAsync(sql, entity); + // return input; + //} + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OperationLogsRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OperationLogsRepository.cs new file mode 100644 index 0000000..9b81b98 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OperationLogsRepository.cs @@ -0,0 +1,26 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// ־ִʵ + /// + public class OperationLogsRepository : BaseRepository, IOperationLogsRepository + { + /// + /// + public OperationLogsRepository() + { + } + + /// + /// + /// + public OperationLogsRepository(IDbContextCore dbContext) : base(dbContext) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrderDetailRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrderDetailRepository.cs new file mode 100644 index 0000000..5070640 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrderDetailRepository.cs @@ -0,0 +1,22 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + public class OrderDetailRepository : BaseRepository, IOrderDetailRepository + { + /// + /// + public OrderDetailRepository() + { + } + + public OrderDetailRepository(IDbContextCore dbContext) : base(dbContext) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrderRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrderRepository.cs new file mode 100644 index 0000000..c855fd4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrderRepository.cs @@ -0,0 +1,22 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + public class OrderRepository : BaseRepository, IOrderRepository + { + /// + /// + public OrderRepository() + { + } + + public OrderRepository(IDbContextCore dbContext) : base(dbContext) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrganizeRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrganizeRepository.cs new file mode 100644 index 0000000..6559a8c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/OrganizeRepository.cs @@ -0,0 +1,43 @@ +using Dapper; +using System.Text; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class OrganizeRepository : BaseRepository, IOrganizeRepository + { + public OrganizeRepository() + { + } + + public OrganizeRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ȡڵ֯ + /// + /// ֯Id + /// + public OrganizeEntity GetRootOrganize(long id) + { + StringBuilder sb = new StringBuilder(";WITH "); + if (dbConnectionOptions.DatabaseType == DatabaseType.MySql) + { + sb.Append(" Recursive "); + } + + sb.Append(" T AS ("); + sb.Append(" SELECT Id, ParentId, FullName, Layers FROM sys_organize"); + sb.AppendFormat(" WHERE Id = '{0}'", id); + sb.Append(" UNION ALL "); + sb.Append( + " SELECT A.Id, A.ParentId, A.FullName, A.Layers FROM sys_organize AS A JOIN T AS B ON A.Id = B.ParentId ) SELECT* FROM T ORDER BY Layers"); + return DapperConn.QueryFirstOrDefault(sb.ToString()); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/PaymentRecordRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/PaymentRecordRepository.cs new file mode 100644 index 0000000..93fe5f2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/PaymentRecordRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// 充值仓储 + /// + public class PaymentRecordRepository : BaseRepository, IPaymentRecordRepository + { + public PaymentRecordRepository() + { + } + + public PaymentRecordRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RechargeIntroRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RechargeIntroRepository.cs new file mode 100644 index 0000000..28923d2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RechargeIntroRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// ֵ + /// + public class RechargeIntroRepository : BaseRepository, IRechargeIntroRepository + { + public RechargeIntroRepository() + { + } + + public RechargeIntroRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RechargeRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RechargeRepository.cs new file mode 100644 index 0000000..25a542c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RechargeRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// ֵ + /// + public class RechargeRepository : BaseRepository, IRechargeRepository + { + public RechargeRepository() + { + } + + public RechargeRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RecruitmentRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RecruitmentRepository.cs new file mode 100644 index 0000000..0955909 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RecruitmentRepository.cs @@ -0,0 +1,34 @@ +using Dapper; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// Ӧ�òִ�ʵ�� + /// + public class CloudcarRepository : BaseRepository, ICloudcarRepository + { + public CloudcarRepository() + { + } + + public CloudcarRepository(IDbContextCore context) : base(context) + { + } + + /// + /// 根据UserId修改招聘信息是否实名认证 + /// + /// + /// + public async Task UpdateIsRealAuthenticationAsync(long userId) + { + string sql = @"UPDATE Cloudcar SET IsRealAuthentication=TRUE WHERE UserId=@UserId"; + return await DapperConn.ExecuteAsync(sql, new { UserId = userId }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RegionRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RegionRepository.cs new file mode 100644 index 0000000..2ed8146 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RegionRepository.cs @@ -0,0 +1,68 @@ +using Dapper; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class RegionRepository : BaseRepository, IRegionRepository + { + public RegionRepository() + { + } + + public RegionRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// areaIdѯ + /// + /// + /// + public async Task GetRegionNameByAreaId(long areaId, long cityId, long provinceId) + { + string sql = ""; + if (areaId != 0) + { + sql = string.Format( + @"select group_concat(`r3`.`Name`,' ',`r2`.`Name`, ' ',`r1`.`Name` separator ',') AS `GROUP_CONCAT(r1.``Name``,' ',r2.``Name``, ' ', r1.``Name`` )` + from Znyc.`sys_region` `r1` + left join Znyc.`sys_region` `r2` on((`r2`.`RegionId` = `r1`.`ParentId`)) + left join Znyc.`sys_region` `r3` on((`r3`.`RegionId` = `r2`.`ParentId`)) + where (`r1`.`RegionId` in ({0}))", areaId); + return await DapperConn.QueryFirstOrDefaultAsync(sql); + } + + if (cityId != 0) + { + sql = string.Format( + @"select group_concat( `r2`.`Name`, ' ',`r1`.`Name` separator ',') AS `GROUP_CONCAT(r2.``Name``,' ',r1.``Name``, ' ' )` + from Znyc.`sys_region` `r1` + left join Znyc.`sys_region` `r2` on((`r2`.`RegionId` = `r1`.`ParentId`)) + where (`r1`.`RegionId` in ({0}))", cityId); + return await DapperConn.QueryFirstOrDefaultAsync(sql); + } + + sql = string.Format(@"SELECT `Name` FROM Znyc.sys_region WHERE Id={0}", provinceId); + return await DapperConn.QueryFirstOrDefaultAsync(sql); + } + + /// + /// cityIdѯ + /// + /// + /// + public async Task GetRegionNameByCityId(string cityId) + { + string sql = string.Format( + @"select group_concat( `r2`.`Name`, ' ',`r1`.`Name` separator ',') AS `GROUP_CONCAT(r2.``Name``,' ',r1.``Name``, ' ' )` + from Znyc.`sys_region` `r1` + left join Znyc.`sys_region` `r2` on((`r2`.`RegionId` = `r1`.`ParentId`)) + where (`r1`.`RegionId` in ({0}))", cityId); + return await DapperConn.QueryFirstOrDefaultAsync(sql); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleAuthorizeRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleAuthorizeRepository.cs new file mode 100644 index 0000000..239f712 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleAuthorizeRepository.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class RoleAuthorizeRepository : BaseRepository, IRoleAuthorizeRepository + { + public RoleAuthorizeRepository() + { + } + + public RoleAuthorizeRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ɫȨ + /// + /// ɫId + /// ɫģ + /// ɫɷ + /// + /// ִгɹtrueΪfalse + public async Task SaveRoleAuthorize(long roleId, List roleAuthorizesList, + List roleDataList, + IDbTransaction trans = null) + { + List> param = new List>(); + Tuple tupel; + tupel = new Tuple(@"delete from Sys_RoleAuthorize where ObjectId=@RoleId;", + new { RoleId = roleId }); + param.Add(tupel); + tupel = new Tuple(@"delete from Sys_RoleData where RoleId=@RoleId;", new { RoleId = roleId }); + param.Add(tupel); + foreach (RoleAuthorizeEntity item in roleAuthorizesList) + { + tupel = new Tuple(@" INSERT INTO Sys_RoleAuthorize + (Id + ,ItemType + ,ItemId + ,ObjectType + ,ObjectId + ,SortCode + ,CreatedTime + ,CreatedUserId) + VALUES(@Id + ,@ItemType + ,@ItemId + ,@ObjectType + ,@ObjectId + ,@SortCode + ,@CreatedTime + ,@CreatedUserId) ", new + { + item.Id, + item.ItemType, + item.ItemId, + item.ObjectType, + item.ObjectId, + item.SortCode, + item.CreatedTime, + item.CreatedUserId + }); + param.Add(tupel); + } + + foreach (RoleDataEntity roleData in roleDataList) + { + tupel = new Tuple(@" INSERT INTO Sys_RoleData + (Id + ,RoleId + ,AuthorizeData + ,DType) + VALUES + (@Id + ,@RoleId + ,@AuthorizeData + ,@DType) ", new + { + roleData.Id, + roleData.RoleId, + roleData.AuthorizeData, + roleData.DType + }); + param.Add(tupel); + } + + Tuple result = await ExecuteTransactionAsync(param); + return result.Item1; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleDataRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleDataRepository.cs new file mode 100644 index 0000000..85b1668 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleDataRepository.cs @@ -0,0 +1,50 @@ +using Dapper; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class RoleDataRepository : BaseRepository, IRoleDataRepository + { + public RoleDataRepository() + { + } + + public RoleDataRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ݽɫȨʲ + /// + /// + /// + public List GetListDeptByRole(string roleIds) + { + string roleIDsStr = string.Format("'{0}'", roleIds.Replace(",", "','")); + string where = " RoleId in(" + roleIDsStr + ") and DType='dept'"; + string sql = $"select AuthorizeData from `{tableName}` "; + if (!string.IsNullOrWhiteSpace(where)) + { + sql += " where " + @where; + } + + using (IDbConnection connection = DapperConn) + { + bool isClosed = connection.State == ConnectionState.Closed; + if (isClosed) + { + connection.Open(); + } + + IEnumerable resultList = connection.Query(sql); + return resultList.ToList(); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleRepository.cs new file mode 100644 index 0000000..487cc59 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/RoleRepository.cs @@ -0,0 +1,18 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class RoleRepository : BaseRepository, IRoleRepository + { + public RoleRepository() + { + } + + public RoleRepository(IDbContextCore dbContext) : base(dbContext) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/StatisticalRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/StatisticalRepository.cs new file mode 100644 index 0000000..aa8ca15 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/StatisticalRepository.cs @@ -0,0 +1,34 @@ +using Dapper; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + public class StatisticalRepository : BaseRepository, IStatisticalRepository + { + /// + /// + public StatisticalRepository() + { + } + + public StatisticalRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ȡǰһͳ + /// + /// + public async Task GetStatisticalAsync() + { + string sql = @"SELECT * FROM sys_statistical ORDER BY CreatedTime DESC"; + return await DapperConn.QueryFirstOrDefaultAsync(sql); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/SystemTypeRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/SystemTypeRepository.cs new file mode 100644 index 0000000..702b2b4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/SystemTypeRepository.cs @@ -0,0 +1,33 @@ +using Dapper; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// 系统类型,也是子系统 + /// + public class SystemTypeRepository : BaseRepository, ISystemTypeRepository + { + public SystemTypeRepository() + { + } + + public SystemTypeRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// 根据系统编码查询系统对象 + /// + /// 系统编码 + /// + public SystemTypeEntity GetByCode(string appkey) + { + string sql = @"SELECT * FROM " + tableName + " t WHERE t.EnCode = @EnCode"; + return DapperConn.QueryFirstOrDefault(sql, new { EnCode = appkey }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/UploadFileRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/UploadFileRepository.cs new file mode 100644 index 0000000..1db1297 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/UploadFileRepository.cs @@ -0,0 +1,53 @@ +using Dapper; +using System; +using System.Data; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + public class UploadFileRepository : BaseRepository, IUploadFileRepository + { + public UploadFileRepository() + { + } + + public UploadFileRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// 根据应用Id和应用标识批量更新数据 + /// + /// 更新后的应用Id + /// 更新前旧的应用Id + /// 应用标识 + /// + /// + public bool UpdateByBeLongAppId(string beLongAppId, string oldBeLongAppId, string belongApp = null, + IDbTransaction trans = null) + { + try + { + trans = DapperConn.BeginTransaction(); + string sqlStr = string.Format("update {0} set beLongAppId='{1}' where beLongAppId='{2}'", tableName, + beLongAppId, oldBeLongAppId); + if (!string.IsNullOrEmpty(belongApp)) + { + sqlStr = string.Format(" and BelongApp='{0}'", belongApp); + } + + long num = DapperConn.Execute(sqlStr, null, trans); + trans.Commit(); + return num >= 0; + } + catch (Exception) + { + trans.Rollback(); + throw; + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/UserRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/UserRepository.cs new file mode 100644 index 0000000..39d893d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/UserRepository.cs @@ -0,0 +1,87 @@ +using Dapper; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + public class UserRepository : BaseRepository, IUserRepository + { + /// + /// + public UserRepository() + { + } + + public UserRepository(IDbContextCore dbContext) : base(dbContext) + { + } + + /// + /// ûUnionIdѯûϢ + /// + /// + /// + public async Task GetUserByUnionId(string unionId) + { + string sql = @"SELECT * FROM `user` t WHERE t.UnionId = @UnionId"; + return await DapperConn.QueryFirstOrDefaultAsync(sql, new { UnionId = unionId }); + } + + public async Task> FindUserWithPagerAsync(SearchUserModel search, PagerInfo info) + { + bool order = search.Order == "asc" ? false : true; + string strwhere = ""; + if (search.CertificationState >= 0 && search.CertificationState != (int)UserCertificationEnum.None) + { + strwhere = $" AND user_certification.`State`={search.CertificationState}"; + } + if (search.CertificationState == (int)UserCertificationEnum.None) + { + strwhere = $" AND `user`.`IsRealAuthentication`=0"; + } + if (!string.IsNullOrEmpty(search.Keywords)) + { + strwhere += string.Format(" and (`user`.UserName like '%{0}%'or `user`.Phone like '%{0}%')", search.Keywords); + } + + if (search.State > 0) + { + strwhere += string.Format(" and `user`.State={0}", search.State); + } + + if (!string.IsNullOrEmpty(search.StartTime)) + { + strwhere += " and `user`.CreatedTime >='" + search.StartTime + " 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + strwhere += " and `user`.CreatedTime <='" + search.EndTime + " 23:59:59'"; + } + + string countSQL = $"select count(`user`.Id) as Total from `user` " + + $"LEFT JOIN user_certification ON `user`.Id = user_certification.UserId " + + $"Where `user`.IsDeleted = 0 {strwhere};"; + int minRow = search.PageSize * (search.CurrenetPageIndex - 1); + string sql = $"select * from `user` where Id IN(select t.Id from (select `user`.Id from `user` " + + $"LEFT JOIN user_certification ON `user`.Id = user_certification.UserId " + + $"Where `user`.IsDeleted = 0 {strwhere} )as t) " + + $"order by `user`.{search.Sort} {search.Order} limit {minRow},{search.PageSize}; "; + + + SqlMapper.GridReader reader = await DapperConnRead.QueryMultipleAsync(countSQL + sql); + info.RecordCount = reader.ReadFirst(); + List list = reader.Read().AsList(); + return list; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/WxUnifyUserRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/WxUnifyUserRepository.cs new file mode 100644 index 0000000..0bca45b --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/WxUnifyUserRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + /// + public class WxUnifyUserRepository : BaseRepository, IWxUnifyUserRepository + { + public WxUnifyUserRepository() + { + } + + public WxUnifyUserRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/WxUserRelationRepository.cs b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/WxUserRelationRepository.cs new file mode 100644 index 0000000..19d595d --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Repositories/Recruitment/WxUserRelationRepository.cs @@ -0,0 +1,21 @@ +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Repositories; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; + +namespace Znyc.Cloudcar.Admin.Security.Repositories +{ + /// + /// + /// + public class WxUserRelationRepository : BaseRepository, IWxUserRelationRepository + { + public WxUserRelationRepository() + { + } + + public WxUserRelationRepository(IDbContextCore context) : base(context) + { + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/APPService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/APPService.cs new file mode 100644 index 0000000..c352c8e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/APPService.cs @@ -0,0 +1,162 @@ +using COSSTS; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Core.App; +using Znyc.Cloudcar.Admin.Commons.Cos; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Dtos.Document; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class APPService : BaseService, IAPPService + { + private readonly IAPPRepository _appRepository; + private static CosOptions _cosOptions; + + public APPService(IAPPRepository repository) : base(repository) + { + _appRepository = repository; + _cosOptions = App.GetService(); + if (_cosOptions == null) + { + throw new ArgumentNullException(nameof(_cosOptions)); + } + } + + /// + /// ͬʵ塣 + /// + /// ʵ + /// + /// + public override long Insert(APPEntity entity, IDbTransaction trans = null) + { + long result = repository.Insert(entity, trans); + UpdateCacheAllowApp(); + return result; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// ID + /// + /// + public override async Task UpdateAsync(APPEntity entity, long id, IDbTransaction trans = null) + { + bool result = await repository.UpdateAsync(entity, id, trans); + UpdateCacheAllowApp(); + return result; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// + /// + public override async Task InsertAsync(APPEntity entity, IDbTransaction trans = null) + { + int result = await repository.InsertAsync(entity, trans); + UpdateCacheAllowApp(); + return result; + } + + /// + /// ȡapp + /// + /// ӦID + /// ӦԿAppSecret + /// + public APPEntity GetAPP(string appid, string secret) + { + return _appRepository.GetAPP(appid, secret); + } + + /// + /// ȡapp + /// + /// ӦID + /// + public APPEntity GetAPP(string appid) + { + return _appRepository.GetAPP(appid); + } + + public IList SelectApp() + { + return _appRepository.SelectApp(); + } + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + public override async Task> FindWithPagerAsync(SearchInputDto search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += string.Format(" and (AppId like '%{0}%' or RequestUrl like '%{0}%')", search.Keywords); + }; + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + public void UpdateCacheAllowApp() + { + CacheHelper cacheHelper = new CacheHelper(); + IEnumerable appList = repository.GetAllByIsNotDeleteAndEnabledMark(); + cacheHelper.Add("AllowAppId", appList); + } + + public CommonResult GetCosToken() + { + CommonResult result = new CommonResult(); + Dictionary values = new() + { + ["bucket"] = _cosOptions.Bucket, + ["region"] = _cosOptions.Region, + ["allowPrefix"] = _cosOptions.AllowPrefix, + ["allowActions"] = _cosOptions.AllowActions, + ["durationSeconds"] = _cosOptions.DurationSeconds, + ["secretId"] = _cosOptions.SecretId, + ["secretKey"] = _cosOptions.SecretKey + }; + Dictionary credential = STSClient.genCredential(values); + result.ResData = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(credential)); + result.ErrCode = "0"; + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ActivityService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ActivityService.cs new file mode 100644 index 0000000..0f60c02 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ActivityService.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + /// + public class ActivityService : BaseService, IActivityService + { + private readonly IActivityRepository _activityRepository; + private readonly IDictionaryService _dictionaryService; + + public ActivityService( + IActivityRepository repository, + IDictionaryService dictionaryService + ) : base(repository) + { + _activityRepository = repository; + _dictionaryService = dictionaryService; + } + + /// + /// 异步新增数据 + /// + /// ʵ�� + /// + public async Task InsertAsync(ActivityEntity input) + { + CommonResult result = new CommonResult(); + if (input.StartTime >= input.EndTime) + { + result.Success = false; + result.ErrMsg = ReturnConst.Time_Error; + return result; + } + if (input.EndTime < DateTime.Now) + { + result.Success = false; + result.ErrMsg = ReturnConst.EndTime_Error; + return result; + } + var list = (await repository.GetListWhereAsync($" ActivityId={input.ActivityId} and State!=2")).MapTo(); + if (list.Count() > 0) + { + foreach (var item in list) + { + if (input.StartTime < item.EndTime && input.EndTime > item.StartTime) + { + result.Success = false; + result.ErrMsg = ReturnConst.Time_Overlap; + return result; + } + } + } + input.ActivityId = input.ActivityId; + input.Icon = input.Icon.Substring(input.Icon.LastIndexOf("/") + 1); + input.StartTime = input.StartTime; + input.EndTime = input.EndTime; + input.PicUrl = input.PicUrl.Substring(input.PicUrl.LastIndexOf("/") + 1); + input.DetailPicUrl = input.DetailPicUrl.Substring(input.DetailPicUrl.LastIndexOf("/") + 1); + if (input.StartTime > DateTime.Now) + { + input.State = (int)ActivityStatusEnum.NotStart; + }else if(input.StartTime < DateTime.Now && input.EndTime > DateTime.Now) + { + input.State = (int)ActivityStatusEnum.Ongoing; + } + input.PageUrl = ""; + input.PicDesc = ""; + input.PicPageUrl = ""; + input.TextDesc = input.TextDesc; + result.Success = await repository.InsertAsync(input) > 0 ? true : false; + return result; + } + + /// + /// 分页查询 + /// + /// + /// + public async Task> FindWithPagerSearchAsync(SearchActivityModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (search.State >= 0) + { + @where += $" and State={search.State}"; + } + + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and StartTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" or EndTime <='{search.EndTime} 23:59:59'"; + } + + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += $" and TextDesc like %{search.Keywords}%"; + } + + //if (search.Filter.ActivityId > 0) + //{ + // @where += $" and ActivityId = {search.Filter.ActivityId}"; + //} + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = (await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order)).MapTo(); + List dictionaryList = await _dictionaryService.GetListByPidAsync(3); + foreach (ActivityOutputDto item in list) + { + item.Name = dictionaryList.Find(x => x.Id == item.ActivityId).Value; + item.Icon = CommonConst.Default_Activity_Prefix + item.Icon; + item.PicUrl = CommonConst.Default_Activity_Prefix + item.PicUrl; + item.DetailPicUrl = CommonConst.Default_Activity_Prefix + item.DetailPicUrl; + } + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 异步更新数据 + /// + /// + /// + public async Task UpdateAsync(ActivityEntity input) + { + CommonResult result = new CommonResult(); + if (input.StartTime >= input.EndTime) + { + result.Success = false; + result.ErrMsg = ReturnConst.Time_Error; + return result; + } + var list = (await repository.GetListWhereAsync($" ActivityId={input.ActivityId} and State!=2 and Id!={input.Id}")).MapTo(); + if (list.Count() > 0) + { + foreach (var item in list) + { + if (input.StartTime < item.EndTime && input.EndTime > item.StartTime) + { + result.Success = false; + result.ErrMsg = ReturnConst.Time_Overlap; + return result; + } + } + } + ActivityEntity info =await repository.GetAsync(input.Id); + if (!(info?.Id > 0)) + { + result.Success = false; + result.ErrMsg = ReturnConst.Not_Exist; + return result; + } + info.Icon = input.Icon.Substring(input.Icon.LastIndexOf("/") + 1); + info.ActivityId = input.ActivityId; + info.TextDesc = input.TextDesc; + info.StartTime = input.StartTime; + info.EndTime = input.EndTime; + info.PicUrl = input.PicUrl.Substring(input.PicUrl.LastIndexOf("/") + 1); + info.DetailPicUrl = input.DetailPicUrl.Substring(input.DetailPicUrl.LastIndexOf("/") + 1); + if (input.StartTime > DateTime.Now) + { + info.State = (int)ActivityStatusEnum.NotStart; + } + if (input.EndTime < DateTime.Now) + { + info.State = (int)ActivityStatusEnum.End; + } + if (input.StartTime < DateTime.Now && input.EndTime > DateTime.Now) + { + info.State = (int)ActivityStatusEnum.Ongoing; + } + info.ModifiedTime=input.ModifiedTime; + info.ModifiedUserId = input.ModifiedUserId; + await repository.UpdateAsync(info, input.Id).ConfigureAwait(false); + result.Success = true; + + return result; + } + + /// + /// 修改活动状态 + /// + /// + public async Task UpdateStatusAsync() + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + List list = (await repository.GetListWhereAsync(" IsDeleted=0 and State!=2")).MapTo(); + foreach (var item in list) + { + if (item.EndTime <= DateTime.Now) + { + item.State = (int)ActivityStatusEnum.End; + } + if (item.StartTime < DateTime.Now && item.EndTime > DateTime.Now) + { + item.State = (int)ActivityStatusEnum.Ongoing; + } + await repository.UpdateAsync(item, item.Id).ConfigureAwait(false); + } + cacheHelper.Remove("activity:list"); + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AdminUserLogOnService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AdminUserLogOnService.cs new file mode 100644 index 0000000..2ac8792 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AdminUserLogOnService.cs @@ -0,0 +1,44 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class AdminUserLogOnService : BaseService, + IAdminUserLogOnService + { + private readonly IAdminUserLogOnRepository _userLogOnRepository; + + public AdminUserLogOnService(IAdminUserLogOnRepository repository) : base(repository) + { + _userLogOnRepository = repository; + } + + /// + /// ݻԱIDȡû¼Ϣʵ + /// + /// + /// + public AdminUserLogOnEntity GetByUserId(long userId) + { + return _userLogOnRepository.GetByUserId(userId); + } + + /// + /// ݻԱIDȡû¼Ϣʵ + /// + /// Ϣ + /// ûId + /// + public async Task SaveUserTheme(UserThemeInputDto info, long userId) + { + string themeJsonStr = info.ToJson(); + string where = $"UserId='{userId}'"; + return await _userLogOnRepository.UpdateTableFieldAsync("Theme", themeJsonStr, where); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AdminUserService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AdminUserService.cs new file mode 100644 index 0000000..6169fca --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AdminUserService.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Encrypt; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class AdminUserService : BaseService, IAdminUserService + { + private readonly IAdminUserLogOnRepository _adminUserLogOnRepository; + private readonly IAdminUserRepository _adminUserRepository; + private readonly IOrganizeService _organizeService; + private readonly IRoleService _roleService; + + /// + /// + /// + /// + /// + /// + /// + public AdminUserService(IAdminUserRepository repository, IAdminUserLogOnRepository adminUserLogOnRepository, + IRoleService roleService, IOrganizeService organizeService) : base(repository) + { + _adminUserRepository = repository; + _roleService = roleService; + _organizeService = organizeService; + _adminUserLogOnRepository = adminUserLogOnRepository; + } + + /// + /// û½֤ + /// + /// û + /// 루һmd5ܺ + /// ֤ɹûʵ壬֤ʧܷnull|ʾϢ + public async Task> Validate(string userName, string password) + { + AdminUserEntity userEntity = await _adminUserRepository.GetUserByLogin(userName); + + if (userEntity == null) + { + return new Tuple(null, ReturnConst.User_Not_Exist); + } + + if (userEntity.State == -1) + { + return new Tuple(null, ReturnConst.User_Disable); + } + + AdminUserLogOnEntity userSinginEntity = _adminUserLogOnRepository.GetByUserId(userEntity.Id); + string inputPassword = MD5Util + .GetMD5_32(DEncrypt.Encrypt(MD5Util.GetMD5_32(password).ToLower(), userSinginEntity.UserSecretkey) + .ToLower()).ToLower(); + + if (inputPassword != userSinginEntity.UserPassword) + { + return new Tuple(null, ReturnConst.Password_Error); + } + else + { + AdminUserLogOnEntity userLogOn = _adminUserLogOnRepository.GetWhere("UserId=" + userEntity.Id); + userLogOn.LogOnCount++; + userLogOn.LastVisitTime = DateTime.Now; + userLogOn.UserOnLine = true; + await _adminUserLogOnRepository.UpdateAsync(userLogOn, userLogOn.Id); + return new Tuple(userEntity, ""); + } + } + + /// + /// û½֤ + /// + /// û + /// 루һmd5ܺ + /// û + /// ֤ɹûʵ壬֤ʧܷnull|ʾϢ + public async Task> Validate(string userName, string password, UserType userType) + { + AdminUserEntity userEntity = await _adminUserRepository.GetUserByLogin(userName); + + if (userEntity == null) + { + return new Tuple(null, ReturnConst.User_Not_Exist); + } + + if (userEntity.State == -1) + { + return new Tuple(null, ReturnConst.User_Disable); + } + + AdminUserLogOnEntity userSinginEntity = _adminUserLogOnRepository.GetByUserId(userEntity.Id); + + string inputPassword = MD5Util + .GetMD5_32(DEncrypt.Encrypt(MD5Util.GetMD5_32(password).ToLower(), userSinginEntity.UserSecretkey) + .ToLower()).ToLower(); + + if (inputPassword != userSinginEntity.UserPassword) + { + return new Tuple(null, ReturnConst.Password_Error); + } + + AdminUserLogOnEntity userLogOn = _adminUserLogOnRepository.GetWhere("UserId='" + userEntity.Id + "'"); + userLogOn.LogOnCount++; + userLogOn.LastVisitTime = DateTime.Now; + userLogOn.UserOnLine = true; + await _adminUserLogOnRepository.UpdateAsync(userLogOn, userLogOn.Id); + return new Tuple(userEntity, ""); + + } + + /// + /// û˺ŲѯûϢ + /// + /// + /// + public async Task GetByUserName(string userName) + { + return await _adminUserRepository.GetByUserName(userName); + } + + /// + /// ûֻѯûϢ + /// + /// ֻ + /// + public async Task GetUserByMobilePhone(string mobilephone) + { + return await _adminUserRepository.GetUserByMobilePhone(mobilephone); + } + + /// + /// AccountֻŲѯûϢ + /// + /// ¼˺ + /// + public async Task GetUserByLogin(string account) + { + return await _adminUserRepository.GetUserByLogin(account); + } + + /// + /// ݵOpenIdѯûϢ + /// + /// + /// OpenIdֵ + /// + public AdminUserEntity GetUserByOpenId(string openIdType, string openId) + { + return _adminUserRepository.GetUserByOpenId(openIdType, openId); + } + + /// + /// userIdѯûϢ + /// + /// + /// userId + /// + public UserOpenIdsEntity GetUserOpenIdByuserId(string openIdType, long userId) + { + return _adminUserRepository.GetUserOpenIdByuserId(openIdType, userId); + } + + /// + /// ûϢ,ƽ̨ + /// + /// + /// + /// + /// + public bool UpdateUserByOpenId(AdminUserEntity entity, AdminUserLogOnEntity userLogOnEntity, + UserOpenIdsEntity userOpenIds, + IDbTransaction trans = null) + { + return _adminUserRepository.UpdateUserByOpenId(entity, userLogOnEntity, userOpenIds, trans); + } + + /// + /// ΢UnionIdѯûϢ + /// + /// UnionIdֵ + /// + public AdminUserEntity GetUserByUnionId(string unionId) + { + return _adminUserRepository.GetUserByUnionId(unionId); + } + + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + public async Task> FindWithPagerSearchAsync(SearchUserModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + + if (!string.IsNullOrEmpty(search.Keywords)) + { + where += string.Format( + " and (UserName like '%{0}%' or Account like '%{0}%' or MobilePhone like '%{0}%')", + search.Keywords); + } + + if (!string.IsNullOrEmpty(search.RoleId)) + { + @where += string.Format(" and RoleId = {0}", search.RoleId); + } + + if (!string.IsNullOrEmpty(search.StartTime)) + { + where += " and CreatedTime >='" + search.StartTime + " 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + where += " and CreatedTime <='" + search.EndTime + " 23:59:59'"; + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + List resultList = list.MapTo(); + List listResult = new List(); + foreach (AdminUserOutputDto item in resultList) + { + if (!string.IsNullOrEmpty(item.OrganizeId.ToString())) + { + item.OrganizeName = _organizeService.Get(item.OrganizeId)?.FullName; + } + + if (!string.IsNullOrEmpty(item.RoleId)) + { + item.RoleName = _roleService.GetRoleNameStr(item.RoleId); + } + + if (!string.IsNullOrEmpty(item.DepartmentId.ToString())) + { + item.DepartmentName = _organizeService.Get(item.DepartmentId).FullName; + } + //if (!string.IsNullOrEmpty(item.DutyId)) + //{ + // item.DutyName = _roleService.Get(item.DutyId).FullName; + //} + listResult.Add(item); + } + + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = listResult, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + public bool CreateUserByWxOpenId(UserInputDto userInPut) + { + throw new NotImplementedException(); + } + + public bool UpdateUserByOpenId(UserInputDto userInPut) + { + throw new NotImplementedException(); + } + + } +} diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ApiService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ApiService.cs new file mode 100644 index 0000000..7091e50 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ApiService.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class ApiService : BaseService, IApiService + { + private readonly IApiRepository _apiRepository; + + /// + /// + /// + public ApiService(IApiRepository repository) : base(repository) + { + _apiRepository = repository; + } + + public async Task GetApiAsync(string apiUrl) + { + string key = string.Format(@"ApiUrl='{0}'", apiUrl); + ApiEntity result = await _apiRepository.GetWhereAsync(key); //x => x.ApiUrl == apiUrl + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ApplyJobService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ApplyJobService.cs new file mode 100644 index 0000000..3f06848 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ApplyJobService.cs @@ -0,0 +1,322 @@ +using System; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// ��ְ���� + /// + public class ApplyJobService : BaseService, IApplyJobService + { + private readonly IApplyJobRepository _applyJobRepository; + private readonly IAuditRepository _auditRepository; + public readonly IDictionaryService _dictionaryService; + private readonly IIndustryJobsService _industryJobsService; + private readonly IRegionRepository _regionRepository; + private readonly IUserRepository _userRepository; + private readonly IWxUnifyUserRepository _wxUnifyUserRepository; + private readonly ICallFeedbackRepository _callFeedbackRepository; + + public ApplyJobService(IApplyJobRepository repository, + IDictionaryService dictionaryService, + IRegionRepository regionRepository, + IIndustryJobsService industryJobsService, + IAuditRepository auditRepository, + IUserRepository userRepository, + ICallFeedbackRepository callFeedbackRepository, + IWxUnifyUserRepository wxUnifyUserRepository + ) : base(repository) + { + _applyJobRepository = repository; + _dictionaryService = dictionaryService; + _regionRepository = regionRepository; + _industryJobsService = industryJobsService; + _auditRepository = auditRepository; + _userRepository = userRepository; + _wxUnifyUserRepository = wxUnifyUserRepository; + _callFeedbackRepository = callFeedbackRepository; + } + + /// + /// ͬ������ʵ�塣 + /// + /// ʵ�� + /// ������� + /// + public override long Insert(ApplyJobEntity entity, IDbTransaction trans = null) + { + long result = repository.Insert(entity, trans); + return result; + } + + /// + /// �첽����ʵ�塣 + /// + /// ʵ�� + /// ����ID + /// ������� + /// + public override async Task UpdateAsync(ApplyJobEntity entity, long id, IDbTransaction trans = null) + { + bool result = await repository.UpdateAsync(entity, id, trans); + return result; + } + + /// + /// 异步新增数据 + /// + /// ʵ�� + /// + public async Task InsertAsync(ApplyJobEntity input) + { + CommonResult result = new CommonResult(); + input.Id = YitIdHelper.NextId(); + input.State = (int)ProductStatusEnum.Review; + input.UserId = 1001; + input.IsPublic = true; + input.SerialNumber = StringHelper.GetSerialNumber(ProductTypeEnum.ApplyJob, input.IndustryId, input.JobId); + input.ModifiedTime = DateTime.Now; + input.RefreshDate = DateTime.Now; + input.AreaId = ""; + input.Address = input.Address.TrimEnd(','); + input.IsRealAuthentication = true; + input.IsTop = false; + if (input.BirthDate != null) + { + input.Age = StringHelper.GetAgeByBirthDate(input.BirthDate); + } + result.Success = await repository.InsertAsync(input) > 0 ? true : false; + return result; + } + + public async Task UpdateAsync(ApplyJobEntity tinfo) + { + CommonResult result = new CommonResult(); + ApplyJobEntity info = await repository.GetAsync(tinfo.Id); + if (!(info?.Id > 0)) + { + result.Success = false; + result.ErrMsg = "求职信息不存在"; + return result; + } + + // info.Title = tinfo.Title; + info.Content = tinfo.Content; + // info.Name = tinfo.Name; + info.Phone = tinfo.Phone; + info.IndustryId = tinfo.IndustryId; + info.JobId = tinfo.JobId; + info.ProvinceId = tinfo.ProvinceId; + info.CityId = tinfo.CityId; + info.State = tinfo.State; + info.IsTop = tinfo.IsTop; + info.IsHaveDriverLicense = tinfo.IsHaveDriverLicense; + info.IsPublic = tinfo.IsPublic; + // info.TopExpireTime = tinfo.TopExpireTime; + info.ExperienceId = tinfo.ExperienceId; + info.ModifiedUserId = tinfo.ModifiedUserId; + info.ModifiedTime = tinfo.ModifiedTime; + info.BirthDate = tinfo.BirthDate; + if (info.BirthDate != null) + { + info.Age = StringHelper.GetAgeByBirthDate(info.BirthDate); + } + info.Gender = tinfo.Gender; + info.Address = tinfo.Address; + await repository.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + result.Success = true; + return result; + } + + /// + /// 求职分页查询 + /// + /// 查询条件 + /// + public async Task> FindWithPagerSearchAsync(SearchCloudcarModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += $" and (Content like '%{search.Keywords}%' or Phone like '%{search.Keywords}%' or SerialNumber like '%{search.Keywords}%' or Address like '%{search.Keywords}%')"; + } + + //if (search.State == (int)ProductStatusEnum.Pass) + //{ + // @where += " and (State=1 or State=2 )"; + //} + + //if (search.State >= 0 && search.State != (int)ProductStatusEnum.Pass) + //{ + // @where += $" and State={search.State}"; + //} + + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and ModifiedTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" and ModifiedTime <='{search.EndTime} 23:59:59'"; + } + + if (search.industryId > 0) + { + @where += $" and IndustryId={search.industryId}"; + } + + if (search.jobId > 0) + { + @where += $" and JobId={search.jobId}"; + } + + System.Collections.Generic.List users = (await _userRepository.GetListWhereAsync(" `State`=10")).MapTo(); + if (!string.IsNullOrEmpty(search.UserName)) + { + System.Collections.Generic.List uIds = users.Where(x => x.UserName.Contains(search.UserName)).Select(x => x.Id).ToList(); + @where += $" and UserId in ({string.Join(",", uIds.ToArray())})"; + } + //行业岗位 + System.Collections.Generic.List industryJobs = await _industryJobsService.GetAllListAsync(); + //工作经验 + System.Collections.Generic.List experiences = await _dictionaryService.GetListByPidAsync(CommonConst.Dictionary_Experience); + //云平台统一用户信息 + System.Collections.Generic.List uninIds = users.Select(x => x.UnionId).ToList(); + System.Collections.Generic.List wxUnifyUsers = (await _wxUnifyUserRepository.GetListWhereAsync($" IsDeleted=0 AND UnionId IN ('{string.Join("','", uninIds.ToArray())}')")) + .MapTo(); + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + System.Collections.Generic.List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + System.Collections.Generic.List listDto = list.MapTo(); + foreach (ApplyJobOutputDto item in listDto) + { + item.ExperienceName = experiences.Find(x => x.Id == item.ExperienceId)?.Value; + item.IndustryName = industryJobs.Find(x => x.Id == item.IndustryId)?.Name; + item.JobName = industryJobs.Find(x => x.Id == item.JobId)?.Name; + item.DriverLicense = ""; + if (item.IsHaveDriverLicense != null) + { + item.DriverLicense = item.IsHaveDriverLicense == true ? "有驾驶证" : "无驾驶证"; + } + item.Top = item.IsTop ? "已置顶" : "未置顶"; + item.TopExpireDate = item.IsTop ? item.TopExpireDate : null; + item.Public = item.IsPublic ? "已公开" : "未公开"; + item.StatusName = EnumExtensions + .ParseEnum(typeof(ProductStatusEnum), item.State.ToString()).ToDescription(); + UserOutputDto user = users.Find(x => x.Id == item.UserId); + item.UserName = user?.UserName ?? CommonConst.Default_UserName; + item.AvatarUrl = CommonConst.Default_Image_Prefix + (user?.AvatarUrl ?? CommonConst.Default_AvataUrl); + if (item.State == (int)ProductStatusEnum.Fail) + { + string key = $" ProductId={ item.Id} AND ProductType=1 AND HandleStatus={item.State} ORDER BY CreatedTime DESC LIMIT 1"; + item.Note = (await _auditRepository.GetWhereAsync(key))?.Note ?? ""; + } + item.NickName = wxUnifyUsers.Find(x => x.UnionId == user.UnionId)?.NickName ?? CommonConst.Default_UserName; + item.WxAvatarUrl = wxUnifyUsers.Find(x => x.UnionId == user.UnionId)?.AvatarUrl ?? (CommonConst.Default_Image_Prefix + CommonConst.Default_AvataUrl); + //通话评价 + item.CallFeedbacks = (await _callFeedbackRepository.GetListWhereAsync($" ProductId={item.Id} AND ProductType=1")).MapTo(); + foreach (var callFeedback in item.CallFeedbacks) + { + var callUser = users.Find(x => x.Id == callFeedback.UserId); + callFeedback.Phone = callUser.Phone; + callFeedback.NickName = wxUnifyUsers.Find(x => x.UnionId == callUser.UnionId)?.NickName ?? CommonConst.Default_UserName; + callFeedback.WxAvatarUrl = wxUnifyUsers.Find(x => x.UnionId == callUser.UnionId)?.AvatarUrl ?? (CommonConst.Default_Image_Prefix + CommonConst.Default_AvataUrl); + callFeedback.Content = EnumExtensions + .ParseEnum(typeof(CallFeedbackStatusEnum), callFeedback.State.ToString()).ToDescription(); + if (callFeedback.IsRead == false && item.IsReadForCallFeedback == false) + { + item.IsReadForCallFeedback = true; + } + } + } + + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = listDto, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 单条查询 + /// + /// + /// + public async Task GetById(long id) + { + ApplyJobOutputDto applyDto = await GetOutDtoAsync(id); + //行业岗位 + System.Collections.Generic.List industryJobs = await _industryJobsService.GetAllListAsync(); + //工作经验 + System.Collections.Generic.List experiences = await _dictionaryService.GetListByPidAsync(CommonConst.Dictionary_Experience); + // + System.Collections.Generic.List users = (await _userRepository.GetListWhereAsync(" `State`=10")).MapTo(); + + applyDto.ExperienceName = experiences.Find(x => x.Id == applyDto.ExperienceId)?.Value; + applyDto.IndustryName = industryJobs.Find(x => x.Id == applyDto.IndustryId)?.Name; + applyDto.JobName = industryJobs.Find(x => x.Id == applyDto.JobId)?.Name; + applyDto.DriverLicense = ""; + if (applyDto.IsHaveDriverLicense != null) + { + applyDto.DriverLicense = applyDto.IsHaveDriverLicense == true ? "有驾驶证" : "无驾驶证"; + } + applyDto.Top = applyDto.IsTop ? "已置顶" : "未置顶"; + applyDto.TopExpireDate = applyDto.IsTop ? applyDto.TopExpireDate : null; + applyDto.Public = applyDto.IsPublic ? "已公开" : "未公开"; + applyDto.StatusName = EnumExtensions + .ParseEnum(typeof(ProductStatusEnum), applyDto.State.ToString()).ToDescription(); + UserOutputDto user = users.Find(x => x.Id == applyDto.UserId); + applyDto.UserName = user?.UserName ?? CommonConst.Default_UserName; + applyDto.AvatarUrl = CommonConst.Default_Image_Prefix + (user?.AvatarUrl ?? CommonConst.Default_AvataUrl); + return applyDto; + } + + /// + /// 下架求职信息 + /// + /// + /// + /// + public async Task RevocationAsync(long id, long userId) + { + CommonResult result = new CommonResult(); + ApplyJobEntity info = await repository.GetAsync(id); + if (!(info?.Id > 0)) + { + result.Success = false; + result.ErrMsg = "求职信息不存在"; + return result; + } + info.State = (int)ProductStatusEnum.Cancel; + info.ModifiedUserId = userId; + info.ModifiedTime = DateTime.Now; + await repository.UpdateAsync(info, info.Id).ConfigureAwait(false); + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AreaService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AreaService.cs new file mode 100644 index 0000000..3593fd0 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AreaService.cs @@ -0,0 +1,129 @@ +using Newtonsoft.Json; +using System.Collections.Generic; +using System.Linq; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// Ϣ + /// + public class AreaService : BaseService, IAreaService + { + private readonly IAreaRepository _repository; + + public AreaService(IAreaRepository repository) : base(repository) + { + _repository = repository; + } + + #region uniappѡ + + /// + /// ȡпõĵuniappѡ + /// + /// + public List GetAllByEnable() + { + List list = new List(); + CacheHelper cacheHelper = new CacheHelper(); + list = JsonConvert.DeserializeObject>(cacheHelper.Get("Area_Enable_Uniapp") + .ToJson()); + if (list == null || list.Count <= 0) + { + List listFunction = _repository.GetAllByIsNotDeleteAndEnabledMark("Layers in (0,1,2)") + .OrderBy(t => t.SortCode).ToList(); + list = UniappViewJson(listFunction, 0); + cacheHelper.Add("Area_Enable_Uniapp", list); + } + + return list; + } + + /// + /// ȡʡС/õĵuniappѡ + /// + /// + public List GetProvinceToAreaByEnable() + { + List list = new List(); + CacheHelper cacheHelper = new CacheHelper(); + list = JsonConvert.DeserializeObject>(cacheHelper + .Get("Area_ProvinceToArea_Enable_Uniapp").ToJson()); + if (list == null || list.Count <= 0) + { + List listFunctionTemp = _repository.GetAllByIsNotDeleteAndEnabledMark("Layers in (1,2,3)") + .OrderBy(t => t.Id).ToList(); + List listFunction = new List(); + foreach (AreaEntity item in listFunctionTemp) + { + if (item.Layers == 1) + { + item.ParentId = 0; + } + + listFunction.Add(item); + } + + list = UniappViewJson(listFunction, 0); + cacheHelper.Add("Area_ProvinceToArea_Enable_Uniapp", list); + } + + return list; + } + + /// + /// + /// + /// + /// + public List UniappViewJson(List data, long ParentId) + { + List list = new List(); + List ChildNodeList = data.FindAll(t => t.ParentId == ParentId).ToList(); + foreach (AreaEntity entity in ChildNodeList) + { + AreaPickerOutputDto treeViewModel = new AreaPickerOutputDto + { + value = entity.Id, + label = entity.FullName, + children = ChildrenUniappViewList(data, entity.Id) + }; + list.Add(treeViewModel); + } + + return list; + } + + /// + /// + /// + /// + /// + public List ChildrenUniappViewList(List data, long ParentId) + { + List listChildren = new List(); + List ChildNodeList = data.FindAll(t => t.ParentId == ParentId).ToList(); + foreach (AreaEntity entity in ChildNodeList) + { + AreaPickerOutputDto treeViewModel = new AreaPickerOutputDto + { + value = entity.Id, + label = entity.FullName, + children = ChildrenUniappViewList(data, entity.Id) + }; + listChildren.Add(treeViewModel); + } + + return listChildren; + } + + #endregion uniappѡ + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AuditService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AuditService.cs new file mode 100644 index 0000000..bbec6f1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/AuditService.cs @@ -0,0 +1,275 @@ +using Senparc.Weixin.Entities.TemplateMessage; +using System; +using System.Data; +using System.Threading.Tasks; +using Wx; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class AuditService : BaseService, IAuditService + { + private readonly IEquipmentRepository _equipmentRepository; + private readonly IAuditRepository _auditRepository; + private readonly ICurrencyRecordRepository _currencyRecordRepository; + private readonly ICurrencyService _currencyService; + private readonly IMessageLogsService _messageLogsService; + private readonly ICloudcarService _CloudcarService; + private readonly IUserService _userService; + + public AuditService( + IEquipmentRepository equipmentRepository, + IAuditRepository repository, + ICloudcarService CloudcarService, + IUserService userService, + IMessageLogsService messageLogsService, + ICurrencyRecordRepository currencyRecordRepository, + ICurrencyService currencyService + ) : base(repository) + { + _auditRepository = repository; + _equipmentRepository = equipmentRepository; + _CloudcarService = CloudcarService; + _userService = userService; + _messageLogsService = messageLogsService; + _currencyRecordRepository = currencyRecordRepository; + _currencyService = currencyService; + } + + /// + /// ͬʵ塣 + /// + /// ʵ + /// + /// + public override long Insert(AuditEntity entity, IDbTransaction trans = null) + { + long result = repository.Insert(entity, trans); + return result; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// ID + /// + /// + public override async Task UpdateAsync(AuditEntity entity, long id, IDbTransaction trans = null) + { + bool result = await repository.UpdateAsync(entity, id, trans); + return result; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// + /// + public override async Task InsertAsync(AuditEntity entity, IDbTransaction trans = null) + { + int result = await repository.InsertAsync(entity, trans); + return result; + } + + public async Task> FindWithPagerSearchAsync(SearchUserModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + where += string.Format( + " and (Title like '%{0}%' or Content like '%{0}%' or Name like '%{0}%' or Phone like '%{0}%')", + search.Keywords); + }; + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + System.Collections.Generic.List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// ͨ + /// + /// + /// + /// + public async Task AuditSuccessAsync(AuditEntity info,int promoteType) + { + CommonResult result = new CommonResult(); + string messageTitle = ""; + string productTitle = ""; + long userId = 0; + string toUser = ""; + string url = ""; + AuditEntity audit = new AuditEntity + { + Id = YitIdHelper.NextId(), + EquipmentId = info.EquipmentId, + AuditUserId = info.CreatedUserId, + HandleStatus = (int)HandleStatusEnum.Finding, + Note = "", + CreatedTime = info.CreatedTime, + ModifiedTime = info.CreatedTime, + CreatedUserId = info.CreatedUserId + }; + + EquipmentEntity equipment = await _equipmentRepository.GetAsync(info.EquipmentId); + if (equipment.State == (int)ProductStatusEnum.Review && equipment!=null) + { + equipment.State = (int)ProductStatusEnum.Sell; + equipment.ModifiedTime = DateTime.Now; + if (equipment.IsTop == true) + { + equipment.TopExpireDate = DateTime.Now.AddDays(1); + } + equipment.PromoteType = promoteType; + equipment.Introduction = EmojiFilterHelper.FilterEmoji(equipment.Introduction); + await _equipmentRepository.UpdateAsync(equipment, equipment.Id).ConfigureAwait(false); + productTitle = equipment.Title; + userId = equipment.UserId; + messageTitle = ReturnConst.Cloud_Approved; + toUser = (await _userService.GetAsync(equipment.UserId)).OpenId; + url = string.Format("/pages/detail/detail?id={0}", info.EquipmentId); + } + else + { + result.ResData = "Ϣڻδ!"; + result.Success = false; + return result; + }; + + + + audit.EquipmentTitle = productTitle; + await _auditRepository.InsertAsync(audit); + MessageInputDto messageInputDto = new MessageInputDto + { + MessageTitle = messageTitle, + EquipmentId = info.EquipmentId, + EquipmentTitle = productTitle, + UserId = userId, + CreatedUserId = info.CreatedUserId, + Content = "" + }; + + await _messageLogsService.AddAsync(messageInputDto).ConfigureAwait(false); + TemplateMessageData templateMessageData = new TemplateMessageData + { + ["thing1"] = new(messageTitle), + ["time2"] = new(DateTime.Now.ToString($"yyyy{ReturnConst.Year}MM{ReturnConst.Month}dd{ReturnConst.Day} HH:mm")), + ["phrase3"] = new(ReturnConst.Approved), + ["thing4"] = new(ReturnConst.Approved_Note) + }; + + + //Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(templateMessageData)); + await CommonHelper.SendProductAsync(templateMessageData, toUser, url).ConfigureAwait(false); + result.Success = true; + return result; + } + + /// + /// ʧ + /// + /// + /// + public async Task AuditFailAsync(AuditEntity productAuditInput) + { + CommonResult result = new CommonResult(); + string messageTitle = ""; + string productTitle = ""; + long userId = 0; + string toUser = ""; + string url = ""; + AuditEntity audit = new AuditEntity + { + Id = YitIdHelper.NextId(), + EquipmentId = productAuditInput.EquipmentId, + AuditUserId = productAuditInput.CreatedUserId, + HandleStatus = (int)HandleStatusEnum.Fail, + Note = productAuditInput.Note, + CreatedTime = productAuditInput.CreatedTime, + ModifiedTime = productAuditInput.CreatedTime, + CreatedUserId = productAuditInput.CreatedUserId + }; + + EquipmentEntity equipment = await _equipmentRepository.GetAsync(productAuditInput.EquipmentId); + // productTitle = apply.Title; + if (equipment.State == (int)ProductStatusEnum.Review && equipment != null) + { + equipment.State = (int)ProductStatusEnum.Fail; + equipment.ModifiedTime = DateTime.Now; + if (equipment.IsTop == true) + { + equipment.IsTop = false; + equipment.TopExpireDate = Convert.ToDateTime("0001-01-01 00:00:00"); + //Ʊ + await _currencyService.TopReturnForApplyJob(equipment.UserId, equipment.Id, productAuditInput.CreatedUserId); + } + equipment.Introduction = EmojiFilterHelper.FilterEmoji(equipment.Introduction); + await _equipmentRepository.UpdateAsync(equipment, equipment.Id).ConfigureAwait(false); + userId = equipment.UserId; + productTitle = equipment.Title; + messageTitle = ReturnConst.Cloud_Audit_Failed; + toUser = (await _userService.GetAsync(equipment.UserId)).OpenId; + url = string.Format("/pages/detail/detail?id={0}", productAuditInput.EquipmentId); + + } + else + { + result.ResData = "Ϣڻδ!"; + result.Success = false; + return result; + } + + + + audit.EquipmentTitle = productTitle; + await _auditRepository.InsertAsync(audit); + MessageInputDto messageInputDto = new MessageInputDto + { + MessageTitle = messageTitle, + EquipmentId = productAuditInput.EquipmentId, + EquipmentTitle = productTitle, + UserId = userId, + CreatedUserId = productAuditInput.CreatedUserId, + Content = "" + }; + await _messageLogsService.AddAsync(messageInputDto).ConfigureAwait(false); + TemplateMessageData templateMessageData = new TemplateMessageData + { + ["thing1"] = new(messageTitle), + ["time2"] = new(DateTime.Now.ToString($"yyyy{ReturnConst.Year}MM{ReturnConst.Month}dd{ReturnConst.Day} HH:mm")), + ["phrase3"] = new(ReturnConst.Audit_Failed), + ["thing4"] = new(productAuditInput.Note) + }; + await CommonHelper.SendProductAsync(templateMessageData, toUser, url).ConfigureAwait(false); + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/BannerService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/BannerService.cs new file mode 100644 index 0000000..8831a73 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/BannerService.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// Banner服务 + /// + public class BannerService : BaseService, IBannerService + { + private readonly IBannerRepository _bannerRepository; + + public BannerService( + IBannerRepository bannerRepository + ) : base(bannerRepository) + { + _bannerRepository = bannerRepository; + } + + + /// + /// 分页查询 + /// + /// + /// + /// + public async Task> FindWithPagerSearchAsync(SearchBannerModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + //关键字查询 + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += $" and (PicDesc like '%{search.Keywords}%')"; + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + //查询Banner表 + List list = (await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order)).MapTo(); + foreach (BannerOutputDto item in list) + { + item.PicUrl = CommonConst.Default_Banner_Prefix + item.PicUrl; + } + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 异步新增数据 + /// + /// ʵ�� + /// + public async Task InsertAsync(BannerEntity input) + { + CommonResult result = new CommonResult(); + if (input.StartTime >= input.EndTime) + { + result.Success = false; + result.ErrMsg = ReturnConst.Time_Error; + return result; + } + if (input.EndTime < DateTime.Now) + { + result.Success = false; + result.ErrMsg = ReturnConst.EndTime_Error; + return result; + } + input.PicUrl = input.PicUrl.Substring(input.PicUrl.LastIndexOf("/") + 1); + input.TextDesc = ""; + if (input.StartTime > DateTime.Now) + { + input.State = (int)ActivityStatusEnum.NotStart; + } + if (input.StartTime < DateTime.Now && input.EndTime > DateTime.Now) + { + input.State = (int)ActivityStatusEnum.Ongoing; + } + result.Success = await repository.InsertAsync(input) > 0 ? true : false; + return result; + } + + /// + /// 更新Banner数据 + /// + /// + /// + /// + public async Task UpdateAsync(BannerEntity input) + { + CommonResult result = new CommonResult(); + if (input.StartTime >= input.EndTime) + { + result.Success = false; + result.ErrMsg = ReturnConst.Time_Error; + return result; + } + BannerEntity info = await repository.GetAsync(input.Id); + if (!(info?.Id > 0)) + { + result.Success = false; + result.ErrMsg = ReturnConst.Not_Exist; + return result; + } + info.PicUrl = input.PicUrl.Substring(input.PicUrl.LastIndexOf("/") + 1); + info.Name = input.Name; + info.Type = input.Type; + info.PageUrl = input.PageUrl; + info.Phone = input.Phone; + info.StartTime = input.StartTime; + info.EndTime = input.EndTime; + if (input.StartTime > DateTime.Now) + { + info.State = (int)ActivityStatusEnum.NotStart; + } + if (input.EndTime < DateTime.Now) + { + info.State = (int)ActivityStatusEnum.End; + } + if (input.StartTime < DateTime.Now && input.EndTime > DateTime.Now) + { + info.State = (int)ActivityStatusEnum.Ongoing; + } + info.ModifiedTime = input.ModifiedTime; + info.ModifiedUserId = input.ModifiedUserId; + await repository.UpdateAsync(info, input.Id).ConfigureAwait(false); + result.Success = true; + + return result; + } + + /// + /// 修改广告状态 + /// + /// + public async Task UpdateStatusAsync() + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + List list = (await repository.GetListWhereAsync(" IsDeleted=0")).MapTo(); + foreach (var item in list) + { + if (item.EndTime <= DateTime.Now) + { + item.State = (int)ActivityStatusEnum.End; + } + if (item.StartTime < DateTime.Now && item.EndTime > DateTime.Now) + { + item.State = (int)ActivityStatusEnum.Ongoing; + } + await repository.UpdateAsync(item, item.Id).ConfigureAwait(false); + } + cacheHelper.Remove("banner:list"); + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CallFeedbackService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CallFeedbackService.cs new file mode 100644 index 0000000..4f506d8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CallFeedbackService.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class CallFeedbackService : BaseService, ICallFeedbackService + { + private readonly ICallFeedbackRepository _callFeedbackRepository; + private readonly IUserRepository _userRepository; + private readonly IWxUnifyUserRepository _wxUnifyUserRepository; + + public CallFeedbackService(ICallFeedbackRepository repository, + IUserRepository userRepository, + IWxUnifyUserRepository wxUnifyUserRepository + ) : base(repository) + { + _callFeedbackRepository = repository; + _userRepository = userRepository; + _wxUnifyUserRepository = wxUnifyUserRepository; + } + + /// + /// ͨ۷ҳѯ + /// + /// ѯ + /// + public async Task> FindWithPagerSearchAsync(SearchCallFeedbackModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (search.Filter.ProductId > 0) + { + @where += $" and ProductId={search.Filter.ProductId}"; + } + if (search.Filter.ProductType > 0) + { + @where += $" and ProductType={search.Filter.ProductType}"; + } + if (search.Filter.State > 0) + { + @where += $" and State={search.Filter.State}"; + } + + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and CreatedTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" and CreatedTime <='{search.EndTime} 23:59:59'"; + } + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = (await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order)).MapTo(); + List uIds = list.Select(x => x.UserId).ToList(); + List usersList = (await _userRepository.GetListWhereAsync($" `State`=10 and Id in ({string.Join(", ", uIds.ToArray())})")).MapTo(); + //ƽ̨ͳһûϢ + List uninIds = usersList.Select(x => x.UnionId).ToList(); + List wxUnifyUsers = (await _wxUnifyUserRepository.GetListWhereAsync($" IsDeleted=0 AND UnionId IN ('{string.Join("','", uninIds.ToArray())}')")) + .MapTo(); + foreach (var item in list) + { + var user = usersList.Find(x => x.Id == item.UserId); + item.Phone = user.Phone; + item.NickName = wxUnifyUsers.Find(x => x.UnionId == user.UnionId).NickName; + item.WxAvatarUrl = wxUnifyUsers.Find(x => x.UnionId == user.UnionId).AvatarUrl; + item.Content = EnumExtensions + .ParseEnum(typeof(CallFeedbackStatusEnum), item.State.ToString()).ToDescription(); + } + + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// ޸ͨѶ + /// + /// + /// + /// + public async Task UpdateIsReadAsync(long userId, long productId, int productType) + { + CommonResult result = new CommonResult(); + await _callFeedbackRepository.UpdateIsReadAsync(userId, productId, productType); + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CertificationService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CertificationService.cs new file mode 100644 index 0000000..066a12c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CertificationService.cs @@ -0,0 +1,246 @@ +using System.Threading.Tasks; +using Wx; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class CertificationService : BaseService, + ICertificationService + { + private readonly ICacheService _cacheService; + private readonly ICertificationRepository _certificationRepository; + private readonly ICurrencyRecordRepository _currencyRecordRepository; + private readonly ICurrencyService _currencyService; + private readonly IMessageLogsService _messageLogsService; + private readonly IUserRepository _userRepository; + private readonly IApplyJobRepository _applyJobRepository; + private readonly ICloudcarRepository _CloudcarRepository; + + public CertificationService( + ICertificationRepository repository, + IMessageLogsService messageLogsService, + IUserRepository userRepository, + ICurrencyService currencyService, + ICurrencyRecordRepository currencyRecordRepository, + IApplyJobRepository applyJobRepository, + ICloudcarRepository CloudcarRepository, + ICacheService cacheService + ) : base(repository) + { + _certificationRepository = repository; + _messageLogsService = messageLogsService; + _userRepository = userRepository; + _currencyRecordRepository = currencyRecordRepository; + _currencyService = currencyService; + _cacheService = cacheService; + _applyJobRepository = applyJobRepository; + _CloudcarRepository = CloudcarRepository; + } + + public async Task> FindWithPagerSearchAsync(SearchUserModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += string.Format( + " and (IdCard like '%{0}%' or IssuedAddress like '%{0}%' or Name like '%{0}%')", + search.Keywords); + } + + if (search.State >= 0) + { + @where += string.Format(" and State={0}", search.State); + } + + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += " and ModifiedTime >='" + search.StartTime + " 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += " and ModifiedTime <='" + search.EndTime + " 23:59:59'"; + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + System.Collections.Generic.List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + System.Collections.Generic.List listDto = list.MapTo(); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = listDto, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// ʵ֤ͨ + /// + /// + /// + public async Task AuditSuccessAsync(CertificationEntity info) + { + string where = string.Format(" Id={0} and IsDeleted=0", info.Id); + CertificationEntity certification = await _certificationRepository.GetWhereAsync(where); + if (certification == null) + { + return false; + } + + certification.State = (int)UserCertificationEnum.Pass; + certification.ModifiedUserId = info.ModifiedUserId; + bool bl = await _certificationRepository.UpdateAsync(certification, certification.Id) + .ConfigureAwait(false); + UserEntity user = await _userRepository.GetUserByUnionId(certification.UnionId); + string messageTitle = ""; + if (bl) + { + string toUser = user.OpenId; + await CommonHelper.SendAuditSuccessAsync(toUser); + messageTitle = ReturnConst.RealName_Approved; + + //ͨӻ + //string key = string.Format("UserId = {0} AND CurrencyType = {1} AND IsDeleted = 0", + // user.Id, (int)OperatingCreditsTypeEnum.RealName); + //CurrencyRecordEntity currencyRecord = await _currencyRecordRepository.GetWhereAsync(key); + //if (currencyRecord == null) + //{ + // await _currencyService.AddCurrencyByCreditsType(user.Id, CurrencyConst.RealName, + // (int)OperatingCreditsTypeEnum.RealName, certification.Id, info.ModifiedUserId); + //} + + await RemoveCertificationCacheAsync(user.Id); + //û + user.IsRealAuthentication = true; + user.UserName = EmojiFilterHelper.FilterEmoji(user.UserName); + await _userRepository.UpdateAsync(user, user.Id); + //ְ + await _applyJobRepository.UpdateIsRealAuthenticationAsync(user.Id); + //Ƹ + await _CloudcarRepository.UpdateIsRealAuthenticationAsync(user.Id); + //ɾûϢ + await RemoveUserCacheAsync(user.Id); + //ɾûƱб + //await RemoveCurrencyIntroCacheAsync(user.Id); + } + + //MessageInputDto messageInputDto = new MessageInputDto + //{ + // MessageTitle = messageTitle, + // ProductId = certification.Id, + // Title = "", + // UserId = (await _userRepository.GetUserByUnionId(certification.UnionId)).Id, + // ProductType = 3, //ϵͳ֪ͨ + // CreatedUserId = info.ModifiedUserId, + // Content = "" + //}; + //await _messageLogsService.AddAsync(messageInputDto); + return bl; + } + + /// + /// ʵ֤ʧ + /// + /// + /// + public async Task AuditFailAsync(CertificationEntity info) + { + CommonResult result = new CommonResult(); + string where = string.Format("Id={0} and IsDeleted=0", info.Id); + CertificationEntity certification = await _certificationRepository.GetWhereAsync(where); + certification.State = (int)UserCertificationEnum.Fail; + certification.ModifiedUserId = info.ModifiedUserId; + UserEntity user = await _userRepository.GetUserByUnionId(certification.UnionId); + bool bl = await _certificationRepository.UpdateAsync(certification, certification.Id) + .ConfigureAwait(false); + string messageTitle = ""; + if (bl) + { + string toUser = user.OpenId; + await CommonHelper.SendAuditFailAsync(toUser); + messageTitle = ReturnConst.RealName_Audit_Failed; + + await RemoveCertificationCacheAsync(user.Id); + //û + user.IsRealAuthentication = false; + await _userRepository.UpdateAsync(user, user.Id); + //ɾûϢ + await RemoveUserCacheAsync(user.Id); + } + + //MessageInputDto messageInputDto = new MessageInputDto + //{ + // MessageTitle = messageTitle, + // ProductId = certification.Id, + // Title = "", + // UserId = (await _userRepository.GetUserByUnionId(certification.UnionId)).Id, + // ProductType = 3, //ϵͳ֪ͨ + // CreatedUserId = info.ModifiedUserId, + // Content = "" + //}; + //await _messageLogsService.AddAsync(messageInputDto); + return bl; + } + + /// + /// ɾû + /// + /// + /// + public async Task RemoveUserCacheAsync(long id) + { + string key = string.Format("user:{0}", id); + await _cacheService.RemoveAsync(key); + } + + /// + /// ɾûʵ֤ + /// + /// + /// + public async Task RemoveCertificationCacheAsync(long id) + { + string key = string.Format("certification:{0}", id); + await _cacheService.RemoveAsync(key); + } + + /// + /// ɾƱԴ + /// + /// + /// + public async Task RemoveCurrencyIntroCacheAsync(long id) + { + string key = string.Format("currency:intro:{0}", id); + await _cacheService.RemoveAsync(key); + } + + /// + /// ʵ + /// + /// + /// + public async Task SetUserCertificationCacheAsync(long id, CertificationOutput certificationOutput) + { + string key = string.Format("certification:{0}", id); + await _cacheService.AddAsync(key, certificationOutput); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CurrencyRecordService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CurrencyRecordService.cs new file mode 100644 index 0000000..3eee052 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CurrencyRecordService.cs @@ -0,0 +1,99 @@ +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// ûƱҷ + /// + public class CurrencyRecordService : BaseService, ICurrencyRecordService + { + private readonly ICurrencyRecordRepository _currencyRecordRepository; + private readonly ICurrencyRepository _currencyRepository; + private readonly IUserRepository _userRepository; + + public CurrencyRecordService( + IUserRepository userRepository, + ICurrencyRepository currencyRepository, + ICurrencyRecordRepository currencyRecordRepository + ) : base(currencyRecordRepository) + { + _userRepository = userRepository; + _currencyRepository = currencyRepository; + _currencyRecordRepository = currencyRecordRepository; + } + + + /// + /// Ʊб + /// + /// + /// + /// + public async Task> FindWithPagerSearchAsync(SearchCurrencyRecordModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + //ûid + @where += $" and UserId ={search.Filter.UserId}"; + //֧; + if (search.CurrencyType > 0) + { + @where += $" and CurrencyType={search.CurrencyType}"; + } + //֧ + if (search.OperatingType > 0) + { + @where += $" and OperatingType={search.OperatingType}"; + } + //ʼʱ + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and CreatedTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" and CreatedTime <='{search.EndTime} 23:59:59'"; + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + //ѯƱҼ¼ + System.Collections.Generic.List list = (await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order)).MapTo(); + //ȡûϢ(黺) + System.Collections.Generic.List users = (await _userRepository.GetListWhereAsync(" `State`=10")).MapTo(); + + foreach (CurrencyRecordOutputDto item in list) + { + UserOutputDto user = users.Find(x => x.Id == item.UserId); + item.UserName = user?.UserName; + item.AvatarUrl = CommonConst.Default_Image_Prefix + user?.AvatarUrl; + item.Phone = user?.Phone; + item.OperatingTypeName = EnumExtensions.ParseEnum(typeof(OperatingTypeEnum), item.OperatingType.ToString()).ToDescription(); + item.CurrencyTypeName = EnumExtensions.ParseEnum(typeof(CurrencyTypeEnum), item.CurrencyType.ToString()).ToDescription(); + } + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CurrencyService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CurrencyService.cs new file mode 100644 index 0000000..a8a6125 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/CurrencyService.cs @@ -0,0 +1,139 @@ +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// ûƱҷ + /// + public class CurrencyService : BaseService, ICurrencyService + { + private readonly ICurrencyRecordRepository _currencyRecordRepository; + private readonly ICurrencyRepository _currencyRepository; + private readonly IUserRepository _userRepository; + + public CurrencyService( + IUserRepository userRepository, + ICurrencyRepository currencyRepository, + ICurrencyRecordRepository currencyRecordRepository + ) : base(currencyRepository) + { + _userRepository = userRepository; + _currencyRepository = currencyRepository; + _currencyRecordRepository = currencyRecordRepository; + } + + /// + /// ʵ֤ӻ + /// + /// + /// Id + /// + public async Task AddCurrencyForRealName(long userId, long createdUserId) + { + string where = string.Format($"CurrencySoureObjectId={userId} and CurrencyType={(int)CurrencyTypeEnum.RealName}"); + CurrencyRecordEntity currencyRecord = await _currencyRecordRepository.GetWhereAsync(where); + if (currencyRecord == null) + { + CurrencyEntity currency = await _currencyRepository.GetWhereAsync($"UserId={userId}"); + if (currency == null) + { + await _currencyRepository.InsertAsync(new CurrencyEntity + { + Id = YitIdHelper.NextId(), + UserId = userId, + OfficialCredits = CurrencyConst.RealName, + AvailableCredits = CurrencyConst.RealName, + CreatedUserId = createdUserId, + CreatedTime = DateTime.Now + }); + } + else + { + currency.OfficialCredits = currency.OfficialCredits + CurrencyConst.RealName; + currency.AvailableCredits = currency.AvailableCredits + CurrencyConst.RealName; + currency.ModifiedUserId = createdUserId; + await _currencyRepository.UpdateAsync(currency, currency.Id).ConfigureAwait(false); + } + await _currencyRecordRepository.InsertAsync(new CurrencyRecordEntity + { + Id = YitIdHelper.NextId(), + UserId = userId, + OperatingCurrency = CurrencyConst.RealName, + OperatingType = (int)OperatingTypeEnum.Add, + CurrencyType = (int)CurrencyTypeEnum.RealName, + CurrencySoureObjectId = 0, + ModifiedTime = DateTime.Now, + CreatedTime = DateTime.Now, + CreatedUserId = createdUserId + }); + return true; + } + return false; + } + + /// + /// ְöƱ + /// + /// + /// 4 + /// + /// + public async Task TopReturnForApplyJob(long userId, long applyJobId, long createdUserId) + { + CurrencyEntity currency = await _currencyRepository.GetWhereAsync($"UserId={userId}"); + currency.AvailableCredits += CurrencyConst.TopApplyJob; + currency.OfficialCredits += CurrencyConst.TopApplyJob; + await _currencyRepository.UpdateAsync(currency, currency.Id); + await _currencyRecordRepository.InsertAsync(new CurrencyRecordEntity + { + Id = YitIdHelper.NextId(), + UserId = userId, + OperatingCurrency = CurrencyConst.TopApplyJob, + OperatingType = (int)OperatingTypeEnum.Add, + CurrencyType = (int)CurrencyTypeEnum.ReturnTopApplyJob, + CurrencySoureObjectId = applyJobId, + ModifiedTime = DateTime.Now, + CreatedTime = DateTime.Now, + CreatedUserId = createdUserId + }); + + } + + /// + /// ƸöƱ + /// + /// + /// + /// + /// + public async Task TopReturnForCloudcar(long userId, long CloudcarId, long createdUserId) + { + CurrencyEntity currency = await _currencyRepository.GetWhereAsync($"UserId={userId}"); + currency.OfficialCredits += CurrencyConst.TopCloudcar; + currency.AvailableCredits += CurrencyConst.TopCloudcar; + await _currencyRepository.UpdateAsync(currency, currency.Id); + await _currencyRecordRepository.InsertAsync(new CurrencyRecordEntity + { + Id = YitIdHelper.NextId(), + UserId = userId, + OperatingCurrency = CurrencyConst.TopCloudcar, + OperatingType = (int)OperatingTypeEnum.Add, + CurrencyType = (int)CurrencyTypeEnum.RenturnTopCloudcar, + CurrencySoureObjectId = CloudcarId, + ModifiedTime = DateTime.Now, + CreatedTime = DateTime.Now, + CreatedUserId = createdUserId + }); + + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/DictionaryService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/DictionaryService.cs new file mode 100644 index 0000000..ab086c3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/DictionaryService.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class DictionaryService : BaseService, IDictionaryService + { + private readonly IDictionaryRepository _repository; + + public DictionaryService(IDictionaryRepository repository) : base(repository) + { + _repository = repository; + } + + /// + /// ȡܲ˵Vue б + /// + /// + public async Task> GetAllDictionaryTreeTable() + { + List reslist = new List(); + IEnumerable diclist = await _repository.GetListWhereAsync(" IsDeleted = 0"); + List list = diclist.OrderBy(t => t.Sort).ToList(); + List oneDictionaryList = list.FindAll(t => t.ParentId == 0); + foreach (DictionaryEntity item in oneDictionaryList) + { + DictionaryOutputDto dicTreeTableOutput = new DictionaryOutputDto(); + dicTreeTableOutput = item.MapTo(); + dicTreeTableOutput.Children = GetSubDictionary(list, item.Id).ToList(); + reslist.Add(dicTreeTableOutput); + } + await SyncDictionaryCache(); + return reslist; + } + + /// + /// ȡӼݹ + /// + /// + /// Id + /// + private List GetSubDictionary(List data, long ParentId) + { + List list = new List(); + DictionaryOutputDto dictionaryOutputDto = new DictionaryOutputDto(); + List ChilList = data.FindAll(t => t.ParentId == ParentId); + foreach (DictionaryEntity entity in ChilList) + { + dictionaryOutputDto = entity.MapTo(); + dictionaryOutputDto.Children = GetSubDictionary(data, entity.Id).OrderBy(t => t.Sort) + .MapTo(); + list.Add(dictionaryOutputDto); + } + + return list; + } + + /// + /// ݱѯֵ + /// + /// + /// + public async Task GetByEnCodAsynce(string enCode) + { + return await _repository.GetByEnCodAsynce(enCode); + } + + /// + /// ʱжϷǷڣųԼ + /// + /// Id + /// + public async Task GetByEnCodAsynce(string enCode, long id) + { + return await _repository.GetByEnCodAsynce(enCode, id); + } + + /// + /// ѯֵ + /// + /// + /// + public async Task GetDictionaryById(long id) + { + DictionaryOutputDto result = (await _repository.GetSingleOrDefaultAsync(x => x.Id == id && x.IsDeleted == false)).MapTo(); + return result; + } + + /// + /// ParentIdѯֵб + /// + /// + /// + public async Task> GetListByPidAsync(long pid) + { + List list = await SyncDictionaryCache(); + list = list.Where(x => x.ParentId == pid).ToList(); + return list; + } + + + + /// + /// ParentIdѯֵб + /// + /// + /// + public async Task> GetListByCodeAsync(long pid,string code) + { + List list = await SyncDictionaryCache(); + list = list.Where(x => x.ParentId == pid && x.Code==code).ToList(); + return list; + } + + + + /// + /// ͬ + /// + /// + public async Task> SyncDictionaryCache() + { + CacheHelper cacheHelper = new CacheHelper(); + List list = cacheHelper.Get>("dictionary:list"); + if (list == null || list.Count < 1) + { + IEnumerable dicList = await repository.GetListWhereAsync(" IsDeleted=0 and IsEnabled=1 order by Sort"); + list = dicList.MapTo(); + cacheHelper.Add("dictionary:list", list, TimeSpan.FromDays(30)); + } + + return list; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/EquipmentService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/EquipmentService.cs new file mode 100644 index 0000000..2b9f3b5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/EquipmentService.cs @@ -0,0 +1,165 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + + + + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + /// + public class EquipmentService : BaseService, IEquipmentService + { + private readonly IEquipmentRepository _equipmentRepository; + private readonly IDictionaryRepository _dictionaryRepository; + private readonly IUserRepository _userRepository; + private readonly IWxUnifyUserRepository _wxUnifyUserRepository; + private readonly IEquipmentPictureRepository _equipmentPictureRepository; + public EquipmentService( + IEquipmentRepository equipmentRepository, + IDictionaryRepository dictionaryRepository, + IUserRepository userRepository , + IWxUnifyUserRepository wxUnifyUserRepository, + IEquipmentPictureRepository equipmentPictureRepository + ) : base(equipmentRepository) + { + _userRepository = userRepository; + _equipmentRepository = equipmentRepository; + _dictionaryRepository = dictionaryRepository; + _wxUnifyUserRepository = wxUnifyUserRepository; + _equipmentPictureRepository = equipmentPictureRepository; + } + + + + + /// + /// 分页查询 + /// + /// + /// + public async Task> FindWithPagerSearchAsync(SearchEquipmentModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and StartTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" or EndTime <='{search.EndTime} 23:59:59'"; + } + + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += $" and Introduction like '%{search.Keywords}%'"; + } + if (search.State > -1) + { + @where += $" and State={search.State}"; + } + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + var equipments = (await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order)).MapTo(); + if (equipments.Count > 0) + { + var users = await _userRepository.GetListWhereAsync(); + var dictionarys = await _dictionaryRepository.GetListWhereAsync(); + var wxUsers = await _wxUnifyUserRepository.GetListWhereAsync(); + CacheHelper cacheHelper = new CacheHelper(); + foreach (var equipment in equipments) + { + equipment.NickName = ""; + var user = users.FirstOrDefault(x => x.Id == equipment.UserId); + if (user != null) + { + equipment.UserName = user?.UserName; + equipment.Avatar = user?.AvatarUrl; + var wxUser = wxUsers.FirstOrDefault(x => x.UnionId == user?.UnionId); + if (wxUser != null) + { + equipment.NickName = wxUser?.NickName; + } + equipment.IsPromote = user.IsPromote; + } + equipment.EquipmentTypeName = dictionarys.FirstOrDefault(x => x.Id == equipment.EquipmentType)?.Name; + equipment.EquipmentBrandName = dictionarys.FirstOrDefault(x => x.Id == equipment.EquipmentBrand)?.Name; + equipment.BoomLengthName = dictionarys.FirstOrDefault(x => x.Id == equipment.BoomLength)?.Name; + equipment.AutomobileChassisName = dictionarys.FirstOrDefault(x => x.Id == equipment.AutomobileChassis)?.Name; + equipment.StateName = typeof(EquipmentState).GetDescription((int)equipment.State); + var equipmentPictures = await _equipmentPictureRepository.GetListWhereAsync($" EquipmentId={equipment.Id}"); + if (equipmentPictures != null && equipmentPictures.Any()) + { + //设备图片 + equipment.EquipmentPictures = equipmentPictures.Where(x => x.PictureType == 10).ToList(); + //行驶证 + equipment.DrivingPictures = equipmentPictures.Where(x => x.PictureType == 20).ToList(); + } + + //equipment.PageView =(await cacheHelper.HGetAsync("PageView", equipment.Id.ToString())).ToInt(); + } + } + var pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = equipments, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 下架 + /// + /// + /// + public async Task CancelAsync(long id) + { + + CommonResult result = new CommonResult(); + var equipment = await _equipmentRepository.GetAsync(id); + if (equipment != null) + { + equipment.State = (int)EquipmentState.Shelved; + result.Success = await _equipmentRepository.UpdateAsync(equipment, equipment.Id).ConfigureAwait(false); + } + return result; + } + + public async Task CompleteAsync(long id) + { + + CommonResult result = new CommonResult(); + var equipment = await _equipmentRepository.GetAsync(id); + if (equipment != null) + { + equipment.State = (int)EquipmentState.Traded; + result.Success = await _equipmentRepository.UpdateAsync(equipment, equipment.Id).ConfigureAwait(false); + } + return result; + } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ExceptionsLogsService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ExceptionsLogsService.cs new file mode 100644 index 0000000..3718dc6 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/ExceptionsLogsService.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class ExceptionsLogsService : BaseService, + IExceptionsLogsService + { + private readonly IExceptionsLogsRepository _iLogRepository; + private readonly IUserRepository _iuserRepository; + + /// + /// + /// + /// + public ExceptionsLogsService(IExceptionsLogsRepository repository, IUserRepository userRepository) : + base(repository) + { + _iLogRepository = repository; + _iuserRepository = userRepository; + } + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + //public async Task> FindWithPagerSearchAsync(SearchExceptionsLogsModel search) + //{ + // bool order = search.Order == "asc" ? false : true; + // string where = GetDataPrivilege(false); + // if (!string.IsNullOrEmpty(search.CreatedTime1)) + // { + // @where += " and CreatedTime >='" + search.CreatedTime1.ToDateTime() + "'"; + // } + + // if (!string.IsNullOrEmpty(search.CreatedTime2)) + // { + // @where += " and CreatedTime <='" + search.CreatedTime2.ToDateTime() + "'"; + // } + + // if (!string.IsNullOrEmpty(search.Filter.IPAddress)) + // { + // @where += string.Format(" and IPAddress = '{0}'", search.Filter.IPAddress); + // }; + // if (!string.IsNullOrEmpty(search.Filter.Account)) + // { + // @where += string.Format(" and Account = '{0}'", search.Filter.Account); + // }; + // PagerInfo pagerInfo = new PagerInfo + // { + // CurrenetPageIndex = search.CurrenetPageIndex, + // PageSize = search.PageSize + // }; + + // //Expression> filter = log => true; + // //if (!string.IsNullOrEmpty(search.Keywords)) + // //{ + // // filter = filter.And(log => log.Account.StartsWith(search.Keywords) || log.ModuleName.StartsWith(search.Keywords) || log.IPAddress.StartsWith(search.Keywords) + // // || log.IPAddressName.StartsWith(search.Keywords) || log.Description.StartsWith(search.Keywords)); + // //} + // //if (!string.IsNullOrEmpty(search.EnCode)) + // //{ + // // filter = filter.And(log=>search.EnCode.Contains(log.Type)); + // //} + // List list = await _iLogRepository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + // PageResult pageResult = new PageResult + // { + // CurrentPage = pagerInfo.CurrenetPageIndex, + // Items = list.MapTo(), + // ItemsPerPage = pagerInfo.PageSize, + // TotalItems = pagerInfo.RecordCount + // }; + // return pageResult; + //} + + /// + /// ϢдûIJ־¼ + /// + /// + /// + /// ϸ + /// + public bool OnOperationLog(string tableName, string operationType, string note) + { + try + { + //Ȼʵ¼ǻҪжϸñǷñ棬ڣ򲻼¼־ + //var identities = _httpContextAccessor.HttpContext.User.Identities; + if (HttpContextHelper.HttpContext == null) + { + return false; + } + + IEnumerable identities = HttpContextHelper.HttpContext.User.Identities; + ClaimsIdentity claimsIdentity = identities.First(); + List claimlist = claimsIdentity.Claims as List; + string userId = claimlist[0].Value; + CacheHelper cacheHelper = new CacheHelper(); + AdminCurrentUser AdminCurrentUser = new AdminCurrentUser(); + AdminCurrentUser user = cacheHelper.Get("login_user_" + userId).ToJson().ToObject(); + if (user != null) + { + AdminCurrentUser = user; + bool insert = operationType == DbLogType.Create.ToString(); + ; //&& settingInfo.InsertLog; + bool update = operationType == DbLogType.Update.ToString(); // && settingInfo.UpdateLog; + bool delete = operationType == DbLogType.Delete.ToString(); // && settingInfo.DeleteLog; + bool deletesoft = operationType == DbLogType.DeleteSoft.ToString(); // && settingInfo.DeleteLog; + bool exception = operationType == DbLogType.Exception.ToString(); // && settingInfo.DeleteLog; + bool sql = operationType == DbLogType.SQL.ToString(); // && settingInfo.DeleteLog; + + if (insert || update || delete || deletesoft || exception || sql) + { + ExceptionsLogsEntity info = new ExceptionsLogsEntity + { + Id = YitIdHelper.NextId() + }; + //info.ModuleName = tableName; + //info.Type = operationType; + //info.Description = note; + //info.Date = info.CreatedTime = DateTime.Now; + //info.CreatedUserId = CurrentUser.UserId; + //info.Account = AdminCurrentUser.Account; + //info.UserName = AdminCurrentUser.UserName; + //info.OrganizeId = AdminCurrentUser.OrganizeId; + //info.IPAddress = AdminCurrentUser.CurrentLoginIP; + //info.IPAddressName = AdminCurrentUser.IPAddressName; + //info.Result = true; + long lg = _iLogRepository.Insert(info); + if (lg > 0) + { + return true; + } + } + } + } + catch (Exception ex) + { + Log4NetHelper.Error("", ex); + return false; + } + + return false; + } + + /// + /// ϢдûIJ־¼ + /// Ҫдģ־ + /// + /// ģ + /// + /// ϸ + /// û + /// + public bool OnOperationLog(string module, string operationType, string note, AdminCurrentUser AdminCurrentUser) + { + //Ȼʵ¼ǻҪжϸñǷñ棬ڣ򲻼¼־ + //OperationLogSettingInfo settingInfo = BLLFactory.Instance.FindByTableName(tableName, trans); + + if (AdminCurrentUser != null) + { + bool login = operationType == DbLogType.Login.ToString(); + bool visit = operationType == DbLogType.Visit.ToString(); + bool exit = operationType == DbLogType.Exit.ToString(); + bool other = operationType == DbLogType.Other.ToString(); + bool insert = operationType == DbLogType.Create.ToString(); + bool update = operationType == DbLogType.Update.ToString(); + bool delete = operationType == DbLogType.Delete.ToString(); + bool deletesoft = operationType == DbLogType.DeleteSoft.ToString(); + bool exception = operationType == DbLogType.Exception.ToString(); + if (login || visit || exit || other || insert || update || delete || deletesoft || exception) + { + ExceptionsLogsEntity info = new ExceptionsLogsEntity + { + Id = YitIdHelper.NextId() + }; + //info.ModuleName = module; + //info.Type = operationType; + //info.Description = note; + //info.Date = info.CreatedTime = DateTime.Now; + //info.CreatedUserId = CurrentUser.UserId; + //info.Account = AdminCurrentUser.Account; + //info.UserName = AdminCurrentUser.UserName; + //info.OrganizeId = AdminCurrentUser.OrganizeId; + //info.IPAddress = AdminCurrentUser.CurrentLoginIP; + //info.IPAddressName = IpAddressUtil.GetCityByIp(AdminCurrentUser.CurrentLoginIP); + //info.Result = true; + long lg = _iLogRepository.Insert(info); + if (lg > 0) + { + return true; + } + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/FeedbackService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/FeedbackService.cs new file mode 100644 index 0000000..f7f8189 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/FeedbackService.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class FeedbackService : BaseService, IFeedbackService + { + private readonly IFeedbackRepository _feedbackRepository; + private readonly IFeedbackPicRepository _feedbackPicRepository; + private readonly IUserRepository _userRepository; + + public FeedbackService(IFeedbackRepository repository, + IFeedbackPicRepository feedbackPicRepository, + IUserRepository userRepository + ) : base(repository) + { + _feedbackRepository = repository; + _feedbackPicRepository = feedbackPicRepository; + _userRepository = userRepository; + } + + /// + /// ҳѯ + /// + /// ѯ + /// + public async Task> FindWithPagerSearchAsync(SearchFeedbackModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + + if (search.State >= 0) + { + @where += $" and State={search.State}"; + } + + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and CreatedTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" and CreatedTime <='{search.EndTime} 23:59:59'"; + } + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = (await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order)).MapTo(); + List usersList = (await _userRepository.GetListWhereAsync(" `State`=10")).MapTo(); + List picList = (await _feedbackPicRepository.GetListWhereAsync(" IsEnabled=true order by Sort")).MapTo(); + foreach (var item in list) + { + var user = usersList.Find(x => x.Id == item.UserId); + + + item.UserName = user.UserName; + item.Phone = user.Phone; + item.AvatarUrl = CommonConst.Default_Image_Prefix + user.AvatarUrl; + item.FeedbackPic = picList.FindAll(x => x.FeedbackId == item.Id).Select(x => CommonConst.Default_FeedbackPic_Prefix + x.PicUrl).ToList(); + } + + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// ༭ + /// + /// + /// + public async Task UpdateAsync(FeedbackEntity input) + { + CommonResult result = new CommonResult(); + FeedbackEntity info = await repository.GetAsync(input.Id); + if (!(info?.Id > 0)) + { + result.Success = false; + result.ErrMsg = "Ϣ"; + return result; + } + info.State = input.State; + await repository.UpdateAsync(info, input.Id).ConfigureAwait(false); + result.Success = true; + + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/IndustryJobsService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/IndustryJobsService.cs new file mode 100644 index 0000000..7bbfc68 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/IndustryJobsService.cs @@ -0,0 +1,148 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// 行业岗位服务 + /// + public class IndustryJobsService : BaseService, + IIndustryJobsService + { + private readonly IIndustryJobsRepository _industryJobsRepository; + + public IndustryJobsService( + IIndustryJobsRepository industryJobsRepository + ) : base(industryJobsRepository) + { + _industryJobsRepository = industryJobsRepository; + } + + /// + /// 获取组织机构适用于Vue 树形列表 + /// + /// + public async Task> GetAllIndustryJobsTreeTable() + { + List reslist = new List(); + IEnumerable elist = await _industryJobsRepository.GetAllAsync(); + List list = elist.OrderBy(t => t.Sort).ToList(); + List oneIndustryJobsList = list.FindAll(t => t.ParentId == 0); + foreach (IndustryJobsEntity item in oneIndustryJobsList) + { + IndustryJobsTreeTableDto industryJobsTreeTable = new IndustryJobsTreeTableDto(); + industryJobsTreeTable = item.MapTo(); + industryJobsTreeTable.Childers = GetSubIndustryJobs(list, item.Id).ToList(); + reslist.Add(industryJobsTreeTable); + } + await GetListByIdAsync(0); + await GetAllListAsync(); + return reslist; + } + + /// + /// 获取子集,递归调用 + /// + /// + /// 父级Id + /// + private List GetSubIndustryJobs(List data, long ParentId) + { + List list = new List(); + IndustryJobsTreeTableDto industryJobsOutputDto = new IndustryJobsTreeTableDto(); + List ChilList = data.FindAll(t => t.ParentId == ParentId); + foreach (IndustryJobsEntity entity in ChilList) + { + industryJobsOutputDto = entity.MapTo(); + industryJobsOutputDto.Childers = GetSubIndustryJobs(data, entity.Id).OrderBy(t => t.Sort) + .MapTo(); + list.Add(industryJobsOutputDto); + } + + return list; + } + + /// + /// 查询行业岗位(树状) + /// + /// + public async Task> GetListByIdAsync(long id) + { + CacheHelper cacheHelper = new CacheHelper(); + List list = cacheHelper.Get>("industryjobs:list"); + if (list == null || list.Count < 1) + { + list = new List(); + IEnumerable industryJobsList = await repository.GetListWhereAsync(" IsDeleted=0 and IsEnabled=1 order by Sort"); + List jobsList = industryJobsList.MapTo(); + foreach (IndustryJobsOutputDto item in jobsList.Where(x => x.ParentId == 0)) + { + IndustryJobsListOutputDto industryJobsListOutput = new IndustryJobsListOutputDto + { + Id = item.Id, + Name = item.Name, + ParentId = item.ParentId, + Sort = item.Sort, + Childers = jobsList.Where(x => x.ParentId == item.Id).ToList() + }; + list.Add(industryJobsListOutput); + } + + cacheHelper.Add("industryjobs:list", list); + } + + if (id > -1) + { + list = list.FindAll(x => x.ParentId == id).ToList(); + } + + return list; + } + + /// + /// 根据id查询行业岗位 + /// + /// + /// + public async Task GetByIdAsync(long id) + { + CacheHelper cacheHelper = new CacheHelper(); + List list = cacheHelper.Get>("allindustryjobs:list"); + if (list == null || list.Count < 1) + { + IEnumerable industryJobsList = await repository.GetListWhereAsync(" IsDeleted=0 and IsEnabled=1 order by Sort"); + list = industryJobsList.MapTo(); + cacheHelper.Add("allindustryjobs:list", list); + } + IndustryJobsOutputDto result = list.Find(x => x.Id == id); + return result; + } + + /// + /// 查询所有行业岗位 + /// + /// + public async Task> GetAllListAsync() + { + CacheHelper cacheHelper = new CacheHelper(); + List list = cacheHelper.Get>("allindustryjobs:list"); + if (list == null || list.Count < 1) + { + IEnumerable industryJobsList = await repository.GetListWhereAsync(" IsDeleted=0 and IsEnabled=1 order by Sort"); + list = industryJobsList.MapTo(); + cacheHelper.Add("allindustryjobs:list", list); + } + return list; + } + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/LoginLogsService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/LoginLogsService.cs new file mode 100644 index 0000000..878e8b2 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/LoginLogsService.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class LoginLogsService : BaseService, ILoginLogsService + { + private readonly ILoginLogsRepository _loginLogsRepository; + private readonly IUserRepository _userRepository; + + /// + /// + /// + /// + public LoginLogsService(ILoginLogsRepository repository, IUserRepository userRepository) : base(repository) + { + _loginLogsRepository = repository; + _userRepository = userRepository; + } + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + public async Task> FindWithPagerSearchAsync(SearchLoginLogsModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + where += string.Format( + " and (UserName like '%{0}%' or IP like '%{0}%' or OS like '%{0}%' or City like '%{0}%' or Result like '%{0}%')", + search.Keywords); + } + + if (search.PlatformType > 0) + { + where += string.Format(" and PlatformType ='{0}'", search.PlatformType); + } + + if (!string.IsNullOrEmpty(search.StartTime)) + { + where += " and CreatedTime >='" + search.StartTime.ToDateTime() + "'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + where += " and CreatedTime <='" + search.EndTime.ToDateTime() + "'"; + } + + if (search.Filter != null) + { + if (!string.IsNullOrEmpty(search.Filter.UserAgent)) + { + where += " and UserAgent='" + search.Filter.UserAgent + "'"; + } + + if (!string.IsNullOrEmpty(search.Filter.IP)) + { + where += string.Format(" and IP = '{0}'", search.Filter.IP); + } + + if (!string.IsNullOrEmpty(search.Filter.OS)) + { + where += string.Format(" and OS = '{0}'", search.Filter.OS); + } + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + + //Expression> filter = log => true; + //if (!string.IsNullOrEmpty(search.Keywords)) + //{ + // filter = filter.And(log => log.Account.StartsWith(search.Keywords) || log.ModuleName.StartsWith(search.Keywords) || log.IPAddress.StartsWith(search.Keywords) + // || log.IPAddressName.StartsWith(search.Keywords) || log.Description.StartsWith(search.Keywords)); + //} + //if (!string.IsNullOrEmpty(search.EnCode)) + //{ + // filter = filter.And(log=>search.EnCode.Contains(log.Type)); + //} + List list = await _loginLogsRepository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// ϢдûIJ־¼ + /// + /// + /// + /// ϸ + /// + public bool OnOperationLog(string tableName, string operationType, string note) + { + try + { + //Ȼʵ¼ǻҪжϸñǷñ棬ڣ򲻼¼־ + //var identities = _httpContextAccessor.HttpContext.User.Identities; + if (HttpContextHelper.HttpContext == null) + { + return false; + } + + IEnumerable identities = HttpContextHelper.HttpContext.User.Identities; + ClaimsIdentity claimsIdentity = identities.First(); + List claimlist = claimsIdentity.Claims as List; + string userId = claimlist[0].Value; + CacheHelper cacheHelper = new CacheHelper(); + AdminCurrentUser AdminCurrentUser = new AdminCurrentUser(); + AdminCurrentUser user = cacheHelper.Get("login_user_" + userId).ToJson().ToObject(); + if (user != null) + { + AdminCurrentUser = user; + bool insert = operationType == DbLogType.Create.ToString(); + ; //&& settingInfo.InsertLog; + bool update = operationType == DbLogType.Update.ToString(); // && settingInfo.UpdateLog; + bool delete = operationType == DbLogType.Delete.ToString(); // && settingInfo.DeleteLog; + bool deletesoft = operationType == DbLogType.DeleteSoft.ToString(); // && settingInfo.DeleteLog; + bool exception = operationType == DbLogType.Exception.ToString(); // && settingInfo.DeleteLog; + bool sql = operationType == DbLogType.SQL.ToString(); // && settingInfo.DeleteLog; + + if (insert || update || delete || deletesoft || exception || sql) + { + //var info = new LoginLogs(); + //info.ModuleName = tableName; + //info.Type = operationType; + //info.Description = note; + //info.Date = info.CreatedTime = DateTime.Now; + //info.CreatedUserId = CurrentUser.UserId; + //info.Account = AdminCurrentUser.Account; + //info.UserName = AdminCurrentUser.UserName; + //info.OrganizeId = AdminCurrentUser.OrganizeId; + //info.IPAddress = AdminCurrentUser.CurrentLoginIP; + //info.IPAddressName = AdminCurrentUser.IPAddressName; + //info.Result = true; + //var lg = _iLoginLogsRepository.Insert(info); + //if (lg > 0) return true; + } + } + } + catch (Exception ex) + { + Log4NetHelper.Error("", ex); + return false; + } + + return false; + } + + /// + /// ϢдûIJ־¼ + /// Ҫдģ־ + /// + /// ģ + /// + /// ϸ + /// û + /// + public bool OnOperationLog(string module, string operationType, string note, AdminCurrentUser AdminCurrentUser) + { + //Ȼʵ¼ǻҪжϸñǷñ棬ڣ򲻼¼־ + //OperationLogSettingInfo settingInfo = BLLFactory.Instance.FindByTableName(tableName, trans); + + if (AdminCurrentUser != null) + { + bool login = operationType == DbLogType.Login.ToString(); + bool visit = operationType == DbLogType.Visit.ToString(); + bool exit = operationType == DbLogType.Exit.ToString(); + bool other = operationType == DbLogType.Other.ToString(); + bool insert = operationType == DbLogType.Create.ToString(); + bool update = operationType == DbLogType.Update.ToString(); + bool delete = operationType == DbLogType.Delete.ToString(); + bool deletesoft = operationType == DbLogType.DeleteSoft.ToString(); + bool exception = operationType == DbLogType.Exception.ToString(); + if (login || visit || exit || other || insert || update || delete || deletesoft || exception) + { + //var info = new Log(); + //info.ModuleName = module; + //info.Type = operationType; + //info.Description = note; + //info.Date = info.CreatedTime = DateTime.Now; + //info.CreatedUserId = CurrentUser.UserId; + //info.Account = AdminCurrentUser.Account; + //info.UserName = AdminCurrentUser.UserName; + //info.OrganizeId = AdminCurrentUser.OrganizeId; + //info.IPAddress = AdminCurrentUser.CurrentLoginIP; + //info.IPAddressName = IpAddressUtil.GetCityByIp(AdminCurrentUser.CurrentLoginIP); + //info.Result = true; + //var lg = _iLogRepository.Insert(info); + //if (lg > 0) return true; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MenuService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MenuService.cs new file mode 100644 index 0000000..f77edc8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MenuService.cs @@ -0,0 +1,262 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Core.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// ˵ + /// + public class MenuService : BaseService, IMenuService + { + private readonly IAdminUserRepository _adminUserRepository; + private readonly IMenuRepository _MenuRepository; + private readonly IRoleAuthorizeRepository roleAuthorizeRepository; + private readonly ISystemTypeRepository systemTypeRepository; + + /// + /// + /// + /// + /// + /// + /// + public MenuService(IMenuRepository repository, IAdminUserRepository adminUserRepository, + IRoleAuthorizeRepository _roleAuthorizeRepository, ISystemTypeRepository _systemTypeRepository + ) : base(repository) + { + _MenuRepository = repository; + _adminUserRepository = adminUserRepository; + roleAuthorizeRepository = _roleAuthorizeRepository; + systemTypeRepository = _systemTypeRepository; + } + + /// + /// ûȡܲ˵ + /// + /// ûID + /// + public List GetMenuByUser(long userId) + { + List result = new List(); + List allMenuls = new List(); + List subMenuls = new List(); + string where = "Layers=1"; + IEnumerable allMenus = _MenuRepository.GetAllByIsNotDeleteAndEnabledMark(); + allMenuls = allMenus.ToList(); + if (userId.ToString() == string.Empty) //Ա + { + return allMenuls; + } + + AdminUserEntity user = _adminUserRepository.Get(userId); + if (user == null) + { + return result; + } + + long userRoles = user.RoleId; + where = string.Format("ItemType = 1 and ObjectType = 1 and ObjectId='{0}'", userRoles); + IEnumerable Menus = roleAuthorizeRepository.GetListWhere(where); + foreach (RoleAuthorizeEntity item in Menus) + { + MenuEntity MenuEntity = allMenuls.Find(t => t.Id == item.ItemId); + if (MenuEntity != null) + { + result.Add(MenuEntity); + } + } + + return result.OrderBy(t => t.SortCode).ToList(); + } + + /// + /// ȡܲ˵Vue б + /// + /// ϵͳId + /// + public async Task> GetAllMenuTreeTable(string systemTypeId) + { + string where = "1=1"; + List reslist = new List(); + if (!string.IsNullOrEmpty(systemTypeId)) + { + IEnumerable elist = await _MenuRepository.GetListWhereAsync("SystemTypeId='" + systemTypeId + "'"); + List list = elist.OrderBy(t => t.SortCode).ToList(); + List oneMenuList = list.FindAll(t => t.ParentId == 0); + foreach (MenuEntity item in oneMenuList) + { + MenuTreeTableOutputDto menuTreeTableOutputDto = new MenuTreeTableOutputDto(); + menuTreeTableOutputDto = item.MapTo(); + menuTreeTableOutputDto.Children = GetSubMenus(list, item.Id).ToList(); + reslist.Add(menuTreeTableOutputDto); + } + } + else + { + IEnumerable listSystemType = await systemTypeRepository.GetListWhereAsync(where); + + foreach (SystemTypeEntity systemType in listSystemType) + { + MenuTreeTableOutputDto menuTreeTableOutputDto = new MenuTreeTableOutputDto + { + Id = systemType.Id, + FullName = systemType.FullName, + EnCode = systemType.EnCode, + UrlAddress = systemType.Url, + IsEnabled = systemType.IsEnabled, + + SystemTag = true + }; + + IEnumerable elist = await _MenuRepository.GetListWhereAsync("SystemTypeId='" + systemType.Id + "'"); + if (elist.Count() > 0) + { + List list = elist.OrderBy(t => t.SortCode).ToList(); + menuTreeTableOutputDto.Children = GetSubMenus(list, 0).ToList(); + } + + reslist.Add(menuTreeTableOutputDto); + } + } + + return reslist; + } + + /// + /// ݽɫIDַŷֿ)ϵͳIDȡӦIJб + /// + /// ɫID + /// ϵͳID + /// ǷDz˵ + /// + public List GetFunctions(string roleIds, string typeID, bool isMenu = false) + { + return _MenuRepository.GetFunctions(roleIds, typeID, isMenu).ToList(); + } + + /// + /// ϵͳIDȡӦIJб + /// + /// ϵͳID + /// + public List GetFunctions(string typeID) + { + return _MenuRepository.GetFunctions(typeID).ToList(); + } + + /// + /// ݸܱѯӼܣҪҳťȨ + /// + /// ˵ܱ + /// + public async Task> GetListByParentEnCode(string enCode) + { + string where = string.Format("EnCode='{0}'", enCode); + MenuEntity function = await repository.GetWhereAsync(where); + where = string.Format("ParentId='{0}'", function.ParentId); + IEnumerable list = await repository.GetAllByIsNotEnabledMarkAsync(where); + return list.MapTo().ToList(); + } + + /// + /// ɾ + /// + /// Id + /// + /// + public CommonResult DeleteBatchWhere(DeletesInputDto idsInfo, IDbTransaction trans = null) + { + CommonResult result = new CommonResult(); + string where = string.Empty; + for (long i = 0; i < idsInfo.Ids.Length; i++) + { + if (idsInfo.Ids[0] != null) + { + @where = string.Format("ParentId='{0}'", idsInfo.Ids[0]); + IEnumerable list = _MenuRepository.GetListWhere(@where); + if (list.Count() > 0) + { + result.ErrMsg = "ܴӼݣɾ"; + return result; + } + } + } + + where = "id in ('" + idsInfo.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + bool bl = repository.DeleteBatchWhere(where); + if (bl) + { + result.ErrCode = "0"; + } + + return result; + } + + /// + /// ɾ + /// + /// Id + /// + /// + public async Task DeleteBatchWhereAsync(DeletesInputDto idsInfo, IDbTransaction trans = null) + { + CommonResult result = new CommonResult(); + string where = string.Empty; + for (long i = 0; i < idsInfo.Ids.Length; i++) + { + if (idsInfo.Ids[0].ToString().Length > 0) + { + @where = string.Format("ParentId='{0}'", idsInfo.Ids[0]); + IEnumerable list = _MenuRepository.GetListWhere(@where); + if (list.Count() > 0) + { + result.ErrMsg = "ܴӼݣɾ"; + return result; + } + } + } + + where = "id in ('" + idsInfo.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + bool bl = await repository.DeleteBatchWhereAsync(where); + if (bl) + { + result.ErrCode = "0"; + } + + return result; + } + + /// + /// ȡӲ˵ݹ + /// + /// + /// Id + /// + private List GetSubMenus(List data, long ParentId) + { + List list = new List(); + MenuTreeTableOutputDto menuTreeTableOutputDto = new MenuTreeTableOutputDto(); + List ChilList = data.FindAll(t => t.ParentId == ParentId); + foreach (MenuEntity entity in ChilList) + { + menuTreeTableOutputDto = entity.MapTo(); + menuTreeTableOutputDto.Children = GetSubMenus(data, entity.Id).OrderBy(t => t.SortCode) + .MapTo(); + list.Add(menuTreeTableOutputDto); + } + + return list; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MessageLogsService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MessageLogsService.cs new file mode 100644 index 0000000..bd6a4d4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MessageLogsService.cs @@ -0,0 +1,109 @@ +using System; +using System.Data; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class MessageLogsService : BaseService, IMessageLogsService + { + private readonly IMessageLogsRepository _messageLogsRepository; + private readonly IMessageRepository _messageRepository; + + public MessageLogsService( + IMessageLogsRepository messageLogsRepository, + IMessageRepository messageRepository + ) : base(messageLogsRepository) + { + _messageLogsRepository = messageLogsRepository; + _messageRepository = messageRepository; + } + + /// + /// ͬʵ塣 + /// + /// ʵ + /// + /// + public override long Insert(MessageLogsEntity entity, IDbTransaction trans = null) + { + entity.Id = YitIdHelper.NextId(); + long result = repository.Insert(entity, trans); + return result; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// ID + /// + /// + public override async Task UpdateAsync(MessageLogsEntity entity, long id, IDbTransaction trans = null) + { + bool result = await repository.UpdateAsync(entity, id, trans); + return result; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// + /// + public override async Task InsertAsync(MessageLogsEntity entity, IDbTransaction trans = null) + { + entity.Id = YitIdHelper.NextId(); + int result = await repository.InsertAsync(entity, trans); + return result; + } + + /// + /// Ϣ¼ + /// + /// + /// + public async Task AddAsync(MessageInputDto input) + { + MessageEntity entity = new MessageEntity + { + Id = YitIdHelper.NextId(), + SendId = input.CreatedUserId, + EquipmentId = input.EquipmentId, + EquipmentTitle = input.EquipmentTitle, + MessageTitle = input.MessageTitle, + GroupId = 0, + Content = "", + SendTime = DateTime.Now, + CreatedTime = DateTime.Now, + CreatedUserId = input.CreatedUserId, + ModifiedTime = DateTime.Now + + }; + int id = await _messageRepository.InsertAsync(entity); + MessageLogsEntity messageLogs = new MessageLogsEntity + { + Id = YitIdHelper.NextId(), + ReceiverId = input.UserId, + MessageId = entity.Id, + State = 0, //δ + CreatedTime = DateTime.Now, + ModifiedTime = DateTime.Now, + CreatedUserId = input.CreatedUserId + }; + await _messageLogsRepository.InsertAsync(messageLogs); + CacheHelper cacheHelper = new CacheHelper(); + string key = string.Format("unread:number:{0}", input.UserId); + cacheHelper.Remove(key); + return true; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MessageService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MessageService.cs new file mode 100644 index 0000000..42e5b22 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/MessageService.cs @@ -0,0 +1,64 @@ +using System.Data; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class MessageService : BaseService, IMessageService + { + private readonly IMessageRepository _messageRepository; + + public MessageService( + IMessageRepository repository + ) : base(repository) + { + _messageRepository = repository; + } + + /// + /// ͬʵ塣 + /// + /// ʵ + /// + /// + public override long Insert(MessageEntity entity, IDbTransaction trans = null) + { + entity.Id = YitIdHelper.NextId(); + long result = repository.Insert(entity, trans); + return result; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// ID + /// + /// + public override async Task UpdateAsync(MessageEntity entity, long id, IDbTransaction trans = null) + { + bool result = await repository.UpdateAsync(entity, id, trans); + return result; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// + /// + public override async Task InsertAsync(MessageEntity entity, IDbTransaction trans = null) + { + entity.Id = YitIdHelper.NextId(); + int result = await repository.InsertAsync(entity, trans); + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OperationLogsService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OperationLogsService.cs new file mode 100644 index 0000000..3ad557e --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OperationLogsService.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// ־ + /// + public class OperationLogsService : BaseService, + IOperationLogsService + { + private readonly IOperationLogsRepository _operationLogsRepository; + private readonly IUserRepository _userRepository; + + /// + /// + /// + /// + public OperationLogsService(IOperationLogsRepository repository, + IUserRepository userRepository + ) : base(repository) + { + _operationLogsRepository = repository; + _userRepository = userRepository; + } + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + public async Task> FindWithPagerSearchAsync(SearchOperationLogsModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.StartTime)) + { + where += " and CreatedTime >='" + search.StartTime.ToDateTime() + "'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + where += " and CreatedTime <='" + search.EndTime.ToDateTime() + "'"; + } + + if (search.Filter != null) + { + if (!string.IsNullOrEmpty(search.Filter.IP)) + { + where += string.Format(" and IP = '{0}'", search.Filter.IP); + }; + if (!string.IsNullOrEmpty(search.Filter.UserName)) + { + where += string.Format(" and UserName = '{0}'", search.Filter.UserName); + }; + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + + //Expression> filter = log => true; + //if (!string.IsNullOrEmpty(search.Keywords)) + //{ + // filter = filter.And(log => log.Account.StartsWith(search.Keywords) || log.ModuleName.StartsWith(search.Keywords) || log.IPAddress.StartsWith(search.Keywords) + // || log.IPAddressName.StartsWith(search.Keywords) || log.Description.StartsWith(search.Keywords)); + //} + //if (!string.IsNullOrEmpty(search.EnCode)) + //{ + // filter = filter.And(log=>search.EnCode.Contains(log.Type)); + //} + List list = await _operationLogsRepository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// ϢдûIJ־¼ + /// + /// + /// + /// ϸ + /// + public bool OnOperationLog(string tableName, string operationType, string note) + { + try + { + //Ȼʵ¼ǻҪжϸñǷñ棬ڣ򲻼¼־ + //var identities = _httpContextAccessor.HttpContext.User.Identities; + if (HttpContextHelper.HttpContext == null) + { + return false; + } + + IEnumerable identities = HttpContextHelper.HttpContext.User.Identities; + ClaimsIdentity claimsIdentity = identities.First(); + List claimlist = claimsIdentity.Claims as List; + string userId = claimlist[0].Value; + CacheHelper cacheHelper = new CacheHelper(); + AdminCurrentUser AdminCurrentUser = new AdminCurrentUser(); + AdminCurrentUser user = cacheHelper.Get("login_user_" + userId).ToJson().ToObject(); + if (user != null) + { + AdminCurrentUser = user; + bool insert = operationType == DbLogType.Create.ToString(); + ; //&& settingInfo.InsertLog; + bool update = operationType == DbLogType.Update.ToString(); // && settingInfo.UpdateLog; + bool delete = operationType == DbLogType.Delete.ToString(); // && settingInfo.DeleteLog; + bool deletesoft = operationType == DbLogType.DeleteSoft.ToString(); // && settingInfo.DeleteLog; + bool exception = operationType == DbLogType.Exception.ToString(); // && settingInfo.DeleteLog; + bool sql = operationType == DbLogType.SQL.ToString(); // && settingInfo.DeleteLog; + + if (insert || update || delete || deletesoft || exception || sql) + { + OperationLogsEntity info = new OperationLogsEntity + { + Id = YitIdHelper.NextId(), + //info.ModuleName = tableName; + //info.Type = operationType; + //info.Description = note; + //info.Date = info.CreatedTime = DateTime.Now; + //info.CreatedUserId = CurrentUser.UserId; + //info.Account = AdminCurrentUser.Account; + //info.UserName = AdminCurrentUser.UserName; + //info.OrganizeId = AdminCurrentUser.OrganizeId; + //info.IPAddress = AdminCurrentUser.CurrentLoginIP; + //info.IPAddressName = AdminCurrentUser.IPAddressName; + //info.Result = true; + CRUD = operationType, + UserName = AdminCurrentUser.UserName + }; + info.OperationTime = info.CreatedTime = DateTime.Now; + info.IP = AdminCurrentUser.CurrentLoginIP; + long lg = _operationLogsRepository.Insert(info); + if (lg > 0) + { + return true; + } + } + } + } + catch (Exception ex) + { + Log4NetHelper.Error("", ex); + return false; + } + + return false; + } + + /// + /// ϢдûIJ־¼ + /// Ҫдģ־ + /// + /// ģ + /// + /// ϸ + /// û + /// + public bool OnOperationLog(string module, string operationType, string note, AdminCurrentUser AdminCurrentUser) + { + //Ȼʵ¼ǻҪжϸñǷñ棬ڣ򲻼¼־ + //OperationLogSettingInfo settingInfo = BLLFactory.Instance.FindByTableName(tableName, trans); + + if (AdminCurrentUser != null) + { + bool login = operationType == DbLogType.Login.ToString(); + bool visit = operationType == DbLogType.Visit.ToString(); + bool exit = operationType == DbLogType.Exit.ToString(); + bool other = operationType == DbLogType.Other.ToString(); + bool insert = operationType == DbLogType.Create.ToString(); + bool update = operationType == DbLogType.Update.ToString(); + bool delete = operationType == DbLogType.Delete.ToString(); + bool deletesoft = operationType == DbLogType.DeleteSoft.ToString(); + bool exception = operationType == DbLogType.Exception.ToString(); + if (login || visit || exit || other || insert || update || delete || deletesoft || exception) + { + OperationLogsEntity info = new OperationLogsEntity + { + Id = YitIdHelper.NextId() + }; + //info.ModuleName = module; + //info.Type = operationType; + //info.Description = note; + //info.Date = info.CreatedTime = DateTime.Now; + //info.CreatedUserId = CurrentUser.UserId; + //info.Account = AdminCurrentUser.Account; + //info.UserName = AdminCurrentUser.UserName; + //info.OrganizeId = AdminCurrentUser.OrganizeId; + //info.IPAddress = AdminCurrentUser.CurrentLoginIP; + //info.IPAddressName = IpAddressUtil.GetCityByIp(AdminCurrentUser.CurrentLoginIP); + //info.Result = true; + long lg = _operationLogsRepository.Insert(info); + if (lg > 0) + { + return true; + } + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrderDetailService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrderDetailService.cs new file mode 100644 index 0000000..24252b8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrderDetailService.cs @@ -0,0 +1,18 @@ +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class OrderDetailService : BaseService, IOrderDetailService + { + private readonly IOrderDetailRepository _orderDetailRepository; + + public OrderDetailService(IOrderDetailRepository repository) : base(repository) + { + _orderDetailRepository = repository; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrderService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrderService.cs new file mode 100644 index 0000000..fa93218 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrderService.cs @@ -0,0 +1,18 @@ +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class OrderService : BaseService, IOrderService + { + private readonly IOrderRepository _orderRepository; + + public OrderService(IOrderRepository repository) : base(repository) + { + _orderRepository = repository; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrganizeService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrganizeService.cs new file mode 100644 index 0000000..9a3de15 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/OrganizeService.cs @@ -0,0 +1,154 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Core.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// ֯ + /// + public class OrganizeService : BaseService, IOrganizeService + { + private readonly IOrganizeRepository _repository; + + /// + /// + /// + /// + public OrganizeService(IOrganizeRepository repository) : base(repository) + { + _repository = repository; + } + + /// + /// ȡ֯Vue б + /// + /// + public async Task> GetAllOrganizeTreeTable() + { + List reslist = new List(); + IEnumerable elist = await _repository.GetAllAsync(); + List list = elist.OrderBy(t => t.SortCode).ToList(); + List oneMenuList = list.FindAll(t => t.ParentId == 0); + foreach (OrganizeEntity item in oneMenuList) + { + OrganizeOutputDto menuTreeTableOutputDto = new OrganizeOutputDto(); + menuTreeTableOutputDto = item.MapTo(); + menuTreeTableOutputDto.Children = GetSubOrganizes(list, item.Id).ToList(); + reslist.Add(menuTreeTableOutputDto); + } + + return reslist; + } + + /// + /// ȡڵ֯ + /// + /// ֯Id + /// + public OrganizeEntity GetRootOrganize(long id) + { + return _repository.Get(id); + } + + /// + /// ɾ + /// + /// Id + /// + /// + public CommonResult DeleteBatchWhere(DeletesInputDto idsInfo, IDbTransaction trans = null) + { + CommonResult result = new CommonResult(); + string where = string.Empty; + for (long i = 0; i < idsInfo.Ids.Length; i++) + { + if (idsInfo.Ids[0] != null) + { + @where = string.Format("ParentId='{0}'", idsInfo.Ids[0]); + IEnumerable list = _repository.GetListWhere(@where); + if (list.Count() > 0) + { + result.ErrMsg = "ܴӼݣɾ"; + return result; + } + } + } + + where = "id in ('" + idsInfo.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + bool bl = repository.DeleteBatchWhere(where); + if (bl) + { + result.ErrCode = "0"; + } + + return result; + } + + /// + /// ɾ + /// + /// Id + /// + /// + public async Task DeleteBatchWhereAsync(DeletesInputDto idsInfo, IDbTransaction trans = null) + { + CommonResult result = new CommonResult(); + string where = string.Empty; + for (long i = 0; i < idsInfo.Ids.Length; i++) + { + if (idsInfo.Ids[0].ToString().Length > 0) + { + @where = string.Format("ParentId='{0}'", idsInfo.Ids[0]); + IEnumerable list = _repository.GetListWhere(@where); + if (list.Count() > 0) + { + result.ErrMsg = "ûӼݣɾ"; + return result; + } + } + } + + where = "id in ('" + idsInfo.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + bool bl = await repository.DeleteBatchWhereAsync(where); + if (bl) + { + result.ErrCode = "0"; + } + + return result; + } + + /// + /// ȡӼݹ + /// + /// + /// Id + /// + private List GetSubOrganizes(List data, long ParentId) + { + List list = new List(); + OrganizeOutputDto OrganizeOutputDto = new OrganizeOutputDto(); + List ChilList = data.FindAll(t => t.ParentId == ParentId); + foreach (OrganizeEntity entity in ChilList) + { + OrganizeOutputDto = entity.MapTo(); + OrganizeOutputDto.Children = GetSubOrganizes(data, entity.Id).OrderBy(t => t.SortCode) + .MapTo(); + list.Add(OrganizeOutputDto); + } + + return list; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/PaymentRecordService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/PaymentRecordService.cs new file mode 100644 index 0000000..5c14d08 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/PaymentRecordService.cs @@ -0,0 +1,93 @@ +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// ֵ + /// + public class PaymentRecordService : BaseService, IPaymentRecordService + { + private readonly IPaymentRecordRepository _PaymentRecordRepository; + private readonly ICurrencyRepository _currencyRepository; + private readonly IUserRepository _userRepository; + + public PaymentRecordService( + IUserRepository userRepository, + ICurrencyRepository currencyRepository, + IPaymentRecordRepository PaymentRecordRepository + ) : base(PaymentRecordRepository) + { + _userRepository = userRepository; + _currencyRepository = currencyRepository; + _PaymentRecordRepository = PaymentRecordRepository; + } + + + /// + /// Ʊб + /// + /// + /// + /// + public async Task> FindWithPagerSearchAsync(SearchPaymentRecordModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + @where += " and PayStatus=20"; + + // + if (search.PaymentMoney > 0) + { + @where += $" and PaymentMoney={search.PaymentMoney}"; + } + //ʼʱ + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and CreatedTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" and CreatedTime <='{search.EndTime} 23:59:59'"; + } + + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + //ѯֵ¼ + System.Collections.Generic.List list = (await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order)).MapTo(); + //ȡûϢ(黺) + System.Collections.Generic.List users = (await _userRepository.GetListWhereAsync(" `State`=10")).MapTo(); + + foreach (PaymentRecordOutputDto item in list) + { + UserOutputDto user = users.Find(x => x.Id == item.UserId); + item.UserName = user?.UserName; + item.AvatarUrl = CommonConst.Default_Image_Prefix + user?.AvatarUrl; + item.Phone = user?.Phone; + // item = EnumExtensions.ParseEnum(typeof(OperatingTypeEnum), item.OperatingType.ToString()).ToDescription(); + // item.CurrencyTypeName = EnumExtensions.ParseEnum(typeof(OperatingCreditsTypeEnum), item.CurrencyType.ToString()).ToDescription(); + } + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RechargeService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RechargeService.cs new file mode 100644 index 0000000..a056272 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RechargeService.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// ֵ + /// + public class RechargeService : BaseService, IRechargeService + { + private readonly IRechargeRepository _rechargeRepository; + private readonly IRechargeIntroRepository _rechargeIntroRepository; + + public RechargeService( + IRechargeRepository repository, + IRechargeIntroRepository rechargeIntroRepository + ) : base(repository) + { + _rechargeRepository = repository; + _rechargeIntroRepository = rechargeIntroRepository; + } + + + /// + /// ҳѯ + /// + /// + /// + public async Task> FindWithPagerSearchAsync(SearchRechargeModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (search.State >= 0) + { + @where += $" and State={search.State}"; + } + + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and StartTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" or EndTime <='{search.EndTime} 23:59:59'"; + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = (await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order)).MapTo(); + foreach (var item in list) + { + item.StatusName = EnumExtensions + .ParseEnum(typeof(ActivityStatusEnum), item.State.ToString()).ToDescription(); + item.rechargeIntros = (await _rechargeIntroRepository.GetListWhereAsync($" ParentId={item.Id}")).MapTo(); + } + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 첽ֵ + /// + /// + /// + /// + /// + public async Task InsertRechargeIntroAsync(List input, long parentId, long userId) + { + //رֵ + RechargeEntity rechargeEntity = await _rechargeRepository.GetWhereAsync($" IsDeleted=0 and State=1 and Id!={parentId}"); + if (rechargeEntity != null) + { + rechargeEntity.State = (int)ActivityStatusEnum.End; + await repository.UpdateAsync(rechargeEntity, rechargeEntity.Id).ConfigureAwait(false); + } + foreach (var item in input) + { + RechargeIntroEntity entity = new RechargeIntroEntity() + { + Id = YitIdHelper.NextId(), + ParentId = parentId, + ProductName = string.Format(CommonConst.RechargeIntro_Name, item.ProductValue), + ProductValue = item.ProductValue, + SendValue = item.SendValue, + AllValue = item.ProductValue + item.SendValue, + Price = item.Price, + Description = string.Format(CommonConst.RechargeIntro_Description, item.ProductValue + item.SendValue), + CreatedUserId = userId, + CreatedTime = DateTime.Now + }; + await _rechargeIntroRepository.InsertAsync(entity); + } + return true; + } + + /// + /// 첽 + /// + /// + /// + /// + public async Task UpdateAsync(RechargeUpdateInput input, long userId) + { + CommonResult result = new CommonResult(); + RechargeEntity info = await repository.GetAsync(input.Id); + if (!(info?.Id > 0)) + { + result.Success = false; + result.ErrMsg = "ֵϢ"; + return result; + } + info.Name = input.Name; + info.State = (int)ActivityStatusEnum.Ongoing; + info.ModifiedUserId = userId; + info.ModifiedTime = DateTime.Now; + foreach (var item in input.rechargeIntros) + { + RechargeIntroEntity entity = await _rechargeIntroRepository.GetAsync(item.Id); + entity.ProductName = string.Format(CommonConst.RechargeIntro_Name, item.ProductValue); + entity.ProductValue = item.ProductValue; + entity.SendValue = item.SendValue; + entity.AllValue = item.ProductValue + item.SendValue; + entity.Price = item.Price; + entity.Description = string.Format(CommonConst.RechargeIntro_Description, item.ProductValue + item.SendValue); + entity.ModifiedUserId = userId; + entity.ModifiedTime = DateTime.Now; + await _rechargeIntroRepository.UpdateAsync(entity, entity.Id).ConfigureAwait(false); + } + await repository.UpdateAsync(info, input.Id).ConfigureAwait(false); + //رֵ + RechargeEntity rechargeEntity = await _rechargeRepository.GetWhereAsync($" IsDeleted=0 and State=1 and Id!={input.Id}"); + if (rechargeEntity != null) + { + rechargeEntity.State = (int)ActivityStatusEnum.End; + await repository.UpdateAsync(rechargeEntity, rechargeEntity.Id).ConfigureAwait(false); + } + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RecruitmentService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RecruitmentService.cs new file mode 100644 index 0000000..a696097 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RecruitmentService.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// 招聘服务 + /// + public class CloudcarService : BaseService, ICloudcarService + { + private readonly IAuditRepository _auditRepository; + private readonly IDictionaryService _dictionaryService; + private readonly IIndustryJobsService _industryJobsService; + private readonly ICloudcarRepository _CloudcarRepository; + private readonly IRegionRepository _regionRepository; + private readonly IUserRepository _userRepository; + private readonly IWxUnifyUserRepository _wxUnifyUserRepository; + private readonly ICallFeedbackRepository _callFeedbackRepository; + + public CloudcarService( + ICloudcarRepository repository, + IDictionaryService dictionaryService, + IIndustryJobsService industryJobsService, + IRegionRepository regionRepository, + IAuditRepository auditRepository, + IUserRepository userRepository, + IWxUnifyUserRepository wxUnifyUserRepository, + ICallFeedbackRepository callFeedbackRepository + ) : base(repository) + { + _CloudcarRepository = repository; + _dictionaryService = dictionaryService; + _industryJobsService = industryJobsService; + _regionRepository = regionRepository; + _auditRepository = auditRepository; + _userRepository = userRepository; + _wxUnifyUserRepository = wxUnifyUserRepository; + _callFeedbackRepository = callFeedbackRepository; + } + + /// + /// 异步新增数据 + /// + /// ʵ�� + /// + public async Task InsertAsync(CloudcarEntity intput) + { + CommonResult result = new CommonResult(); + intput.Id = YitIdHelper.NextId(); + intput.State = (int)ProductStatusEnum.Review; + intput.UserId = 1; + intput.IsPublic = true; + intput.AreaId = 0; + intput.SerialNumber = + StringHelper.GetSerialNumber(ProductTypeEnum.Cloudcar, intput.IndustryId, intput.JobId); + intput.ModifiedTime = DateTime.Now; + intput.RefreshDate = DateTime.Now; + result.Success = await repository.InsertAsync(intput) > 0 ? true : false; + return result; + } + + /// + /// 异步修改数据 + /// + /// + /// + public async Task UpdateAsync(CloudcarEntity tinfo) + { + CommonResult result = new CommonResult(); + CloudcarEntity info = await repository.GetAsync(tinfo.Id); + if (!(info?.Id > 0)) + { + result.Success = false; + result.ErrMsg = "招聘信息不存在"; + return result; + } + + info.Title = tinfo.Title; + info.Content = tinfo.Content; + info.Phone = tinfo.Phone; + info.IndustryId = tinfo.IndustryId; + info.JobId = tinfo.JobId; + info.ProvinceId = tinfo.ProvinceId; + info.CityId = tinfo.CityId; + info.State = tinfo.State; + info.IsTop = tinfo.IsTop; + info.IsPublic = tinfo.IsPublic; + info.TopExpireDate = tinfo.TopExpireDate; + info.Welfare = tinfo.Welfare; + info.Address = tinfo.Address; + info.ModifiedTime = tinfo.ModifiedTime; + info.ModifiedUserId = tinfo.ModifiedUserId; + await repository.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + result.Success = true; + return result; + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 指定对象的集合 + public async Task> FindWithPagerSearchAsync(SearchCloudcarModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += $" and (Title like '%{search.Keywords}%' or Content like '%{search.Keywords}%' or Phone like '%{search.Keywords}%' " + + $"or SerialNumber like '%{search.Keywords}%' or Address like '%{search.Keywords}%')"; + } + + //if (search.State == (int)ProductStatusEnum.Pass) + //{ + // @where += $" and (State=1 or State=2 )"; + //} + + //if (search.State >= 0 && search.State != (long)ProductStatusEnum.Pass) + //{ + // @where += $" and State={search.State}"; + //} + + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += $" and ModifiedTime >='{search.StartTime} 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += $" and ModifiedTime <='{search.EndTime} 23:59:59'"; + } + + if (search.industryId > 0) + { + @where += $" and IndustryId={search.industryId}"; + } + + if (search.jobId > 0) + { + @where += $" and JobId={search.jobId}"; + } + + List users = (await _userRepository.GetListWhereAsync(" `State`=10")).MapTo(); + if (!string.IsNullOrEmpty(search.UserName)) + { + List uIds = users.Where(x => x.UserName.Contains(search.UserName)).Select(x => x.Id).ToList(); + @where += $" and UserId in ({string.Join(",", uIds.ToArray())})"; + } + //行业岗位 + List industryJobs = await _industryJobsService.GetAllListAsync(); + //福利待遇 + List welfares = await _dictionaryService.GetListByPidAsync(CommonConst.Dictionary_Welfare); + //云平台统一用户信息 + List uninIds = users.Select(x => x.UnionId).ToList(); + List wxUnifyUsers = (await _wxUnifyUserRepository.GetListWhereAsync($" IsDeleted=0 AND UnionId IN ('{string.Join("','", uninIds.ToArray())}')")) + .MapTo(); + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + List listDto = list.MapTo(); + foreach (CloudcarOutputDto item in listDto) + { + item.IndustryName = industryJobs.Find(x => x.Id == item.IndustryId)?.Name; + item.JobName = industryJobs.Find(x => x.Id == item.JobId)?.Name; + string[] welfare = item.Welfare.Split(","); + item.WelfareList = welfares.FindAll(x => welfare.Contains(x.Id.ToString())); + UserOutputDto user = users.Find(x => x.Id == item.UserId); + item.UserName = user?.UserName ?? CommonConst.Default_UserName; + item.AvatarUrl = CommonConst.Default_Image_Prefix + (user?.AvatarUrl ?? CommonConst.Default_AvataUrl); + item.Top = item.IsTop ? "已置顶" : "未置顶"; + item.TopExpireDate = item.IsTop ? item.TopExpireDate : null; + item.Public = item.IsPublic ? "已公开" : "未公开"; + item.StatusName = EnumExtensions + .ParseEnum(typeof(ProductStatusEnum), item.State.ToString()).ToDescription(); + if (item.State == (int)ProductStatusEnum.Fail) + { + string key = $" ProductId={item.Id} AND ProductType=2 AND HandleStatus={item.State} ORDER BY CreatedTime DESC LIMIT 1"; + item.Note = (await _auditRepository.GetWhereAsync(key))?.Note ?? ""; + } + item.NickName = wxUnifyUsers.Find(x => x.UnionId == user.UnionId)?.NickName ?? CommonConst.Default_UserName; + item.WxAvatarUrl = wxUnifyUsers.Find(x => x.UnionId == user.UnionId)?.AvatarUrl ?? (CommonConst.Default_Image_Prefix + CommonConst.Default_AvataUrl); + //通话评价 + item.CallFeedbacks = (await _callFeedbackRepository.GetListWhereAsync($" ProductId={item.Id} AND ProductType=2")).MapTo(); + foreach (var callFeedback in item.CallFeedbacks) + { + var callUser = users.Find(x => x.Id == callFeedback.UserId); + callFeedback.Phone = callUser.Phone; + callFeedback.NickName = wxUnifyUsers.Find(x => x.UnionId == callUser.UnionId)?.NickName ?? CommonConst.Default_UserName; + callFeedback.WxAvatarUrl = wxUnifyUsers.Find(x => x.UnionId == callUser.UnionId)?.AvatarUrl ?? (CommonConst.Default_Image_Prefix + CommonConst.Default_AvataUrl); + callFeedback.Content = EnumExtensions + .ParseEnum(typeof(CallFeedbackStatusEnum), callFeedback.State.ToString()).ToDescription(); + if (callFeedback.IsRead == false && item.IsReadForCallFeedback == false) + { + item.IsReadForCallFeedback = true; + } + } + } + + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = listDto, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + + /// + /// + /// + /// + /// + public async Task GetById(long id) + { + CloudcarOutputDto CloudcarDto = await GetOutDtoAsync(id); + //行业岗位 + List industryJobs = await _industryJobsService.GetAllListAsync(); + //福利待遇 + List welfares = await _dictionaryService.GetListByPidAsync(CommonConst.Dictionary_Welfare); + + List users = (await _userRepository.GetListWhereAsync(" `State`=10")).MapTo(); + + CloudcarDto.IndustryName = industryJobs.Find(x => x.Id == CloudcarDto.IndustryId)?.Name; + CloudcarDto.JobName = industryJobs.Find(x => x.Id == CloudcarDto.JobId)?.Name; + string[] welfare = CloudcarDto.Welfare.Split(","); + CloudcarDto.WelfareList = welfares.FindAll(x => welfare.Contains(x.Id.ToString())); + UserOutputDto user = users.Find(x => x.Id == CloudcarDto.UserId); + CloudcarDto.UserName = user?.UserName ?? CommonConst.Default_UserName; + CloudcarDto.AvatarUrl = CommonConst.Default_Image_Prefix + (user?.AvatarUrl ?? CommonConst.Default_AvataUrl); + CloudcarDto.Top = CloudcarDto.IsTop ? "已置顶" : "未置顶"; + CloudcarDto.TopExpireDate = CloudcarDto.IsTop ? CloudcarDto.TopExpireDate : null; + CloudcarDto.Public = CloudcarDto.IsPublic ? "已公开" : "未公开"; + CloudcarDto.StatusName = EnumExtensions + .ParseEnum(typeof(ProductStatusEnum), CloudcarDto.State.ToString()).ToDescription(); + return CloudcarDto; + } + + /// + /// 下架招聘信息 + /// + /// + /// + /// + public async Task RevocationAsync(long id, long userId) + { + CommonResult result = new CommonResult(); + CloudcarEntity info = await repository.GetAsync(id); + if (!(info?.Id > 0)) + { + result.Success = false; + result.ErrMsg = "招聘信息不存在"; + return result; + } + info.State = (int)ProductStatusEnum.Cancel; + info.ModifiedUserId = userId; + info.ModifiedTime = DateTime.Now; + await repository.UpdateAsync(info, info.Id).ConfigureAwait(false); + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RegionService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RegionService.cs new file mode 100644 index 0000000..441dfc1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RegionService.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// Ϣ + /// + public class RegionService : BaseService, IRegionService + { + private readonly IRegionRepository _regionRepository; + + public RegionService(IRegionRepository regionRepository) : base(regionRepository) + { + _regionRepository = regionRepository; + } + + /// + /// ѯʡ + /// + /// + public async Task> GetAllRegionList() + { + CacheHelper cacheHelper = new CacheHelper(); + List list = cacheHelper.Get>("region:list "); + if (list == null) + { + list = await AsyncRegionCache(); + } + + return list; + } + + /// + /// ͬ + /// + /// + public async Task> AsyncRegionCache() + { + List regionList = new List(); + CacheHelper cacheHelper = new CacheHelper(); + IEnumerable list = await _regionRepository.GetListWhereAsync(" ParentId=0"); + foreach (RegionEntity item in list) + { + RegionOutputDto regionListOutputs = new RegionOutputDto + { + RegionId = item.RegionId, + Name = item.Name, + ParentId = item.ParentId + }; + string where = string.Format(@" IsDeleted = 0 and ParentId = {0}", item.RegionId); + IEnumerable regions = await _regionRepository.GetListWhereAsync(where); + regionListOutputs.Childers = regions.MapTo(); + regionList.Add(regionListOutputs); + } + + cacheHelper.Add("region:list ", regionList, TimeSpan.FromDays(30)); + return regionList; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleAuthorizeService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleAuthorizeService.cs new file mode 100644 index 0000000..293b066 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleAuthorizeService.cs @@ -0,0 +1,132 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class RoleAuthorizeService : BaseService, + IRoleAuthorizeService + { + private readonly IRoleAuthorizeRepository _repository; + + private readonly IMenuRepository menuRepository; + private readonly ISystemTypeRepository systemTypeRepository; + + /// + /// + /// + /// + /// + /// + public RoleAuthorizeService(IRoleAuthorizeRepository repository, IMenuRepository _menuRepository, + ISystemTypeRepository _systemTypeRepository) : base(repository) + { + _repository = repository; + menuRepository = _menuRepository; + systemTypeRepository = _systemTypeRepository; + } + + /// + /// ݽɫĿͲѯȨ + /// + /// ɫId + /// + /// + public IEnumerable GetListRoleAuthorizeByRoleId(string roleIds, string itemType) + { + IEnumerable list = _repository.GetListWhere(string.Format("ItemType in({0}) and ObjectId in ({1}) and ObjectType=1", + itemType, roleIds)); + return list; + } + + /// + /// ȡܲ˵Vue Tree + /// + /// + public async Task> GetAllFunctionTree() + { + string where = " 1=1"; + List reslist = new List(); + IEnumerable listSystemType = await systemTypeRepository.GetListWhereAsync(where); + foreach (SystemTypeEntity systemType in listSystemType) + { + ModuleFunctionOutputDto menuTreeTableOutputDto = new ModuleFunctionOutputDto + { + Id = systemType.Id, + FullName = systemType.FullName, + FunctionTag = 0, + IsShow = true + }; + + IEnumerable elist = await menuRepository.GetListWhereAsync(" SystemTypeId='" + systemType.Id + "'"); + if (elist.Count() > 0) + { + List list = elist.OrderBy(t => t.SortCode).ToList(); + menuTreeTableOutputDto.Children = GetSubMenus(list, 0).ToList(); + } + + reslist.Add(menuTreeTableOutputDto); + } + + return reslist; + } + + /// + /// ɫȨ + /// + /// ɫId + /// ɫģ + /// ɫɷ + /// + /// ִгɹtrueΪfalse + public async Task SaveRoleAuthorize(long roleId, List roleAuthorizesList, + List roleDataList, + IDbTransaction trans = null) + { + return await _repository.SaveRoleAuthorize(roleId, roleAuthorizesList, roleDataList); + } + + /// + /// ȡӲ˵ݹ + /// + /// + /// Id + /// + private List GetSubMenus(List data, long ParentId) + { + List list = new List(); + List ChilList = data.FindAll(t => t.ParentId == ParentId); + foreach (MenuEntity entity in ChilList) + { + ModuleFunctionOutputDto menuTreeTableOutputDto = new ModuleFunctionOutputDto + { + Id = entity.Id, + FullName = entity.FullName, + IsShow = false + }; + if (entity.MenuType == "F") + { + menuTreeTableOutputDto.FunctionTag = 2; + } + else + { + menuTreeTableOutputDto.FunctionTag = 1; + } + + menuTreeTableOutputDto.Children = GetSubMenus(data, entity.Id).MapTo(); + list.Add(menuTreeTableOutputDto); + } + + return list; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleDataService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleDataService.cs new file mode 100644 index 0000000..1f0bcfb --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleDataService.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class RoleDataService : BaseService, IRoleDataService + { + private readonly IRoleDataRepository _repository; + + public RoleDataService(IRoleDataRepository repository) : base(repository) + { + _repository = repository; + } + + /// + /// ݽɫȨʲ + /// + /// + /// + public List GetListDeptByRole(string roleIds) + { + return _repository.GetListDeptByRole(roleIds); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleService.cs new file mode 100644 index 0000000..cc9ad82 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/RoleService.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class RoleService : BaseService, IRoleService + { + private readonly IOrganizeService _organizeService; + private readonly IRoleRepository _repository; + + public RoleService(IRoleRepository repository, IOrganizeService organizeService) : + base(repository) + { + _repository = repository; + _organizeService = organizeService; + } + + /// + /// ݽɫȡɫ + /// + /// + /// + public RoleEntityEntity GetRole(string enCode) + { + string where = string.Format("EnCode='{0}'", enCode); + return _repository.GetWhere(where); + } + + /// + /// ûɫIDȡɫ + /// + /// ɫIDַá,ָ + /// + public string GetRoleEnCode(string ids) + { + string roleIDsStr = string.Format("'{0}'", ids.Replace(",", "','")); + string sqlWhere = string.Format("Id in({0})", roleIDsStr); + IEnumerable listRoles = _repository.GetListWhere(sqlWhere); + string strEnCode = string.Empty; + foreach (RoleEntityEntity item in listRoles) + { + strEnCode += item.EnCode + ","; + } + + return strEnCode; + } + + /// + /// ûɫIDȡɫ + /// + /// ɫIDַá,ָ + /// + public string GetRoleNameStr(string ids) + { + string roleIDsStr = string.Format("'{0}'", ids.Replace(",", "','")); + string sqlWhere = string.Format("Id in({0})", roleIDsStr); + IEnumerable listRoles = _repository.GetListWhere(sqlWhere); + string strEnCode = string.Empty; + foreach (RoleEntityEntity item in listRoles) + { + strEnCode += item.FullName + ","; + } + + return strEnCode; + } + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + public override async Task> FindWithPagerAsync( + SearchInputDto search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += string.Format(" and (FullName like '%{0}%' or EnCode like '%{0}%')", search.Keywords); + }; + where += " and Category=1"; + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + List resultList = list.MapTo(); + List listResult = new List(); + foreach (RoleOutputDto item in resultList) + { + if (!string.IsNullOrEmpty(item.OrganizeId.ToString())) + { + item.OrganizeName = _organizeService.Get(item.OrganizeId).FullName; + } + + listResult.Add(item); + } + + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = listResult.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/StatisticalService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/StatisticalService.cs new file mode 100644 index 0000000..32be18c --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/StatisticalService.cs @@ -0,0 +1,132 @@ +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + public class StatisticalService : BaseService, IStatisticalService + { + private readonly IApplyJobService _applyJobService; + private readonly ILoginLogsRepository _loginLogsRepository; + private readonly IOrderService _orderService; + private readonly ICloudcarService _CloudcarService; + private readonly IStatisticalRepository _statisticalRepository; + private readonly IUserService _userService; + + public StatisticalService(IStatisticalRepository repository, + IUserService userService, + ILoginLogsRepository loginLogsRepository, + IOrderService orderService, + IApplyJobService applyJobService, + ICloudcarService CloudcarService + ) : base(repository) + { + _statisticalRepository = repository; + _userService = userService; + _loginLogsRepository = loginLogsRepository; + _orderService = orderService; + _applyJobService = applyJobService; + _CloudcarService = CloudcarService; + } + + /// + /// 첽ҳѯ + /// + /// + /// + public async Task> FindWithPagerSearchAsync(SearchUserModel search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.StartTime)) + { + @where += " and CreatedTime >='" + search.StartTime + " 00:00:00'"; + } + + if (!string.IsNullOrEmpty(search.EndTime)) + { + @where += " and CreatedTime <='" + search.EndTime + " 23:59:59'"; + } + + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + System.Collections.Generic.List list = await _statisticalRepository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + System.Collections.Generic.List listDto = list.MapTo(); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = listDto, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 첽 + /// + /// + public async Task InsertAsync() + { + CommonResult result = new CommonResult(); + StatisticalEntity statistical = await GetStatisticalAsync(); + int userAddTotal = await _userService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"); + dynamic todayIncome = await _orderService.GetSumValueByFieldAsync("PaymentMoney", + "OrderStatus >= 20 and date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"); + dynamic income = await _orderService.GetSumValueByFieldAsync("PaymentMoney", "OrderStatus >= 20"); + StatisticalEntity info = new StatisticalEntity + { + Id = YitIdHelper.NextId(), + Time = DateTime.Now.ToString("yyyy-MM-dd"), + UserAddTotal = userAddTotal, + UserSumTotal = await _userService.GetCountByWhereAsync("IsDeleted = 0"), + ApplyJobsAddTotal = + await _applyJobService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"), + CloudcarAddTotal = + await _CloudcarService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"), + ActiveUserTotal = await _loginLogsRepository.GetActiveUserTotal(), + TodayIncome = todayIncome.sumVaule, + Income = income.sumVaule, + ModifiedTime = DateTime.Now, + CreatedTime = DateTime.Now + }; + if (statistical == null) + { + info.UserAddTotalPercent = 0; + info.TodayIncomePercent = 0; + } + else + { + //UserAddTotalPercent = statistical.UserSumTotal!=0 ? (userAddTotal / statistical.UserSumTotal) * 100 : 0, + info.UserAddTotalPercent = StringHelper.GetPercent(userAddTotal, statistical.UserSumTotal); + //TodayIncomePercent = statistical.Income!=0 ? (todayIncome.sumVaule / statistical.Income) * 100 :0, + info.TodayIncomePercent = StringHelper.GetPercent(todayIncome.sumVaule, statistical.Income); + } + long ln = await _statisticalRepository.InsertAsync(info).ConfigureAwait(false); + result.Success = ln > 0 ? true : false; + return result; + } + + /// + /// ȡһ + /// + /// + public async Task GetStatisticalAsync() + { + StatisticalEntity statistical = await _statisticalRepository.GetStatisticalAsync(); + return statistical; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/SystemTypeService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/SystemTypeService.cs new file mode 100644 index 0000000..6ecd898 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/SystemTypeService.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class SystemTypeService : BaseService, ISystemTypeService + { + private readonly ISystemTypeRepository _repository; + private readonly IRoleAuthorizeService roleAuthorizeService; + + /// + /// + /// + /// + public SystemTypeService( + ISystemTypeRepository repository, + IRoleAuthorizeService _roleAuthorizeService) : base(repository) + { + _repository = repository; + roleAuthorizeService = _roleAuthorizeService; + } + + /// + /// ϵͳѯϵͳ + /// + /// ϵͳ + /// + public SystemTypeEntity GetByCode(string appkey) + { + return _repository.GetByCode(appkey); + } + + /// + /// ݽɫȡԷϵͳ + /// + /// ɫId',' + /// + public List GetSubSystemList(string roleIds) + { + string roleIDsStr = string.Empty; + if (roleIds.IndexOf(',') > 0) + { + roleIDsStr = string.Format("'{0}'", roleIds.Replace(",", "','")); + } + else + { + roleIDsStr = string.Format("'{0}'", roleIds); + } + + IEnumerable roleAuthorizes = roleAuthorizeService.GetListRoleAuthorizeByRoleId(roleIDsStr, "0"); + string strWhere = string.Empty; + if (roleAuthorizes.Count() > 0) + { + strWhere = " Id in ("; + foreach (RoleAuthorizeEntity item in roleAuthorizes) + { + strWhere += "'" + item.ItemId + "',"; + } + + strWhere = strWhere.Substring(0, strWhere.Length - 1) + ")"; + } + + List list = _repository.GetAllByIsNotDeleteAndEnabledMark(strWhere).OrderBy(t => t.SortCode).ToList() + .MapTo(); + return list; + } + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + public override async Task> FindWithPagerAsync( + SearchInputDto search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += string.Format(" and (FullName like '%{0}%' or EnCode like '%{0}%')", search.Keywords); + }; + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/UploadFileService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/UploadFileService.cs new file mode 100644 index 0000000..76a9b79 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/UploadFileService.cs @@ -0,0 +1,69 @@ +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class UploadFileService : BaseService, IUploadFileService + { + private readonly IUploadFileRepository _uploadFileRepository; + + public UploadFileService(IUploadFileRepository repository) : base(repository) + { + _uploadFileRepository = repository; + } + + /// + /// 根据应用Id和应用标识批量更新数据 + /// + /// 应用Id + /// 更新前旧的应用Id + /// 应用标识 + /// + /// + public bool UpdateByBeLongAppId(string beLongAppId, string oldBeLongAppId, string belongApp = null, + IDbTransaction trans = null) + { + return _uploadFileRepository.UpdateByBeLongAppId(beLongAppId, oldBeLongAppId, belongApp, trans); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// 查询的条件 + /// 指定对象的集合 + public override async Task> FindWithPagerAsync( + SearchInputDto search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += string.Format(" and FileName like '%{0}%' ", search.Keywords); + }; + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + System.Collections.Generic.List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/UserService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/UserService.cs new file mode 100644 index 0000000..fea9366 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/UserService.cs @@ -0,0 +1,173 @@ +using System.Data; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class UserService : BaseService, IUserService + { + private readonly ICertificationRepository _certificationRepository; + private readonly ILoginLogsRepository _loginLogsRepository; + private readonly IUserRepository _userRepository; + + public UserService(IUserRepository repository, + ILoginLogsRepository loginLogsRepository, + ICertificationRepository certificationRepository) : base(repository) + { + _userRepository = repository; + _certificationRepository = certificationRepository; + _loginLogsRepository = loginLogsRepository; + } + + /// + /// 첽ʵ塣 + /// + /// ʵ + /// ID + /// + /// + public override async Task UpdateAsync(UserEntity entity, long id, IDbTransaction trans = null) + { + bool result = await repository.UpdateAsync(entity, id, trans); + return result; + } + + /// + /// ѯݿ,ض󼯺(ڷҳʾ) + /// + /// ѯ + /// ָļ + public override async Task> FindWithPagerAsync(SearchInputDto search) + { + bool order = search.Order == "asc" ? false : true; + string where = GetDataPrivilege(false); + if (!string.IsNullOrEmpty(search.Keywords)) + { + @where += string.Format(" and (UserName like '%{0}%')", search.Keywords); + }; + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + System.Collections.Generic.List list = await repository.FindWithPagerAsync(where, pagerInfo, search.Sort, order); + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list.MapTo(), + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 첽ҳѯʱ״̬ؼ֣ + /// + /// + /// + public async Task> FindWithPagerSearchAsync(SearchUserModel search) + { + PagerInfo pagerInfo = new PagerInfo + { + CurrenetPageIndex = search.CurrenetPageIndex, + PageSize = search.PageSize + }; + + System.Collections.Generic.List list = (await _userRepository.FindUserWithPagerAsync(search, pagerInfo)).MapTo(); + System.Collections.Generic.List LastLoginLogsList = await _loginLogsRepository.GetLastLoginLogAsync(); + + foreach (UserOutputDto item in list) + { + item.PositivePhoto = ""; + item.ReversePhoto = ""; + item.IdCard = ""; + item.IssuedAddress = ""; + item.Gender = ""; + item.CertificationState = (int)UserCertificationEnum.None; + CertificationEntity certification = await _certificationRepository.GetWhereAsync($"UserId={item.Id}"); + if (certification != null) + { + item.CertificationId = certification.Id; + item.PositivePhoto = string.Format(CommonConst.Default_Identity_Prefix, item.Id) + certification.PositivePhoto; + item.ReversePhoto = string.Format(CommonConst.Default_Identity_Prefix, item.Id) + certification.ReversePhoto; + item.IdCard = certification.IdCard; + item.IssuedAddress = certification.IssuedAddress; + item.Gender = certification.Gender; + item.CertificationState = certification.State; + } + item.AvatarUrl = item.AvatarUrl; + item.LastLoginTime = LastLoginLogsList.Find(x => x.CreatedUserId == item.Id)?.LoginTime; + item.Contact = item.Contact; + } + + PageResult pageResult = new PageResult + { + CurrentPage = pagerInfo.CurrenetPageIndex, + Items = list, + ItemsPerPage = pagerInfo.PageSize, + TotalItems = pagerInfo.RecordCount + }; + return pageResult; + } + + /// + /// 첽/û + /// + /// + /// 1-/99- + /// + public async Task UpdateStatusAsync(long id, int status) + { + CommonResult result = new CommonResult(); + UserEntity user = await repository.GetAsync(id); + if (!(user?.Id > 0)) + { + result.Success = false; + result.ErrMsg = "û"; + return result; + } + + user.State = status; + await repository.UpdateAsync(user, id); + result.Success = true; + return result; + } + + + /// + /// 첽/û + /// + /// + /// + public async Task UpdateIsPromoteAsync(long id) + { + CommonResult result = new CommonResult(); + UserEntity user = await repository.GetAsync(id); + if (!(user?.Id > 0)) + { + result.Success = false; + result.ErrMsg = "û"; + return result; + } + + user.IsPromote = !user.IsPromote; + await repository.UpdateAsync(user, id); + result.Success = true; + return result; + } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/WxUserRelationService.cs b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/WxUserRelationService.cs new file mode 100644 index 0000000..f32d1f9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Services/Recruitment/WxUserRelationService.cs @@ -0,0 +1,53 @@ +using Senparc.Weixin.MP.CommonAPIs; +using Senparc.Weixin.MP.Containers; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Services; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.Security.Services +{ + /// + /// + public class WxUserRelationService : BaseService, IWxUserRelationService + { + private readonly ICertificationRepository _certificationRepository; + private readonly ILoginLogsRepository _loginLogsRepository; + private readonly IWxUserRelationRepository _repository; + + public WxUserRelationService(IWxUserRelationRepository repository, + ILoginLogsRepository loginLogsRepository, + ICertificationRepository certificationRepository) : base(repository) + { + _repository = repository; + _certificationRepository = certificationRepository; + _loginLogsRepository = loginLogsRepository; + } + + /// + /// + /// + /// + /// + public async Task UpdateAsync(string wxOpenId) + { + CommonResult result = new CommonResult(); + await AccessTokenContainer.RegisterAsync("wx07c574aca93ae8d9", "f212eda7f2db58eb0a72c539ba2a6f38"); + var wxUser = CommonApi.GetUserInfo("wx07c574aca93ae8d9", wxOpenId); + string where = string.Format("unionId='{0}'", wxUser.unionid); + var wxUserRelation = await GetWhereAsync(where); + if (wxUserRelation != null) + { + wxUserRelation.WxOfficialOpenId = wxOpenId; + wxUserRelation.ModifiedTime = DateTime.Now; + await _repository.UpdateAsync(wxUserRelation, wxUserRelation.Id); + } + result.Success = true; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.Security.Core/Yuebon.Security.Core.csproj b/Znyc.Cloudcar.Admin.Security.Core/Yuebon.Security.Core.csproj new file mode 100644 index 0000000..19c7747 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Yuebon.Security.Core.csproj @@ -0,0 +1,92 @@ + + + + Library + net5.0 + + + ZNYC.Admin.Security + 上海越邦网络科技有限公司 + 上海越邦网络科技有限公司 版权所有 + YuebonNetCore开发框架权限管理系统类库 + YuebonNetCore开发框架权限管理系统类库 + true + 1.3.2.32 + 更新最新公共库 + Yuebon + true + + https://gitee.com/yuebon/YuebonNetCore + + https://gitee.com/yuebon/YuebonNetCore + LICENSE + logo.png + 1.3.2.32 + 1.3.2.32 + + + + + + + + + bin\Release\ + bin\Release\ZNYC.Admin.Security.Core.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + True + + + + + + + + + diff --git a/Znyc.Cloudcar.Admin.Security.Core/Znyc.Cloudcar.Admin.Security.Core.csproj b/Znyc.Cloudcar.Admin.Security.Core/Znyc.Cloudcar.Admin.Security.Core.csproj new file mode 100644 index 0000000..b76ea91 --- /dev/null +++ b/Znyc.Cloudcar.Admin.Security.Core/Znyc.Cloudcar.Admin.Security.Core.csproj @@ -0,0 +1,81 @@ + + + Library + net6.0 + + + Znyc.Recruitment.Admin.Security + + + + + true + 1.0 + 更新最新公共库 + Znyc.Admin + true + + + + + 1.3.2.32 + 1.3.2.32 + MIT + + + + + + + + + bin\Release\ + bin\Release\Znyc.Recruitment.Admin.Security.Core.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/CodeRecord.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/CodeRecord.cs new file mode 100644 index 0000000..5acc1cf --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/CodeRecord.cs @@ -0,0 +1,15 @@ +using Senparc.Weixin.MP.AdvancedAPIs.QrCode; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.Download +{ + public class CodeRecord + { + public string Key { get; set; } + public int QrCodeId { get; set; } + public CreateQrCodeResult QrCodeTicket { get; set; } + public string Version { get; set; } + public bool Used { get; set; } + public bool AllowDownload { get; set; } + public bool IsWebVersion { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/Config.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/Config.cs new file mode 100644 index 0000000..0f35992 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/Config.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace Znyc.WeChat.CommonService.Download +{ + public class Config + { + public int QrCodeId { get; set; } + + /// + /// chm版 + /// + public List Versions { get; set; } + + /// + /// 网页版 + /// + public List WebVersions { get; set; } + + public int DownloadCount { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/ConfigHelper.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/ConfigHelper.cs new file mode 100644 index 0000000..caa69ae --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Download/ConfigHelper.cs @@ -0,0 +1,107 @@ +using Senparc.CO2NET.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Znyc.WeChat.CommonService.Download; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.Download +{ + public class ConfigHelper + { + //Key:guid,Value: + public static Dictionary CodeCollection = + new(StringComparer.OrdinalIgnoreCase); + + public static object Lock = new(); + + private string GetDatabaseFilePath() + { + return ServerUtility.ContentRootMapPath("~/App_Data/Document/Config.xml"); + } + + private XDocument GetXDocument() + { + XDocument doc = XDocument.Load(GetDatabaseFilePath()); + return doc; + } + + /// + /// 获取配置文件 + /// + /// + /// + public Config GetConfig() + { + XDocument doc = GetXDocument(); + Config config = new Config + { + QrCodeId = int.Parse(doc.Root.Element("QrCodeId").Value), + DownloadCount = int.Parse(doc.Root.Element("DownloadCount").Value), + Versions = doc.Root.Element("Versions").Elements("Version").Select(z => z.Value).ToList(), + WebVersions = doc.Root.Element("WebVersions").Elements("Version").Select(z => z.Value).ToList() + }; + return config; + } + + /// + /// 获取一个二维码场景标示(自增,唯一) + /// + /// + public int GetQrCodeId() + { + lock (Lock) + { + Config config = GetConfig(); + config.QrCodeId++; + Save(config); + return config.QrCodeId; + } + } + + public void Save(Config config) + { + XDocument doc = GetXDocument(); + doc.Root.Element("QrCodeId").Value = config.QrCodeId.ToString(); + doc.Root.Element("DownloadCount").Value = config.DownloadCount.ToString(); + doc.Root.Element("Versions").Elements().Remove(); + foreach (string version in config.Versions) + { + doc.Root.Element("Versions").Add(new XElement("Version", version)); + } +#if NET45 + doc.Save(GetDatabaseFilePath()); +#else + using (FileStream fs = new FileStream(GetDatabaseFilePath(), FileMode.OpenOrCreate, FileAccess.ReadWrite)) + { + doc.Save(fs); + } +#endif + } + + public string Download(string version, bool isWebVersion) + { + lock (Lock) + { + Config config = GetConfig(); + config.DownloadCount++; + Save(config); + } + + //打包下载文件 + //FileStream fs = new FileStream(_context.ServerUtility.ContentRootMapPath(string.Format("~/App_Data/Document/Files/Senparc.Weixin-v{0}.rar", version)), FileMode.Open); + //return fs; + + string filePath = ServerUtility.ContentRootMapPath(string.Format( + "~/App_Data/Document/Files/Senparc.Weixin{0}-v{1}.rar", isWebVersion ? "-Web" : "", version)); + if (!File.Exists(filePath)) + { + //使用.zip文件 + filePath = filePath.Replace(".rar", ".zip"); + } + + return filePath; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/EventService.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/EventService.cs new file mode 100644 index 0000000..a3559c4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/EventService.cs @@ -0,0 +1,166 @@ +using Senparc.CO2NET.Trace; +using Senparc.CO2NET.Utilities; +using Senparc.NeuChar.Entities; +using Senparc.NeuChar.Helpers; +using Senparc.Weixin; +using Senparc.Weixin.Exceptions; +using Senparc.Weixin.MP; +using Senparc.Weixin.MP.Entities; +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.WeChat.CommonService.TemplateMessage; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService +{ + /// + /// 全局微信事件有关的处理程序 + /// + public class EventService + { + /// + /// 微信MessageHandler事件处理,此代码的简化MessageHandler方法已由/CustomerMessageHandler/CustomerMessageHandler_Event.cs完成, + /// 此方法不再更新 + /// + /// + /// + public ResponseMessageBase GetResponseMessage(RequestMessageEventBase requestMessage) + { + ResponseMessageBase responseMessage = null; + switch (requestMessage.Event) + { + case Event.ENTER: + { + ResponseMessageText strongResponseMessage = requestMessage.CreateResponseMessage(); + strongResponseMessage.Content = "您刚才发送了ENTER事件请求。"; + responseMessage = strongResponseMessage; + break; + } + case Event.LOCATION: + throw new Exception("暂不可用"); + //break; + case Event.subscribe: //订阅 + { + ResponseMessageText strongResponseMessage = requestMessage.CreateResponseMessage(); + + //获取Senparc.Weixin.MP.dll版本信息 +#if NET45 + var dllPath = HttpContext.Current.Server.MapPath("~/bin/Senparc.Weixin.MP.dll"); +#else + //var dllPath = ServerUtility.ContentRootMapPath("~/bin/Release/netcoreapp2.2/Senparc.Weixin.MP.dll");//本地测试路径 + string dllPath = ServerUtility.ContentRootMapPath("~/Senparc.Weixin.MP.dll"); //发布路径 +#endif + + FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(dllPath); + + string version = fileVersionInfo.FileVersion; + strongResponseMessage.Content = string.Format( + "欢迎关注【Senparc.Weixin.MP 微信公众平台SDK】,当前运行版本:v{0}。\r\n您还可以发送【位置】【图片】【语音】信息,查看不同格式的回复。\r\nSDK官方地址:https://sdk.weixin.senparc.com", + version); + responseMessage = strongResponseMessage; + break; + } + case Event.unsubscribe: //退订 + { + //实际上用户无法收到非订阅账号的消息,所以这里可以随便写。 + //unsubscribe事件的意义在于及时删除网站应用中已经记录的OpenID绑定,消除冗余数据。 + ResponseMessageText strongResponseMessage = requestMessage.CreateResponseMessage(); + strongResponseMessage.Content = "有空再来"; + responseMessage = strongResponseMessage; + break; + } + case Event.CLICK: //菜单点击事件,根据自己需要修改 + //这里的CLICK在此DEMO中不会被执行到,因为已经重写了OnEvent_ClickRequest + break; + + default: + throw new ArgumentOutOfRangeException(); + } + + return responseMessage; + } + + public void ConfigOnWeixinExceptionFunc(WeixinException ex) + { + SenparcTrace.SendCustomLog("进入 ConfigOnWeixinExceptionFunc() 方法", ex.Message); + try + { + Task.Factory.StartNew(async () => + { + string appId = Config.SenparcWeixinSetting.WeixinAppId; + + string openId = ""; //收到通知的管理员OpenId + string host = "A1 / AccessTokenOrAppId:" + (ex.AccessTokenOrAppId ?? "null"); + string service = null; + string message = ex.Message; + string status = ex.GetType().Name; + string remark = "\r\n这是一条通过OnWeixinExceptionFunc事件发送的异步模板消息"; + string url = + "https://github.com/JeffreySu/WeiXinMPSDK/blob/24aca11630bf833f6a4b6d36dce80c5b171281d3/src/Senparc.Weixin.MP.Sample/Senparc.Weixin.MP.Sample/Global.asax.cs#L246"; //需要点击打开的URL + + bool sendTemplateMessage = true; + + if (ex is ErrorJsonResultException) + { + ErrorJsonResultException jsonEx = (ErrorJsonResultException)ex; + service = jsonEx.Url; + message = jsonEx.Message; + + //需要忽略的类型 + ReturnCode[] ignoreErrorCodes = + { + ReturnCode.获取access_token时AppSecret错误或者access_token无效, + ReturnCode.template_id不正确, + ReturnCode.缺少access_token参数, + ReturnCode.api功能未授权, + ReturnCode.用户未授权该api, + ReturnCode.参数错误invalid_parameter, + ReturnCode.接口调用超过限制, + ReturnCode.需要接收者关注 //43004 + + //其他更多可能的情况 + }; + if (ignoreErrorCodes.Contains(jsonEx.JsonResult.errcode)) + { + sendTemplateMessage = false; //防止无限递归,这种请款那个下不发送消息 + } + + //TODO:防止更多的接口自身错误导致的无限递归。 + } + else + { + if (ex.Message.StartsWith("openid:")) + { + openId = ex.Message.Split(':')[1]; //发送给指定OpenId + } + + service = "WeixinException"; + message = ex.Message; + } + + if (sendTemplateMessage) // DPBMARK MP + { + int sleepSeconds = 3; + Thread.Sleep(sleepSeconds * 1000); + WeixinTemplate_ExceptionAlert data = new WeixinTemplate_ExceptionAlert(string.Format("微信发生异常(延时{0}秒)", sleepSeconds), + host, service, status, message, remark); + + //修改OpenId、启用以下代码后即可收到模板消息 + if (!string.IsNullOrEmpty(openId)) + { + Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage.SendTemplateMessageResult result = await Senparc.Weixin.MP.AdvancedAPIs.TemplateApi.SendTemplateMessageAsync( + appId, openId, data.TemplateId, + url, data); + } + } // DPBMARK_END + }); + } + catch (Exception e) + { + SenparcTrace.SendCustomLog("OnWeixinExceptionFunc过程错误", e.Message); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/FixWeixinBugWeixinResult.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/FixWeixinBugWeixinResult.cs new file mode 100644 index 0000000..1505c9c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/FixWeixinBugWeixinResult.cs @@ -0,0 +1,139 @@ +using Microsoft.AspNetCore.Mvc; +using Senparc.NeuChar.MessageHandlers; +using System.Text; +using System.Threading.Tasks; + +namespace CommonService +{ + /// + /// 修复微信换行 bug + /// + public class FixWeixinBugWeixinResult : ContentResult + { + //private string _content; + protected IMessageHandlerDocument _messageHandlerDocument; + + /// + /// 这个类型只用于特殊阶段:目前IOS版本微信有换行的bug,\r\n会识别为2行 + /// + public FixWeixinBugWeixinResult(IMessageHandlerDocument messageHandlerDocument) + { + _messageHandlerDocument = messageHandlerDocument; + } + + public FixWeixinBugWeixinResult(string content) + { + //_content = content; + base.Content = content; + } + + + public new string Content + { + get + { + if (base.Content != null) + { + return base.Content; + } + + if (_messageHandlerDocument != null) + { + //var textResponseMessag = _messageHandlerDocument.TextResponseMessage; + if (_messageHandlerDocument.TextResponseMessage != null) + { + return _messageHandlerDocument.TextResponseMessage.Replace("\r\n", "\n"); + } + + //if (_messageHandlerDocument.TextResponseMessage.Equals(String.Empty)) + //{ + // //无需响应,开发者返回了ResponseNoResponse + // return null; + //} + + //if (_messageHandlerDocument.ResponseDocument != null) + //{ + // //返回XML响应信息 + // return _messageHandlerDocument.TextResponseMessage.Replace("\r\n", "\n"); + //} + //else + //{ + // //返回XML响应信息或用户指定的文本内容 + // return _messageHandlerDocument.TextResponseMessage; + //} + } + return null; + } + set { base.Content = value; } + } + +#if NET45 + public override void ExecuteResult(ControllerContext context) + { + var content = this.Content; + + if (content == null) + { + //使用IMessageHandler输出 + if (_messageHandlerDocument == null) + { + throw new Senparc.Weixin.Exceptions.WeixinException("执行WeixinResult时提供的MessageHandler不能为Null!", null); + } + var finalResponseDocument = _messageHandlerDocument.FinalResponseDocument; + + + if (finalResponseDocument == null) + { + //throw new Senparc.Weixin.MP.WeixinException("FinalResponseDocument不能为Null!", null); + } + else + { + content = finalResponseDocument.ToString(); + } + } + + context.HttpContext.Response.ClearContent(); + context.HttpContext.Response.ContentType = "text/xml"; + content = (content ?? "").Replace("\r\n", "\n"); + + var bytes = Encoding.UTF8.GetBytes(content); + context.HttpContext.Response.OutputStream.Write(bytes, 0, bytes.Length); + } + +#else + public override async Task ExecuteResultAsync(ActionContext context) + { + var content = this.Content; + + if (content == null) + { + //使用IMessageHandler输出 + if (_messageHandlerDocument == null) + { + throw new Senparc.Weixin.Exceptions.WeixinException("执行WeixinResult时提供的MessageHandler不能为Null!", null); + } + var finalResponseDocument = _messageHandlerDocument.FinalResponseDocument; + + + if (finalResponseDocument == null) + { + //throw new Senparc.Weixin.MP.WeixinException("FinalResponseDocument不能为Null!", null); + } + else + { + content = finalResponseDocument.ToString(); + } + } + + context.HttpContext.Response.ContentType = "text/xml"; + content = (content ?? "").Replace("\r\n", "\n"); + + var bytes = Encoding.UTF8.GetBytes(content); + //context.HttpContext.Response.Body.Seek(0, SeekOrigin.Begin); + await context.HttpContext.Response.Body.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); + + // return base.ExecuteResultAsync(context); + } +#endif + } +} diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/LocationService.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/LocationService.cs new file mode 100644 index 0000000..1a8da8e --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/LocationService.cs @@ -0,0 +1,92 @@ +using Senparc.CO2NET.Helpers; +using Senparc.CO2NET.Helpers.BaiduMap; +using Senparc.CO2NET.Helpers.GoogleMap; +using Senparc.NeuChar.Entities; +using Senparc.Weixin.MP.Entities; +using System.Collections.Generic; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService +{ + /// + /// 地理位置信息处理 + /// + public class LocationService + { + public ResponseMessageNews GetResponseMessage(RequestMessageLocation requestMessage) + { + ResponseMessageNews responseMessage = ResponseMessageBase.CreateFromRequestMessage(requestMessage); + + #region 百度地图 + + { + List markersList = new List + { + new() + { + Longitude = requestMessage.Location_X, + Latitude = requestMessage.Location_Y, + Color = "red", + Label = "S", + Size = BaiduMarkerSize.m + } + }; + + string mapUrl = BaiduMapHelper.GetBaiduStaticMap(requestMessage.Location_X, requestMessage.Location_Y, 1, + 6, markersList); + responseMessage.Articles.Add(new Article + { + Description = string.Format("【来自百度地图】您刚才发送了地理位置信息。Location_X:{0},Location_Y:{1},Scale:{2},标签:{3}", + requestMessage.Location_X, requestMessage.Location_Y, + requestMessage.Scale, requestMessage.Label), + PicUrl = mapUrl, + Title = "定位地点周边地图", + Url = mapUrl + }); + } + + #endregion 百度地图 + + #region GoogleMap + + { + List markersList = new List + { + new() + { + X = requestMessage.Location_X, + Y = requestMessage.Location_Y, + Color = "red", + Label = "S", + Size = GoogleMapMarkerSize.Default + } + }; + string mapSize = "480x600"; + string mapUrl = GoogleMapHelper.GetGoogleStaticMap( + 19 /*requestMessage.Scale*/ /*微信和GoogleMap的Scale不一致,这里建议使用固定值*/, + markersList, mapSize); + responseMessage.Articles.Add(new Article + { + Description = string.Format( + "【来自GoogleMap】您刚才发送了地理位置信息。Location_X:{0},Location_Y:{1},Scale:{2},标签:{3}", + requestMessage.Location_X, requestMessage.Location_Y, + requestMessage.Scale, requestMessage.Label), + PicUrl = mapUrl, + Title = "定位地点周边地图", + Url = mapUrl + }); + } + + #endregion GoogleMap + + responseMessage.Articles.Add(new Article + { + Title = "微信公众平台SDK 官网链接", + Description = "Senparc.Weixin.MK SDK地址", + PicUrl = "https://sdk.weixin.senparc.com/images/logo.jpg", + Url = "https://sdk.weixin.senparc.com" + }); + + return responseMessage; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/Async/CustomMessageHandlerAsync_Events.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/Async/CustomMessageHandlerAsync_Events.cs new file mode 100644 index 0000000..d6f54b5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/Async/CustomMessageHandlerAsync_Events.cs @@ -0,0 +1,29 @@ +using Senparc.NeuChar.Entities; +using Senparc.Weixin.MP.Entities; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.CustomMessageHandler +{ + /// + /// 自定义MessageHandler + /// + public partial class CustomMessageHandler + { + public override Task OnEvent_ClickRequestAsync(RequestMessageEvent_Click requestMessage) + { + return Task.Factory.StartNew(() => + { + IResponseMessageBase syncResponseMessage = + OnEvent_ClickRequest(requestMessage); //这里为了保持Demo的连贯性,结果先从同步方法获取,实际使用过程中可以全部直接定义异步方法 + //常识获取Click事件的同步方法 + if (syncResponseMessage is ResponseMessageText) + { + ResponseMessageText textResponseMessage = syncResponseMessage as ResponseMessageText; + textResponseMessage.Content += "\r\n\r\n -- 来自【异步MessageHandler】的回复"; + } + + return syncResponseMessage; + }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageContext.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageContext.cs new file mode 100644 index 0000000..963b183 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageContext.cs @@ -0,0 +1,52 @@ +using Senparc.NeuChar; +using Senparc.NeuChar.Context; +using Senparc.NeuChar.Entities; +using System; +using System.Xml.Linq; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.CustomMessageHandler +{ + public class CustomMessageContext : MessageContext + { + public CustomMessageContext() + { + base.MessageContextRemoved += CustomMessageContext_MessageContextRemoved; + } + + public override IRequestMessageBase GetRequestEntityMappingResult(RequestMsgType requestMsgType, + XDocument doc = null) + { + throw new NotImplementedException(); + } + + public override IResponseMessageBase GetResponseEntityMappingResult(ResponseMsgType responseMsgType, + XDocument doc = null) + { + throw new NotImplementedException(); + } + + /// + /// 当上下文过期,被移除时触发的时间 + /// + /// + /// + private void CustomMessageContext_MessageContextRemoved(object sender, + WeixinContextRemovedEventArgs e) + { + /* 注意,这个事件不是实时触发的(当然你也可以专门写一个线程监控) + * 为了提高效率,根据WeixinContext中的算法,这里的过期消息会在过期后下一条请求执行之前被清除 + */ + + CustomMessageContext messageContext = e.MessageContext as CustomMessageContext; + if (messageContext == null) + { + return; //如果是正常的调用,messageContext不会为null + } + + //TODO:这里根据需要执行消息过期时候的逻辑,下面的代码仅供参考 + + //Log.InfoFormat("{0}的消息上下文已过期",e.OpenId); + //api.SendMessage(e.OpenId, "由于长时间未搭理客服,您的客服状态已退出!"); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler.cs new file mode 100644 index 0000000..d63c867 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler.cs @@ -0,0 +1,580 @@ +/*---------------------------------------------------------------- + Copyright (C) 2019 Senparc + + 文件名:CustomMessageHandler.cs + 文件功能描述:微信公众号自定义MessageHandler + + 创建标识:Senparc - 20150312 + + 修改标识:Senparc - 20171027 + 修改描述:v14.8.3 添加OnUnknownTypeRequest()方法Demo + + 修改标识:Senparc - 20191002 + 修改描述:v16.9.102 提供 MessageHandler 中间件 + +----------------------------------------------------------------*/ + +//DPBMARK_FILE MP + +using Senparc.CO2NET.Helpers; +using Senparc.CO2NET.Trace; +using Senparc.CO2NET.Utilities; +using Senparc.NeuChar.Entities; +using Senparc.NeuChar.Entities.Request; +using Senparc.NeuChar.Helpers; +using Senparc.Weixin; +using Senparc.Weixin.Exceptions; +using Senparc.Weixin.MP; +using Senparc.Weixin.MP.AdvancedAPIs; +using Senparc.Weixin.MP.Entities; +using Senparc.Weixin.MP.Entities.Request; +using Senparc.Weixin.MP.MessageHandlers; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +#if NET45 +using System.Web; +using System.Configuration; +using System.Web.Configuration; +using Senparc.Weixin.MP.Sample.CommonService.Utilities; +#else +#endif + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.CustomMessageHandler +{ + /// + /// 自定义MessageHandler + /// 把MessageHandler作为基类,重写对应请求的处理方法 + /// + public partial class + CustomMessageHandler : MessageHandler /*如果不需要自定义,可以直接使用:MessageHandler */ + { + /* + * 重要提示:v1.5起,MessageHandler提供了一个DefaultResponseMessage的抽象方法, + * DefaultResponseMessage必须在子类中重写,用于返回没有处理过的消息类型(也可以用于默认消息,如帮助信息等); + * 其中所有原OnXX的抽象方法已经都改为虚方法,可以不必每个都重写。若不重写,默认返回DefaultResponseMessage方法中的结果。 + */ + + + private readonly string appId = "wx07c574aca93ae8d9"; + + /// + /// 模板消息集合(Key:checkCode,Value:OpenId) + /// 注意:这里只做测试,只适用于单服务器 + /// + public static Dictionary TemplateMessageCollection = new(); + + /// + /// 为中间件提供生成当前类的委托 + /// + public static Func GenerateMessageHandler = + (stream, postModel, maxRecordCount) + => new CustomMessageHandler(stream, postModel, maxRecordCount /* 是否只允许处理加密消息,以提高安全性 */); + + public CustomMessageHandler(Stream inputStream, PostModel postModel, int maxRecordCount = 0, + bool onlyAllowEcryptMessage = false) + : base(inputStream, postModel, maxRecordCount, onlyAllowEcryptMessage) + { + //这里设置仅用于测试,实际开发可以在外部更全局的地方设置, + //比如MessageHandler.GlobalGlobalMessageContext.ExpireMinutes = 3。 + GlobalMessageContext.ExpireMinutes = 3; + + //OnlyAllowEcryptMessage = true;//是否只允许接收加密消息,默认为 false + + if (!string.IsNullOrEmpty(postModel.AppId)) + { + appId = postModel.AppId; //通过第三方开放平台发送过来的请求 + } + + //在指定条件下,不使用消息去重 + OmitRepeatedMessageFunc = requestMessage => + { + RequestMessageText textRequestMessage = requestMessage as RequestMessageText; + if (textRequestMessage != null && textRequestMessage.Content == "容错") + { + return false; + } + + return true; + }; + } + + /// + /// 处理文字请求 + /// + /// 请求消息 + /// + public override async Task OnTextRequestAsync(RequestMessageText requestMessage) + { + //说明:实际项目中这里的逻辑可以交给Service处理具体信息,参考OnLocationRequest方法或/Service/LocationSercice.cs + + #region 书中例子 + + //if (requestMessage.Content == "你好") + //{ + // var responseMessage = base.CreateResponseMessage(); + // var title = "Title"; + // var description = "Description"; + // var picUrl = "PicUrl"; + // var url = "Url"; + // responseMessage.Articles.Add(new Article() + // { + // Title = title, + // Description = description, + // PicUrl = picUrl, + // Url = url + // }); + // return responseMessage; + //} + //else if (requestMessage.Content == "Senparc") + //{ + // //相似处理逻辑 + //} + //else + //{ + // //... + //} + + #endregion 书中例子 + + #region 历史方法 + + //方法一(v0.1),此方法调用太过繁琐,已过时(但仍是所有方法的核心基础),建议使用方法二到四 + //var responseMessage = + // ResponseMessageBase.CreateFromRequestMessage(RequestMessage, ResponseMsgType.Text) as + // ResponseMessageText; + + //方法二(v0.4) + //var responseMessage = ResponseMessageBase.CreateFromRequestMessage(RequestMessage); + + //方法三(v0.4),扩展方法,需要using Senparc.Weixin.MP.Helpers; + //var responseMessage = RequestMessage.CreateResponseMessage(); + + //方法四(v0.6+),仅适合在HandlerMessage内部使用,本质上是对方法三的封装 + //注意:下面泛型ResponseMessageText即返回给客户端的类型,可以根据自己的需要填写ResponseMessageNews等不同类型。 + + #endregion 历史方法 + + ResponseMessageText defaultResponseMessage = base.CreateResponseMessage(); + + RequestMessageTextKeywordHandler requestHandler = await requestMessage.StartHandler() + //关键字不区分大小写,按照顺序匹配成功后将不再运行下面的逻辑 + .Keyword("约束", () => + { + defaultResponseMessage.Content = + @"您正在进行微信内置浏览器约束判断测试。您可以: +点击这里进行客户端约束测试(地址:https://sdk.weixin.senparc.com/FilterTest/),如果在微信外打开将直接返回文字。 +或: +点击这里进行客户端约束测试(地址:https://sdk.weixin.senparc.com/FilterTest/Redirect),如果在微信外打开将重定向一次URL。"; + return defaultResponseMessage; + }) + .Keywords(new[] { "测试", "退出" }, () => + { + /* + * 这是一个特殊的过程,此请求通常来自于微微嗨(http://www.weiweihi.com)的“盛派网络小助手”应用请求(https://www.weiweihi.com/User/App/Detail/1), + * 用于演示微微嗨应用商店的处理过程,由于微微嗨的应用内部可以单独设置对话过期时间,所以这里通常不需要考虑对话状态,只要做最简单的响应。 + */ + if (defaultResponseMessage.Content == "测试") + { + //进入APP测试 + defaultResponseMessage.Content = + "您已经进入【盛派网络小助手】的测试程序,请发送任意信息进行测试。发送文字【退出】退出测试对话。10分钟内无任何交互将自动退出应用对话状态。"; + } + else + { + //退出APP测试 + defaultResponseMessage.Content = "您已经退出【盛派网络小助手】的测试程序。"; + } + + return defaultResponseMessage; + }) + .Keyword("AsyncTest", () => + { + //异步并发测试(提供给单元测试使用) +#if NET45 + var begin = SystemTime.Now; + int t1, t2, t3; + System.Threading.ThreadPool.GetAvailableThreads(out t1, out t3); + System.Threading.ThreadPool.GetMaxThreads(out t2, out t3); + System.Threading.Thread.Sleep(TimeSpan.FromSeconds(4)); + var end = SystemTime.Now; + var thread = System.Threading.Thread.CurrentThread; + defaultResponseMessage.Content = + string.Format("TId:{0}\tApp:{1}\tBegin:{2:mm:ss,ffff}\tEnd:{3:mm:ss,ffff}\tTPool:{4}", + thread.ManagedThreadId, + HttpContext.Current != null ? HttpContext.Current.ApplicationInstance.GetHashCode() : -1, + begin, + end, + t2 - t1 + ); +#endif + + return defaultResponseMessage; + }) + .Keyword("OPEN", () => + { + ResponseMessageNews openResponseMessage = requestMessage.CreateResponseMessage(); + openResponseMessage.Articles.Add(new Article + { + Title = "开放平台微信授权测试!", + Description = @"点击进入Open授权页面。 + +授权之后,您的微信所收到的消息将转发到第三方(盛派网络小助手)的服务器上,并获得对应的回复。 + +测试完成后,您可以登陆公众号后台取消授权。", + Url = "https://sdk.weixin.senparc.com/OpenOAuth/JumpToMpOAuth" + }); + return openResponseMessage; + }) + .Keyword("错误", () => + { + ResponseMessageText errorResponseMessage = requestMessage.CreateResponseMessage(); + //因为没有设置errorResponseMessage.Content,所以这小消息将无法正确返回。 + return errorResponseMessage; + }) + .Keyword("容错", () => + { + Thread.Sleep(4900); //故意延时1.5秒,让微信多次发送消息过来,观察返回结果 + ResponseMessageText faultTolerantResponseMessage = requestMessage.CreateResponseMessage(); + faultTolerantResponseMessage.Content = string.Format("测试容错,MsgId:{0},Ticks:{1}", + requestMessage.MsgId, + SystemTime.Now.Ticks); + return faultTolerantResponseMessage; + }) + .Keyword("TM", () => + { + string openId = requestMessage.FromUserName; + string checkCode = Guid.NewGuid().ToString("n").Substring(0, 3); //为了防止openId泄露造成骚扰,这里启用验证码 + TemplateMessageCollection[checkCode] = openId; + defaultResponseMessage.Content = + string.Format(@"新的验证码为:{0},请在网页上输入。网址:https://sdk.weixin.senparc.com/AsyncMethods", checkCode); + return defaultResponseMessage; + }) + .Keyword("OPENID", () => + { + string openId = requestMessage.FromUserName; //获取OpenId + Senparc.Weixin.MP.AdvancedAPIs.User.UserInfoJson userInfo = UserApi.Info(appId, openId); + + defaultResponseMessage.Content = string.Format( + "您的OpenID为:{0}\r\n昵称:{1}\r\n性别:{2}\r\n地区(国家/省/市):{3}/{4}/{5}\r\n关注时间:{6}\r\n关注状态:{7}", + requestMessage.FromUserName, userInfo.nickname, (WeixinSex)userInfo.sex, userInfo.country, + userInfo.province, userInfo.city, DateTimeHelper.GetDateTimeFromXml(userInfo.subscribe_time), + userInfo.subscribe); + return defaultResponseMessage; + }) + .Keyword("EX", () => + { + WeixinException ex = new WeixinException("openid:" + requestMessage.FromUserName + + ":这是一条测试异常信息"); //回调过程在global的ConfigWeixinTraceLog()方法中 + defaultResponseMessage.Content = "请等待异步模板消息发送到此界面上(自动延时数秒)。\r\n当前时间:" + SystemTime.Now; + return defaultResponseMessage; + }) + .Keyword("MUTE", () => //不回复任何消息 + { + //方案一: + return new SuccessResponseMessage(); + + //方案二: + ResponseMessageNoResponse muteResponseMessage = base.CreateResponseMessage(); + return muteResponseMessage; + + //方案三: + TextResponseMessage = "success"; + return null; + + //方案四: + return null; //在 Action 中结合使用 return new FixWeixinBugWeixinResult(messageHandler); + }) + .Keyword("JSSDK", () => + { + defaultResponseMessage.Content = "点击打开:https://sdk.weixin.senparc.com/WeixinJsSdk"; + return defaultResponseMessage; + }) + + //选择菜单,关键字:101(微信服务器端最终格式:id="s:101",content="满意") + .SelectMenuKeyword("101", () => + { + defaultResponseMessage.Content = $"感谢您的评价({requestMessage.Content})!我们会一如既往为提高企业和开发者生产力而努力!"; + return defaultResponseMessage; + }) + //选择菜单,关键字:102(微信服务器端最终格式:id="s:102",content="一般") + .SelectMenuKeyword("102", () => + { + defaultResponseMessage.Content = $"感谢您的评价({requestMessage.Content})!希望我们的服务能让您越来越满意!"; + return defaultResponseMessage; + }) + //选择菜单,关键字:103(微信服务器端最终格式:id="s:103",content="不满意") + .SelectMenuKeyword("103", () => + { + defaultResponseMessage.Content = + $"感谢您的评价({requestMessage.Content})!我们需要您的意见或建议,欢迎向我们反馈! 点击这里"; + return defaultResponseMessage; + }) + .SelectMenuKeywords(new[] { "110", "111" }, () => + { + defaultResponseMessage.Content = "这里只是演示,可以同时支持多个选择菜单"; + return defaultResponseMessage; + }) + + //“一次订阅消息”接口测试 + .Keyword("订阅", () => + { + defaultResponseMessage.Content = "点击打开:https://sdk.weixin.senparc.com/SubscribeMsg"; + return defaultResponseMessage; + }) + //正则表达式 + .Regex(@"^\d+#\d+$", () => + { + defaultResponseMessage.Content = + string.Format("您输入了:{0},符合正则表达式:^\\d+#\\d+$", requestMessage.Content); + return defaultResponseMessage; + }) + + //当 Default 使用异步方法时,需要写在最后一个,且 requestMessage.StartHandler() 前需要使用 await 等待异步方法执行; + //当 Default 使用同步方法,不一定要在最后一个,并且不需要使用 await + .Default(async () => + { + StringBuilder result = new StringBuilder(); + result.AppendFormat("您刚才发送了文字信息:{0}\r\n\r\n", requestMessage.Content); + + CustomMessageContext currentMessageContext = await base.GetCurrentMessageContext(); + if (currentMessageContext.RequestMessages.Count > 1) + { + result.AppendFormat("您刚才还发送了如下消息({0}/{1}):\r\n", currentMessageContext.RequestMessages.Count, + currentMessageContext.StorageData); + for (int i = currentMessageContext.RequestMessages.Count - 2; i >= 0; i--) + { + IRequestMessageBase historyMessage = currentMessageContext.RequestMessages[i]; + result.AppendFormat("{0} 【{1}】{2}\r\n", + historyMessage.CreateTime.ToString("HH:mm:ss"), + historyMessage.MsgType.ToString(), + historyMessage is RequestMessageText + ? (historyMessage as RequestMessageText).Content + : "[非文字类型]" + ); + } + + result.AppendLine("\r\n"); + } + + result.AppendFormat("如果您在{0}分钟内连续发送消息,记录将被自动保留(当前设置:最多记录{1}条)。过期后记录将会自动清除。\r\n", + GlobalMessageContext.ExpireMinutes, GlobalMessageContext.MaxRecordCount); + result.AppendLine("\r\n"); + result.AppendLine( + "您还可以发送【位置】【图片】【语音】【视频】等类型的信息(注意是这几种类型,不是这几个文字),查看不同格式的回复。\r\nSDK官方地址:https://sdk.weixin.senparc.com"); + + defaultResponseMessage.Content = result.ToString(); + + return defaultResponseMessage; + }); + + return requestHandler.GetResponseMessage(); + } + + /// + /// 处理位置请求 + /// + /// + /// + public override async Task OnLocationRequestAsync(RequestMessageLocation requestMessage) + { + LocationService locationService = new LocationService(); + ResponseMessageNews responseMessage = locationService.GetResponseMessage(requestMessage); + return responseMessage; + } + + public override async Task OnShortVideoRequestAsync( + RequestMessageShortVideo requestMessage) + { + ResponseMessageText responseMessage = CreateResponseMessage(); + responseMessage.Content = "您刚才发送的是小视频"; + return responseMessage; + } + + /// + /// 处理图片请求 + /// + /// + /// + public override async Task OnImageRequestAsync(RequestMessageImage requestMessage) + { + //一隔一返回News或Image格式 + if (base.GlobalMessageContext.GetMessageContext(requestMessage).RequestMessages.Count() % 2 == 0) + { + ResponseMessageNews responseMessage = CreateResponseMessage(); + + responseMessage.Articles.Add(new Article + { + Title = "您刚才发送了图片信息", + Description = "您发送的图片将会显示在边上", + PicUrl = requestMessage.PicUrl, + Url = "https://sdk.weixin.senparc.com" + }); + responseMessage.Articles.Add(new Article + { + Title = "第二条", + Description = "第二条带连接的内容", + PicUrl = requestMessage.PicUrl, + Url = "https://sdk.weixin.senparc.com" + }); + + return responseMessage; + } + else + { + ResponseMessageImage responseMessage = CreateResponseMessage(); + responseMessage.Image.MediaId = requestMessage.MediaId; + return responseMessage; + } + } + + /// + /// 处理语音请求 + /// + /// + /// + public override async Task OnVoiceRequestAsync(RequestMessageVoice requestMessage) + { + ResponseMessageMusic responseMessage = CreateResponseMessage(); + //上传缩略图 + //var accessToken = Containers.AccessTokenContainer.TryGetAccessToken(appId, appSecret); + Senparc.Weixin.MP.AdvancedAPIs.Media.UploadTemporaryMediaResult uploadResult = MediaApi.UploadTemporaryMedia(appId, UploadMediaFileType.image, + ServerUtility.ContentRootMapPath("~/Images/Logo.jpg")); + + //设置音乐信息 + responseMessage.Music.Title = "天籁之音"; + responseMessage.Music.Description = "播放您上传的语音"; + responseMessage.Music.MusicUrl = + "https://sdk.weixin.senparc.com/Media/GetVoice?mediaId=" + requestMessage.MediaId; + responseMessage.Music.HQMusicUrl = + "https://sdk.weixin.senparc.com/Media/GetVoice?mediaId=" + requestMessage.MediaId; + responseMessage.Music.ThumbMediaId = uploadResult.media_id; + + //推送一条客服消息 + try + { + CustomApi.SendText(appId, OpenId, "本次上传的音频MediaId:" + requestMessage.MediaId); + } + catch + { + } + + return responseMessage; + } + + /// + /// 处理视频请求 + /// + /// + /// + public override async Task OnVideoRequestAsync(RequestMessageVideo requestMessage) + { + ResponseMessageText responseMessage = CreateResponseMessage(); + responseMessage.Content = "您发送了一条视频信息,ID:" + requestMessage.MediaId; + + #region 上传素材并推送到客户端 + + Task.Factory.StartNew(async () => + { + //上传素材 + string dir = ServerUtility.ContentRootMapPath("~/App_Data/TempVideo/"); + string file = await MediaApi.GetAsync(appId, requestMessage.MediaId, dir); + Senparc.Weixin.MP.AdvancedAPIs.Media.UploadTemporaryMediaResult uploadResult = + await MediaApi.UploadTemporaryMediaAsync(appId, UploadMediaFileType.video, file, 50000); + await CustomApi.SendVideoAsync(appId, WeixinOpenId, uploadResult.media_id, "这是您刚才发送的视频", "这是一条视频消息"); + }).ContinueWith(async task => + { + if (task.Exception != null) + { + WeixinTrace.Log("OnVideoRequest()储存Video过程发生错误:", task.Exception.Message); + + string msg = string.Format("上传素材出错:{0}\r\n{1}", + task.Exception.Message, + task.Exception.InnerException != null + ? task.Exception.InnerException.Message + : null); + await CustomApi.SendTextAsync(appId, WeixinOpenId, msg); + } + }); + + #endregion 上传素材并推送到客户端 + + return responseMessage; + } + + /// + /// 处理链接消息请求 + /// + /// + /// + public override async Task OnLinkRequestAsync(RequestMessageLink requestMessage) + { + ResponseMessageText responseMessage = ResponseMessageBase.CreateFromRequestMessage(requestMessage); + responseMessage.Content = string.Format(@"您发送了一条连接信息: +Title:{0} +Description:{1} +Url:{2}", requestMessage.Title, requestMessage.Description, requestMessage.Url); + return responseMessage; + } + + public override async Task OnFileRequestAsync(RequestMessageFile requestMessage) + { + ResponseMessageText responseMessage = requestMessage.CreateResponseMessage(); + responseMessage.Content = string.Format(@"您发送了一个文件: +文件名:{0} +说明:{1} +大小:{2} +MD5:{3}", requestMessage.Title, requestMessage.Description, requestMessage.FileTotalLen, requestMessage.FileMd5); + return responseMessage; + } + + /// + /// 处理事件请求(这个方法一般不用重写,这里仅作为示例出现。除非需要在判断具体Event类型以外对Event信息进行统一操作 + /// + /// + /// + public override async Task OnEventRequestAsync(IRequestMessageEventBase requestMessage) + { + IResponseMessageBase eventResponseMessage = + await base.OnEventRequestAsync(requestMessage); //对于Event下属分类的重写方法,见:CustomerMessageHandler_Events.cs + //TODO: 对Event信息进行统一操作 + return eventResponseMessage; + } + + public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) + { + /* 所有没有被处理的消息会默认返回这里的结果, + * 因此,如果想把整个微信请求委托出去(例如需要使用分布式或从其他服务器获取请求), + * 只需要在这里统一发出委托请求,如: + * var responseMessage = MessageAgent.RequestResponseMessage(agentUrl, agentToken, RequestDocument.ToString()); + * return responseMessage; + */ + + ResponseMessageText responseMessage = CreateResponseMessage(); + responseMessage.Content = "这条消息来自DefaultResponseMessage。"; + return responseMessage; + } + + public override async Task OnUnknownTypeRequestAsync( + RequestMessageUnknownType requestMessage) + { + /* + * 此方法用于应急处理SDK没有提供的消息类型, + * 原始XML可以通过requestMessage.RequestDocument(或this.RequestDocument)获取到。 + * 如果不重写此方法,遇到未知的请求类型将会抛出异常(v14.8.3 之前的版本就是这么做的) + */ + string msgType = MsgTypeHelper.GetRequestMsgTypeString(requestMessage.RequestDocument); + ResponseMessageText responseMessage = CreateResponseMessage(); + responseMessage.Content = "未知消息类型:" + msgType; + + SenparcTrace.SendCustomLog("未知请求消息类型", requestMessage.RequestDocument.ToString()); //记录到日志中 + + return responseMessage; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler_Events.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler_Events.cs new file mode 100644 index 0000000..be3d32c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler_Events.cs @@ -0,0 +1,584 @@ +using Senparc.CO2NET.Extensions; +using Senparc.CO2NET.Trace; +using Senparc.CO2NET.Utilities; +using Senparc.NeuChar.Entities; +using Senparc.Weixin.Exceptions; +using Senparc.Weixin.MP; +using Senparc.Weixin.MP.AdvancedAPIs; +using Senparc.Weixin.MP.Entities; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.WeChat.CommonService.Download; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.CustomMessageHandler +{ + /// + /// 自定义MessageHandler + /// + public partial class CustomMessageHandler + { + private string GetWelcomeInfo() + { + //获取Senparc.Weixin.MP.dll版本信息 +#if NET45 + var filePath = ServerUtility.ContentRootMapPath("~/bin/Senparc.Weixin.MP.dll");//发布路径 +#else + //var filePath = ServerUtility.ContentRootMapPath("~/bin/Release/netcoreapp2.2/Senparc.Weixin.MP.dll");//本地测试路径 + string filePath = ServerUtility.ContentRootMapPath("~/Senparc.Weixin.MP.dll"); //发布路径 +#endif + FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath); + + string version = fileVersionInfo == null + ? "-" + : string.Format("{0}.{1}.{2}", fileVersionInfo.FileMajorPart, fileVersionInfo.FileMinorPart, + fileVersionInfo.FileBuildPart); + + return string.Format( + @"欢迎关注【Senparc.Weixin 微信公众平台SDK】,当前运行版本:v{0}。 +您可以发送【文字】【位置】【图片】【语音】【文件】等不同类型的信息,查看不同格式的回复。 +您也可以直接点击菜单查看各种类型的回复。 +还可以点击菜单体验微信支付。 +SDK官方地址:https://weixin.senparc.com +SDK Demo:https://sdk.weixin.senparc.com +源代码及Demo下载地址:https://github.com/JeffreySu/WeiXinMPSDK +Nuget地址:https://www.nuget.org/packages/Senparc.Weixin.MP +QQ群:289181996 +=============== +更多: +1、JSSDK测试:https://sdk.weixin.senparc.com/WeixinJSSDK +2、开放平台测试(建议PC上打开):https://sdk.weixin.senparc.com/OpenOAuth/JumpToMpOAuth +3、回复关键字: +【open】 进入第三方开放平台(Senparc.Weixin.Open)测试 +【tm】 测试异步模板消息 +【openid】 获取OpenId等用户信息 +【约束】 测试微信浏览器约束 +【AsyncTest】 异步并发测试 +【错误】 体验发生错误无法返回正确信息 +【容错】 体验去重容错 +【ex】 体验错误日志推送提醒 +【mute】 不返回任何消息,也无出错信息 +【jssdk】 测试JSSDK图文转发接口 +格式:【数字#数字】,如2010#0102,调用正则表达式匹配 +【订阅】 测试“一次性订阅消息”接口 +", + version); + } + + public string GetDownloadInfo(CodeRecord codeRecord) + { + return string.Format(@"您已通过二维码验证,浏览器即将开始下载 Senparc.Weixin SDK 帮助文档。 +当前选择的版本:v{0}({1}) +我们期待您的意见和建议,客服热线:400-031-8816。 +感谢您对盛派网络的支持! +© {2} Senparc", codeRecord.Version, codeRecord.IsWebVersion ? "网页版" : ".chm文档版", SystemTime.Now.Year); + } + + public override IResponseMessageBase OnTextOrEventRequest(RequestMessageText requestMessage) + { + // 预处理文字或事件类型请求。 + // 这个请求是一个比较特殊的请求,通常用于统一处理来自文字或菜单按钮的同一个执行逻辑, + // 会在执行OnTextRequest或OnEventRequest之前触发,具有以下一些特征: + // 1、如果返回null,则继续执行OnTextRequest或OnEventRequest + // 2、如果返回不为null,则终止执行OnTextRequest或OnEventRequest,返回最终ResponseMessage + // 3、如果是事件,则会将RequestMessageEvent自动转为RequestMessageText类型,其中RequestMessageText.Content就是RequestMessageEvent.EventKey + + if (requestMessage.Content == "OneClick") + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + strongResponseMessage.Content = "您点击了底部按钮。\r\n为了测试微信软件换行bug的应对措施,这里做了一个——\r\n换行"; + return strongResponseMessage; + } + + return null; //返回null,则继续执行OnTextRequest或OnEventRequest + } + + /// + /// 点击事件 + /// + /// 请求消息 + /// + public override IResponseMessageBase OnEvent_ClickRequest(RequestMessageEvent_Click requestMessage) + { + IResponseMessageBase reponseMessage = null; + //菜单点击,需要跟创建菜单时的Key匹配 + + switch (requestMessage.EventKey) + { + case "OneClick": + { + //这个过程实际已经在OnTextOrEventRequest中命中“OneClick”关键字,并完成回复,这里不会执行到。 + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Content = "您点击了底部按钮。\r\n为了测试微信软件换行bug的应对措施,这里做了一个——\r\n换行"; + } + break; + + case "SubClickRoot_Text": + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Content = "您点击了子菜单按钮。"; + } + break; + + case "SubClickRoot_News": + { + ResponseMessageNews strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Articles.Add(new Article + { + Title = "您点击了子菜单图文按钮", + Description = "您点击了子菜单图文按钮,这是一条图文信息。这个区域是Description内容\r\n可以使用\\r\\n进行换行。", + PicUrl = "https://sdk.weixin.senparc.com/Images/qrcode.jpg", + Url = "https://sdk.weixin.senparc.com" + }); + + //随机添加一条图文,或只输出一条图文信息 + if (SystemTime.Now.Second % 2 == 0) + { + strongResponseMessage.Articles.Add(new Article + { + Title = "这是随机产生的第二条图文信息,用于测试多条图文的样式", + Description = "这是随机产生的第二条图文信息,用于测试多条图文的样式", + PicUrl = "https://sdk.weixin.senparc.com/Images/qrcode.jpg", + Url = "https://sdk.weixin.senparc.com" + }); + } + } + break; + + case "SubClickRoot_Music": + { + //上传缩略图 + string filePath = "~/wwwroot/Images/Logo.thumb.jpg"; + Senparc.Weixin.MP.AdvancedAPIs.Media.UploadTemporaryMediaResult uploadResult = MediaApi.UploadTemporaryMedia(appId, UploadMediaFileType.thumb, + ServerUtility.ContentRootMapPath(filePath)); + //PS:缩略图官方没有特别提示文件大小限制,实际测试哪怕114K也会返回文件过大的错误,因此尽量控制在小一点(当前图片39K) + + //设置音乐信息 + ResponseMessageMusic strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Music.Title = "天籁之音"; + strongResponseMessage.Music.Description = "真的是天籁之音"; + strongResponseMessage.Music.MusicUrl = "https://sdk.weixin.senparc.com/Content/music1.mp3"; + strongResponseMessage.Music.HQMusicUrl = "https://sdk.weixin.senparc.com/Content/music1.mp3"; + strongResponseMessage.Music.ThumbMediaId = uploadResult.thumb_media_id; + } + break; + + case "SubClickRoot_Image": + { + string filePath = "~/wwwroot/Images/Logo.jpg"; + Senparc.Weixin.MP.AdvancedAPIs.Media.UploadTemporaryMediaResult uploadResult = MediaApi.UploadTemporaryMedia(appId, UploadMediaFileType.image, + ServerUtility.ContentRootMapPath(filePath)); + //设置图片信息 + ResponseMessageImage strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Image.MediaId = uploadResult.media_id; + } + break; + + case "SendMenu": //菜单消息 + { + //注意: + //1、此接口可以在任意地方调用(包括后台线程),此处演示为通过 + //2、一下"s:"前缀只是 Senparc.Weixin 的内部约定,可以使用 OnTextRequest事件中的 requestHandler.SelectMenuKeyword() 方法自动匹配到后缀(如101) + + List menuContentList = new List + { + new("101", "满意"), + new("102", "一般"), + new("103", "不满意") + }; + //使用异步接口 + CustomApi.SendMenuAsync(appId, OpenId, "请对 Senparc.Weixin SDK 给出您的评价", menuContentList, "感谢您的参与!"); + + reponseMessage = new ResponseMessageNoResponse(); //不返回任何消息 + } + break; + + + case "OAuth": //OAuth授权测试 + { + ResponseMessageNews strongResponseMessage = CreateResponseMessage(); + + strongResponseMessage.Articles.Add(new Article + { + Title = "OAuth2.0测试", + Description = "选择下面两种不同的方式进行测试,区别在于授权成功后,最后停留的页面。" + //Url = "https://sdk.weixin.senparc.com/oauth2", + //PicUrl = "https://sdk.weixin.senparc.com/Images/qrcode.jpg" + }); + + strongResponseMessage.Articles.Add(new Article + { + Title = "OAuth2.0测试(不带returnUrl),测试环境可使用", + Description = "OAuth2.0测试(不带returnUrl)", + Url = "https://sdk.weixin.senparc.com/oauth2", + PicUrl = "https://sdk.weixin.senparc.com/Images/qrcode.jpg" + }); + + string returnUrl = "/OAuth2/TestReturnUrl"; + strongResponseMessage.Articles.Add(new Article + { + Title = "OAuth2.0测试(带returnUrl),生产环境强烈推荐使用", + Description = "OAuth2.0测试(带returnUrl)", + Url = "https://sdk.weixin.senparc.com/oauth2?returnUrl=" + returnUrl.UrlEncode(), + PicUrl = "https://sdk.weixin.senparc.com/Images/qrcode.jpg" + }); + + reponseMessage = strongResponseMessage; + } + break; + + case "Description": + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + strongResponseMessage.Content = GetWelcomeInfo(); + reponseMessage = strongResponseMessage; + } + break; + + case "SubClickRoot_PicPhotoOrAlbum": + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Content = "您点击了【微信拍照】按钮。系统将会弹出拍照或者相册发图。"; + } + break; + + case "SubClickRoot_ScancodePush": + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Content = "您点击了【微信扫码】按钮。"; + } + break; + + case "ConditionalMenu_Male": + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Content = "您点击了个性化菜单按钮,您的微信性别设置为:男。"; + } + break; + + case "ConditionalMenu_Femle": + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + reponseMessage = strongResponseMessage; + strongResponseMessage.Content = "您点击了个性化菜单按钮,您的微信性别设置为:女。"; + } + break; + + case "GetNewMediaId": //获取新的MediaId + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + try + { + Senparc.Weixin.MP.AdvancedAPIs.Media.UploadForeverMediaResult result = MediaApi.UploadForeverMedia(appId, + ServerUtility.ContentRootMapPath("~/Images/logo.jpg")); + strongResponseMessage.Content = result.media_id; + } + catch (Exception e) + { + strongResponseMessage.Content = "发生错误:" + e.Message; + SenparcTrace.SendCustomLog("调用UploadForeverMedia()接口发生异常", e.Message); + } + } + break; + + default: + { + ResponseMessageText strongResponseMessage = CreateResponseMessage(); + strongResponseMessage.Content = "您点击了按钮,EventKey:" + requestMessage.EventKey; + reponseMessage = strongResponseMessage; + } + break; + } + + return reponseMessage; + } + + /// + /// 进入事件 + /// + /// + /// + public override IResponseMessageBase OnEvent_EnterRequest(RequestMessageEvent_Enter requestMessage) + { + ResponseMessageText responseMessage = ResponseMessageBase.CreateFromRequestMessage(requestMessage); + responseMessage.Content = "您刚才发送了ENTER事件请求。"; + return responseMessage; + } + + /// + /// 位置事件 + /// + /// + /// + public override IResponseMessageBase OnEvent_LocationRequest(RequestMessageEvent_Location requestMessage) + { + //这里是微信客户端(通过微信服务器)自动发送过来的位置信息 + ResponseMessageText responseMessage = CreateResponseMessage(); + responseMessage.Content = "这里写什么都无所谓,比如:上帝爱你!"; + return responseMessage; //这里也可以返回null(需要注意写日志时候null的问题) + } + + /// + /// 通过二维码扫描关注扫描事件 + /// + /// + /// + public override IResponseMessageBase OnEvent_ScanRequest(RequestMessageEvent_Scan requestMessage) + { + //通过扫描关注 + ResponseMessageText responseMessage = CreateResponseMessage(); + + //下载文档 + if (!string.IsNullOrEmpty(requestMessage.EventKey)) + { + long sceneId = long.Parse(requestMessage.EventKey.Replace("qrscene_", "")); + //var configHelper = new ConfigHelper(new HttpContextWrapper(HttpContext.Current)); + CodeRecord codeRecord = + ConfigHelper.CodeCollection.Values.FirstOrDefault(z => + z.QrCodeTicket != null && z.QrCodeId == sceneId); + + if (codeRecord != null) + { + //确认可以下载 + codeRecord.AllowDownload = true; + responseMessage.Content = GetDownloadInfo(codeRecord); + } + } + + responseMessage.Content = + responseMessage.Content ?? string.Format("通过扫描二维码进入,场景值:{0}", requestMessage.EventKey); + + return responseMessage; + } + + /// + /// 打开网页事件 + /// + /// + /// + public override IResponseMessageBase OnEvent_ViewRequest(RequestMessageEvent_View requestMessage) + { + //说明:这条消息只作为接收,下面的responseMessage到达不了客户端,类似OnEvent_UnsubscribeRequest + ResponseMessageText responseMessage = CreateResponseMessage(); + responseMessage.Content = "您点击了view按钮,将打开网页:" + requestMessage.EventKey; + return responseMessage; + } + + /// + /// 群发完成事件 + /// + /// + /// + public override IResponseMessageBase OnEvent_MassSendJobFinishRequest( + RequestMessageEvent_MassSendJobFinish requestMessage) + { + ResponseMessageText responseMessage = CreateResponseMessage(); + responseMessage.Content = "接收到了群发完成的信息。"; + return responseMessage; + } + + /// + /// 订阅(关注)事件 + /// + /// + public override IResponseMessageBase OnEvent_SubscribeRequest(RequestMessageEvent_Subscribe requestMessage) + { + ResponseMessageText responseMessage = ResponseMessageBase.CreateFromRequestMessage(requestMessage); + responseMessage.Content = GetWelcomeInfo(); + if (!string.IsNullOrEmpty(requestMessage.EventKey)) + { + responseMessage.Content += "\r\n============\r\n场景值:" + requestMessage.EventKey; + } + + //推送消息 + //下载文档 + if (requestMessage.EventKey.StartsWith("qrscene_")) + { + long sceneId = long.Parse(requestMessage.EventKey.Replace("qrscene_", "")); + //var configHelper = new ConfigHelper(new HttpContextWrapper(HttpContext.Current)); + CodeRecord codeRecord = + ConfigHelper.CodeCollection.Values.FirstOrDefault(z => + z.QrCodeTicket != null && z.QrCodeId == sceneId); + + if (codeRecord != null) + { + if (codeRecord.AllowDownload) + { + Task.Factory.StartNew(() => + CustomApi.SendTextAsync(null, OpenId, "下载已经开始,如需下载其他版本,请刷新页面后重新扫一扫。")); + } + else + { + //确认可以下载 + codeRecord.AllowDownload = true; + Task.Factory.StartNew(() => CustomApi.SendTextAsync(null, OpenId, GetDownloadInfo(codeRecord))); + } + } + } + + return responseMessage; + } + + /// + /// 退订 + /// 实际上用户无法收到非订阅账号的消息,所以这里可以随便写。 + /// unsubscribe事件的意义在于及时删除网站应用中已经记录的OpenID绑定,消除冗余数据。并且关注用户流失的情况。 + /// + /// + public override IResponseMessageBase OnEvent_UnsubscribeRequest(RequestMessageEvent_Unsubscribe requestMessage) + { + ResponseMessageText responseMessage = base.CreateResponseMessage(); + responseMessage.Content = "有空再来"; + return responseMessage; + } + + /// + /// 事件之扫码推事件(scancode_push) + /// + /// + /// + public override IResponseMessageBase OnEvent_ScancodePushRequest( + RequestMessageEvent_Scancode_Push requestMessage) + { + ResponseMessageText responseMessage = base.CreateResponseMessage(); + responseMessage.Content = "事件之扫码推事件"; + return responseMessage; + } + + /// + /// 事件之扫码推事件且弹出“消息接收中”提示框(scancode_waitmsg) + /// + /// + /// + public override IResponseMessageBase OnEvent_ScancodeWaitmsgRequest( + RequestMessageEvent_Scancode_Waitmsg requestMessage) + { + ResponseMessageText responseMessage = base.CreateResponseMessage(); + responseMessage.Content = "事件之扫码推事件且弹出“消息接收中”提示框"; + return responseMessage; + } + + /// + /// 事件之弹出拍照或者相册发图(pic_photo_or_album) + /// + /// + /// + public override IResponseMessageBase OnEvent_PicPhotoOrAlbumRequest( + RequestMessageEvent_Pic_Photo_Or_Album requestMessage) + { + ResponseMessageText responseMessage = base.CreateResponseMessage(); + responseMessage.Content = "事件之弹出拍照或者相册发图"; + return responseMessage; + } + + /// + /// 事件之弹出系统拍照发图(pic_sysphoto) + /// 实际测试时发现微信并没有推送RequestMessageEvent_Pic_Sysphoto消息,只能接收到用户在微信中发送的图片消息。 + /// + /// + /// + public override IResponseMessageBase OnEvent_PicSysphotoRequest(RequestMessageEvent_Pic_Sysphoto requestMessage) + { + ResponseMessageText responseMessage = base.CreateResponseMessage(); + responseMessage.Content = "事件之弹出系统拍照发图"; + return responseMessage; + } + + /// + /// 事件之弹出微信相册发图器(pic_weixin) + /// + /// + /// + public override IResponseMessageBase OnEvent_PicWeixinRequest(RequestMessageEvent_Pic_Weixin requestMessage) + { + ResponseMessageText responseMessage = base.CreateResponseMessage(); + responseMessage.Content = "事件之弹出微信相册发图器"; + return responseMessage; + } + + /// + /// 事件之弹出地理位置选择器(location_select) + /// + /// + /// + public override IResponseMessageBase OnEvent_LocationSelectRequest( + RequestMessageEvent_Location_Select requestMessage) + { + ResponseMessageText responseMessage = base.CreateResponseMessage(); + responseMessage.Content = "事件之弹出地理位置选择器"; + return responseMessage; + } + + /// + /// 事件之发送模板消息返回结果 + /// + /// + /// + public override IResponseMessageBase OnEvent_TemplateSendJobFinishRequest( + RequestMessageEvent_TemplateSendJobFinish requestMessage) + { + switch (requestMessage.Status) + { + case "success": + //发送成功 + + break; + + case "failed:user block": + //送达由于用户拒收(用户设置拒绝接收公众号消息)而失败 + break; + + case "failed: system failed": + //送达由于其他原因失败 + break; + + default: + throw new WeixinException("未知模板消息状态:" + requestMessage.Status); + } + + //注意:此方法内不能再发送模板消息,否则会造成无限循环! + + try + { + string msg = @"已向您发送模板消息 +状态:{0} +MsgId:{1} +(这是一条来自MessageHandler的客服消息)".FormatWith(requestMessage.Status, requestMessage.MsgID); + CustomApi.SendText(appId, OpenId, msg); //发送客服消息 + } + catch (Exception e) + { + SenparcTrace.SendCustomLog("模板消息发送失败", e.ToString()); + } + + //无需回复文字内容 + //return requestMessage + // .CreateResponseMessage(); + return null; + } + + #region 微信认证事件推送 + + public override IResponseMessageBase OnEvent_QualificationVerifySuccessRequest( + RequestMessageEvent_QualificationVerifySuccess requestMessage) + { + //以下方法可以强制定义返回的字符串值 + //TextResponseMessage = "your content"; + //return null; + + return new SuccessResponseMessage(); //返回"success"字符串 + } + + #endregion 微信认证事件推送 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/OpenMessageHandler/OpenCheckMessageHandler.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/OpenMessageHandler/OpenCheckMessageHandler.cs new file mode 100644 index 0000000..e2ceeb9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/OpenMessageHandler/OpenCheckMessageHandler.cs @@ -0,0 +1,78 @@ +using Senparc.NeuChar.Entities; +using Senparc.NeuChar.Helpers; +using Senparc.Weixin.MP.AdvancedAPIs; +using Senparc.Weixin.MP.Entities; +using Senparc.Weixin.MP.Entities.Request; +using Senparc.Weixin.MP.MessageHandlers; +using Senparc.Weixin.Open.ComponentAPIs; +using System.IO; +using Znyc.Cloudcar.Admin.WeChat.CommonService.CustomMessageHandler; +using Znyc.Cloudcar.Admin.WeChat.CommonService.OpenTicket; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.OpenMessageHandler +{ + /// + /// 开放平台全网发布之前需要做的验证 + /// + public class OpenCheckMessageHandler : MessageHandler + { + /* + https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318611&lang=zh_CN + 自动化测试的专用测试公众号的信息如下: + (1)appid: wx570bc396a51b8ff8 + (2)Username: gh_3c884a361561 + */ + + //private string testAppId = "wx570bc396a51b8ff8"; + + private readonly string componentAppId = "ComponentAppId"; + private readonly string componentSecret = "Component_Secret"; + + public OpenCheckMessageHandler(Stream inputStream, PostModel postModel, int maxRecordCount = 0) + : base(inputStream, postModel, maxRecordCount) + { + } + + public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage) + { + if (requestMessage.Content == "TESTCOMPONENT_MSG_TYPE_TEXT") + { + ResponseMessageText responseMessage = requestMessage.CreateResponseMessage(); + responseMessage.Content = + requestMessage.Content + "_callback"; //固定为TESTCOMPONENT_MSG_TYPE_TEXT_callback + return responseMessage; + } + + if (requestMessage.Content.StartsWith("QUERY_AUTH_CODE:")) + { + string openTicket = OpenTicketHelper.GetOpenTicket(componentAppId); + string query_auth_code = requestMessage.Content.Replace("QUERY_AUTH_CODE:", ""); + string component_access_token = ComponentApi + .GetComponentAccessToken(componentAppId, componentSecret, openTicket).component_access_token; + QueryAuthResult oauthResult = ComponentApi.QueryAuth(component_access_token, componentAppId, query_auth_code); + + //调用客服接口 + string content = query_auth_code + "_from_api"; + Senparc.Weixin.Entities.WxJsonResult sendResult = CustomApi.SendText( + oauthResult.authorization_info.authorizer_access_token, + requestMessage.FromUserName, content); + } + + return null; + } + + public override IResponseMessageBase OnEventRequest(IRequestMessageEventBase requestMessage) + { + ResponseMessageText responseMessage = requestMessage.CreateResponseMessage(); + responseMessage.Content = requestMessage.Event + "from_callback"; + return responseMessage; + } + + public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) + { + ResponseMessageText responseMessage = requestMessage.CreateResponseMessage(); + responseMessage.Content = "默认消息"; + return responseMessage; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WebSocket/CustomNetCoreWebSocketMessageHandler.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WebSocket/CustomNetCoreWebSocketMessageHandler.cs new file mode 100644 index 0000000..b98c90c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WebSocket/CustomNetCoreWebSocketMessageHandler.cs @@ -0,0 +1,77 @@ +using Senparc.CO2NET.Trace; +using Senparc.WebSocket; +using Senparc.Weixin; +using Senparc.Weixin.WxOpen.Containers; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.MessageHandlers.WebSocket +{ + /// + /// .NET Core 自定义 WebSocket 处理类 + /// + public class CustomNetCoreWebSocketMessageHandler : WebSocketMessageHandler + { + public override Task OnConnecting(WebSocketHelper webSocketHandler) + { + //TODO:处理连接时的逻辑 + return base.OnConnecting(webSocketHandler); + } + + public override Task OnDisConnected(WebSocketHelper webSocketHandler) + { + //TODO:处理断开连接时的逻辑 + return base.OnDisConnected(webSocketHandler); + } + + public override async Task OnMessageReceiced(WebSocketHelper webSocketHandler, ReceivedMessage receivedMessage, + string originalData) + { + if (receivedMessage == null || string.IsNullOrEmpty(receivedMessage.Message)) + { + return; + } + + string message = receivedMessage.Message; + + await webSocketHandler.SendMessage("originalData:" + originalData, + webSocketHandler.WebSocket.Clients.Caller); + await webSocketHandler.SendMessage("您发送了文字:" + message, webSocketHandler.WebSocket.Clients.Caller); + await webSocketHandler.SendMessage("正在处理中(反转文字)...", webSocketHandler.WebSocket.Clients.Caller); + + await Task.Delay(1000); + + //处理文字 + string result = string.Concat(message.Reverse()); + await webSocketHandler.SendMessage(result, webSocketHandler.WebSocket.Clients.Caller); + + string appId = Config.SenparcWeixinSetting.WxOpenAppId; //与微信小程序账号后台的AppId设置保持一致,区分大小写。 + + try + { + SessionBag sessionBag = SessionContainer.GetSession(receivedMessage.SessionId); + + //临时演示使用固定openId + string openId = sessionBag != null ? sessionBag.OpenId : "onh7q0DGM1dctSDbdByIHvX4imxA"; // "用户未正确登陆"; + + //await webSocketHandler.SendMessage("OpenId:" + openId, webSocketHandler.WebSocket.Clients.Caller); + //await webSocketHandler.SendMessage("FormId:" + formId); + + //群发 + await webSocketHandler.SendMessage( + $"[群发消息] [来自 OpenId:***{openId.Substring(openId.Length - 10, 10)},昵称:{sessionBag.DecodedUserInfo?.nickName}]:{message}", + webSocketHandler.WebSocket.Clients.All); + } + catch (Exception ex) + { + string msg = ex.Message + "\r\n\r\n" + originalData + "\r\n\r\nAPPID:" + appId; + + await webSocketHandler.SendMessage(msg, + webSocketHandler.WebSocket.Clients.Caller); //VS2017以下如果编译不通过,可以注释掉这一行 + + SenparcTrace.SendCustomLog("WebSocket OnMessageReceiced()过程出错", msg); + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WxOpenMessageHandler/CustomWxOpenMessageContext.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WxOpenMessageHandler/CustomWxOpenMessageContext.cs new file mode 100644 index 0000000..0cbe7c1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WxOpenMessageHandler/CustomWxOpenMessageContext.cs @@ -0,0 +1,52 @@ +using Senparc.NeuChar; +using Senparc.NeuChar.Context; +using Senparc.NeuChar.Entities; +using System; +using System.Xml.Linq; + +namespace Znyc.Cloudcar.Admin.WeChat.MessageHandlers.WxOpenMessageHandler +{ + public class CustomWxOpenMessageContext : MessageContext + { + public CustomWxOpenMessageContext() + { + base.MessageContextRemoved += CustomMessageContext_MessageContextRemoved; + } + + public override IRequestMessageBase GetRequestEntityMappingResult(RequestMsgType requestMsgType, + XDocument doc = null) + { + throw new NotImplementedException(); + } + + public override IResponseMessageBase GetResponseEntityMappingResult(ResponseMsgType responseMsgType, + XDocument doc = null) + { + throw new NotImplementedException(); + } + + /// + /// 当上下文过期,被移除时触发的时间 + /// + /// + /// + private void CustomMessageContext_MessageContextRemoved(object sender, + WeixinContextRemovedEventArgs e) + { + /* 注意,这个事件不是实时触发的(当然你也可以专门写一个线程监控) + * 为了提高效率,根据WeixinContext中的算法,这里的过期消息会在过期后下一条请求执行之前被清除 + */ + + CustomWxOpenMessageContext messageContext = e.MessageContext as CustomWxOpenMessageContext; + if (messageContext == null) + { + return; //如果是正常的调用,messageContext不会为null + } + + //TODO:这里根据需要执行消息过期时候的逻辑,下面的代码仅供参考 + + //Log.InfoFormat("{0}的消息上下文已过期",e.OpenId); + //api.SendMessage(e.OpenId, "由于长时间未搭理客服,您的客服状态已退出!"); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WxOpenMessageHandler/CustomWxOpenMessageHandler.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WxOpenMessageHandler/CustomWxOpenMessageHandler.cs new file mode 100644 index 0000000..8520934 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/MessageHandlers/WxOpenMessageHandler/CustomWxOpenMessageHandler.cs @@ -0,0 +1,83 @@ +using Senparc.NeuChar.Entities; +using Senparc.Weixin; +using Senparc.Weixin.WxOpen.Entities; +using Senparc.Weixin.WxOpen.Entities.Request; +using Senparc.Weixin.WxOpen.MessageHandlers; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.WeChat.MessageHandlers.WxOpenMessageHandler +{ + /// + /// 自定义MessageHandler + /// 把MessageHandler作为基类,重写对应请求的处理方法 + /// + public class CustomWxOpenMessageHandler : WxOpenMessageHandler + { + /// + /// 为中间件提供生成当前类的委托 + /// + public static Func GenerateMessageHandler = + (stream, postModel, maxRecordCount) => new CustomWxOpenMessageHandler(stream, postModel, maxRecordCount); + + private readonly string appId = Config.SenparcWeixinSetting.WxOpenAppId; + private readonly string appSecret = Config.SenparcWeixinSetting.WxOpenAppSecret; + + public CustomWxOpenMessageHandler(Stream inputStream, PostModel postModel, int maxRecordCount = 0) + : base(inputStream, postModel, maxRecordCount) + { + //这里设置仅用于测试,实际开发可以在外部更全局的地方设置, + //比如MessageHandler.GlobalGlobalMessageContext.ExpireMinutes = 3。 + GlobalMessageContext.ExpireMinutes = 3; + + if (!string.IsNullOrEmpty(postModel.AppId)) + { + appId = postModel.AppId; //通过第三方开放平台发送过来的请求 + } + + //在指定条件下,不使用消息去重 + OmitRepeatedMessageFunc = requestMessage => + { + RequestMessageText textRequestMessage = requestMessage as RequestMessageText; + if (textRequestMessage != null && textRequestMessage.Content == "容错") + { + return false; + } + + return true; + }; + } + + public override async Task OnExecutingAsync(CancellationToken cancellationToken) + { + //测试MessageContext.StorageData + CustomWxOpenMessageContext currentMessageContext = await base.GetCurrentMessageContext(); + if (currentMessageContext.StorageData == null || currentMessageContext.StorageData is int) + { + currentMessageContext.StorageData = 0; + } + + await base.OnExecutingAsync(cancellationToken); + } + + public override async Task OnExecutedAsync(CancellationToken cancellationToken) + { + await base.OnExecutedAsync(cancellationToken); + CustomWxOpenMessageContext currentMessageContext = await base.GetCurrentMessageContext(); + currentMessageContext.StorageData = (int)currentMessageContext.StorageData + 1; + } + + public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) + { + //所有没有被处理的消息会默认返回这里的结果 + + return new SuccessResponseMessage(); + + //return new SuccessResponseMessage();等效于: + //base.TextResponseMessage = "success"; + //return null; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/OpenTicket/OpenTicketHelper.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/OpenTicket/OpenTicketHelper.cs new file mode 100644 index 0000000..2ca5849 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/OpenTicket/OpenTicketHelper.cs @@ -0,0 +1,38 @@ +using Senparc.CO2NET.Utilities; +using Senparc.Weixin.Exceptions; +using System.IO; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.OpenTicket +{ + /// + /// OpenTicket即ComponentVerifyTicket + /// + public class OpenTicketHelper + { + public static string GetOpenTicket(string componentAppId) + { + //实际开发过程不一定要用文件记录,也可以用数据库。 + string openTicketPath = ServerUtility.ContentRootMapPath("~/App_Data/OpenTicket"); + string openTicket = null; + string filePath = Path.Combine(openTicketPath, string.Format("{0}.txt", componentAppId)); + if (File.Exists(filePath)) + { + using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) + { + using (TextReader tr = new StreamReader(fs)) + { + openTicket = tr.ReadToEnd(); + } + } + } + else + { + throw new WeixinException("OpenTicket不存在!"); + } + + //其他逻辑 + + return openTicket; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/SubscribeMessage/WxApplet/WxAppletSubscribeMessage.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/SubscribeMessage/WxApplet/WxAppletSubscribeMessage.cs new file mode 100644 index 0000000..8dc1e83 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/SubscribeMessage/WxApplet/WxAppletSubscribeMessage.cs @@ -0,0 +1,132 @@ +using Senparc.Weixin.Entities; +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.WxOpen.AdvancedAPIs; +using Znyc.Cloudcar.Admin.Commons.Core.App; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.SubscribeMessage.WxApplet +{ + /// + /// 小程序订阅消息 + /// + public class WxAppletSubscribeMessage + { + private static readonly SenparcWeixinSetting senparcWeixinSetting = App.GetService(); + private static readonly string weixinAppId = senparcWeixinSetting.WxOpenAppId; + + /// + /// 留言提醒,模板编号:1069 + /// + /// 接收者(用户)的 openid + /// 消息模板Id + /// 留言内容,20个以内字符 + /// 留言时间,4小时制时间格式(支持+年月日) 例如:15:01,或:2019年10月1日 15:01 + /// 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + public static WxJsonResult SendCommentNotice(string toUser, string templateId, string text, string date, + string page) + { + TemplateMessageData data = new TemplateMessageData + { + ["thing1"] = new(text), + ["time2"] = new(date) + }; + var submitData = new + { + touser = toUser, + template_id = templateId, + page, + data + }; + return MessageApi.SendSubscribe(weixinAppId, toUser, templateId, data, page); + } + + /// + /// 新的评论提醒 ,模板编号:484 + /// + /// 接收者(用户)的 openid + /// 消息模板Id + /// 文章标题,20个以内字符 + /// 评论内容,20个以内字符 + /// 评论时间,4小时制时间格式(支持+年月日) 例如:15:01,或:2019年10月1日 15:01 + /// 评论用户,20个以内字符 + /// + public static WxJsonResult SendRemarkNotice(string toUser, string templateId, string title, string desc, + string date, string userNick, string page) + { + TemplateMessageData data = new TemplateMessageData + { + {"thing1", new TemplateMessageDataValue(title)}, + {"thing2", new TemplateMessageDataValue(desc)}, + {"time3", new TemplateMessageDataValue(date)}, + {"thing5", new TemplateMessageDataValue(userNick)} + }; + return MessageApi.SendSubscribe(weixinAppId, toUser, templateId, data, page); + } + + /// + /// 动态点赞通知,模板编号:579 + /// + /// 接收者(用户)的 openid + /// 消息模板Id + /// 点赞用户,20个以内字符 + /// 点赞时间,4小时制时间格式(支持+年月日) 例如:15:01,或:2019年10月1日 15:01 + /// 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + public static WxJsonResult SendGoodNotice(string toUser, string templateId, string name, string date, + string page) + { + TemplateMessageData data = new TemplateMessageData + { + {"name1", new TemplateMessageDataValue(name)}, + {"date2", new TemplateMessageDataValue(date)} + }; + return MessageApi.SendSubscribe(weixinAppId, toUser, templateId, data, page); + } + + /// + /// 资讯早报通知,模板编号:269 + /// + /// 接收者(用户)的 openid + /// 消息模板Id + /// 更新内容,20个以内字符 + /// 备注,20个以内字符 + /// 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + public static WxJsonResult SendNewsMorningNotice(string toUser, string templateId, string title, string remark, + string page) + { + TemplateMessageData data = new TemplateMessageData + { + ["thing1"] = new(title), + ["thing2"] = new(remark) + }; + var submitData = new + { + touser = toUser, + template_id = templateId, + page, + data + }; + return MessageApi.SendSubscribe(weixinAppId, toUser, templateId, data, page); + } + + /// + /// 校验一张图片是否含有违法违规内容 + /// https://developers.weixin.qq.com/miniprogram/dev/api/imgSecCheck.html + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// 文件完整物理路径格式支持PNG、JPEG、JPG、GIF,图片尺寸不超过 750px * 1334px + /// + /// + //[ApiBind(Senparc.NeuChar.PlatformType.WeChat_MiniProgram, "WxAppApi.ImgSecCheck", true)] + //public async static Task ImgSecCheck(string accessTokenOrAppId, string filePath, int timeOut = Config.TIME_OUT) + //{ + // return WxOpenApiHandlerWapper.TryCommonApi(async accessToken => + // { + // string urlFormat = Config.ApiMpHost + "/wxa/img_sec_check?access_token={0}"; + // var url = urlFormat.FormatWith(accessToken); + // var fileDic = new Dictionary(); + // fileDic["media"] = filePath; + // return await Senparc.CO2NET.HttpUtility.Post.PostFileGetJsonAsync(url,fileDictionary: fileDic); + + // }, accessTokenOrAppId); + //} + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage.cs new file mode 100644 index 0000000..9e0994b --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage.cs @@ -0,0 +1,77 @@ +using Senparc.CO2NET.Cache; +using Senparc.Weixin.TenPay.V3; +using Senparc.Weixin.WxOpen.Containers; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.WeChat.CommonService.TemplateMessage.WxOpen; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService +{ + public class TemplateMessageService + { + public async Task RunTemplateTestAsync(string wxOpenAppId, string sessionId, string formId) + { + SessionBag sessionBag = await SessionContainer.GetSessionAsync(sessionId); + string openId = sessionBag != null ? sessionBag.OpenId : "用户未正确登陆"; + + string title = null; + decimal price = 1; //单位:分,实际使用过程中,通过数据库获取订单并读取 + string productName = null; + string orderNumber = null; + + if (formId.StartsWith("prepay_id=")) + { + formId = formId.Replace("prepay_id=", ""); + title = "这是来自小程序支付的模板消息(仅测试接收,数据不一定真实)"; + + IBaseObjectCacheStrategy cacheStrategy = CacheStrategyFactory.GetObjectCacheStrategyInstance(); + TenPayV3UnifiedorderRequestData unifiedorderRequestData = + await cacheStrategy.GetAsync( + $"WxOpenUnifiedorderRequestData-{openId}"); //获取订单请求信息缓存 + UnifiedorderResult unifedorderResult = + await cacheStrategy.GetAsync( + $"WxOpenUnifiedorderResultData-{openId}"); //获取订单信息缓存 + + if (unifedorderResult != null && formId == unifedorderResult.prepay_id) + { + price = unifiedorderRequestData.TotalFee; + productName = unifiedorderRequestData.Body + "/缓存获取 prepay_id 成功"; + orderNumber = unifiedorderRequestData.OutTradeNo; + } + else + { + productName = "缓存获取 prepay_id 失败"; + orderNumber = "1234567890"; + } + + productName += " | 注意:这条消息是从小程序发起的!仅作为UI上支付成功的演示!不能确定支付真实成功! | prepay_id:" + + unifedorderResult.prepay_id; + } + else + { + title = "在线购买(仅测试小程序接收模板消息,数据不一定真实)"; + productName = "商品名称-模板消息测试"; + orderNumber = "9876543210"; + } + + WxOpenTemplateMessage_PaySuccessNotice data = new WxOpenTemplateMessage_PaySuccessNotice(title, SystemTime.Now, productName, orderNumber, + price, + "400-031-8816", "https://sdk.senparc.weixin.com"); + + //await Senparc.Weixin.WxOpen.AdvancedAPIs + // .Template.TemplateApi + // .SendTemplateMessageAsync( + // wxOpenAppId, openId, data.TemplateId, data, formId, "pages/index/index", "图书", "#fff00"); + + return sessionBag; + } + + [Obsolete("建议使用 RunTemplateTestAsync 方法")] + public SessionBag RunTemplateTest(string wxOpenAppId, string sessionId, string formId) + { + SessionBag sessionBag = RunTemplateTestAsync(wxOpenAppId, sessionId, formId).ConfigureAwait(false).GetAwaiter() + .GetResult(); + return sessionBag; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/TemplateApi.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/TemplateApi.cs new file mode 100644 index 0000000..be1dc0c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/TemplateApi.cs @@ -0,0 +1,132 @@ +using Senparc.NeuChar; +using Senparc.Weixin; +using Senparc.Weixin.CommonAPIs; +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.MP; +using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage; +using System.Threading.Tasks; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.TemplateMessage +{ + /// + /// 模板消息接口 + /// + public static class TemplateApi + { + /// + /// 获取URL:一次性订阅消息,第一步引导用户打开链接进行授权 + /// 文档地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1500374289_66bvB + /// + /// 公众号的唯一标识 + /// 重定向后会带上scene参数,开发者可以填0-10000的整形值,用来标识订阅场景值 + /// 订阅消息模板ID,登录公众平台后台,在接口权限列表处可查看订阅模板ID + /// 授权后重定向的回调地址,请使用UrlEncode对链接进行处理。注:要求redirect_url的域名要跟登记的业务域名一致,且业务域名不能带路径 + /// (非必填)用于保持请求和回调的状态,授权请后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验,开发者可以填写a-zA-Z0-9的参数值,最多128字节 + /// 直接填get_confirm即可,保留默认值 + /// + [ApiBind(Senparc.NeuChar.PlatformType.WeChat_OfficialAccount, "TemplateApi.GetSubscribeMsgUrl", true)] + public static string GetSubscribeMsgUrl(string appId, int scene, string templateId, string redirectUrl, string reserved = null, string action = "get_confirm") + { + //无论直接打开还是做页面302重定向时,必须带#wechat_redirect参数 + return string.Format("https://mp.weixin.qq.com/mp/subscribemsg?action={0}&appid={1}&scene={2}&template_id={3}&redirect_url={4}&reserved={5}#wechat_redirect", + action, appId, scene, templateId, redirectUrl, reserved); + } + + + /// + /// 模板消息接口 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// 填接收消息的用户openid + /// 订阅消息模板ID + /// (非必须)点击消息跳转的链接,需要有ICP备案 + /// 消息正文,value为消息内容文本(200字以内),没有固定格式,可用\n换行,color为整段消息内容的字体颜色(目前仅支持整段消息为一种颜色) + /// (非必须)跳小程序所需数据,不需跳小程序可不用传该数据 + /// 代理请求超时时间(毫秒) + /// + [ApiBind(Senparc.NeuChar.PlatformType.WeChat_OfficialAccount, "TemplateApi.SendTemplateMessage", true)] + public static SendTemplateMessageResult SendTemplateMessage(string accessTokenOrAppId, string openId, string templateId, string url, object data, TemplateModel_MiniProgram miniProgram = null, int timeOut = Config.TIME_OUT) + { + //文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1500374289_66bvB + + return ApiHandlerWapper.TryCommonApi(accessToken => + { + string urlFormat = Config.ApiMpHost + "/cgi-bin/message/template/send?access_token={0}"; + var msgData = new TemplateModel() + { + touser = openId, + template_id = templateId, + // topcolor = topcolor, + url = url, + miniprogram = miniProgram, + data = data, + }; + return CommonJsonSend.Send(accessToken, urlFormat, msgData, timeOut: timeOut); + + }, accessTokenOrAppId); + } + + /// + /// 模板消息接口 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// + /// + /// 跳小程序所需数据,不需跳小程序可不用传该数据 + /// 代理请求超时时间(毫秒) + /// + [ApiBind(Senparc.NeuChar.PlatformType.WeChat_OfficialAccount, "TemplateApi.SendTemplateMessage", true)] + public static SendTemplateMessageResult SendTemplateMessage(string accessTokenOrAppId, string openId, ITemplateMessageBase templateMessageData, TemplateModel_MiniProgram miniProgram = null, int timeOut = Config.TIME_OUT) + { + return SendTemplateMessage(accessTokenOrAppId, openId, templateMessageData.TemplateId, + templateMessageData.Url, templateMessageData, miniProgram, timeOut); + } + /// + /// 【异步方法】模板消息接口 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// 填接收消息的用户openid + /// 订阅消息模板ID + /// (非必须)点击消息跳转的链接,需要有ICP备案 + /// 消息正文,value为消息内容文本(200字以内),没有固定格式,可用\n换行,color为整段消息内容的字体颜色(目前仅支持整段消息为一种颜色) + /// (非必须)跳小程序所需数据,不需跳小程序可不用传该数据 + /// 代理请求超时时间(毫秒) + /// /// + [ApiBind(Senparc.NeuChar.PlatformType.WeChat_OfficialAccount, "TemplateApi.SendTemplateMessageAsync", true)] + public static async Task SendTemplateMessageAsync(string accessTokenOrAppId, string openId, string templateId, string url, object data, TemplateModel_MiniProgram miniProgram = null, int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + string urlFormat = Config.ApiMpHost + "/cgi-bin/message/template/send?access_token={0}"; + var msgData = new TemplateModel() + { + touser = openId, + template_id = templateId, + // topcolor = topcolor, + url = url, + miniprogram = miniProgram, + data = data, + }; + return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(accessToken, urlFormat, msgData, timeOut: timeOut).ConfigureAwait(false); + + }, accessTokenOrAppId).ConfigureAwait(false); + } + + + /// + /// 【异步方法】模板消息接口 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// + /// 跳小程序所需数据,不需跳小程序可不用传该数据 + /// + /// 代理请求超时时间(毫秒) + /// + [ApiBind(Senparc.NeuChar.PlatformType.WeChat_OfficialAccount, "TemplateApi.SendTemplateMessageAsync", true)] + public static async Task SendTemplateMessageAsync(string accessTokenOrAppId, string openId, ITemplateMessageBase templateMessageData, TemplateModel_MiniProgram miniProgram = null, int timeOut = Config.TIME_OUT) + { + return await SendTemplateMessageAsync(accessTokenOrAppId, openId, templateMessageData.TemplateId, + templateMessageData.Url, templateMessageData, miniProgram, timeOut).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_ExceptionAlert.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_ExceptionAlert.cs new file mode 100644 index 0000000..158bb92 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_ExceptionAlert.cs @@ -0,0 +1,65 @@ +//DPBMARK_FILE MP + +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage; +using System; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.TemplateMessage +{ + /* + {{first.DATA}} + Time:{{keyword1.DATA}} + Host:{{keyword2.DATA}} + Service:{{keyword3.DATA}} + State:{{keyword4.DATA}} + Message:{{keyword5.DATA}} + {{remark.DATA}} + */ + + public class WeixinTemplate_ExceptionAlert : TemplateMessageBase + { + private const string TEMPLATE_ID = "ur6TqESOo-32FEUk4qJxeWZZVt4KEOPjqbAFDGWw6gg"; //每个公众号都不同,需要根据实际情况修改 + + public WeixinTemplate_ExceptionAlert(string _first, string host, string service, string status, string message, + string _remark, string url = null, string templateId = TEMPLATE_ID) + : base(templateId, url, "系统异常告警通知") + { + first = new TemplateDataItem(_first); + keyword1 = new TemplateDataItem(SystemTime.Now.LocalDateTime.ToString()); + keyword2 = new TemplateDataItem(host); + keyword3 = new TemplateDataItem(service); + keyword4 = new TemplateDataItem(status); + keyword5 = new TemplateDataItem(message); + remark = new TemplateDataItem(_remark); + } + + public TemplateDataItem first { get; set; } + + /// + /// Time + /// + public TemplateDataItem keyword1 { get; set; } + + /// + /// Host + /// + public TemplateDataItem keyword2 { get; set; } + + /// + /// Service + /// + public TemplateDataItem keyword3 { get; set; } + + /// + /// State + /// + public TemplateDataItem keyword4 { get; set; } + + /// + /// Message + /// + public TemplateDataItem keyword5 { get; set; } + + public TemplateDataItem remark { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_PaySuccess.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_PaySuccess.cs new file mode 100644 index 0000000..d05e86c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_PaySuccess.cs @@ -0,0 +1,29 @@ +//DPBMARK_FILE MP + +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.TemplateMessage +{ + /// + /// 支付成功模板消息(购买成功通知) + /// + public class WeixinTemplate_PaySuccess : TemplateMessageBase + { + private const string TEMPLATE_ID = "66Gf81swxfWt_P_HkH0Bapvj1nlpiWGmEkXDeCvWcVo"; //每个公众号都不同,需要根据实际情况修改 + + public WeixinTemplate_PaySuccess(string url, string productName, string notice) + : base(TEMPLATE_ID, url, "购买成功通知") + { + name = new TemplateDataItem(productName); + remark = new TemplateDataItem(notice); + } + + public TemplateDataItem name { get; set; } + + /// + /// Time + /// + public TemplateDataItem remark { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_Subscription.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_Subscription.cs new file mode 100644 index 0000000..b26b87a --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WeixinTemplate_Subscription.cs @@ -0,0 +1,35 @@ +//DPBMARK_FILE MP + +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.TemplateMessage +{ + + /// + /// 订阅岗位提醒 + /// + public class WeixinTemplate_Subscription : TemplateMessageBase + { + private const string TEMPLATE_ID = "h-rFy4M52_DhSCo-sL-l77632U8zkdswppyAJMIUrlk"; //每个公众号都不同,需要根据实际情况修改 + + public WeixinTemplate_Subscription(string _first, string company, string jobName, string address, string salary, + string _remark, string url = null, string templateId = TEMPLATE_ID) + : base(templateId, url, "订阅成功通知") + { + first = new TemplateDataItem(_first); + keyword1 = new TemplateDataItem(company); + keyword2 = new TemplateDataItem(jobName); + keyword3 = new TemplateDataItem(address); + keyword4 = new TemplateDataItem(salary); + remark = new TemplateDataItem(_remark); + } + + public TemplateDataItem first { get; set; } + public TemplateDataItem keyword1 { get; set; } + public TemplateDataItem keyword2 { get; set; } + public TemplateDataItem keyword3 { get; set; } + public TemplateDataItem keyword4 { get; set; } + public TemplateDataItem remark { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WxOpen/WxOpenTemplateMessage_PaySuccessNotice.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WxOpen/WxOpenTemplateMessage_PaySuccessNotice.cs new file mode 100644 index 0000000..b848f7d --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/TemplateMessage/WxOpen/WxOpenTemplateMessage_PaySuccessNotice.cs @@ -0,0 +1,55 @@ +//DPBMARK_FILE MiniProgram + +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage; +using System; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.TemplateMessage.WxOpen +{ + public class WxOpenTemplateMessage_PaySuccessNotice : TemplateMessageBase + { + /// + /// “购买成功通知”模板消息数据 + /// + /// 购买地点 + /// 购买时间 + /// 物品名称 + /// 交易单号 + /// 购买价格 + /// 售后电话 + /// + /// + public WxOpenTemplateMessage_PaySuccessNotice( + string payAddress, DateTimeOffset payTime, string productName, + string orderNumber, decimal orderPrice, string hotLine, + string url, + //根据实际的“模板ID”进行修改 + string templateId = "Ap1S3tRvsB8BXsWkiILLz93nhe7S8IgAipZDfygy9Bg") + : base(templateId, url, "购买成功通知") + { + /* + 关键词 + 购买地点 {{keyword1.DATA}} + 购买时间 {{keyword2.DATA}} + 物品名称 {{keyword3.DATA}} + 交易单号 {{keyword4.DATA}} + 购买价格 {{keyword5.DATA}} + 售后电话 {{keyword6.DATA}} + */ + + keyword1 = new TemplateDataItem(payAddress); + keyword2 = new TemplateDataItem(payTime.LocalDateTime.ToString()); + keyword3 = new TemplateDataItem(productName); + keyword4 = new TemplateDataItem(orderNumber); + keyword5 = new TemplateDataItem(orderPrice.ToString("C")); + keyword6 = new TemplateDataItem(hotLine); + } + + public TemplateDataItem keyword1 { get; set; } + public TemplateDataItem keyword2 { get; set; } + public TemplateDataItem keyword3 { get; set; } + public TemplateDataItem keyword4 { get; set; } + public TemplateDataItem keyword5 { get; set; } + public TemplateDataItem keyword6 { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Utilities/Server.cs b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Utilities/Server.cs new file mode 100644 index 0000000..ea10269 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/CommonService/Utilities/Server.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Http; + +namespace Znyc.Cloudcar.Admin.WeChat.CommonService.Utilities +{ + public static class Server + { + public static HttpContext HttpContext + { + get + { + HttpContext context = new DefaultHttpContext(); + return context; + } + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/Model/PostModel.cs b/Znyc.Cloudcar.Admin.WeChat.Core/Model/PostModel.cs new file mode 100644 index 0000000..a6042a5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/Model/PostModel.cs @@ -0,0 +1,31 @@ +using Senparc.NeuChar; + +namespace Model +{ + /// + /// 微信公众服务器Post过来的加密参数集合(不包括PostData) + /// 如需使用 NeuChar,需要在 MessageHandler 中提供 PostModel 并设置 AppId + /// + public class PostModel : EncryptPostModel + { + public override string DomainId + { + get => this.AppId; + set => this.AppId = value; + } + + public string AppId { get; set; } + + /// 设置服务器内部保密信息 + /// + /// + /// + public void SetSecretInfo(string token, string encodingAESKey, string appId) + { + this.Token = token; + this.EncodingAESKey = encodingAESKey; + this.AppId = appId; + } + } +} + diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/Model/WxMessage.cs b/Znyc.Cloudcar.Admin.WeChat.Core/Model/WxMessage.cs new file mode 100644 index 0000000..c512201 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/Model/WxMessage.cs @@ -0,0 +1,14 @@ +namespace Model +{ + public class WxMessage + { + public string ToUserName { get; set; } + public string FromUserName { get; set; } + public long CreateTime { get; set; } + + public string Content { get; set; } + public string MsgType { get; set; } + public string EventName { get; set; } + public string EventKey { get; set; } + } +} diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/Model/WxUserInfo.cs b/Znyc.Cloudcar.Admin.WeChat.Core/Model/WxUserInfo.cs new file mode 100644 index 0000000..3297fc1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/Model/WxUserInfo.cs @@ -0,0 +1,73 @@ +namespace Znyc.Cloudcar.Admin.WeChat.Model +{ + /// + /// 微信用户信息实体对象 + /// + public class WxUserInfo + { + /// + /// 设置或获取昵称 + /// + public string UserName { get; set; } + + /// + /// 设置或获取用户头像图片的 URL + /// + public string avatarUrl { get; set; } + + /// + /// 设置或获取用户性别 + /// + public int gender { get; set; } + + /// + /// 设置或获取用户所在国家 + /// + public string country { get; set; } + + /// + /// 设置或获取用户所在省份 + /// + public string province { get; set; } + + /// + /// 设置或获取所在城市 + /// + public string city { get; set; } + + /// + /// 设置或获取用户所在国家 + /// + public string language { get; set; } + + /// + /// 设置或获取用户openId + /// + public string openId { get; set; } + + /// + /// 设置或获取用户openIdType + /// + public string openIdType { get; set; } + + /// + /// 设置或获取推广者ReferralUserId + /// + public int ReferralUserId { get; set; } + + /// + /// 设置或获取包括敏感数据在内的完整用户信息的加密数据 + /// + public string EncryptedData { get; set; } + + /// + /// 设置或获取加密算法的初始向量 + /// + public string Iv { get; set; } + + /// + /// 设置或获取微信登录的SessionId + /// + public string SessionId { get; set; } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/Properties/PublishProfiles/FolderProfile.pubxml b/Znyc.Cloudcar.Admin.WeChat.Core/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..ccb19b1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,13 @@ + + + + + FileSystem + Release + Any CPU + netcoreapp3.1 + bin\Release\netcoreapp3.1\publish\ + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/Wx/CommonHelper.cs b/Znyc.Cloudcar.Admin.WeChat.Core/Wx/CommonHelper.cs new file mode 100644 index 0000000..638effd --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/Wx/CommonHelper.cs @@ -0,0 +1,313 @@ +using Senparc.CO2NET.Extensions; +using Senparc.CO2NET.HttpUtility; +using Senparc.Weixin; +using Senparc.Weixin.CommonAPIs; +using Senparc.Weixin.Entities; +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.Exceptions; +using Senparc.Weixin.MP; +using Senparc.Weixin.MP.Containers; +using Senparc.Weixin.MP.Entities; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons.Cache; + +namespace Wx +{ + /// + /// 通用接口 + /// 通用接口用于和微信服务器通讯,一般不涉及自有网站服务器的通讯 + /// + public static class CommonHelper + { + #region 同步方法 + + /// + /// 获取凭证接口 + /// + /// 获取access_token填写client_credential + /// 第三方用户唯一凭证 + /// 第三方用户唯一凭证密钥,既appsecret + /// + public static AccessTokenResult GetToken(string appid, string secret, string grant_type = "client_credential") + { + //注意:此方法不能再使用ApiHandlerWapper.TryCommonApi(),否则会循环 + string url = string.Format(Config.ApiMpHost + "/cgi-bin/token?grant_type={0}&appid={1}&secret={2}", + grant_type.AsUrlData(), appid.AsUrlData(), secret.AsUrlData()); + + AccessTokenResult result = Get.GetJson(CommonDI.CommonSP, url); //此处为最原始接口,不再使用重试获取的封装 + + if (Config.ThrownWhenJsonResultFaild && result.errcode != ReturnCode.请求成功) + { + throw new ErrorJsonResultException( + string.Format("微信请求发生错误(CommonApi.GetToken)!错误代码:{0},说明:{1}", + (int)result.errcode, result.errmsg), null, result); + } + + return result; + } + + /// + /// 用户信息接口 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// + /// + public static WeixinUserInfoResult GetUserInfo(string accessTokenOrAppId, string openId) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + string url = string.Format(Config.ApiMpHost + "/cgi-bin/user/info?access_token={0}&openid={1}", + accessToken.AsUrlData(), openId.AsUrlData()); + WeixinUserInfoResult result = CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET); + return result; + }, accessTokenOrAppId); + } + + /// + /// 获取调用微信JS接口的临时票据 + /// + /// + /// + /// 默认为jsapi,当作为卡券接口使用时,应当为wx_card + /// + public static JsApiTicketResult GetTicket(string appId, string secret, string type = "jsapi") + { + string accessToken = AccessTokenContainer.TryGetAccessToken(appId, secret); + return GetTicketByAccessToken(accessToken, type); + } + + /// + /// 获取调用微信JS接口的临时票据 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// 默认为jsapi,当作为卡券接口使用时,应当为wx_card + /// + public static JsApiTicketResult GetTicketByAccessToken(string accessTokenOrAppId, string type = "jsapi") + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + string url = string.Format(Config.ApiMpHost + "/cgi-bin/ticket/getticket?access_token={0}&type={1}", + accessToken.AsUrlData(), type.AsUrlData()); + + JsApiTicketResult result = CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET); + return result; + }, accessTokenOrAppId); + } + + /// + /// 获取微信服务器的ip段 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// + public static GetCallBackIpResult GetCallBackIp(string accessTokenOrAppId) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + string url = string.Format(Config.ApiMpHost + "/cgi-bin/getcallbackip?access_token={0}", + accessToken.AsUrlData()); + + return CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET); + }, accessTokenOrAppId); + } + + /// + /// 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// + /// + /// + public static WxJsonResult Clear_quota(string accessTokenOrAppId, string appId, int timeOut = Config.TIME_OUT) + { + return ApiHandlerWapper.TryCommonApi(accessToken => + { + string urlFormat = string.Format(Config.ApiMpHost + "/cgi-bin/clear_quota?access_token={0}", + accessToken.AsUrlData()); + var data = new + { + appid = appId + }; + + return CommonJsonSend.Send(null, urlFormat, data, timeOut: timeOut); + }, accessTokenOrAppId); + } + + #endregion 同步方法 + + #region 异步方法 + + /// + /// 【异步方法】获取凭证接口 + /// + /// 获取access_token填写client_credential + /// 第三方用户唯一凭证 + /// 第三方用户唯一凭证密钥,既appsecret + /// + public static async Task GetTokenAsync(string appid, string secret, + string grant_type = "client_credential") + { + CacheHelper cacheHelper = new CacheHelper(); + AccessTokenResult result; + result = cacheHelper.Get(appid); + if (result == null) + { + string url = string.Format(Config.ApiMpHost + "/cgi-bin/token?grant_type={0}&appid={1}&secret={2}", + grant_type.AsUrlData(), appid.AsUrlData(), secret.AsUrlData()); + + result = await Get.GetJsonAsync(CommonDI.CommonSP, url); //此处为最原始接口,不再使用重试获取的封装 + + if (Config.ThrownWhenJsonResultFaild && result.errcode != ReturnCode.请求成功) + { + throw new ErrorJsonResultException( + string.Format("微信请求发生错误(CommonApi.GetToken)!错误代码:{0},说明:{1}", + (int)result.errcode, result.errmsg), null, result); + } + + TimeSpan expiresSliding = DateTime.Now.AddSeconds(7200) - DateTime.Now; + cacheHelper.Add(appid, result, expiresSliding); + } + + return result; + } + + /// + /// 【异步方法】用户信息接口 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// + /// + public static async Task GetUserInfoAsync(string accessTokenOrAppId, string openId) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + string url = string.Format(Config.ApiMpHost + "/cgi-bin/user/info?access_token={0}&openid={1}", + accessToken.AsUrlData(), openId.AsUrlData()); + Task result = CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET); + return await result.ConfigureAwait(false); + }, accessTokenOrAppId).ConfigureAwait(false); + } + + /// + /// 【异步方法】获取调用微信JS接口的临时票据 + /// + /// + /// + /// 默认为jsapi,当作为卡券接口使用时,应当为wx_card + /// + public static async Task GetTicketAsync(string appId, string secret, string type = "jsapi") + { + string accessToken = await AccessTokenContainer.TryGetAccessTokenAsync(appId, secret).ConfigureAwait(false); + return GetTicketByAccessToken(accessToken, type); + } + + /// + /// 【异步方法】获取调用微信JS接口的临时票据 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// 默认为jsapi,当作为卡券接口使用时,应当为wx_card + /// + public static async Task GetTicketByAccessTokenAsync(string accessTokenOrAppId, + string type = "jsapi") + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + string url = string.Format(Config.ApiMpHost + "/cgi-bin/ticket/getticket?access_token={0}&type={1}", + accessToken.AsUrlData(), type.AsUrlData()); + + Task result = CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET); + return await result.ConfigureAwait(false); + }, accessTokenOrAppId).ConfigureAwait(false); + } + + /// + /// 【异步方法】获取微信服务器的ip段 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// + public static async Task GetCallBackIpAsync(string accessTokenOrAppId) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + string url = string.Format(Config.ApiMpHost + "/cgi-bin/getcallbackip?access_token={0}", + accessToken.AsUrlData()); + + return await CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET) + .ConfigureAwait(false); + }, accessTokenOrAppId).ConfigureAwait(false); + } + + /// + /// 【异步方法】公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// + /// + /// + public static async Task Clear_quotaAsync(string accessTokenOrAppId, string appId, + int timeOut = Config.TIME_OUT) + { + return await ApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + string urlFormat = string.Format(Config.ApiMpHost + "/cgi-bin/clear_quota?access_token={0}", + accessToken.AsUrlData()); + var data = new + { + appid = appId + }; + + return await CommonJsonSend.SendAsync(null, urlFormat, data, timeOut: timeOut) + .ConfigureAwait(false); + }, accessTokenOrAppId).ConfigureAwait(false); + } + + /// + /// 求职/招聘审核通知 + /// + /// + public static async Task SendProductAsync(TemplateMessageData tmessageData, string toUser, string url) + { + await MessageHelper.SendSubscribeAsync(tmessageData, + "dm1yuO5nVqiRQyMWcS4VZOjOZY5rDCjhiqiUcueyMJc", toUser, url); + } + + /// + /// 实名认证失败发送通知 + /// + /// + public static async Task SendAuditFailAsync(string toUser) + { + string thing1 = "您的实名认证信息认证失败"; + TemplateMessageData templateMessageData = new TemplateMessageData + { + ["thing1"] = new TemplateMessageDataValue(thing1), + ["time2"] = new TemplateMessageDataValue(SystemTime.Now.ToString("yyyy年MM月dd日 HH:mm")), + ["phrase3"] = new TemplateMessageDataValue("审核失败"), + ["thing4"] = new TemplateMessageDataValue("实名认证信息有误") + }; + await MessageHelper.SendSubscribeAsync(templateMessageData, + "dm1yuO5nVqiRQyMWcS4VZOjOZY5rDCjhiqiUcueyMJc", toUser, "pages/verification/verification"); + } + + /// + /// 实名认证审核成功 + /// + /// + /// + public static async Task SendAuditSuccessAsync(string toUser) + { + string thing1 = "您的实名认证信息认证成功"; + TemplateMessageData templateMessageData = new TemplateMessageData + { + ["thing1"] = new(thing1), + ["time2"] = new(SystemTime.Now.ToString("yyyy年MM月dd日 HH:mm")), + ["phrase3"] = new("审核通过"), + ["thing4"] = new("满足通过条件") + }; + await MessageHelper.SendSubscribeAsync(templateMessageData, + "dm1yuO5nVqiRQyMWcS4VZOjOZY5rDCjhiqiUcueyMJc", toUser, "pages/verification/verification"); + } + + #endregion 异步方法 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/Wx/MessageHelper.cs b/Znyc.Cloudcar.Admin.WeChat.Core/Wx/MessageHelper.cs new file mode 100644 index 0000000..2fdebd9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/Wx/MessageHelper.cs @@ -0,0 +1,101 @@ +using Senparc.Weixin; +using Senparc.Weixin.CommonAPIs; +using Senparc.Weixin.Entities; +using Senparc.Weixin.Entities.TemplateMessage; +using Senparc.Weixin.WxOpen; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Log; + +namespace Wx +{ + /// + /// 小程序订阅消息接口 + /// + public class MessageHelper + { + #region 同步方法 + + /// + /// 发送订阅消息 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// 接收者(用户)的 openid + /// 所需下发的订阅模板id + /// 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } } + /// 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + /// + /// + public static WxJsonResult SendSubscribe(string accessTokenOrAppId, string toUser, string templateId, + TemplateMessageData data, string page = null, int timeOut = Config.TIME_OUT) + { + return WxOpenApiHandlerWapper.TryCommonApi(accessToken => + { + string urlFormat = Config.ApiMpHost + "/cgi-bin/message/subscribe/send?access_token={0}"; + var submitData = new + { + touser = toUser, + template_id = templateId, + page, + data + }; + return CommonJsonSend.Send(accessToken, urlFormat, submitData, timeOut: timeOut); + }, accessTokenOrAppId); + } + + #endregion 同步方法 + + #region 异步方法 + + public static async Task SendSubscribeAsync(TemplateMessageData templateMessageData, string templateId, + string toUser, + string pageUrl) + { + try + { + Senparc.Weixin.MP.Entities.AccessTokenResult accessTokenResult = await CommonHelper.GetTokenAsync( + Configs.GetConfigurationValue("SenparcWeixinSetting", "WxOpenAppId"), + Configs.GetConfigurationValue("SenparcWeixinSetting", "WxOpenAppSecret")); + string page = pageUrl; + WxJsonResult sU = await SendSubscribeAsync(accessTokenResult.access_token, + toUser, templateId, templateMessageData, + page); + } + catch (Exception ex) + { + Log4NetHelper.Error("SendSubscribeAsync" + ex); + } + } + + /// + /// 【异步方法】发送订阅消息 + /// + /// AccessToken或AppId(推荐使用AppId,需要先注册) + /// 接收者(用户)的 openid + /// 所需下发的订阅模板id + /// 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } } + /// 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 + /// + /// + public static async Task SendSubscribeAsync(string accessTokenOrAppId, string toUser, + string templateId, TemplateMessageData data, string page = null, int timeOut = Config.TIME_OUT) + { + return await WxOpenApiHandlerWapper.TryCommonApiAsync(async accessToken => + { + string urlFormat = Config.ApiMpHost + "/cgi-bin/message/subscribe/send?access_token={0}"; + var submitData = new + { + touser = toUser, + template_id = templateId, + page, + data + }; + + return await CommonJsonSend.SendAsync(accessToken, urlFormat, submitData, timeOut: timeOut); + }, accessTokenOrAppId); + } + + #endregion 异步方法 + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/Yuebon.WeChat.Core.csproj b/Znyc.Cloudcar.Admin.WeChat.Core/Yuebon.WeChat.Core.csproj new file mode 100644 index 0000000..897ce23 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/Yuebon.WeChat.Core.csproj @@ -0,0 +1,49 @@ + + + + net5.0 + ZNYC.Admin.WeChat + 上海越邦网络科技有限公司 + Yuebon + YuebonNetCore 微信开放接口类库 + true + 上海越邦网络科技有限公司 版权所有 + YuebonNetCore 微信公众号、小程序、开放平台接口实现类库 + false + https://gitee.com/yuebon/YuebonNetCore + + + 1.1.1.9 + LICENSE + logo.png + https://gitee.com/yuebon/YuebonNetCore + + + + + True + + + + True + + + + + + + + + + + + + + + + + + + + + diff --git a/Znyc.Cloudcar.Admin.WeChat.Core/Znyc.Cloudcar.Admin.WeChat.Core.csproj b/Znyc.Cloudcar.Admin.WeChat.Core/Znyc.Cloudcar.Admin.WeChat.Core.csproj new file mode 100644 index 0000000..283245e --- /dev/null +++ b/Znyc.Cloudcar.Admin.WeChat.Core/Znyc.Cloudcar.Admin.WeChat.Core.csproj @@ -0,0 +1,38 @@ + + + + net6.0 + + + + + + + + false + + + MIT + 1.0 + LICENSE + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/.config/dotnet-tools.json b/Znyc.Cloudcar.Admin.WebApi/.config/dotnet-tools.json new file mode 100644 index 0000000..5112d4b --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "3.1.8", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Attributes/QuartzAttribute.cs b/Znyc.Cloudcar.Admin.WebApi/Attributes/QuartzAttribute.cs new file mode 100644 index 0000000..c8f21f9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Attributes/QuartzAttribute.cs @@ -0,0 +1,48 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.WebApi.Auth; + +namespace Znyc.Cloudcar.Admin.WebApi.Attributes +{ + /// + /// 定时任务启动密钥 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] + public class QuartzAttribute : AuthorizeAttribute, IAuthorizationFilter, IAsyncAuthorizationFilter + { + private IApiHandler _apiHandler; + + /// + /// + /// + /// + public Task OnAuthorizationAsync(AuthorizationFilterContext context) + { + OnAuthorization(context); + return Task.CompletedTask; + } + + /// + /// + /// + public async void OnAuthorization(AuthorizationFilterContext context) + { + string apiUrl = context.HttpContext.Request.Path.Value; + _apiHandler = context.HttpContext.RequestServices.GetService(); + Security.Entitys.ApiEntity entity = await _apiHandler.ValidateAsync(apiUrl); + //key/value 存入数据库去查询,不同的api对应不同的key/value + string authHeader = context.HttpContext.Request.Headers[entity.AuthKey]; + if (authHeader != null && authHeader.Equals(entity.AuthValue)) + { + return; + } + + context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Auth/ApiHandler.cs b/Znyc.Cloudcar.Admin.WebApi/Auth/ApiHandler.cs new file mode 100644 index 0000000..3f49d84 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Auth/ApiHandler.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Auth +{ + /// + /// 定时任务 + /// + public class ApiHandler : IApiHandler + { + private readonly IApiService _apiService; + + /// + /// + /// + public ApiHandler(IApiService apiService) + { + _apiService = apiService; + } + + /// + /// + /// + /// + public async Task ValidateAsync(string apiUrl) + { + ApiEntity result = await _apiService.GetApiAsync(apiUrl); + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Auth/IApiHandler.cs b/Znyc.Cloudcar.Admin.WebApi/Auth/IApiHandler.cs new file mode 100644 index 0000000..309ed4f --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Auth/IApiHandler.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.WebApi.Auth +{ + /// + /// 定时任务 + /// + public interface IApiHandler + { + /// + /// + /// + /// + public Task ValidateAsync(string apiUrl); + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Config/HangFireQueuesConfig.cs b/Znyc.Cloudcar.Admin.WebApi/Config/HangFireQueuesConfig.cs new file mode 100644 index 0000000..a64a54b --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Config/HangFireQueuesConfig.cs @@ -0,0 +1,34 @@ +using System.ComponentModel; + +namespace Znyc.Cloudcar.Admin.WebApi.Config +{ + /// + /// HangFire定时任务相关 + /// + public enum HangFireQueuesConfig + { + /// + /// 默认 + /// + [Description("默认")] + @default = 1, + + /// + /// 接口 + /// + [Description("接口")] + apis = 2, + + /// + /// 网站 + /// + [Description("网站")] + web = 3, + + /// + /// 循环时间 + /// + [Description("循环时间")] + recurring = 4, + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/APPController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/APPController.cs new file mode 100644 index 0000000..1f61546 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/APPController.cs @@ -0,0 +1,123 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Encrypt; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 应用管理接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class APPController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public APPController(IAPPService service) : base(service) + { + _service = service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(APPEntity info) + { + info.Id = 0; + info.AppSecret = MD5Util.GetMD5_32(GuidUtils.NewGuidFormatN()).ToUpper(); + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(APPEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(APPEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("Update")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(APPInputDto tinfo) + { + CommonResult result = new CommonResult(); + + APPEntity info = _service.Get(tinfo.Id); + info.AppId = tinfo.AppId; + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(true); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 重置AppSecret + /// + /// + [HttpGet("ResetAppSecret")] + [FunctionAuthorize("ResetAppSecret")] + public async Task ResetAppSecret(int id) + { + CommonResult result = new CommonResult(); + APPEntity aPP = _service.Get(id); + aPP.AppSecret = MD5Util.GetMD5_32(GuidUtils.NewGuidFormatN()).ToUpper(); + bool bl = await _service.UpdateAsync(aPP, id); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = aPP.AppSecret; + result.Success = true; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/ActivityController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/ActivityController.cs new file mode 100644 index 0000000..6b79b58 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/ActivityController.cs @@ -0,0 +1,143 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + ActivityController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public ActivityController(IActivityService _service) : base(_service) + { + + } + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(ActivityEntity info) + { + info.Id = YitIdHelper.NextId(); + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(ActivityEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(ActivityEntity info) + { + info.IsDeleted = true; + } + + + /// + /// 分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchActivityModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("InsertAsync")] + [FunctionAuthorize("Add")] + + public async Task InsertAsync(ActivityAddInput input) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + ActivityEntity info = input.MapTo(); + OnBeforeInsert(info); + result = await _service.InsertAsync(info); + if (result.Success) + { + cacheHelper.Remove("activity:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = result.ErrMsg; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("UpdateAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(ActivityUpdateInput input) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + ActivityEntity entity = input.MapTo(); + OnBeforeUpdate(entity); + result = await _service.UpdateAsync(entity); + if (result.Success) + { + cacheHelper.Remove("activity:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = result.ErrMsg; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/AdminUserController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/AdminUserController.cs new file mode 100644 index 0000000..5df725b --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/AdminUserController.cs @@ -0,0 +1,407 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter; +using Znyc.Cloudcar.Admin.AspNetCore.ViewModel; +using Znyc.Cloudcar.Admin.Commons.Encrypt; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 系统用户接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + [AllowAnonymous] + [NoPermissionRequired] + public class AdminUserController : AreaApiController + { + private readonly IAdminUserLogOnService _adminUserLogOnService; + private readonly IOrganizeService _organizeService; + private readonly IRoleService _roleService; + + /// + /// + /// + /// + /// + /// + public AdminUserController(IAdminUserService service, IOrganizeService organizeService, + IRoleService roleService, + IAdminUserLogOnService adminUserLogOnService + ) : base(service) + { + _service = service; + _organizeService = organizeService; + _roleService = roleService; + _adminUserLogOnService = adminUserLogOnService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(AdminUserEntity info) + { + info.Id = YitIdHelper.NextId(); + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.OrganizeId = _organizeService.GetRootOrganize(info.DepartmentId).ParentId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(AdminUserEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + info.OrganizeId = _organizeService.GetRootOrganize(info.DepartmentId).ParentId; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(AdminUserEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("Insert")] + [FunctionAuthorize("Add")] + public async Task InsertAsync(AdminUserInputDto tinfo) + { + CommonResult result = new CommonResult(); + if (!string.IsNullOrEmpty(tinfo.Account)) + { + string where = string.Format("Account='{0}' or MobilePhone='{0}'", tinfo.Account); + AdminUserEntity Admin = _service.GetWhere(where); + if (Admin != null) + { + result.ErrMsg = "登录账号不能重复"; + return ToJsonContent(result); + } + } + else + { + result.ErrMsg = "登录账号不能为空"; + return ToJsonContent(result); + } + + AdminUserEntity info = tinfo.MapTo(); + OnBeforeInsert(info); + info.State = 1; + info.ModifiedTime = DateTime.Now; + await _service.InsertAsync(info); + AdminUserLogOnEntity adminLogOn = new AdminUserLogOnEntity + { + UserId = info.Id, + UserSecretkey = MD5Util.GetMD5_16(GuidUtils.NewGuidFormatN()).ToLower() + }; + adminLogOn.UserPassword = MD5Util + .GetMD5_32(DEncrypt.Encrypt(MD5Util.GetMD5_32("12345678").ToLower(), adminLogOn.UserSecretkey) + .ToLower()).ToLower(); + adminLogOn.LogOnCount = 0; + adminLogOn.Language = ""; + adminLogOn.Theme = ""; + adminLogOn.Id = YitIdHelper.NextId(); + await _adminUserLogOnService.InsertAsync(adminLogOn); + result.Success = adminLogOn.UserId > 0; + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43001; + result.ErrCode = "43001"; + } + + return ToJsonContent(result); + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("Update")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(AdminUserInputDto tinfo) + { + CommonResult result = new CommonResult(); + if (string.IsNullOrEmpty(tinfo.Account)) + { + result.ErrMsg = "登录账号不能为空"; + return ToJsonContent(result); + } + + AdminUserEntity info = _service.Get(tinfo.Id); + info.Account = tinfo.Account; + info.HeadIcon = tinfo.HeadIcon; + info.UserName = tinfo.UserName; + info.Gender = tinfo.Gender; + info.MobilePhone = tinfo.MobilePhone; + info.DepartmentId = tinfo.DepartmentId; + info.RoleId = tinfo.RoleId; + info.IsAdministrator = tinfo.IsAdministrator; + info.State = tinfo.State; + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + if (bl) + { + + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 根据用户登录账号获取详细信息 + /// + /// + /// + [HttpGet("GetByUserName")] + [FunctionAuthorize("")] + public async Task GetByUserName(string userName) + { + CommonResult result = new CommonResult(); + try + { + AdminUserEntity Admin = await _service.GetByUserName(userName); + result.ResData = Admin.MapTo(); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取用户异常", ex); //错误记录 + result.ErrMsg = ex.Message; + } + + return ToJsonContent(result); + } + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchUserModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + /// + /// 重置密码 + /// + /// + [HttpPost("ResetPassword")] + [FunctionAuthorize("ResetPassword")] + public async Task ResetPassword(long userId) + { + CommonResult result = new CommonResult(); + try + { + string where = string.Format("UserId={0}", userId); + AdminUserLogOnEntity adminLogOn = _adminUserLogOnService.GetWhere(where); + adminLogOn.UserSecretkey = MD5Util.GetMD5_16(GuidUtils.NewGuidFormatN()).ToLower(); + adminLogOn.UserPassword = MD5Util + .GetMD5_32(DEncrypt.Encrypt(MD5Util.GetMD5_32("12345678").ToLower(), adminLogOn.UserSecretkey) + .ToLower()).ToLower(); + adminLogOn.ChangePasswordDate = DateTime.Now; + bool bl = await _adminUserLogOnService.UpdateAsync(adminLogOn, adminLogOn.Id); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + result.Success = true; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + catch (Exception ex) + { + Log4NetHelper.Error("重置密码异常", ex); //错误记录 + result.ErrMsg = ex.Message; + } + + return ToJsonContent(result); + } + + /// + /// 修改密码 + /// + /// 原密码 + /// 新密码 + /// 重复新密码 + /// + [HttpPost("ModifyPassword")] + [FunctionAuthorize("ModifyPassword")] + public async Task ModifyPassword(string oldpassword, string password, string password2) + { + CommonResult result = new CommonResult(); + try + { + if (string.IsNullOrEmpty(oldpassword)) + { + result.ErrMsg = "原密码不能为空!"; + } + else if (string.IsNullOrEmpty(password)) + { + result.ErrMsg = "密码不能为空!"; + } + else if (string.IsNullOrEmpty(password2)) + { + result.ErrMsg = "重复输入密码不能为空!"; + } + else if (password == password2) + { + AdminUserLogOnEntity AdminSinginEntity = _adminUserLogOnService.GetByUserId(CurrentUser.UserId); + string inputPassword = MD5Util.GetMD5_32(DEncrypt.Encrypt(MD5Util.GetMD5_32(oldpassword).ToLower(), + AdminSinginEntity.UserSecretkey).ToLower()).ToLower(); + if (inputPassword != AdminSinginEntity.UserPassword) + { + result.ErrMsg = "原密码错误!"; + } + else + { + string where = string.Format("UserId='{0}'", CurrentUser.UserId); + AdminUserLogOnEntity AdminLogOn = _adminUserLogOnService.GetWhere(where); + + AdminLogOn.UserSecretkey = MD5Util.GetMD5_16(GuidUtils.NewGuidFormatN()).ToLower(); + AdminLogOn.UserPassword = MD5Util + .GetMD5_32(DEncrypt.Encrypt(MD5Util.GetMD5_32(password).ToLower(), + AdminLogOn.UserSecretkey).ToLower()).ToLower(); + AdminLogOn.ChangePasswordDate = DateTime.Now; + bool bl = await _adminUserLogOnService.UpdateAsync(AdminLogOn, AdminLogOn.Id); + if (bl) + { + result.ErrCode = ErrCode.successCode; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + } + else + { + result.ErrMsg = "两次输入的密码不一样"; + } + } + catch (Exception ex) + { + Log4NetHelper.Error("重置密码异常", ex); //错误记录 + result.ErrMsg = ex.Message; + } + + return ToJsonContent(result); + } + + /// + /// 异步批量禁用/启用数据 + /// + /// + [HttpPost("SetStatusBatchAsync")] + [FunctionAuthorize("")] + public async Task SetStatusBatchAsync(UpdateEnableViewModel info) + { + CommonResult result = new CommonResult(); + string where = string.Empty; + if (typeof(int) == typeof(string)) + { + @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + } + else if (typeof(int) == typeof(int)) + { + @where = "id in (" + info.Ids.Join(",") + ")"; + } + + if (!string.IsNullOrEmpty(where)) + { + bool blResult = await _service.SetStatusByWhereAsync(info.Flag.ToInt(), where, CurrentUser.UserId); + if (blResult) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + + return ToJsonContent(result); + } + + /// + /// 保存用户自定义的软件主题 + /// + /// 主题配置信息 + /// + [HttpPost("SaveUserTheme")] + [FunctionAuthorize("SaveUserTheme")] + public async Task SaveUserTheme(UserThemeInputDto info) + { + CommonResult result = new CommonResult(); + try + { + result.Success = await _adminUserLogOnService.SaveUserTheme(info, CurrentUser.UserId); + result.ErrCode = ErrCode.successCode; + } + catch (Exception ex) + { + Log4NetHelper.Error("保存用户自定义的软件主题异常", ex); //错误记录 + result.ErrMsg = ex.Message; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/ApplyJobController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/ApplyJobController.cs new file mode 100644 index 0000000..2af55a8 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/ApplyJobController.cs @@ -0,0 +1,191 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 求职 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + ApplyJobController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public ApplyJobController(IApplyJobService _service) : base(_service) + { + _service = _service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(ApplyJobEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(ApplyJobEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(ApplyJobEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("InsertAsync")] + [FunctionAuthorize("Add")] + public new async Task InsertAsync(ApplyJobInputDto input) + { + CommonResult result = new CommonResult(); + ApplyJobEntity applyJob = input.MapTo(); + OnBeforeInsert(applyJob); + result = await _service.InsertAsync(applyJob); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("UpdateAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(ApplyJobInputDto input) + { + CommonResult result = new CommonResult(); + ApplyJobEntity applyJob = input.MapTo(); + OnBeforeUpdate(applyJob); + result = await _service.UpdateAsync(applyJob); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + [AllowAnonymous] + public async Task FindWithPagerSearchAsync(SearchCloudcarModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + + /// + /// 根据主键Id获取一个对象信息 + /// + /// 主键Id + /// + [HttpGet("GetById")] + [AllowAnonymous] + public async Task> GetById(long id) + { + CommonResult result = new CommonResult(); + ApplyJobOutputDto info = await _service.GetById(id); + if (info != null) + { + result.ErrCode = ErrCode.successCode; + result.ResData = info; + } + else + { + result.ErrMsg = ErrCode.err50001; + result.ErrCode = "50001"; + } + + return result; + } + + /// + /// 下架求职信息 + /// + /// + /// + [HttpPost("RevocationAsync")] + [FunctionAuthorize("Edit")] + public async Task RevocationAsync(long id) + { + CommonResult result = new CommonResult(); + result = await _service.RevocationAsync(id, CurrentUser.UserId); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/AreaController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/AreaController.cs new file mode 100644 index 0000000..12bc7b4 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/AreaController.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 地区接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class AreaController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public AreaController(IAreaService _service) : base(_service) + { + _service = _service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(AreaEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + if (info.SortCode == null) + { + info.SortCode = 99; + } + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(AreaEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(AreaEntity info) + { + info.IsDeleted = true; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/AuditController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/AuditController.cs new file mode 100644 index 0000000..256576f --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/AuditController.cs @@ -0,0 +1,129 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 审核 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class AuditController : AreaApiController + { + private readonly IAuditService _productAuditService; + + /// + /// 构造函数 + /// + public AuditController( + IAuditService productAuditService, + IUserService userService + ) : base(productAuditService) + { + _productAuditService = productAuditService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(AuditEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(AuditEntity info) + { + info.AuditUserId = CurrentUser.UserId; + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(AuditEntity info) + { + info.IsDeleted = true; + } + + /// + /// 审核通过 + /// + /// + /// + /// + [HttpPut("AuditSuccessAsync")] + [FunctionAuthorize("")] + public async Task AuditSuccessAsync(long equipmentId,int promoteType) + { + CommonResult result = new CommonResult(); + AuditEntity info = new AuditEntity + { + EquipmentId = equipmentId + }; + OnBeforeInsert(info); + result = await _productAuditService.AuditSuccessAsync(info, promoteType); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 审核失败 + /// + /// + /// + [HttpPut("AuditFailAsync")] + [FunctionAuthorize("")] + public async Task AuditFailAsync(AuditInputDto productAuditInput) + { + CommonResult result = new CommonResult(); + AuditEntity info = productAuditInput.MapTo(); + OnBeforeInsert(info); + result = await _productAuditService.AuditFailAsync(info); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/BannerController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/BannerController.cs new file mode 100644 index 0000000..9f43deb --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/BannerController.cs @@ -0,0 +1,174 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + BannerController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public BannerController(IBannerService _service) : base(_service) + { + + } + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(BannerEntity info) + { + info.Id = YitIdHelper.NextId(); + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(BannerEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(BannerEntity info) + { + info.IsDeleted = true; + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + + /// + /// 分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + //[FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchBannerModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + /// + /// 新增banner/活动 + /// + /// + /// + [HttpPost("InsertAsync")] + [FunctionAuthorize("Add")] + + public async Task InsertAsync(BannerInput input) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + BannerEntity banner = input.MapTo(); + OnBeforeInsert(banner); + result = await _service.InsertAsync(banner); + if (result.Success) + { + //清除缓存 + cacheHelper.Remove("banner:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + + } + else + { + result.ErrMsg = result.ErrMsg; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("UpdateAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(BannerUpdateInput input) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + BannerEntity bannerEntity = input.MapTo(); + OnBeforeUpdate(bannerEntity); + result = await _service.UpdateAsync(bannerEntity); + if (result.Success) + { + cacheHelper.Remove("banner:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = result.ErrMsg; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + + /// + /// 异步软删除数据 + /// + /// + /// + [HttpDelete("DeleteSoftAsync")] + [FunctionAuthorize("Delete")] + public async Task DeleteSoftAsync(long id) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + result.Success = await _service.DeleteSoftAsync(false, id, CurrentUser.UserId); + if (result.Success) + { + cacheHelper.Remove("banner:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43001; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/CallFeedbackController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/CallFeedbackController.cs new file mode 100644 index 0000000..cae56c1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/CallFeedbackController.cs @@ -0,0 +1,108 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + CallFeedbackController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public CallFeedbackController(ICallFeedbackService _service) : base(_service) + { + + } + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(CallFeedbackEntity info) + { + info.Id = YitIdHelper.NextId(); + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(CallFeedbackEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(CallFeedbackEntity info) + { + info.IsDeleted = true; + } + + + /// + /// 通话评价分页查询 + /// + /// status:-1全部/1真实有效/2已经找到/3联系不上/4虚假信息 + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchCallFeedbackModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + /// + /// 修改通话反馈已读 + /// + /// + /// + /// + [HttpPut("UpdateIsReadAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateIsReadAsync(long id, int productType) + { + CommonResult result = new CommonResult(); + result = await _service.UpdateIsReadAsync(CurrentUser.UserId, id, productType); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43001; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/CertificationController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/CertificationController.cs new file mode 100644 index 0000000..68f6614 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/CertificationController.cs @@ -0,0 +1,146 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 实名认证管理接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class CertificationController : AreaApiController + { + private readonly ICertificationService _certificationService; + + /// + /// 构造函数 + /// + /// + public CertificationController(ICertificationService certificationService) : base( + certificationService) + { + _certificationService = certificationService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(CertificationEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(CertificationEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(CertificationEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchUserModel search) + { + CommonResult> result = new CommonResult> + { + ErrCode = ErrCode.successCode, + ErrMsg = ErrCode.err0, + ResData = await _certificationService.FindWithPagerSearchAsync(search) + }; + return ToJsonContent(result); + } + + /// + /// 实名认证审核成功 + /// + /// + /// + [HttpPut("AuditSuccessAsync")] + [FunctionAuthorize("")] + public async Task AuditSuccessAsync(long id) + { + CommonResult result = new CommonResult(); + CertificationEntity info = new CertificationEntity + { + Id = id + }; + OnBeforeUpdate(info); + bool bl = await _certificationService.AuditSuccessAsync(info); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 实名认证审核失败 + /// + /// + /// + [HttpPut("AuditFailAsync")] + [FunctionAuthorize("")] + public async Task AuditFailAsync(long id) + { + CommonResult result = new CommonResult(); + CertificationEntity info = new CertificationEntity + { + Id = id + }; + OnBeforeUpdate(info); + bool bl = await _certificationService.AuditFailAsync(info); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/CurrencyController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/CurrencyController.cs new file mode 100644 index 0000000..de56192 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/CurrencyController.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 云币服务 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + CurrencyController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public CurrencyController(ICurrencyService _service) : base(_service) + { + _service = _service; + } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/CurrencyRecordController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/CurrencyRecordController.cs new file mode 100644 index 0000000..00a68b3 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/CurrencyRecordController.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 云币记录服务 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + CurrencyRecordController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public CurrencyRecordController(ICurrencyRecordService _service) : base(_service) + { + _service = _service; + } + + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task>> FindWithPagerSearchAsync(SearchCurrencyRecordModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/DictionaryController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/DictionaryController.cs new file mode 100644 index 0000000..fac3959 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/DictionaryController.cs @@ -0,0 +1,373 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Linq; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.ViewModel; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 数据字典接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class DictionaryController : AreaApiController + { + //private readonly IDictionaryService _service; + + /// + /// 构造函数 + /// + /// + public DictionaryController(IDictionaryService service) : + base(service) + { + _service = service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(DictionaryEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(DictionaryEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(DictionaryEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("Insert")] + [FunctionAuthorize("Add")] + public async Task InsertAsync(DictionaryInputDto tinfo) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + if (tinfo.ParentId == 0) + { + DictionaryEntity isExsit = await _service.GetByEnCodAsynce(tinfo.Code); + if (isExsit != null) + { + result.ErrMsg = ReturnConst.Dictionary_Code_Exist; + return ToJsonContent(result); + } + } + else + { + tinfo.Code = (await _service.GetDictionaryById(tinfo.ParentId)).Code; + } + DictionaryEntity info = tinfo.MapTo(); + OnBeforeInsert(info); + info.Id = YitIdHelper.NextId(); + info.Code = tinfo.Code; + info.Description = info.Description == null ? CommonConst.String_Empty : info.Description; + int ln = await _service.InsertAsync(info).ConfigureAwait(false); + if (ln > 0) + { + cacheHelper.Remove("dictionary:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43001; + result.ErrCode = "43001"; + } + + return ToJsonContent(result); + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("Update")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(DictionaryInputDto tinfo) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + if (tinfo.ParentId == 0) + { + DictionaryEntity isExsit = await _service.GetByEnCodAsynce(tinfo.Code, tinfo.Id); + if (isExsit != null) + { + result.ErrMsg = ReturnConst.Dictionary_Code_Exist; + return ToJsonContent(result); + } + } + else + { + tinfo.Code = (await _service.GetDictionaryById(tinfo.ParentId)).Code; + } + + DictionaryEntity info = _service.Get(tinfo.Id); + info.ParentId = tinfo.ParentId; + info.Code = tinfo.Code; + info.Value = tinfo.Value; + info.Description = tinfo.Description; + info.Name = tinfo.Name; + info.IsEnabled = tinfo.IsEnabled; + info.Sort = tinfo.Sort; + info.Description = info.Description == null ? CommonConst.String_Empty : tinfo.Description; + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + if (bl) + { + cacheHelper.Remove("dictionary:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 获取功能菜单适用于Vue 树形列表 + /// + /// + [HttpGet("GetAllDictionaryTreeTable")] + [FunctionAuthorize("List")] + public async Task GetAllDictionaryTreeTable() + { + CommonResult result = new CommonResult(); + try + { + System.Collections.Generic.List list = await _service.GetAllDictionaryTreeTable(); + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ResData = list; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取菜单异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return ToJsonContent(result); + } + + /// + /// 查询单条数据字典 + /// + /// + /// + [HttpGet("GetDictionaryById")] + [FunctionAuthorize("")] + public async Task GetDictionaryById(long id) + { + CommonResult result = new CommonResult + { + ResData = await _service.GetDictionaryById(id), + ErrCode = ErrCode.successCode, + ErrMsg = ErrCode.err0 + }; + return ToJsonContent(result); + } + + /// + /// 异步批量禁用数据 + /// + /// + [HttpPost("SetEnabledMarktBatchAsync")] + [FunctionAuthorize("")] + public async Task SetEnabledMarktBatchAsync(UpdateEnableViewModel info) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + string where = string.Empty; + if (typeof(int) == typeof(string)) + { + @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + } + else if (typeof(int) == typeof(int)) + { + @where = "id in (" + info.Ids.Join(",") + ")"; + } + + if (!string.IsNullOrEmpty(where)) + { + bool bl = false; + if (info.Flag == "1") + { + bl = true; + } + + bool blResult = await _service.SetEnabledMarkByWhereAsync(bl, where, CurrentUser.UserId); + if (blResult) + { + cacheHelper.Remove("dictionary:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + + return ToJsonContent(result); + } + + /// + /// 异步软删除信息 + /// + /// 主键Id + /// 删除标识,默认为1:即设为删除,0:未删除 + [HttpDelete("DeleteSoftAsync")] + [FunctionAuthorize("DeleteSoft")] + public async Task DeleteSoftAsync(long id, string bltag = "1") + { + CommonResult result = new CommonResult(); + System.Collections.Generic.IEnumerable dictionaryList = await _service.GetListWhereAsync($" ParentId={id} and IsDeleted=0 and IsEnabled=1"); + if (dictionaryList != null && dictionaryList.Count() > 0) + { + result.ErrMsg = "字典存在启用下级,不能删除"; + return ToJsonContent(result); + } + + CacheHelper cacheHelper = new CacheHelper(); + bool bl = false; + if (bltag == "0") + { + bl = true; + } + + bool blResult = await _service.DeleteSoftAsync(bl, id, CurrentUser.UserId); + if (blResult) + { + cacheHelper.Remove("dictionary:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + return ToJsonContent(result); + } + + /// + /// 异步批量软删除信息 + /// + /// + /// + [HttpDelete("DeleteSoftBatchAsync")] + [FunctionAuthorize("DeleteSoft")] + public async Task DeleteSoftBatchAsync(UpdateEnableViewModel info) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + string where = string.Empty; + string key = string.Empty; + if (typeof(int) == typeof(string)) + { + @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + @key = " ParentId in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "') and IsDeleted=0 and IsEnabled=1"; + } + else if (typeof(int) == typeof(int)) + { + @where = "id in (" + info.Ids.Join(",") + ")"; + @key = " ParentId in (" + info.Ids.Join(",") + ") and IsDeleted=0 and IsEnabled=1"; + } + if (!string.IsNullOrEmpty(key)) + { + System.Collections.Generic.IEnumerable dictionaryList = await _service.GetListWhereAsync(key); + if (dictionaryList != null && dictionaryList.Count() > 0) + { + result.ErrMsg = "字典存在启用下级,不能删除"; + return ToJsonContent(result); + } + } + if (!string.IsNullOrEmpty(where)) + { + bool bl = false; + if (info.Flag == "0") + { + bl = true; + } + + bool blResult = await _service.DeleteSoftBatchAsync(bl, where, CurrentUser.UserId); + if (blResult) + { + cacheHelper.Remove("dictionary:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + return ToJsonContent(result); + } + + /// + /// 根据ParentId查询数据字典列表 + /// + /// + /// + [HttpGet("GetListByPidAsync")] + [FunctionAuthorize("")] + public async Task GetListByPidAsync(long pid) + { + var result = new CommonResult + { + ResData = await _service.GetListByPidAsync(pid), + ErrCode = ErrCode.successCode, + ErrMsg = ErrCode.err0 + }; + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/EquipmentController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/EquipmentController.cs new file mode 100644 index 0000000..763124c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/EquipmentController.cs @@ -0,0 +1,131 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 设备 + /// + [ApiController] + [Route("api/Security/[controller]")] + + public class EquipmentController : AreaApiController + { + /// + /// 设备管理 + /// + /// + public EquipmentController(IEquipmentService service) : base(service) + { + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(EquipmentEntity info) + { + info.Id = YitIdHelper.NextId(); + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(EquipmentEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(EquipmentEntity info) + { + info.IsDeleted = true; + } + /// + /// 分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + [AllowAnonymous] + public async Task FindWithPagerSearchAsync(SearchEquipmentModel search) + { + var result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + + /// + /// 下架 + /// + /// + [HttpPut] + + public async Task CancelAsync(long id) + { + CommonResult result = new CommonResult(); + result= await _service.CancelAsync(id); + + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + return ToJsonContent(result); + } + + /// + /// 成交 + /// + /// + [HttpPut("CompleteAsync")] + public async Task CompleteAsync(long id) + { + CommonResult result = new CommonResult(); + result = await _service.CompleteAsync(id); + + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/ExceptionsLogsController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/ExceptionsLogsController.cs new file mode 100644 index 0000000..a3ba47c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/ExceptionsLogsController.cs @@ -0,0 +1,81 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 日志接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class ExceptionsLogsController : AreaApiController + { + private readonly IOrganizeService organizeService; + + /// + /// + /// + /// + public ExceptionsLogsController(IExceptionsLogsService service, IOrganizeService _organizeService) : + base(service) + { + _service = service; + organizeService = _organizeService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(ExceptionsLogsEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(ExceptionsLogsEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(ExceptionsLogsEntity info) + { + info.IsDeleted = true; + } + + ///// + ///// 异步分页查询 + ///// + ///// + ///// + //[HttpPost("FindWithPagerSearchAsync")] + //[FunctionAuthorize("List")] + //public async Task FindWithPagerSearchAsync(SearchExceptionsLogsModel search) + //{ + // CommonResult> result = new CommonResult> + // { + // ResData = await _service.FindWithPagerSearchAsync(search), + // ErrCode = ErrCode.successCode + // }; + // return ToJsonContent(result); + //} + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/FeedbackController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/FeedbackController.cs new file mode 100644 index 0000000..d975a57 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/FeedbackController.cs @@ -0,0 +1,114 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + FeedbackController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public FeedbackController(IFeedbackService _service) : base(_service) + { + + } + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(FeedbackEntity info) + { + info.Id = YitIdHelper.NextId(); + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(FeedbackEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(FeedbackEntity info) + { + info.IsDeleted = true; + } + + + /// + /// 分页查询 + /// + /// status:0未处理/1已处理/-1全部 + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchFeedbackModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + /// + /// 异步更新数据 + /// + /// + /// 0未处理/1已处理 + /// + [HttpPost("UpdateAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(long id, int status) + { + CommonResult result = new CommonResult(); + FeedbackEntity info = new FeedbackEntity() + { + Id = id, + State = status + }; + OnBeforeUpdate(info); + result = await _service.UpdateAsync(info); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43001; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/FilesController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/FilesController.cs new file mode 100644 index 0000000..1a28acb --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/FilesController.cs @@ -0,0 +1,297 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.IO; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extend; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Security.Application; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 文件上传 + /// + [Route("api/[controller]")] + [ApiController] + public class FilesController : ApiController + { + private readonly IWebHostEnvironment _hostingEnvironment; + private string _belongApp; //所属应用 + private string _belongAppId; //所属应用ID + private string _dbFilePath; //数据库中的文件路径 + private string _dbThumbnail; //数据库中的缩略图路径 + private string _fileName; //文件名称 + private string _filePath; + + public FilesController(IWebHostEnvironment hostingEnvironment) + { + _hostingEnvironment = hostingEnvironment; + } + + /// + /// 单文件上传接口 + /// + /// + /// 服务器存储的文件信息 + [HttpPost("Upload")] + public IActionResult Upload([FromForm] IFormCollection formCollection) + { + CommonResult result = new CommonResult(); + + FormFileCollection filelist = (FormFileCollection)formCollection.Files; + string belongApp = formCollection["belongApp"].ToString(); + string belongAppId = formCollection["belongAppId"].ToString(); + _fileName = filelist[0].FileName; + try + { + result.ResData = Add(filelist[0], belongApp, belongAppId); + result.ErrCode = ErrCode.successCode; + result.Success = true; + } + catch (Exception ex) + { + result.ErrCode = "500"; + result.ErrMsg = ex.Message; + Log4NetHelper.Error("", ex); + throw ex; + } + + return ToJsonContent(result); + } + + /// + /// 批量上传文件接口 + /// + /// + /// 服务器存储的文件信息 + [HttpPost("Uploads")] + public IActionResult Uploads([FromForm] IFormCollection formCollection) + { + CommonResult result = new CommonResult(); + FormFileCollection filelist = (FormFileCollection)formCollection.Files; + string belongApp = formCollection["belongApp"].ToString(); + string belongAppId = formCollection["belongAppId"].ToString(); + try + { + result.ResData = Adds(filelist, belongApp, belongAppId); + } + catch (Exception ex) + { + Log4NetHelper.Error("", ex); + result.ErrCode = "500"; + result.ErrMsg = ex.Message; + } + + return ToJsonContent(result); + } + + /// + /// 删除文件 + /// + /// + /// + [HttpGet("DeleteFile")] + public IActionResult DeleteFile(int id) + { + CommonResult result = new CommonResult(); + try + { + UploadFileEntity uploadFile = new UploadFileApp().Get(id); + + CacheHelper cacheHelper = new CacheHelper(); + SysSettingEntity sysSetting = cacheHelper.Get("SysSetting").ToJson().ToObject(); + string localpath = _hostingEnvironment.WebRootPath; + if (uploadFile != null) + { + string filepath = (localpath + "/" + uploadFile.FilePath).ToFilePath(); + if (System.IO.File.Exists(filepath)) + { + System.IO.File.Delete(filepath); + } + + string filepathThu = (localpath + "/" + uploadFile.Thumbnail).ToFilePath(); + if (System.IO.File.Exists(filepathThu)) + { + System.IO.File.Delete(filepathThu); + } + + result.ErrCode = ErrCode.successCode; + result.Success = true; + } + else + { + result.ErrCode = ErrCode.failCode; + result.Success = false; + } + } + catch (Exception ex) + { + Log4NetHelper.Error("", ex); + result.ErrCode = "500"; + result.ErrMsg = ex.Message; + } + + return ToJsonContent(result); + } + + /// + /// 批量上传文件 + /// + /// 文件 + /// 所属应用,如文章article + /// 所属应用ID,如文章id + /// + private List Adds(IFormFileCollection files, string belongApp, string belongAppId) + { + List result = new List(); + foreach (IFormFile file in files) + { + if (file != null) + { + result.Add(Add(file, belongApp, belongAppId)); + } + } + + return result; + } + + /// + /// 单个上传文件 + /// + /// + /// + /// + /// + private UploadFileResultOuputDto Add(IFormFile file, string belongApp, string belongAppId) + { + _belongApp = belongApp; + _belongAppId = belongAppId; + if (file != null && file.Length > 0 && file.Length < 10485760) + { + using (BinaryReader binaryReader = new BinaryReader(file.OpenReadStream())) + { + string fileName = string.Empty; + fileName = _fileName; + + byte[] data = binaryReader.ReadBytes((int)file.Length); + UploadFile(fileName, data); + ; + UploadFileEntity filedb = new UploadFileEntity + { + Id = 0, + FilePath = _dbFilePath, + Thumbnail = _dbThumbnail, + FileName = fileName, + FileSize = file.Length.ToInt(), + FileType = Path.GetExtension(fileName), + Extension = Path.GetExtension(fileName), + BelongApp = _belongApp, + BelongAppId = _belongAppId + }; + //new UploadFileApp().Insert(filedb); + UploadFileResultOuputDto uploadFileResultOuputDto = filedb.MapTo(); + uploadFileResultOuputDto.PhysicsFilePath = + (_hostingEnvironment.WebRootPath + "/" + _dbThumbnail).ToFilePath(); + ; + return uploadFileResultOuputDto; + } + } + + Log4NetHelper.Info("文件过大"); + throw new Exception("文件过大"); + } + + /// + /// 实现文件上传到服务器保存,并生成缩略图 + /// + /// 文件名称 + /// 文件字节流 + private void UploadFile(string fileName, byte[] fileBuffers) + { + //判断文件是否为空 + if (string.IsNullOrEmpty(fileName)) + { + Log4NetHelper.Info("文件名不能为空"); + throw new Exception("文件名不能为空"); + } + + //判断文件是否为空 + if (fileBuffers.Length < 1) + { + Log4NetHelper.Info("文件不能为空"); + throw new Exception("文件不能为空"); + } + + CacheHelper cacheHelper = new CacheHelper(); + SysSettingEntity sysSetting = cacheHelper.Get("SysSetting").ToJson().ToObject(); + string folder = DateTime.Now.ToString("yyyyMMdd"); + _filePath = _hostingEnvironment.WebRootPath; + string _tempfilepath = sysSetting.Filepath; + + if (!string.IsNullOrEmpty(_belongApp)) + { + _tempfilepath += "/" + _belongApp; + } + + if (!string.IsNullOrEmpty(_belongAppId)) + { + _tempfilepath += "/" + _belongAppId; + } + + if (sysSetting.Filesave == "1") + { + _tempfilepath = _tempfilepath + "/" + folder + "/"; + } + + if (sysSetting.Filesave == "2") + { + DateTime date = DateTime.Now; + _tempfilepath = _tempfilepath + "/" + date.Year + "/" + date.Month + "/" + date.Day + "/"; + } + + string uploadPath = _filePath + "/" + _tempfilepath; + if (sysSetting.Fileserver == "localhost") + { + if (!Directory.Exists(uploadPath)) + { + Directory.CreateDirectory(uploadPath); + } + } + + string ext = Path.GetExtension(fileName).ToLower(); + Guid newName = Guid.NewGuid(); + string newfileName = newName + ext; + + using (FileStream fs = new FileStream(uploadPath + newfileName, FileMode.Create)) + { + fs.Write(fileBuffers, 0, fileBuffers.Length); + fs.Close(); + //生成缩略图 + if (ext.Contains(".jpg") || ext.Contains(".jpeg") || ext.Contains(".png") || ext.Contains(".bmp") || + ext.Contains(".gif")) + { + string thumbnailName = newName + "_" + sysSetting.Thumbnailwidth + "x" + sysSetting.Thumbnailheight + + ext; + ImgHelper.MakeThumbnail(uploadPath + newfileName, uploadPath + thumbnailName, + sysSetting.Thumbnailwidth.ToInt(), sysSetting.Thumbnailheight.ToInt()); + _dbThumbnail = _tempfilepath + thumbnailName; + } + + _dbFilePath = _tempfilepath + newfileName; + } + } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/FunctionController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/FunctionController.cs new file mode 100644 index 0000000..5000e94 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/FunctionController.cs @@ -0,0 +1,81 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 功能模块接口 + /// + [ApiController] + [Produces("application/json")] + [Route("api/[controller]")] + public class FunctionController : AreaApiController + { + /// + /// + /// + public FunctionController(IMenuService service) : base(service) + { + _service = service; + } + + /// + /// 根据父级功能编码查询所有子集功能,主要用于页面操作按钮权限 + /// + /// 菜单功能编码 + /// + [HttpGet("GetListByParentEnCode")] + [FunctionAuthorize("")] + public async Task GetListByParentEnCode(string enCode) + { + CommonResult result = new CommonResult(); + try + { + if (CurrentUser != null) + { + CacheHelper cacheHelper = new CacheHelper(); + List functions = new List(); + functions = cacheHelper.Get("User_Function_" + CurrentUser.UserId).ToJson() + .ToObject>(); + MenuOutputDto functionOutputDto = functions.Find(s => s.EnCode == enCode); + List nowFunList = new List(); + if (functionOutputDto != null) + { + nowFunList = functions + .FindAll(s => s.ParentId == functionOutputDto.Id && s.IsShow && s.MenuType.Equals("F")) + .OrderBy(s => s.SortCode).ToList(); + } + + result.ErrCode = ErrCode.successCode; + result.ResData = nowFunList; + } + else + { + result.ErrCode = "40008"; + result.ErrMsg = ErrCode.err40008; + } + } + catch (Exception ex) + { + Log4NetHelper.Error("根据父级功能编码查询所有子集功能,主要用于页面操作按钮权限,代码生成异常", ex); + result.ErrCode = ErrCode.failCode; + result.ErrMsg = "获取模块功能异常"; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/IndustryJobsController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/IndustryJobsController.cs new file mode 100644 index 0000000..89d3438 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/IndustryJobsController.cs @@ -0,0 +1,308 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Linq; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.ViewModel; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 行业岗位 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + IndustryJobsController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public IndustryJobsController(IIndustryJobsService service) : base(service) + { + _service = service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(IndustryJobsEntity info) + { + info.Id = 0; + info.IsEnabled = true; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(IndustryJobsEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(IndustryJobsEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("Insert")] + [FunctionAuthorize("Add")] + public async Task InsertAsync(IndustryJobsInputDto tinfo) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + IndustryJobsEntity info = tinfo.MapTo(); + OnBeforeInsert(info); + info.Id = YitIdHelper.NextId(); + int bl = await _service.InsertAsync(info).ConfigureAwait(false); + if (bl > 0) + { + cacheHelper.Remove("industryjobs:list"); + cacheHelper.Remove("allindustryjobs:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("UpdateAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(IndustryJobsInputDto tinfo) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + IndustryJobsEntity info = _service.Get(tinfo.Id); + info.ParentId = tinfo.ParentId; + info.Name = tinfo.Name; + info.Sort = tinfo.Sort; + info.IsEnabled = tinfo.IsEnabled; + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + if (bl) + { + cacheHelper.Remove("industryjobs:list"); + cacheHelper.Remove("allindustryjobs:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 获取行业岗位适用于Vue 树形列表 + /// + /// + [HttpGet("GetAllIndustryJobsTreeTable")] + [FunctionAuthorize("")] + public async Task GetAllIndustryJobsTreeTable() + { + CommonResult result = new CommonResult(); + try + { + System.Collections.Generic.List list = await _service.GetAllIndustryJobsTreeTable(); + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ResData = list; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取组织结构异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return ToJsonContent(result); + } + + /// + /// 异步批量禁用数据 + /// + /// + [HttpPost("SetEnabledMarktBatchAsync")] + [FunctionAuthorize("")] + public async Task SetEnabledMarktBatchAsync(UpdateEnableViewModel info) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + string where = string.Empty; + if (typeof(int) == typeof(string)) + { + @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + } + else if (typeof(int) == typeof(int)) + { + @where = "id in (" + info.Ids.Join(",") + ")"; + } + + if (!string.IsNullOrEmpty(where)) + { + bool bl = false; + if (info.Flag == "1") + { + bl = true; + } + + bool blResult = await _service.SetEnabledMarkByWhereAsync(bl, where, CurrentUser.UserId); + if (blResult) + { + cacheHelper.Remove("industryjobs:list"); + cacheHelper.Remove("allindustryjobs:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + + return ToJsonContent(result); + } + + /// + /// 异步软删除信息 + /// + /// 主键Id + /// 删除标识,默认为1:即设为删除,0:未删除 + [HttpDelete("DeleteSoftAsync")] + [FunctionAuthorize("DeleteSoft")] + public async Task DeleteSoftAsync(long id, string bltag = "1") + { + CommonResult result = new CommonResult(); + System.Collections.Generic.IEnumerable IndustryJobList = await _service.GetListWhereAsync($" ParentId={id} and IsDeleted=0 and IsEnabled=1"); + if (IndustryJobList != null && IndustryJobList.Count() > 0) + { + result.ErrMsg = "行业存在启用岗位,不能删除"; + return ToJsonContent(result); + } + CacheHelper cacheHelper = new CacheHelper(); + bool bl = false; + if (bltag == "0") + { + bl = true; + } + + bool blResult = await _service.DeleteSoftAsync(bl, id, CurrentUser.UserId); + if (blResult) + { + cacheHelper.Remove("industryjobs:list"); + cacheHelper.Remove("allindustryjobs:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步批量软删除信息 + /// + /// + /// + [HttpDelete("DeleteSoftBatchAsync")] + [FunctionAuthorize("DeleteSoft")] + public async Task DeleteSoftBatchAsync(UpdateEnableViewModel info) + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + string where = string.Empty; + string key = string.Empty; + if (typeof(int) == typeof(string)) + { + @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + @key = " ParentId in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "') and IsDeleted=0 and IsEnabled=1"; + } + else if (typeof(int) == typeof(int)) + { + @where = "id in (" + info.Ids.Join(",") + ")"; + @key = " ParentId in (" + info.Ids.Join(",") + ") and IsDeleted=0 and IsEnabled=1"; + } + if (!string.IsNullOrEmpty(key)) + { + System.Collections.Generic.IEnumerable IndustryJobList = await _service.GetListWhereAsync(key); + if (IndustryJobList != null && IndustryJobList.Count() > 0) + { + result.ErrMsg = "行业存在启用岗位,不能删除"; + return ToJsonContent(result); + } + } + if (!string.IsNullOrEmpty(where)) + { + bool bl = false; + if (info.Flag == "0") + { + bl = true; + } + + bool blResult = await _service.DeleteSoftBatchAsync(bl, where, CurrentUser.UserId); + if (blResult) + { + cacheHelper.Remove("industryjobs:list"); + cacheHelper.Remove("allindustryjobs:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/LoginController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/LoginController.cs new file mode 100644 index 0000000..606ea54 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/LoginController.cs @@ -0,0 +1,293 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Common; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Core.App; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Net; +using Znyc.Cloudcar.Admin.Commons.Options; +using Znyc.Cloudcar.Admin.Security.Application; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 用户登录接口控制器 + /// + [ApiController] + [ApiVersion("1.0")] + [Produces("application/json")] + [Route("api/[controller]")] + public class LoginController : ApiController + { + private readonly IAPPService _appService; + private readonly ILoginLogsService _loginLogsService; + private readonly IRoleDataService _roleDataService; + private readonly IRoleService _roleService; + private readonly ISystemTypeService _systemTypeService; + private readonly IAdminUserLogOnService _userLogOnService; + private readonly IAdminUserService _userService; + private readonly ILogger _logger; + + /// + /// 构造函数注入服务 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public LoginController(IAdminUserService _service, IAdminUserLogOnService userLogOnService, + ISystemTypeService systemTypeService, ILoginLogsService loginLogsService, IAPPService appService, + IRoleService roleService, IRoleDataService roleDataService, IMenuService menuService, ILogger logger) + { + _logger = logger; + _userService = _service; + _userLogOnService = userLogOnService; + _systemTypeService = systemTypeService; + _loginLogsService = loginLogsService; + _appService = appService; + _roleService = roleService; + _roleDataService = roleDataService; + } + + /// + /// 用户登录,必须要有验证码 + /// + /// 用户名 + /// 密码 + /// AppId + /// 系统编码 + /// 返回用户User对象 + [HttpGet("GetCheckUser")] + [NoPermissionRequired] + public async Task GetCheckUser(string username, string password, string appId, string systemCode) + { + Log4NetHelper.Debug("Debug"); + Log4NetHelper.Error("Error"); + Log4NetHelper.Info("Info"); + Log4NetHelper.Warn("Warn"); + + CommonResult result = new CommonResult(); + RemoteIpParser remoteIpParser = new RemoteIpParser(); + string strIp = remoteIpParser.GetClientIp(HttpContext).MapToIPv4().ToString(); + CacheHelper cacheHelper = new CacheHelper(); + LoginLogsEntity loginlogEntity = new LoginLogsEntity(); + + if (string.IsNullOrEmpty(username)) + { + result.ErrMsg = "用户名不能为空!"; + } + else if (string.IsNullOrEmpty(password)) + { + result.ErrMsg = ErrCode.err1; + } + + if (string.IsNullOrEmpty(systemCode)) + { + result.ErrMsg = ErrCode.err40006; + } + else + { + string strHost = Request.Host.ToString(); + APPEntity app = _appService.GetAPP(appId); + if (app == null) + { + result.ErrCode = "40001"; + result.ErrMsg = ErrCode.err40001; + } + else + { + SystemTypeEntity systemType = _systemTypeService.GetByCode(systemCode); + if (systemType == null) + { + result.ErrMsg = ErrCode.err40006; + } + else + { + Tuple userLogin = await _userService.Validate(username, password); + if (userLogin != null) + { + string ipAddressName = "未知"; //IpAddressUtil.GetCityByIp(); + if (userLogin.Item1 != null) + { + result.Success = true; + AdminUserEntity user = userLogin.Item1; + JwtOption jwtModel = App.GetService(); + TokenProvider tokenProvider = new TokenProvider(jwtModel); + TokenResult tokenResult = tokenProvider.LoginToken(user, appId); + AdminCurrentUser currentSession = new AdminCurrentUser + { + UserId = user.Id, + Name = user.UserName, + AccessToken = tokenResult.AccessToken, + AppKey = appId, + CreateTime = DateTime.Now, + Role = _roleService.GetRoleEnCode(user.RoleId.ToString()), + ActiveSystemId = systemType.Id, + CurrentLoginIP = strIp, + IPAddressName = ipAddressName + }; + TimeSpan expiresSliding = DateTime.Now.AddMinutes(120) - DateTime.Now; + cacheHelper.Add("login_user_" + user.Id, currentSession, expiresSliding, + true); + + + CurrentUser = currentSession; + result.ResData = currentSession; + result.ErrCode = ErrCode.successCode; + result.Success = true; + loginlogEntity.UserName = user.UserName; + loginlogEntity.LoginTime = DateTime.Now; + loginlogEntity.PlatformType = (int)PlatformTypeEnum.Management; + loginlogEntity.IP = CurrentUser.CurrentLoginIP; + loginlogEntity.OS = "PC"; + loginlogEntity.Browser = ""; + loginlogEntity.City = ""; + loginlogEntity.Result = "登陆成功"; + loginlogEntity.UserAgent = ""; + loginlogEntity.Id = YitIdHelper.NextId(); + loginlogEntity.IsEnabled = true; + _loginLogsService.Insert(loginlogEntity); + } + else + { + result.ErrCode = ErrCode.failCode; + result.ErrMsg = userLogin.Item2; + loginlogEntity.UserName = ""; + loginlogEntity.LoginTime = DateTime.Now; + loginlogEntity.PlatformType = (int)PlatformTypeEnum.Management; + loginlogEntity.IP = strIp; //CurrentUser.CurrentLoginIP; + loginlogEntity.OS = "PC"; + loginlogEntity.Browser = ""; + loginlogEntity.City = ""; + loginlogEntity.Result = $"登陆失败|ErrMsg:{result.ErrMsg}"; + loginlogEntity.UserAgent = ""; + loginlogEntity.Id = YitIdHelper.NextId(); + loginlogEntity.IsEnabled = true; + _loginLogsService.Insert(loginlogEntity); + } + } + } + } + } + cacheHelper.Remove("LoginValidateCode"); + return ToJsonContent(result, true); + } + + /// + /// 获取登录用户权限信息 + /// + /// 返回用户User对象 + [HttpGet("GetUserInfo")] + [FunctionAuthorize("")] + public IActionResult GetUserInfo() + { + CommonResult result = new CommonResult(); + AdminUserEntity user = _userService.Get(CurrentUser.UserId); + CacheHelper cacheHelper = new CacheHelper(); + SystemTypeEntity systemType = _systemTypeService.Get(CurrentUser.ActiveSystemId); + AdminCurrentUser currentSession = new AdminCurrentUser + { + UserId = user.Id, + Account = user.Account, + Name = user.UserName, + AccessToken = CurrentUser.AccessToken, + AppKey = CurrentUser.AppKey, + CreateTime = DateTime.Now, + HeadIcon = user.HeadIcon, + Gender = user.Gender, + Role = _roleService.GetRoleEnCode(user.RoleId.ToString()), + MobilePhone = user.MobilePhone, + OrganizeId = user.OrganizeId, + DeptId = user.DepartmentId, + CurrentLoginIP = CurrentUser.CurrentLoginIP, + IPAddressName = CurrentUser.IPAddressName, + TenantId = 0, + UserTheme = "default" + }; + CurrentUser = currentSession; + + CurrentUser.ActiveSystemId = systemType.Id; + CurrentUser.ActiveSystem = systemType.FullName; + CurrentUser.ActiveSystemUrl = systemType.Url; + + List listFunction = new List(); + MenuApp menuApp = new MenuApp(); + if (Permission.IsAdmin(CurrentUser)) + { + CurrentUser.SubSystemList = + _systemTypeService.GetAllByIsNotDeleteAndEnabledMark().MapTo(); + //取得用户可使用的授权功能信息,并存储在缓存中 + listFunction = menuApp.GetFunctionsBySystem(CurrentUser.ActiveSystemId.ToString()); + CurrentUser.MenusRouter = menuApp.GetVueRouter(0, systemType.EnCode); + } + else + { + CurrentUser.SubSystemList = _systemTypeService.GetSubSystemList(user.RoleId.ToString()); + //取得用户可使用的授权功能信息,并存储在缓存中 + listFunction = menuApp.GetFunctionsByUser(user.Id, CurrentUser.ActiveSystemId.ToString()); + CurrentUser.MenusRouter = menuApp.GetVueRouter(user.RoleId, systemType.EnCode); + } + + AdminUserLogOnEntity userLogOn = _userLogOnService.GetByUserId(CurrentUser.UserId); + //CurrentUser.UserTheme = userLogOn.Theme == null ? "default" : userLogOn.Theme; + TimeSpan expiresSliding = DateTime.Now.AddMinutes(120) - DateTime.Now; + cacheHelper.Add("User_Function_" + user.Id, listFunction, expiresSliding, true); + List listModules = new List(); + foreach (MenuOutputDto item in listFunction) + { + listModules.Add(item.EnCode); + } + + CurrentUser.Modules = listModules; + cacheHelper.Add("login_user_" + user.Id, CurrentUser, expiresSliding, true); + //该用户的数据权限 + List roleDateList = _roleDataService.GetListDeptByRole(user.RoleId.ToString()); + cacheHelper.Add("User_RoleData_" + user.Id, roleDateList, expiresSliding, true); + result.ResData = CurrentUser; + result.ErrCode = ErrCode.successCode; + result.Success = true; + return ToJsonContent(result, true); + } + + + /// + /// 退出登录 + /// + /// + [HttpGet("Logout")] + [FunctionAuthorize("")] + public IActionResult Logout() + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + cacheHelper.Remove("login_user_" + CurrentUser.UserId); + cacheHelper.Remove("User_Function_" + CurrentUser.UserId); + AdminUserLogOnEntity userLogOn = _userLogOnService.GetWhere("UserId='" + CurrentUser.UserId + "'"); + userLogOn.UserOnLine = false; + _userLogOnService.Update(userLogOn, userLogOn.Id); + CurrentUser = null; + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ErrMsg = "成功退出"; + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/LoginLogsController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/LoginLogsController.cs new file mode 100644 index 0000000..b227e8c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/LoginLogsController.cs @@ -0,0 +1,80 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 日志接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class LoginLogsController : AreaApiController + { + private readonly IOrganizeService organizeService; + + /// + /// + /// + /// + public LoginLogsController(ILoginLogsService service, IOrganizeService _organizeService) : base(service) + { + _service = service; + organizeService = _organizeService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(LoginLogsEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(LoginLogsEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(LoginLogsEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步分页查询 + /// + /// + /// + //[HttpPost("FindWithPagerSearchAsync")] + //[FunctionAuthorize("List")] + //public async Task FindWithPagerSearchAsync(SearchDbLogsModel search) + //{ + // CommonResult> result = new CommonResult> + // { + // ResData = await _service.FindWithPagerSearchAsync(search), + // ErrCode = ErrCode.successCode + // }; + // return ToJsonContent(result); + //} + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/MenuController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/MenuController.cs new file mode 100644 index 0000000..a640dad --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/MenuController.cs @@ -0,0 +1,328 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 功能菜单接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class MenuController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public MenuController(IMenuService service) : base(service) + { + _service = service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(MenuEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + if (info.SortCode == null) + { + info.SortCode = 99; + } + + if (string.IsNullOrEmpty(info.ParentId.ToString())) + { + info.Layers = 1; + info.ParentId = 0; + } + else + { + info.Layers = _service.Get(info.ParentId).Layers + 1; + } + + if (info.MenuType == "F") + { + info.IsFrame = false; + info.Component = ""; + info.UrlAddress = ""; + } + } + + /// + /// 新增 + /// + /// + /// + [HttpPost("Insert")] + [FunctionAuthorize("Add")] + public async Task InsertAsync(MenuInputDto info) + { + CommonResult result = new CommonResult(); + MenuEntity menu = info.MapTo(); + long ln = 0; + if (info.IsBatch) + { + string strEnCode = info.EnCode; + MenuEntity listInfo = new MenuEntity(); + listInfo = menu; + listInfo.FullName = "列表"; + listInfo.EnCode = strEnCode + "/List"; + listInfo.Icon = "list"; + OnBeforeInsert(listInfo); + long listId = info.ParentId; + ln = _service.Insert(listInfo); + + MenuEntity addInfo = new MenuEntity(); + addInfo = menu; + addInfo.Id = 0; + addInfo.FullName = "新增"; + addInfo.EnCode = strEnCode + "/Add"; + addInfo.ParentId = listId; + addInfo.Icon = "add"; + addInfo.SortCode = 1; + OnBeforeInsert(addInfo); + ln = _service.Insert(addInfo); + + MenuEntity viewInfo = new MenuEntity(); + viewInfo = menu; + viewInfo.Id = 0; + viewInfo.FullName = "查看"; + viewInfo.EnCode = strEnCode + "/View"; + viewInfo.ParentId = listId; + viewInfo.Icon = "eye-open"; + viewInfo.SortCode = 1; + OnBeforeInsert(viewInfo); + ln = _service.Insert(viewInfo); + + MenuEntity editnfo = new MenuEntity(); + editnfo = menu; + editnfo.Id = 0; + editnfo.FullName = "修改"; + editnfo.EnCode = strEnCode + "/Edit"; + editnfo.ParentId = listId; + editnfo.Icon = "write"; + editnfo.SortCode = 2; + OnBeforeInsert(editnfo); + ln = _service.Insert(editnfo); + + MenuEntity enableInfo = new MenuEntity(); + enableInfo = menu; + enableInfo.Id = 0; + enableInfo.FullName = "禁用"; + enableInfo.EnCode = strEnCode + "/Enable"; + enableInfo.ParentId = listId; + enableInfo.Icon = "pause"; + enableInfo.SortCode = 3; + OnBeforeInsert(enableInfo); + ln = _service.Insert(enableInfo); + + MenuEntity enableInfo1 = new MenuEntity(); + enableInfo1 = menu; + enableInfo1.Id = 0; + enableInfo1.FullName = "启用"; + enableInfo1.EnCode = strEnCode + "/Enable"; + enableInfo1.ParentId = listId; + enableInfo1.Icon = "play"; + enableInfo1.SortCode = 4; + OnBeforeInsert(enableInfo1); + ln = _service.Insert(enableInfo1); + + MenuEntity deleteSoftInfo = new MenuEntity(); + deleteSoftInfo = menu; + deleteSoftInfo.Id = 0; + deleteSoftInfo.FullName = "软删除"; + deleteSoftInfo.EnCode = strEnCode + "/DeleteSoft"; + deleteSoftInfo.ParentId = listId; + deleteSoftInfo.Icon = "remove"; + deleteSoftInfo.SortCode = 5; + OnBeforeInsert(deleteSoftInfo); + ln = _service.Insert(deleteSoftInfo); + + MenuEntity deleteInfo = new MenuEntity(); + deleteInfo = menu; + deleteInfo.Id = 0; + deleteInfo.FullName = "删除"; + deleteInfo.EnCode = strEnCode + "/Delete"; + deleteInfo.ParentId = listId; + deleteInfo.Icon = "remove"; + deleteInfo.SortCode = 6; + OnBeforeInsert(deleteInfo); + ln = _service.Insert(deleteInfo); + } + else + { + OnBeforeInsert(menu); + ln = await _service.InsertAsync(menu); + } + + if (ln >= 0) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrCode = "43001"; + } + + return ToJsonContent(result); + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(MenuEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + + if (info.SortCode == null) + { + info.SortCode = 99; + } + + if (string.IsNullOrEmpty(info.ParentId.ToString())) + { + info.Layers = 1; + info.ParentId = 0; + } + else + { + info.Layers = _service.Get(info.ParentId).Layers + 1; + } + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(MenuEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("Update")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(MenuInputDto tinfo) + { + CommonResult result = new CommonResult(); + + MenuEntity info = _service.Get(tinfo.Id); + info.FullName = tinfo.FullName; + info.EnCode = tinfo.EnCode; + info.SystemTypeId = tinfo.SystemTypeId; + info.ParentId = tinfo.ParentId; + info.Icon = tinfo.Icon; + + info.SortCode = tinfo.SortCode; + info.Description = tinfo.Description; + info.MenuType = tinfo.MenuType; + info.ActiveMenu = tinfo.ActiveMenu; + if (info.MenuType == "F") + { + info.IsFrame = false; + info.Component = ""; + info.UrlAddress = ""; + } + else + { + info.Component = tinfo.Component; + info.IsFrame = tinfo.IsFrame; + info.UrlAddress = tinfo.UrlAddress; + } + + info.IsShow = tinfo.IsShow; + + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 获取功能菜单适用于Vue 树形列表 + /// + /// 子系统Id + /// + [HttpGet("GetAllMenuTreeTable")] + [FunctionAuthorize("List")] + public async Task GetAllMenuTreeTable(string systemTypeId) + { + CommonResult result = new CommonResult(); + try + { + System.Collections.Generic.List list = await _service.GetAllMenuTreeTable(systemTypeId); + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ResData = list; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取菜单异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return ToJsonContent(result); + } + + ///// + ///// 异步批量物理删除 + ///// + ///// + //[HttpDelete("DeleteBatchAsync")] + //[FunctionAuthorize("Delete")] + //public override async Task DeleteBatchAsync(DeletesInputDto info) + //{ + // var result = new CommonResult(); + + // if (info.Ids.Length > 0) + // { + // result = await _service.DeleteBatchWhereAsync(info).ConfigureAwait(false); + // if (result.Success) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrCode = "43003"; + // } + // } + + // return ToJsonContent(result); + //} + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/OperationLogsController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/OperationLogsController.cs new file mode 100644 index 0000000..684fc07 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/OperationLogsController.cs @@ -0,0 +1,85 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 操作日志接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class OperationLogsController : AreaApiController + { + private readonly IOrganizeService organizeService; + + /// + /// + /// + /// + public OperationLogsController(IOperationLogsService service, IOrganizeService _organizeService) : base(service) + { + _service = service; + organizeService = _organizeService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(OperationLogsEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(OperationLogsEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(OperationLogsEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchOperationLogsModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/OrganizeController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/OrganizeController.cs new file mode 100644 index 0000000..56644f5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/OrganizeController.cs @@ -0,0 +1,279 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.ViewModel; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 组织机构接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + OrganizeController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public OrganizeController(IOrganizeService service) : base(service) + { + _service = service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(OrganizeEntity info) + { + info.IsEnabled = true; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + if (info.SortCode == 0) + { + info.SortCode = 99; + } + + if (info.ParentId == 0) + { + info.Layers = 1; + info.ParentId = 0; + } + else + { + info.Layers = _service.Get(info.ParentId).Layers + 1; + } + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(OrganizeEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + if (string.IsNullOrEmpty(info.ParentId.ToString())) + { + info.Layers = 1; + info.ParentId = 0; + } + else + { + info.Layers = _service.Get(info.ParentId).Layers + 1; + } + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(OrganizeEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("Insert")] + [FunctionAuthorize("Add")] + public async Task InsertAsync(OrganizeInputDto tinfo) + { + CommonResult result = new CommonResult(); + OrganizeEntity info = tinfo.MapTo(); + OnBeforeInsert(info); + info.Id = YitIdHelper.NextId(); + int bl = await _service.InsertAsync(info).ConfigureAwait(false); + if (bl > 0) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("Update")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(OrganizeInputDto tinfo) + { + CommonResult result = new CommonResult(); + + OrganizeEntity info = _service.Get(tinfo.Id); + info.ParentId = tinfo.ParentId; + info.FullName = tinfo.FullName; + info.EnCode = tinfo.EnCode; + info.ManagerName = tinfo.ManagerName; + info.CategoryName = tinfo.CategoryName; + info.SortCode = tinfo.SortCode; + info.Description = tinfo.Description; + info.IsEnabled = tinfo.IsEnabled; + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 获取组织机构适用于Vue 树形列表 + /// + /// + [HttpGet("GetAllOrganizeTreeTable")] + [FunctionAuthorize("List")] + public async Task GetAllOrganizeTreeTable() + { + CommonResult result = new CommonResult(); + try + { + System.Collections.Generic.List list = await _service.GetAllOrganizeTreeTable(); + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ResData = list; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取组织结构异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return ToJsonContent(result); + } + + /// + /// 获取组织机构适用于Vue Tree树形 + /// + /// + [HttpGet("GetAllOrganizeTree")] + [FunctionAuthorize("List")] + public async Task GetAllOrganizeTree() + { + CommonResult result = new CommonResult(); + try + { + System.Collections.Generic.List list = await _service.GetAllOrganizeTreeTable(); + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ResData = list; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取组织结构异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return ToJsonContent(result); + } + + /// + /// 异步批量禁用数据 + /// + /// + [HttpPost("SetEnabledMarktBatchAsync")] + [FunctionAuthorize("")] + public async Task SetEnabledMarktBatchAsync(UpdateEnableViewModel info) + { + CommonResult result = new CommonResult(); + string where = string.Empty; + if (typeof(int) == typeof(string)) + { + @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + } + else if (typeof(int) == typeof(int)) + { + @where = "id in (" + info.Ids.Join(",") + ")"; + } + + if (!string.IsNullOrEmpty(where)) + { + bool bl = false; + if (info.Flag == "1") + { + bl = true; + } + + bool blResult = await _service.SetEnabledMarkByWhereAsync(bl, where, CurrentUser.UserId); + if (blResult) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + + return ToJsonContent(result); + } + + ///// + ///// 异步批量物理删除 + ///// + ///// + //[HttpDelete("DeleteBatchAsync")] + //[FunctionAuthorize("Delete")] + //public override async Task DeleteBatchAsync(DeletesInputDto info) + //{ + // var result = new CommonResult(); + + // if (info.Ids.Length > 0) + // { + // result = await _service.DeleteBatchWhereAsync(info).ConfigureAwait(false); + // if (result.Success) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrCode = "43003"; + // } + // } + + // return ToJsonContent(result); + //} + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/PaymentRecordController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/PaymentRecordController.cs new file mode 100644 index 0000000..3e608cc --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/PaymentRecordController.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 付款服务 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + PaymentRecordController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public PaymentRecordController(IPaymentRecordService _service) : base(_service) + { + _service = _service; + } + + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + [AllowAnonymous] + public async Task>> FindWithPagerSearchAsync(SearchPaymentRecordModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/QuartzController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/QuartzController.cs new file mode 100644 index 0000000..4cde422 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/QuartzController.cs @@ -0,0 +1,193 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Senparc.Weixin.MP.AdvancedAPIs; +using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; +using Znyc.Cloudcar.Admin.WebApi.Attributes; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 定时调度 + /// + [Quartz] + [Route("api/Security/[controller]")] + [AllowAnonymous] + public class QuartzController : AreaApiController + { + private readonly IStatisticalService _statisticalService; + private readonly IActivityService _activityService; + private readonly IBannerService _bannerService; + private readonly IApplyJobService _applyJobService; + private readonly ICloudcarService _CloudcarService; + private readonly IIndustryJobsService _industryJobsService; + + /// + /// 构造函数 + /// + /// + /// + /// + public QuartzController(IApiService service, + IStatisticalService statisticalService, + IActivityService activityService, + IBannerService bannerService, + IApplyJobService applyJobService, + ICloudcarService CloudcarService, + IIndustryJobsService industryJobsService + ) : base(service) + { + _service = service; + _statisticalService = statisticalService; + _activityService = activityService; + _bannerService = bannerService; + _applyJobService = applyJobService; + _CloudcarService = CloudcarService; + _industryJobsService = industryJobsService; + } + + /// + /// 添加统计数据 + /// + /// + [HttpGet("InsertAsync")] + [AllowAnonymous] + + //[FunctionAuthorize("Add")] + public async Task AddAsync() + { + CommonResult result = new CommonResult(); + result = await _statisticalService.InsertAsync(); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + + /// + /// 修改活动状态 + /// + /// + [HttpGet("UpdateActivityStatusAsync")] + [AllowAnonymous] + public async Task UpdateActivityStatusAsync() + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + result = await _activityService.UpdateStatusAsync(); + if (result.Success) + { + cacheHelper.Remove("activity:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 修改广告状态 + /// + /// + [HttpGet("UpdateBannerStatusAsync")] + [AllowAnonymous] + public async Task UpdateBannerStatusAsync() + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + result = await _bannerService.UpdateStatusAsync(); + if (result.Success) + { + cacheHelper.Remove("banner:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + + /// + /// 求职信息匹配 + /// + /// + [HttpGet("MatchingApplyJobAsync")] + [AllowAnonymous] + + public async Task MatchingApplyJobAsync() + { + var applyJobs = await _applyJobService.GetListWhereAsync(" IsPublic=1 and IsDeleted=0 and State=1"); + foreach (var applyJob in applyJobs) + { + var Cloudcar = await _CloudcarService.GetWhereAsync($" IndustryId={applyJob.IndustryId} && JobId={applyJob.JobId} && ProvinceId={applyJob.ProvinceId} && CityId={applyJob.CityId}"); + if (Cloudcar != null) + { //行业岗位 + List industryJobs = await _industryJobsService.GetAllListAsync(); + string jobName = industryJobs.Find(x => x.Id == Cloudcar.JobId)?.Name; + WeChat.CommonService.TemplateMessage.WeixinTemplate_Subscription data = new WeChat.CommonService.TemplateMessage.WeixinTemplate_Subscription("最新招聘信息通知!", "占位", jobName, Cloudcar.Address, "占位", "占位"); + TemplateModel_MiniProgram miniProgram = new TemplateModel_MiniProgram(); + miniProgram.appid = "wx71f2b227f8eaf00a"; + miniProgram.pagepath = $"pages/detail/detail?type=Cloudcar&id={Cloudcar.Id}"; + var result = await TemplateApi.SendTemplateMessageAsync("wx07c574aca93ae8d9", "oYbbE6Dh0e3P9s2cXF0vrISNhAZI", data.TemplateId, "pages/index/index", data, miniProgram); + } + } + + } + + + /// + /// 求职信息匹配 + /// + /// + [HttpGet("MatchingCloudcarAsync")] + [AllowAnonymous] + + public async Task MatchingCloudcarAsync() + { + var Cloudcars = await _CloudcarService.GetListWhereAsync(" IsPublic=1 and IsDeleted=0 and State=1"); + foreach (var Cloudcar in Cloudcars) + { + var applyJob = await _applyJobService.GetWhereAsync($" IndustryId={Cloudcar.IndustryId} && JobId={Cloudcar.JobId} && ProvinceId={Cloudcar.ProvinceId} && CityId={Cloudcar.CityId}"); + if (applyJob != null) + { //行业岗位 + List industryJobs = await _industryJobsService.GetAllListAsync(); + string jobName = industryJobs.Find(x => x.Id == applyJob.JobId)?.Name; + WeChat.CommonService.TemplateMessage.WeixinTemplate_Subscription data = new WeChat.CommonService.TemplateMessage.WeixinTemplate_Subscription("最新求职信息通知!", "占位", jobName, applyJob.Address, "占位", "占位"); + TemplateModel_MiniProgram miniProgram = new TemplateModel_MiniProgram(); + miniProgram.appid = "wx71f2b227f8eaf00a"; + miniProgram.pagepath = $"pages/detail/detail?type=apply&id={applyJob.Id}"; + var result = await TemplateApi.SendTemplateMessageAsync("wx07c574aca93ae8d9", "oYbbE6Dh0e3P9s2cXF0vrISNhAZI", data.TemplateId, "pages/index/index", data, miniProgram); + } + } + + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/RechargeController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/RechargeController.cs new file mode 100644 index 0000000..1ec5d60 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/RechargeController.cs @@ -0,0 +1,146 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Enums; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 充值活动 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + RechargeController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public RechargeController(IRechargeService _service) : base(_service) + { + + } + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(RechargeEntity info) + { + info.Id = YitIdHelper.NextId(); + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(RechargeEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(RechargeEntity info) + { + info.IsDeleted = true; + } + + + /// + /// 分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + [AllowAnonymous] + public async Task FindWithPagerSearchAsync(SearchRechargeModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("InsertAsync")] + [FunctionAuthorize("Add")] + + public async Task InsertAsync(RechargeAddInput input) + { + CommonResult result = new CommonResult(); + RechargeEntity info = input.MapTo(); + CacheHelper cacheHelper = new CacheHelper(); + OnBeforeInsert(info); + info.Name = input.Name; + info.State = (int)ActivityStatusEnum.Ongoing; + long ln = await _service.InsertAsync(info).ConfigureAwait(false); + bool isSuccess = await _service.InsertRechargeIntroAsync(input.rechargeIntros, info.Id, info.CreatedUserId); + if (ln > 0 && isSuccess) + { + cacheHelper.Remove("recharge:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43001; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("UpdateAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(RechargeUpdateInput input) + { + CommonResult result = await _service.UpdateAsync(input, CurrentUser.UserId); + CacheHelper cacheHelper = new CacheHelper(); + if (result.Success) + { + cacheHelper.Remove("recharge:list"); + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43001; + result.ErrCode = "43001"; + } + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/RecruitmentController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/RecruitmentController.cs new file mode 100644 index 0000000..e8de588 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/RecruitmentController.cs @@ -0,0 +1,189 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 招聘 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class CloudcarController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public CloudcarController(ICloudcarService service) : base(service) + { + _service = service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(CloudcarEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(CloudcarEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(CloudcarEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchCloudcarModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("InsertAsync")] + [FunctionAuthorize("Add")] + public new async Task InsertAsync(CloudcarInputDto input) + { + CommonResult result = new CommonResult(); + CloudcarEntity info = input.MapTo(); + OnBeforeInsert(info); + result = await _service.InsertAsync(info); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("UpdateAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(CloudcarInputDto input) + { + CommonResult result = new CommonResult(); + CloudcarEntity info = input.MapTo(); + OnBeforeUpdate(info); + result = await _service.UpdateAsync(info); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 根据主键Id获取一个对象信息 + /// + /// 主键Id + /// + [HttpGet("GetById")] + // [FunctionAuthorize("")] + //[NoPermissionRequired] + [AllowAnonymous] + public async Task> GetById(long id) + { + CommonResult result = new CommonResult(); + CloudcarOutputDto info = await _service.GetById(id); + if (info != null) + { + result.ErrCode = ErrCode.successCode; + result.ResData = info; + } + else + { + result.ErrMsg = ErrCode.err50001; + result.ErrCode = "50001"; + } + return result; + } + + /// + /// 下架招聘信息 + /// + /// + /// + [HttpPost("RevocationAsync")] + [FunctionAuthorize("Edit")] + public async Task RevocationAsync(long id) + { + CommonResult result = new CommonResult(); + result = await _service.RevocationAsync(id, CurrentUser.UserId); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/RegionController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/RegionController.cs new file mode 100644 index 0000000..593ba6c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/RegionController.cs @@ -0,0 +1,83 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 省市区地区管理 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + RegionController + { + private readonly IRegionService _regionService; + + /// + /// 构造函数 + /// + /// + public RegionController(IRegionService regionService) + { + _regionService = regionService; + } + + /// + /// 省市区 + /// + /// + [HttpGet("GetAllRegionList")] + [FunctionAuthorize("")] + public async Task GetAllRegionList() + { + CommonResult result = new CommonResult(); + try + { + System.Collections.Generic.List list = await _regionService.GetAllRegionList(); + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ResData = list; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取省市区缓存异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return result; + } + + /// + /// 同步地区缓存 + /// + /// + [HttpGet("AsyncRegionCache")] + [FunctionAuthorize("")] + public async Task AsyncRegionCache() + { + CommonResult result = new CommonResult(); + try + { + System.Collections.Generic.List list = await _regionService.AsyncRegionCache(); + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ResData = list; + } + catch (Exception ex) + { + Log4NetHelper.Error("同步地区缓存异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return result; + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleAuthorizeController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleAuthorizeController.cs new file mode 100644 index 0000000..9832337 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleAuthorizeController.cs @@ -0,0 +1,242 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 角色权限接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class RoleAuthorizeController : AreaApiController + { + private readonly IMenuService menuService; + private readonly IOrganizeService organizeService; + private readonly IRoleDataService roleDataService; + + /// + /// + /// + /// + /// + /// + public RoleAuthorizeController(IRoleAuthorizeService service, IMenuService _menuService, + IRoleDataService _roleDataService, IOrganizeService _organizeService) : base(service) + { + _service = service; + menuService = _menuService; + roleDataService = _roleDataService; + organizeService = _organizeService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(RoleAuthorizeEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + if (info.SortCode == null) + { + info.SortCode = 99; + } + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(RoleAuthorizeEntity info) + { + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(RoleAuthorizeEntity info) + { + } + + /// + /// 角色分配权限树 + /// + /// + /// + /// + [HttpGet("GetRoleAuthorizeFunction")] + [FunctionAuthorize("List")] + public async Task GetRoleAuthorizeFunction(long roleId, string itemType) + { + CommonResult result = new CommonResult(); + // roleId = "'" + roleId + "'"; + List resultlist = new List(); + IEnumerable list = _service.GetListRoleAuthorizeByRoleId(roleId.ToString(), itemType); + foreach (RoleAuthorizeEntity info in list) + { + resultlist.Add(info.ItemId); + } + + result.ResData = resultlist; + result.ErrCode = ErrCode.successCode; + return ToJsonContent(result); + } + + /// + /// 保存角色权限 + /// + /// 功能权限 + /// + [HttpPost("SaveRoleAuthorize")] + [FunctionAuthorize("List")] + public async Task SaveRoleAuthorize(RoleAuthorizeDataInputDto roleinfo) + { + CommonResult result = new CommonResult(); + try + { + List inList = new List(); + foreach (int item in roleinfo.RoleFunctios) + { + MenuEntity menu = menuService.Get(item); + if (menu != null) + { + RoleAuthorizeEntity info = new RoleAuthorizeEntity + { + ObjectId = roleinfo.RoleId, + ItemType = menu.MenuType == "C" || menu.MenuType == "M" ? 1 : 2, + ObjectType = 1, + ItemId = menu.Id + }; + OnBeforeInsert(info); + inList.Add(info); + } + } + + List roleDataList = new List(); + foreach (string item in roleinfo.RoleData) + { + RoleDataEntity info = new RoleDataEntity + { + RoleId = roleinfo.RoleId, + AuthorizeData = item, + DType = "dept" + }; + roleDataList.Add(info); + } + + foreach (int item in roleinfo.RoleSystem) + { + RoleAuthorizeEntity info = new RoleAuthorizeEntity + { + ObjectId = roleinfo.RoleId, + ItemType = 0, + ObjectType = 1, + ItemId = item + }; + OnBeforeInsert(info); + inList.Add(info); + } + + result.Success = await _service.SaveRoleAuthorize(roleinfo.RoleId, inList, roleDataList); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + } + } + catch (Exception ex) + { + result.ErrMsg = ex.Message; + } + + return ToJsonContent(result); + } + + private List SubFunction(List list, int roleId) + { + List inList = new List(); + foreach (ModuleFunctionOutputDto item in list) + { + RoleAuthorizeEntity info = new RoleAuthorizeEntity + { + ObjectId = roleId, + ItemType = 1, + ObjectType = 1, + ItemId = item.Id + }; + OnBeforeInsert(info); + inList.Add(info); + inList.Concat(SubFunction(item.Children, roleId)); + } + + return inList; + } + + /// + /// 获取功能菜单适用于Vue Tree树形 + /// + /// + [HttpGet("GetAllFunctionTree")] + [FunctionAuthorize("List")] + public async Task GetAllFunctionTree() + { + CommonResult result = new CommonResult(); + try + { + List list = await _service.GetAllFunctionTree(); + result.Success = true; + result.ErrCode = ErrCode.successCode; + result.ResData = list; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取菜单异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return ToJsonContent(result); + } + + /// + /// 获取功能菜单适用于Vue 树形列表 + /// + /// 子系统Id + /// + //[HttpGet("GetAllFunctionTreeTable")] + //[FunctionAuthorize("List")] + //public async Task GetAllFunctionTreeTable(string systemTypeId) + //{ + // CommonResult result = new CommonResult(); + // try + // { + // List list = await menuService.GetAllFunctionTreeTable(systemTypeId); + // result.Success = true; + // result.ErrCode = ErrCode.successCode; + // result.ResData = list; + // } + // catch (Exception ex) + // { + // Log4NetHelper.Error("获取菜单异常", ex); + // result.ErrMsg = ErrCode.err40110; + // result.ErrCode = "40110"; + // } + // return ToJsonContent(result); + //} + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleController.cs new file mode 100644 index 0000000..96cf6c9 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleController.cs @@ -0,0 +1,202 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.ViewModel; +using Znyc.Cloudcar.Admin.Commons.Dtos; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 角色接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class RoleController : AreaApiController + { + private readonly IOrganizeService organizeService; + + /// + /// 构造函数 + /// + /// + /// + public RoleController(IRoleService service, IOrganizeService _organizeService) : base(service) + { + _service = service; + organizeService = _organizeService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(RoleEntityEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + if (info.SortCode == null) + { + info.SortCode = 99; + } + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(RoleEntityEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(RoleEntityEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步新增数据 + /// + /// + /// + [HttpPost("Insert")] + [FunctionAuthorize("Add")] + public async Task InsertAsync(RoleInputDto tinfo) + { + CommonResult result = new CommonResult(); + RoleEntityEntity info = tinfo.MapTo(); + OnBeforeInsert(info); + info.Id = YitIdHelper.NextId(); + long bl = await _service.InsertReturnPrimaryKeyAsync(info).ConfigureAwait(false); + if (bl > 0) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("Update")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(RoleInputDto tinfo) + { + CommonResult result = new CommonResult(); + + RoleEntityEntity info = _service.Get(tinfo.Id); + info.OrganizeId = tinfo.OrganizeId; + info.FullName = tinfo.FullName; + info.EnCode = tinfo.EnCode; + + info.SortCode = tinfo.SortCode; + info.Description = tinfo.Description; + info.Type = tinfo.Type; + + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 根据条件查询数据库,并返回对象集合(用于分页数据显示) + /// + /// + /// + [HttpPost("FindWithPagerAsync")] + [FunctionAuthorize("List")] + public virtual async Task>> FindWithPagerAsync( + SearchInputDto search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerAsync(search), + ErrCode = ErrCode.successCode + }; + return result; + } + + /// + /// 异步批量禁用数据 + /// + /// + [HttpPost("SetEnabledMarktBatchAsync")] + [FunctionAuthorize("")] + public async Task SetEnabledMarktBatchAsync(UpdateEnableViewModel info) + { + CommonResult result = new CommonResult(); + string where = string.Empty; + if (typeof(int) == typeof(string)) + { + @where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + } + else if (typeof(int) == typeof(int)) + { + @where = "id in (" + info.Ids.Join(",") + ")"; + } + + if (!string.IsNullOrEmpty(where)) + { + bool bl = false; + if (info.Flag == "1") + { + bl = true; + } + + bool blResult = await _service.SetEnabledMarkByWhereAsync(bl, where, CurrentUser.UserId); + if (blResult) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleDataController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleDataController.cs new file mode 100644 index 0000000..58865da --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/RoleDataController.cs @@ -0,0 +1,82 @@ +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 角色数据权限接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + RoleDataController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public RoleDataController(IRoleDataService service) : base(service) + { + _service = service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(RoleDataEntity info) + { + info.Id = 0; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(RoleDataEntity info) + { + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(RoleDataEntity info) + { + } + + /// + /// 角色可以访问数据 + /// + /// 角色Id + /// + [HttpGet("GetAllRoleDataByRoleId")] + [FunctionAuthorize("List")] + public async Task GetAllRoleDataByRoleId(string roleId) + { + CommonResult result = new CommonResult(); + string where = string.Format("RoleId='{0}'", roleId); + List resultlist = new List(); + IEnumerable list = await _service.GetListWhereAsync(where); + foreach (RoleDataEntity info in list) + { + resultlist.Add(info.AuthorizeData); + } + + result.ResData = resultlist; + result.ErrCode = ErrCode.successCode; + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/StatisticalController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/StatisticalController.cs new file mode 100644 index 0000000..6ed7cdb --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/StatisticalController.cs @@ -0,0 +1,157 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Yitter.IdGenerator; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 数据字典接口 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class StatisticalController : AreaApiController + { + private readonly IApplyJobService _applyJobService; + private readonly ILoginLogsRepository _loginLogsRepository; + private readonly IOrderService _orderService; + private readonly ICloudcarService _CloudcarService; + private readonly IStatisticalService _statisticalService; + private readonly IUserService _userService; + + + /// + /// 构造函数 + /// + /// + /// + /// + /// + /// + /// + /// + public StatisticalController(IStatisticalService statisticalService, + IUserService userService, + ICloudcarService CloudcarService, + IApplyJobService applyJobService, + ILoginLogsRepository loginLogsRepository, + IOrderService orderService + ) : base(statisticalService) + { + _statisticalService = statisticalService; + _applyJobService = applyJobService; + _userService = userService; + _CloudcarService = CloudcarService; + _loginLogsRepository = loginLogsRepository; + _orderService = orderService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(StatisticalEntity info) + { + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(StatisticalEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 异步新增数据 + /// + /// + [HttpPost("InsertAsync")] + [FunctionAuthorize("Add")] + public async Task InsertAsync() + { + CommonResult result = new CommonResult(); + StatisticalEntity statistical = await _statisticalService.GetStatisticalAsync(); + int userAddTotal = await _userService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"); + dynamic todayIncome = await _orderService.GetSumValueByFieldAsync("PaymentMoney", + "OrderStatus >= 20 and date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"); + dynamic income = await _orderService.GetSumValueByFieldAsync("PaymentMoney", "OrderStatus >= 20"); + StatisticalEntity info = new StatisticalEntity + { + Id = YitIdHelper.NextId(), + Time = DateTime.Now.ToString("yyyy-MM-dd"), + UserAddTotal = userAddTotal, + UserSumTotal = await _userService.GetCountByWhereAsync("IsDeleted = 0"), + ApplyJobsAddTotal = + await _applyJobService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"), + CloudcarAddTotal = + await _CloudcarService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"), + ActiveUserTotal = await _loginLogsRepository.GetActiveUserTotal(), + TodayIncome = todayIncome.sumVaule, + Income = income.sumVaule, + ModifiedTime = DateTime.Now, + CreatedTime = DateTime.Now + }; + if (statistical == null) + { + info.UserAddTotalPercent = 0; + info.TodayIncomePercent = 0; + } + else + { + //UserAddTotalPercent = statistical.UserSumTotal!=0 ? (userAddTotal / statistical.UserSumTotal) * 100 : 0, + info.UserAddTotalPercent = StringHelper.GetPercent(userAddTotal, statistical.UserSumTotal); + //TodayIncomePercent = statistical.Income!=0 ? (todayIncome.sumVaule / statistical.Income) * 100 :0, + info.TodayIncomePercent = StringHelper.GetPercent(todayIncome.sumVaule, statistical.Income); + } + OnBeforeInsert(info); + long ln = await _service.InsertAsync(info).ConfigureAwait(false); + if (ln > 0) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43001; + result.ErrCode = "43001"; + } + + return ToJsonContent(result); + } + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchUserModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _statisticalService.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/SysSettingController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/SysSettingController.cs new file mode 100644 index 0000000..2467e38 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/SysSettingController.cs @@ -0,0 +1,342 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Encrypt; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Extend; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Mapping; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IRepositories; +using Znyc.Cloudcar.Admin.Security.IServices; +using Znyc.Cloudcar.Admin.WebApi.Areas.Security.Entitys; + +namespace Znyc.Cloudcar.Admin.WebApi.Areas.Security +{ + /// + /// 系统基本信息 + /// + [Route("api/Security/[controller]")] + [ApiController] + public class SysSettingController : ApiController + { + private readonly IAdminUserService _adminUserService; + private readonly IApplyJobService _applyJobService; + private readonly IAPPService _aPPService; + private readonly IWebHostEnvironment _hostingEnvironment; + private readonly ILoginLogsRepository _loginLogsRepository; + private readonly ILoginLogsService _loginLogsService; + private readonly IMenuService _menuService; + private readonly IOrderService _orderService; + private readonly ICloudcarService _CloudcarService; + private readonly IRoleService _roleService; + private readonly IStatisticalService _statisticalService; + private readonly IUserService _userService; + private readonly ICertificationRepository _certificationRepository; + private readonly IEquipmentService _equipmentService; + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public SysSettingController(IWebHostEnvironment hostingEnvironment, + IAdminUserService adminUserService, + IMenuService menuService, + IRoleService roleService, + IUserService userService, + ICloudcarService CloudcarService, + IApplyJobService applyJobService, + ILoginLogsService loginLogsService, + ILoginLogsRepository loginLogsRepository, + IStatisticalService statisticalService, + IOrderService orderService, + ICertificationRepository certificationRepository, + IAPPService aPPService, + IEquipmentService equipmentService) + { + _hostingEnvironment = hostingEnvironment; + _adminUserService = adminUserService; + _menuService = menuService; + _roleService = roleService; + _aPPService = aPPService; + _userService = userService; + _CloudcarService = CloudcarService; + _applyJobService = applyJobService; + _loginLogsService = loginLogsService; + _loginLogsRepository = loginLogsRepository; + _statisticalService = statisticalService; + _orderService = orderService; + _certificationRepository = certificationRepository; + _equipmentService = equipmentService; + } + + /// + /// 获取系统信息 + /// + /// + [HttpGet("GetSysInfo")] + [FunctionAuthorize("GetSysInfo")] + public async Task GetSysInfo() + { + CommonResult result = new CommonResult(); + try + { + SysSettingEntity sysSetting = XmlConverter.Deserialize("xmlconfig/sys.config"); + CacheHelper cacheHelper = new CacheHelper(); + cacheHelper.Add("SysSetting", sysSetting); + DashboardOutModel dashboardOutModel = new DashboardOutModel + { + CertificatedCompany = sysSetting.CompanyName, + WebUrl = sysSetting.WebUrl, + Title = sysSetting.SoftName, + MachineName = Environment.MachineName, + ProcessorCount = Environment.ProcessorCount, + SystemPageSize = Environment.SystemPageSize, + WorkingSet = Environment.WorkingSet, + TickCount = Environment.TickCount, + RunTimeLength = (Environment.TickCount / 1000).ToBrowseTime(), + FrameworkDescription = RuntimeInformation.FrameworkDescription, + OSName = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "Linux" : + RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "OSX" : "Windows", + OSDescription = + RuntimeInformation.OSDescription + " " + RuntimeInformation.OSArchitecture, + OSArchitecture = RuntimeInformation.OSArchitecture.ToString(), + ProcessArchitecture = RuntimeInformation.ProcessArchitecture.ToString(), + + Directory = AppContext.BaseDirectory + }; + Version version = Environment.Version; + dashboardOutModel.SystemVersion = version.Major + "." + version.Minor + "." + version.Build; + dashboardOutModel.Version = AppVersionHelper.Version; + dashboardOutModel.Manufacturer = AppVersionHelper.Manufacturer; + dashboardOutModel.WebSite = AppVersionHelper.WebSite; + dashboardOutModel.UpdateUrl = AppVersionHelper.UpdateUrl; + dashboardOutModel.IPAdress = Request.HttpContext.Connection.LocalIpAddress.ToString(); + dashboardOutModel.Port = Request.HttpContext.Connection.LocalPort.ToString(); + dashboardOutModel.TotalUser = await _adminUserService.GetCountByWhereAsync("1=1"); + dashboardOutModel.TotalModule = await _menuService.GetCountByWhereAsync("1=1"); + dashboardOutModel.TotalRole = await _roleService.GetCountByWhereAsync("1=1"); + result.ResData = dashboardOutModel; + result.ErrCode = ErrCode.successCode; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取系统信息异常", ex); + result.ErrMsg = ErrCode.err60001; + result.ErrCode = "60001"; + } + + return ToJsonContent(result); + } + + /// + /// 首页统计数据 + /// + /// + [HttpGet("GetStatisticalDataInfo")] + [FunctionAuthorize("")] + public async Task GetStatisticalDataInfo() + { + CommonResult result = new CommonResult(); + + try + { + StatisticalEntity statistical = await _statisticalService.GetStatisticalAsync(); + StatisticalOutputDto statisticalData = new StatisticalOutputDto + { + //用户 + UserSumTotal = await _userService.GetCount(), + UserAddTotal = + await _userService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"), + ActiveUserTotal = await _loginLogsRepository.GetActiveUserTotal() + }; + + //收入 + dynamic todayIncome = await _orderService.GetSumValueByFieldAsync("PaymentMoney", + "OrderStatus >= 20 and date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"); + dynamic income = await _orderService.GetSumValueByFieldAsync("PaymentMoney", "OrderStatus >= 20"); + statisticalData.Income = income.sumVaule; + statisticalData.TodayIncome = todayIncome.sumVaule; + if (statistical == null) + { + statisticalData.UserAddTotalPercent = 0; + statisticalData.DayAddPercent = 0; + statisticalData.TodayIncomePercent = 0; + statisticalData.IncomeIncremental = statisticalData.TodayIncome; + statisticalData.IncomePercent = 0; + } + else + { + statisticalData.UserAddTotalPercent = statistical.UserAddTotalPercent; + //statisticalData.DayAddPercent = statistical.UserAddTotal!=0 ? + // (statisticalData.UserAddTotal - statistical.UserAddTotal) / statistical.UserAddTotal*100 : 0; + statisticalData.DayAddPercent = + StringHelper.GetPercent(statisticalData.UserAddTotal - statistical.UserAddTotal, + statistical.UserAddTotal); + //statisticalData.TodayIncomePercent =statistical.TodayIncome!=0 ? + // (todayIncome.sumVaule - statistical.TodayIncome) / statistical.TodayIncome * 100 : 0; + //statisticalData.IncomePercent =statistical.Income!=0 ? statistical.TodayIncome / statistical.Income * 100 : 0; + statisticalData.TodayIncomePercent = + StringHelper.GetPercent(todayIncome.sumVaule - statistical.TodayIncome, + statistical.TodayIncome); + statisticalData.IncomeIncremental = statisticalData.TodayIncome - statistical.TodayIncome; + statisticalData.IncomePercent = + StringHelper.GetPercent(statistical.TodayIncome, statistical.Income); + + + } + statisticalData.EquipmentTotal = await _equipmentService.GetCountByWhereAsync(" State=10"); + + //待审核 + //statisticalData.ReviewApplyJobsTotal = await _equipmentService.GetCountByWhereAsync("State=0"); + //statisticalData.ReviewCloudcarTotal = await _CloudcarService.GetCountByWhereAsync("State=0"); + //statisticalData.ReviewCertificationTotal = await _certificationRepository.GetCountByWhereAsync("State=0"); + //tatisticalData.ApplyJobsAddTotal = await _applyJobService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"); + //statisticalData.CloudcarAddTotal = await _CloudcarService.GetCountByWhereAsync("date_format(CreatedTime,'%Y-%m-%d') = date_format(NOW(),'%Y-%m-%d')"); + result.ResData = statisticalData; + result.ErrCode = ErrCode.successCode; + } + catch (Exception ex) + { + Log4NetHelper.Error("获取系统信息异常", ex); + result.ErrMsg = ErrCode.err60001; + result.ErrCode = "60001"; + } + + return ToJsonContent(result); + } + + /// + /// 获取系统基本信息不完整信息 + /// + /// + [HttpGet("GetInfo")] + [NoPermissionRequired] + public IActionResult GetInfo() + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + SysSettingEntity sysSetting = cacheHelper.Get("SysSetting").ToJson().ToObject(); + SysSettingOutputDto sysSettingOutputDto = new SysSettingOutputDto(); + if (sysSetting == null) + { + sysSetting = XmlConverter.Deserialize("xmlconfig/sys.config"); + } + + sysSetting.Email = ""; + sysSettingOutputDto = sysSetting.MapTo(); + if (sysSettingOutputDto != null) + { + sysSettingOutputDto.CopyRight = UIConstants.CopyRight; + result.ResData = sysSettingOutputDto; + result.Success = true; + result.ErrCode = ErrCode.successCode; + } + else + { + result.ErrMsg = ErrCode.err60001; + result.ErrCode = "60001"; + } + + System.Collections.Generic.IEnumerable appList = _aPPService.GetAllByIsNotDeleteAndEnabledMark(); + cacheHelper.Add("AllowAppId", appList); + return ToJsonContent(result); + } + + /// + /// 获取系统基本信息 + /// + /// + [HttpGet("GetAllInfo")] + [FunctionAuthorize("GetSysInfo")] + public IActionResult GetAllInfo() + { + CommonResult result = new CommonResult(); + CacheHelper cacheHelper = new CacheHelper(); + SysSettingEntity sysSetting = cacheHelper.Get("SysSetting").ToJson().ToObject(); + SysSettingOutputDto sysSettingOutputDto = new SysSettingOutputDto(); + if (sysSetting == null) + { + sysSetting = XmlConverter.Deserialize("xmlconfig/sys.config"); + } + + //对关键信息解密 + if (!string.IsNullOrEmpty(sysSetting.Email)) + { + sysSetting.Email = DEncrypt.Decrypt(sysSetting.Email); + } + + sysSettingOutputDto = sysSetting.MapTo(); + if (sysSettingOutputDto != null) + { + sysSettingOutputDto.CopyRight = UIConstants.CopyRight; + result.ResData = sysSettingOutputDto; + result.Success = true; + result.ErrCode = ErrCode.successCode; + } + else + { + result.ErrMsg = ErrCode.err60001; + result.ErrCode = "60001"; + } + + return ToJsonContent(result); + } + + /// + /// 保存系统设置信息 + /// + /// + [HttpPost("Save")] + [FunctionAuthorize("Edit")] + public IActionResult Save(SysSettingEntity info) + { + CommonResult result = new CommonResult(); + info.LocalPath = _hostingEnvironment.WebRootPath; + SysSettingEntity sysSetting = XmlConverter.Deserialize("xmlconfig/sys.config"); + sysSetting = info; + //对关键信息加密 + string uploadPath = _hostingEnvironment.WebRootPath + "/" + sysSetting.Filepath; + if (!Directory.Exists(uploadPath)) + { + Directory.CreateDirectory(uploadPath); + } + + CacheHelper cacheHelper = new CacheHelper(); + if (cacheHelper.Exists("SysSetting")) + { + cacheHelper.Replace("SysSetting", sysSetting); + } + else + { + //写入缓存 + cacheHelper.Add("SysSetting", sysSetting); + } + + XmlConverter.Serialize(sysSetting, "xmlconfig/sys.config"); + result.ErrCode = ErrCode.successCode; + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/SystemTypeController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/SystemTypeController.cs new file mode 100644 index 0000000..0396c4d --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/SystemTypeController.cs @@ -0,0 +1,147 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Encrypt; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 系统类型 + /// + [ApiController] + [Route("api/Security/[controller]")] + public class + SystemTypeController : AreaApiController + { + /// + /// 构造函数 + /// + /// + public SystemTypeController(ISystemTypeService service) : base(service) + { + _service = service; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(SystemTypeEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = CurrentUser.UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(SystemTypeEntity info) + { + info.ModifiedUserId = CurrentUser.UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(SystemTypeEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("Update")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(SystemTypeInputDto tinfo) + { + CommonResult result = new CommonResult(); + + SystemTypeEntity info = _service.Get(tinfo.Id); + //info.FullName = tinfo.FullName; + //info.EnCode = tinfo.EnCode; + //info.Url = tinfo.Url; + //info.AllowEdit = tinfo.AllowEdit; + //info.AllowDelete = tinfo.AllowDelete; + //info.SortCode = tinfo.SortCode; + + //info.Description = tinfo.Description; + + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(true); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 系统切换时获取凭据 + /// 适用于不同子系统分别独立部署站点场景 + /// + /// 子系统编码 + /// + [HttpGet("ZnycConnecSys")] + [FunctionAuthorize("")] + public IActionResult ZnycConnecSys(string systype) + { + CommonResult result = new CommonResult(); + try + { + if (!string.IsNullOrEmpty(systype)) + { + SystemTypeEntity systemType = _service.GetByCode(systype); + string openmf = MD5Util.GetMD5_32(DEncrypt.Encrypt(CurrentUser.UserId + systemType.Id.ToString(), + GuidUtils.NewGuidFormatN())).ToLower(); + CacheHelper cacheHelper = new CacheHelper(); + TimeSpan expiresSliding = DateTime.Now.AddSeconds(200) - DateTime.Now; + cacheHelper.Add("openmf" + openmf, CurrentUser.UserId, expiresSliding); + result.ErrCode = ErrCode.successCode; + result.ResData = systemType.Url + "?openmf=" + openmf; + } + else + { + result.ErrCode = ErrCode.failCode; + result.ErrMsg = "切换子系统参数错误"; + } + } + catch (Exception ex) + { + Log4NetHelper.Error("切换子系统异常", ex); + result.ErrMsg = ErrCode.err40110; + result.ErrCode = "40110"; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/TokenController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/TokenController.cs new file mode 100644 index 0000000..2c6edc1 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/TokenController.cs @@ -0,0 +1,205 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Json; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Options; +using Znyc.Cloudcar.Admin.Security.IServices; + +// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// Token令牌接口控制器 + /// + [Route("api/[controller]")] + [ApiController] + public class TokenController : ControllerBase + { + private readonly IAPPService _iAPPService; + private readonly JwtOption _jwtModel; + private readonly IAdminUserService userService; + + /// + /// 构造函数 + /// + /// + /// + /// + public TokenController(IAPPService iAPPService, IAdminUserService _userService, JwtOption jwtModel) + { + if (iAPPService == null) + { + throw new ArgumentNullException(nameof(iAPPService)); + } + + _iAPPService = iAPPService; + userService = _userService; + _jwtModel = jwtModel; + } + + /// + /// 根据应用信息获得token令牌 + /// + /// 获取access_token填写client_credential + /// 应用唯一凭证,应用AppId + /// 应用密钥AppSecret + /// + [HttpGet] + [AllowAnonymous] + public IActionResult Get(string grant_type, string appid, string secret) + { + CommonResult result = new CommonResult(); + if (!grant_type.Equals(GrantType.ClientCredentials)) + { + result.ErrCode = "40003"; + result.ErrMsg = ErrCode.err40003; + return ToJsonContent(result); + } + + if (string.IsNullOrEmpty(grant_type)) + { + result.ErrCode = "40003"; + result.ErrMsg = ErrCode.err40003; + return ToJsonContent(result); + } + + string strHost = Request.Host.ToString(); + Security.Entitys.APPEntity app = _iAPPService.GetAPP(appid, secret); + Console.WriteLine(app); + if (app == null) + { + result.ErrCode = "40001"; + result.ErrMsg = ErrCode.err40001; + } + else + { + TokenProvider tokenProvider = new TokenProvider(_jwtModel); + TokenResult tokenResult = tokenProvider.GenerateToken(grant_type, appid, secret); + result.ResData = tokenResult; + result.ErrCode = "0"; + return ToJsonContent(result); + } + + return ToJsonContent(result); + } + + /// + /// 验证token的合法性。 + /// + /// + /// + [HttpGet("CheckToken")] + [AllowAnonymous] + public IActionResult CheckToken(string token) + { + CommonResult result = new CommonResult(); + TokenProvider tokenProvider = new TokenProvider(_jwtModel); + result = tokenProvider.ValidateToken(token); + return ToJsonContent(result); + } + + /// + /// 刷新token。 + /// + /// + /// + [HttpGet("RefreshToken")] + [AllowAnonymous] + public async Task RefreshToken(string token) + { + CommonResult result = new CommonResult(); + TokenProvider tokenProvider = new TokenProvider(_jwtModel); + if (!string.IsNullOrEmpty(token)) + { + JwtSecurityToken jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token); +#if DEBUG + Log4NetHelper.Debug(jwtToken.ToJson()); +#endif + if (jwtToken != null) + { + //根据应用获取token + if (jwtToken.Subject == GrantType.ClientCredentials) + { + TokenResult tresult = new TokenResult(); + List claimlist = jwtToken?.Payload.Claims as List; + string strHost = Request.Host.ToString(); + Security.Entitys.APPEntity app = _iAPPService.GetAPP(claimlist[0].Value); + if (app == null) + { + result.ErrCode = "40001"; + result.ErrMsg = ErrCode.err40001; + } + else + { + TokenResult tokenResult = tokenProvider.GenerateToken(GrantType.ClientCredentials, app.AppId, + app.AppSecret); + result.ResData = tokenResult; + result.ErrCode = "0"; + result.Success = true; + } + } + + // 用户账号密码登录获取token类型 + if (jwtToken.Subject == GrantType.Password) + { + List claimlist = jwtToken?.Payload.Claims as List; + Security.Entitys.AdminUserEntity user = await userService.GetByUserName(claimlist[2].Value); + TokenResult tokenResult = tokenProvider.LoginToken(user, claimlist[0].Value); + result.ResData = tokenResult; + result.ErrCode = "0"; + result.Success = true; + } + } + else + { + result.ErrMsg = ErrCode.err40004; + result.ErrCode = "40004"; + } + } + else + { + result.ErrMsg = ErrCode.err40004; + result.ErrCode = "40004"; + } + + return ToJsonContent(result); + } + + /// + /// 把object对象转换为ContentResult + /// + /// + /// + [HttpPost] + [Route("api/ToJsonContent")] + protected IActionResult ToJsonContent(object obj) + { + string result = JsonConvert.SerializeObject(obj, Formatting.Indented); + return Content(obj.ToJson()); + } + + /// + /// 获取CosToken + /// + /// + [HttpGet] + [AllowAnonymous] + [Route("api/GetCosToken")] + + public CommonResult GetCosToken() + { + return _iAPPService.GetCosToken(); + } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/UploadFileController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/UploadFileController.cs new file mode 100644 index 0000000..499969e --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/UploadFileController.cs @@ -0,0 +1,72 @@ +using Microsoft.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 文件管理 + /// + [Route("api/Security/[controller]")] + [ApiController] + public class UploadFileController : AreaApiController + { + /// + /// + /// + public UploadFileController(IUploadFileService service) : base(service) + { + _service = service; + } + + ///// + ///// 异步批量物理删除 + ///// + ///// 主键Id数组 + //[HttpDelete("DeleteBatchAsync")] + //[FunctionAuthorize("Delete")] + //public override async Task DeleteBatchAsync(DeletesInputDto info) + //{ + // var result = new CommonResult(); + // var where = string.Empty; + // where = "id in ('" + info.Ids.Join(",").Trim(',').Replace(",", "','") + "')"; + + // if (!string.IsNullOrEmpty(where)) + // { + // var jobsId = info.Ids; + // foreach (var item in jobsId) + // { + // if (string.IsNullOrEmpty(item.ToString())) continue; + // UploadFile uploadFile = new UploadFileApp().Get(item.ToString()); + // var cacheHelper = new CacheHelper(); + // var sysSetting = cacheHelper.Get("SysSetting").ToJson().ToObject(); + // if (uploadFile != null) + // { + // if (System.IO.File.Exists(sysSetting.LocalPath + "/" + uploadFile.FilePath)) + // System.IO.File.Delete(sysSetting.LocalPath + "/" + uploadFile.FilePath); + // if (!string.IsNullOrEmpty(uploadFile.Thumbnail)) + // if (System.IO.File.Exists(sysSetting.LocalPath + "/" + uploadFile.Thumbnail)) + // System.IO.File.Delete(sysSetting.LocalPath + "/" + uploadFile.Thumbnail); + // } + // } + + // var bl = await _service.DeleteBatchWhereAsync(where).ConfigureAwait(false); + // if (bl) + // { + // result.ErrCode = ErrCode.successCode; + // result.ErrMsg = ErrCode.err0; + // } + // else + // { + // result.ErrMsg = ErrCode.err43003; + // result.ErrCode = "43003"; + // } + // } + + // return ToJsonContent(result); + //} + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/UserController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/UserController.cs new file mode 100644 index 0000000..1eae2ae --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/UserController.cs @@ -0,0 +1,178 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Znyc.Cloudcar.Admin.AspNetCore.Controllers; +using Znyc.Cloudcar.Admin.AspNetCore.Entitys; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter; +using Znyc.Cloudcar.Admin.Commons.Entitys; +using Znyc.Cloudcar.Admin.Commons.Pages; +using Znyc.Cloudcar.Admin.Security.Dtos; +using Znyc.Cloudcar.Admin.Security.Entitys; +using Znyc.Cloudcar.Admin.Security.IServices; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 用户接口 + /// + [ApiController] + [AllowAnonymous] + [NoPermissionRequired] + [Route("api/Security/[controller]")] + public class UserController : AreaApiController + { + private readonly IOrganizeService organizeService; + private readonly IRoleService roleService; + private readonly IAdminUserLogOnService userLogOnService; + + /// + /// + /// + /// + /// + /// + public UserController(IUserService service, IOrganizeService _organizeService, IRoleService _roleService, + IAdminUserLogOnService _userLogOnService) : base(service) + { + _service = service; + organizeService = _organizeService; + roleService = _roleService; + userLogOnService = _userLogOnService; + } + + /// + /// 新增前处理数据 + /// + /// + protected override void OnBeforeInsert(UserEntity info) + { + info.Id = 0; + info.CreatedTime = DateTime.Now; + info.CreatedUserId = new AdminCurrentUser().UserId; + info.IsDeleted = false; + } + + /// + /// 在更新数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeUpdate(UserEntity info) + { + info.ModifiedUserId = new AdminCurrentUser().UserId; + info.ModifiedTime = DateTime.Now; + } + + /// + /// 在软删除数据前对数据的修改操作 + /// + /// + /// + protected override void OnBeforeSoftDelete(UserEntity info) + { + info.IsDeleted = true; + } + + /// + /// 异步更新数据 + /// + /// + /// + [HttpPost("UpdateAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateAsync(UserInputDto tinfo) + { + CommonResult result = new CommonResult(); + UserEntity info = _service.Get(tinfo.Id); + info.UserName = tinfo.UserName; + info.AvatarUrl = tinfo.AvatarUrl; + info.Phone = tinfo.Phone; + OnBeforeUpdate(info); + bool bl = await _service.UpdateAsync(info, tinfo.Id).ConfigureAwait(false); + if (bl) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步禁用/启用用户 + /// + /// + /// 1-启用/99-禁用 + /// + [HttpPost("UpdateStatusAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateStatusAsync(int id, int status) + { + CommonResult result = new CommonResult(); + result = await _service.UpdateStatusAsync(id, status); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + + /// + /// 异步分页查询 + /// + /// + /// + [HttpPost("FindWithPagerSearchAsync")] + [FunctionAuthorize("List")] + public async Task FindWithPagerSearchAsync(SearchUserModel search) + { + CommonResult> result = new CommonResult> + { + ResData = await _service.FindWithPagerSearchAsync(search), + ErrCode = ErrCode.successCode + }; + return ToJsonContent(result); + } + + + + /// + /// 设置推广账号 + /// + /// + /// + [HttpPost("UpdateIsPromoteAsync")] + [FunctionAuthorize("Edit")] + public async Task UpdateIsPromoteAsync(long id) + { + CommonResult result = new CommonResult(); + result = await _service.UpdateIsPromoteAsync(id); + if (result.Success) + { + result.ErrCode = ErrCode.successCode; + result.ErrMsg = ErrCode.err0; + } + else + { + result.ErrMsg = ErrCode.err43002; + result.ErrCode = "43002"; + } + + return ToJsonContent(result); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Controllers/WeixinController.cs b/Znyc.Cloudcar.Admin.WebApi/Controllers/WeixinController.cs new file mode 100644 index 0000000..99d45e5 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Controllers/WeixinController.cs @@ -0,0 +1,115 @@ +using Microsoft.AspNetCore.Mvc; +using Model; +using Senparc.Weixin.MP; +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using Znyc.Cloudcar.Admin.Security.IServices; +using PostModel = Senparc.Weixin.MP.Entities.Request.PostModel; + +namespace Znyc.Cloudcar.Admin.WebApi.Controllers +{ + /// + /// 微信公众号 + /// + public class WeixinController : ControllerBase + { + public static readonly string Token = "rzC0pRTuBznwd3"; + //Config.SenparcWeixinSetting.MpSetting.Token;//与微信公众账号后台的Token设置保持一致,区分大小写。 + public static readonly string EncodingAESKey = "VtEIJLTcbrkGT18EkevZzKIBYgqpURtxyH6w2iWR5eD"; + //Config.SenparcWeixinSetting.MpSetting.EncodingAESKey;//与微信公众账号后台的EncodingAESKey设置保持一致,区分大小写。 + public static readonly string AppId = "wx07c574aca93ae8d9"; + //Config.SenparcWeixinSetting.MpSetting.WeixinAppId;//与微信公众账号后台的AppId设置保持一致,区分大小写。 + private readonly IWxUserRelationService _wxUserRelationService; + + + + public WeixinController(IWxUserRelationService wxUserRelationService) + { + _wxUserRelationService = wxUserRelationService; + } + /// + /// 微信后台验证地址 + /// + [HttpGet] + [ActionName("Index")] + public ActionResult Get(PostModel postModel, string echostr) + { + if (CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, Token)) + { + return Content(echostr); //返回随机字符串则表示验证通过 + } + else + { + return Content("failed:" + postModel.Signature + "," + Senparc.Weixin.MP.CheckSignature.GetSignature(postModel.Timestamp, postModel.Nonce, Token) + "。" + + "如果你在浏览器中看到这句话,说明此地址可以被作为微信公众账号后台的Url,请注意保持Token一致。"); + } + } + + /// + /// 用户发送消息后,微信平台自动Post一个请求到这里,并等待响应XML。 + /// PS:此方法为简化方法,效果与OldPost一致。 + /// v0.8之后的版本可以结合Senparc.Weixin.MP.MvcExtension扩展包,使用WeixinResult,见MiniPost方法。 + /// + [HttpPost] + [ActionName("Index")] + public async Task Post(string signature, string timestamp, string nonce) + { + + try + { + StreamReader sr = new StreamReader(Request.Body, Encoding.UTF8); + XmlDocument doc = new XmlDocument(); + doc.Load(sr); + sr.Close(); + sr.Dispose(); + WxMessage wxMessage = new WxMessage(); + wxMessage.ToUserName = doc.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText; + wxMessage.FromUserName = doc.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText; + wxMessage.MsgType = doc.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText; + wxMessage.CreateTime = int.Parse(doc.SelectSingleNode("xml").SelectSingleNode("CreateTime").InnerText); + if (wxMessage.MsgType == "event") + { + wxMessage.EventName = doc.SelectSingleNode("xml").SelectSingleNode("Event").InnerText; + if (!string.IsNullOrEmpty(wxMessage.EventName) && wxMessage.EventName == "subscribe") + { + string content = "您好,欢迎关注众能云车服务号"; + content = SendTextMessage(wxMessage, content); + await _wxUserRelationService.UpdateAsync(wxMessage.FromUserName); + return Content(content); + } + } + } + catch (Exception) + { + //记录日志 + return Content(""); + } + return Content(""); + } + + + /// + /// Send + /// + /// + /// + /// + private string SendTextMessage(WxMessage wxmessage, string content) + { + string result = string.Format(@" + + + {2} + + + ", wxmessage.FromUserName, wxmessage.ToUserName, DateTime.Now.Ticks, content); + return result; + } + + + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Dockerfile b/Znyc.Cloudcar.Admin.WebApi/Dockerfile new file mode 100644 index 0000000..11bbb18 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Dockerfile @@ -0,0 +1,30 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 8091 +EXPOSE 443 + +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["Znyc.Cloudcar.Admin.WebApi/Znyc.Cloudcar.Admin.WebApi.csproj", "Znyc.Cloudcar.Admin.WebApi/"] +COPY ["Znyc.Cloudcar.Admin.Security.Core/Znyc.Cloudcar.Admin.Security.Core.csproj", "Znyc.Cloudcar.Admin.Security.Core/"] +COPY ["Znyc.Cloudcar.Admin.Commons/Znyc.Cloudcar.Admin.Commons.csproj", "Znyc.Cloudcar.Admin.Commons/"] +COPY ["Znyc.Cloudcar.Admin.WeChat.Core/Znyc.Cloudcar.Admin.WeChat.Core.csproj", "Znyc.Cloudcar.Admin.WeChat.Core/"] +COPY ["Znyc.Cloudcar.Admin.MongoDb/Znyc.Cloudcar.Admin.MongoDb.Core.csproj", "Znyc.Cloudcar.Admin.MongoDb/"] +COPY ["Znyc.Cloudcar.Admin.AspNetCore/Znyc.Cloudcar.Admin.AspNetCore.csproj", "Znyc.Cloudcar.Admin.AspNetCore/"] +RUN dotnet restore "Znyc.Cloudcar.Admin.WebApi/Znyc.Cloudcar.Admin.WebApi.csproj" +COPY . . +WORKDIR "/src/Znyc.Cloudcar.Admin.WebApi" +RUN dotnet build "Znyc.Cloudcar.Admin.WebApi.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "Znyc.Cloudcar.Admin.WebApi.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Znyc.Cloudcar.Admin.WebApi.dll"] \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Program.cs b/Znyc.Cloudcar.Admin.WebApi/Program.cs new file mode 100644 index 0000000..f312b6f --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Program.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using System; +using System.IO; +using Znyc.Cloudcar.Admin.Commons; +using Znyc.Cloudcar.Admin.Commons.Core.App; + +namespace Znyc.Cloudcar.Admin.WebApi +{ + /// + /// + public class Program + { + /// + /// 启动程序 + /// + /// + public static void Main(string[] args) + { + try + { + Console.WriteLine("start..."); + CreateHostBuilder(args).Build().Run(); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + /// + /// + /// + /// + public static IHostBuilder CreateHostBuilder(string[] args) + { + IConfigurationRoot config = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile( + $"appsettings.{Environment.GetEnvironmentVariable(SystemConst.ASPNETCORE_ENVIRONMENT)}.json") + .Build(); + App.Configuration = config; + return Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup() + .UseUrls("http://*:8091"); + }); + } + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Properties/PublishProfiles/FolderProfile.pubxml b/Znyc.Cloudcar.Admin.WebApi/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..0813337 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,20 @@ + + + + + True + False + True + Release + Any CPU + FileSystem + bin\Release\net6.0\publish\ + FileSystem + + net6.0 + 64c6211f-c371-471f-a3b6-9f6258621ae4 + false + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Startup.cs b/Znyc.Cloudcar.Admin.WebApi/Startup.cs new file mode 100644 index 0000000..a51bc41 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Startup.cs @@ -0,0 +1,579 @@ +using AutoMapper; +using Hangfire; +using Hangfire.Dashboard.BasicAuthorization; +using Hangfire.Redis; +using log4net; +using log4net.Repository; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Versioning; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Caching.StackExchangeRedis; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using Pursue.Extension.MongoDB; +using Senparc.CO2NET; +using Senparc.CO2NET.RegisterServices; +using Senparc.Weixin.MP.Containers; +using Senparc.Weixin.RegisterServices; +using Swashbuckle.AspNetCore.Filters; +using System; +using System.IO; +using System.Linq; +using System.Runtime.Loader; +using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Unicode; +using Znyc.Cloudcar.Admin.AspNetCore.Common; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc; +using Znyc.Cloudcar.Admin.AspNetCore.Mvc.Filter; +using Znyc.Cloudcar.Admin.Commons.Cache; +using Znyc.Cloudcar.Admin.Commons.Core.App; +using Znyc.Cloudcar.Admin.Commons.Cos; +using Znyc.Cloudcar.Admin.Commons.DbContextCore; +using Znyc.Cloudcar.Admin.Commons.Extensions; +using Znyc.Cloudcar.Admin.Commons.Helpers; +using Znyc.Cloudcar.Admin.Commons.IDbContext; +using Znyc.Cloudcar.Admin.Commons.Linq; +using Znyc.Cloudcar.Admin.Commons.Log; +using Znyc.Cloudcar.Admin.Commons.Module; +using Znyc.Cloudcar.Admin.Commons.Options; +using Znyc.Cloudcar.Admin.Hangfire; +using Znyc.Cloudcar.Admin.MongoDb; +using Znyc.Cloudcar.Admin.MongoDb.Core.IRepositorys; +using Znyc.Cloudcar.Admin.MongoDb.Core.Repositorys; +using Znyc.Cloudcar.Admin.WebApi.Auth; +using Znyc.Cloudcar.Admin.WebApi.Config; + +namespace Znyc.Cloudcar.Admin.WebApi +{ + /// + /// + public class Startup + { + private IApiVersionDescriptionProvider apiVersionProvider; //api接口版本控制 + private IMvcBuilder mvcBuilder; + + private string targetPath = string.Empty; + + /// + /// + /// + public Startup(IConfiguration configuration, IWebHostEnvironment env) + { + Configuration = configuration; + //初始化log4net + LoggerRepository = LogManager.CreateRepository("NETCoreRepository"); + Log4NetHelper.SetConfig(LoggerRepository, "log4net.config"); + if (env.IsProduction()) + { + Log4NetHelper.SetConfig(LoggerRepository, "log4net.Production.config"); + + } + } + + /// + /// + public static ILoggerRepository LoggerRepository { get; set; } + + /// + /// + public IConfiguration Configuration { get; } + + /// + /// This method gets called by the runtime. Use this method to add services to the container. + /// + /// + /// + public void ConfigureServices(IServiceCollection services) + { + services.TryAddSingleton(); + services.AddHttpContextAccessor(); + //如果部署在linux系统上,需要加上下面的配置: + services.Configure(options => options.AllowSynchronousIO = true); + services.AddOptions(); + services.Configure(options => options.AllowSynchronousIO = true); + + #region Swagger Api文档 + + // Api多版本版本配置 + services.AddApiVersioning(o => + { + o.ReportApiVersions = true; //是否在请求头中返回受支持的版本信息。 + o.ApiVersionReader = + new HeaderApiVersionReader("api-version"); ////版本信息放到header ,不写在不配置路由的情况下,版本信息放到response url 中 + o.AssumeDefaultVersionWhenUnspecified = true; //请求没有指明版本的情况下是否使用默认的版本。 + o.DefaultApiVersion = new ApiVersion(1, 0); //默认的版本号。 + }).AddVersionedApiExplorer(option => + { + // 版本名的格式:v+版本号 + option.GroupNameFormat = "'v'V"; + option.AssumeDefaultVersionWhenUnspecified = true; + }); + //获取webapi版本信息,用于swagger多版本支持 + apiVersionProvider = services.BuildServiceProvider().GetRequiredService(); + services.AddSwaggerGen(options => + { + foreach (ApiVersionDescription description in apiVersionProvider.ApiVersionDescriptions) + { + options.SwaggerDoc(description.GroupName, + new OpenApiInfo + { + Title = $"{Configuration.GetSection("SwaggerDoc:Title").Value}v{description.ApiVersion}", + Version = description.ApiVersion.ToString(), + Description = Configuration.GetSection("SwaggerDoc:Description").Value + } + ); + } + + Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.xml").ToList().ForEach(file => + { + options.IncludeXmlComments(file, true); + }); + options.DocumentFilter(); // 在接口类、方法标记属性 [HiddenApi],可以阻止【Swagger文档】生成 + //给api添加token令牌证书 + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"", + Name = "Authorization", //jwt默认的参数名称 + In = ParameterLocation.Header, //jwt默认存放Authorization信息的位置(请求头中) + Type = SecuritySchemeType.ApiKey, + BearerFormat = "JWT", + Scheme = "Bearer" + }); + //添加安全请求 + options.AddSecurityRequirement( + new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" + } + }, + new string[] { } + } + } + ); + //开启加权锁 + options.OperationFilter(); + options.OperationFilter(); + options.OperationFilter(); + }); + + #endregion Swagger Api文档 + + #region 全局设置跨域访问 + + //允许所有跨域访问,测试用 + services.AddCors(options => options.AddPolicy("Cors", + policy => policy.WithOrigins("*").AllowAnyHeader().AllowAnyMethod())); + // 跨域设置 建议正式环境 + //services.AddCors(options => options.AddPolicy("ZnycCors", + // policy => policy.WithOrigins(Configuration.GetSection("AppSetting:AllowOrigins").Value.Split(',', StringSplitOptions.RemoveEmptyEntries)).AllowAnyHeader().AllowAnyMethod())); + + #endregion 全局设置跨域访问 + + #region MiniProfiler + + services.AddMiniProfiler(options => { options.RouteBasePath = "/profiler"; }).AddEntityFramework(); + + #endregion MiniProfiler + + #region 控制器 + + services.AddControllers().AddJsonOptions(options => + { + options.JsonSerializerOptions.WriteIndented = true; + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + //设置时间格式 + options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter()); + options.JsonSerializerOptions.Converters.Add(new DateTimeNullableConverter()); + //设置bool获取格式 + options.JsonSerializerOptions.Converters.Add(new BooleanJsonConverter()); + //设置Decimal获取格式 + options.JsonSerializerOptions.Converters.Add(new DecimalJsonConverter()); + //设置数字 + options.JsonSerializerOptions.Converters.Add(new IntJsonConverter()); + options.JsonSerializerOptions.PropertyNamingPolicy = new UpperFirstCaseNamingPolicy(); + options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); + }); + + mvcBuilder = services.AddMvc(option => + { + //option.Filters.Add(); + option.Filters.Add(new ExceptionHandlingAttribute()); + // option.Filters.Add(); + }).SetCompatibilityVersion(CompatibilityVersion.Latest).AddRazorRuntimeCompilation(); + + services.AddMvcCore() + .AddAuthorization().AddApiExplorer(); + + #endregion 控制器 + + services.AddSignalR(); //使用 SignalR + InitIoC(services); + services.AddCors(options => options.AddPolicy("ZnycCors", + policy => policy.WithOrigins("*").AllowAnyHeader().AllowAnyMethod())); + + services.AddSenparcWeixinServices(Configuration); + services.TryAddSingleton(); + + #region Handfire + services.AddHangfire(x => x.UseRedisStorage(Configuration.GetSection("CacheProvider:Redis_ConnectionString").Value)); + services.AddHangfireServer(options => + { + options.Queues = new[] { HangFireQueuesConfig.@default.ToString(), HangFireQueuesConfig.apis.ToString(), HangFireQueuesConfig.web.ToString(), HangFireQueuesConfig.recurring.ToString() }; + options.ServerTimeout = TimeSpan.FromMinutes(4); + options.SchedulePollingInterval = TimeSpan.FromSeconds(15);//秒级任务需要配置短点,一般任务可以配置默认时间,默认15秒 + options.ShutdownTimeout = TimeSpan.FromMinutes(30); //超时时间 + options.WorkerCount = Math.Max(Environment.ProcessorCount, 20); //工作线程数,当前允许的最大线程,默认20 + }); + #endregion + } + + /// + /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + /// + /// + /// + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions senparcSetting) + { + if (app != null) + { + app.UseStaticHttpContextAccessor(); + IServiceProvider provider = app.ApplicationServices; + AutoMapperService.UsePack(provider); + //加载插件应用 + LoadMoudleApps(env); + + app.UseMiniProfiler(); + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Home/Error"); + app.UseHsts(); + } + + + app.UseSwagger(); + app.UseSwaggerUI(options => + { + foreach (ApiVersionDescription description in apiVersionProvider.ApiVersionDescriptions) + { + options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", + $"{Configuration.GetSection("SwaggerDoc:Title").Value + description.GroupName.ToUpperInvariant()}"); + options.RoutePrefix = string.Empty; //这里主要是不需要再输入swagger这个默认前缀 + } + }); + + app.Use((context, next) => + { + context.Request.EnableBuffering(); + return next(); + }); + app.UseStaticFiles(); + app.UseRouting(); + app.UseAuthentication(); + app.UseAuthorization(); + //跨域 + app.UseMiddleware(); + app.UseCors("Cors"); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapControllerRoute("default", "api/{controller=Home}/{action=Index}/{id?}"); + }); + app.UseStatusCodePages(); + + #region WxSdk 注册 + + IRegisterService register = RegisterService.Start(senparcSetting.Value) + .UseSenparcGlobal(); + register.UseSenparcGlobal(true); + AccessTokenContainer.Register("wx07c574aca93ae8d9", "466411f6865d130f50cc48ae1566de99"); + + #endregion WxSdk 注册 + + #region Hangfire + var filter = new BasicAuthAuthorizationFilter( + new BasicAuthAuthorizationFilterOptions + { + SslRedirect = false, + // Require secure connection for dashboard + RequireSsl = false, + // Case sensitive login checking + LoginCaseSensitive = false, + // Users + Users = new[] + { + new BasicAuthAuthorizationUser + { + Login = Configuration.GetSection("Hangfire:Login").Value, + PasswordClear = Configuration.GetSection("Hangfire:Password").Value + } + } + }); + + var options = new DashboardOptions + { + AppPath = "/",//返回时跳转的地址 + DisplayStorageConnectionString = false,//是否显示数据库连接信息 + Authorization = new[] + { + filter + }, + IsReadOnlyFunc = Context => + { + return false;//是否只读面板 + } + }; + + app.UseHangfireDashboard("/admin_job", options); + HangfireDispose.HangfireService(); + #endregion + } + } + + /// + /// IoC初始化 + /// + /// + /// + private void InitIoC(IServiceCollection services) + { + #region 缓存 + + CacheProvider cacheProvider = new CacheProvider + { + IsUseRedis = Configuration.GetSection("CacheProvider:UseRedis").Value.ToBool(), + ConnectionString = Configuration.GetSection("CacheProvider:Redis_ConnectionString").Value, + InstanceName = Configuration.GetSection("CacheProvider:Redis_InstanceName").Value + }; + + JsonSerializerOptions options = new JsonSerializerOptions(); + options.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); + options.WriteIndented = true; + options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + options.AllowTrailingCommas = true; + //设置时间格式 + options.Converters.Add(new DateTimeJsonConverter()); + options.Converters.Add(new DateTimeNullableConverter()); + //设置bool获取格式 + options.Converters.Add(new BooleanJsonConverter()); + //设置数字 + options.Converters.Add(new IntJsonConverter()); + options.PropertyNamingPolicy = new UpperFirstCaseNamingPolicy(); + options.PropertyNameCaseInsensitive = true; //忽略大小写 + + + + //判断是否使用Redis,如果不使用 Redis就默认使用 MemoryCache + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + if (cacheProvider.IsUseRedis) + { + //Use Redis + services.AddStackExchangeRedisCache(options => + { + options.Configuration = cacheProvider.ConnectionString; + options.InstanceName = cacheProvider.InstanceName; + }); + services.AddSingleton(typeof(ICacheService), new RedisCacheService(new RedisCacheOptions + { + Configuration = cacheProvider.ConnectionString, + InstanceName = cacheProvider.InstanceName + }, options)); + services.Configure(option => + option.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)); //设置Redis缓存有效时间为5分钟。 + } + else + { + //Use MemoryCache + services.AddSingleton(factory => + { + MemoryCache cache = new MemoryCache(new MemoryCacheOptions()); + return cache; + }); + services.AddSingleton(); + services.Configure( + options => options.AbsoluteExpirationRelativeToNow = + TimeSpan.FromMinutes(5)); //设置MemoryCache缓存有效时间为5分钟 + } + + services.AddTransient(); + services.AddMemoryCache(); // 启用MemoryCache + + services.AddSingleton(cacheProvider); //注册缓存配置 + + #endregion 缓存 + + #region 身份认证授权 + + IConfigurationSection jwtConfig = Configuration.GetSection("Jwt"); + JwtOption jwtOption = new JwtOption + { + Issuer = jwtConfig["Issuer"], + Expiration = Convert.ToInt16(jwtConfig["Expiration"]), + Secret = jwtConfig["Secret"], + Audience = jwtConfig["Audience"], + refreshJwtTime = Convert.ToInt16(jwtConfig["refreshJwtTime"]) + }; + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + ; + }).AddJwtBearer(jwtBearerOptions => + { + jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = + new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOption.Secret)), //秘钥 + ValidateIssuer = true, + ValidIssuer = jwtOption.Issuer, + ValidateAudience = true, + ValidAudience = jwtOption.Audience, + ValidateLifetime = true, + ClockSkew = TimeSpan.FromMinutes(5) + }; + }); + services.AddSingleton(jwtOption); //注册配置 + + #endregion 身份认证授权 + + services.AddAutoScanInjection(); //自动化注入仓储和服务 + services.AddTransient(); //注入EF上下文 + + #region automapper + + System.Collections.Generic.List myAssembly = RuntimeHelper.GetAllZnycAssemblies().ToList(); + services.AddAutoMapper(myAssembly); + services.AddTransient(); + + #endregion automapper + + services + .AddMongoDBContext(options => + { + options.UseMongo(Configuration.GetSection("MongoConnection:ConnectionString").Value, + Configuration.GetSection("MongoConnection:Database").Value); + }); + + services + .AddMongoDbService(); + + + services.AddTransient(); + + #region Cos + + CosOptions cosOptions = new CosOptions + { + SecretId = Configuration.GetSection("CosOptions:SecretId").Value, + SecretKey = Configuration.GetSection("CosOptions:SecretKey").Value, + Bucket = Configuration.GetSection("CosOptions:Bucket").Value, + Region = Configuration.GetSection("CosOptions:Region").Value, + AllowPrefix = Configuration.GetSection("CosOptions:AllowPrefix").Value, + DurationSeconds = Configuration.GetSection("CosOptions:DurationSeconds").Value.ToInt(), + AllowActions = new string[] { "name/cos:PutObject", + // 表单上传、小程序上传 + "name/cos:PostObject", + // 分片上传 + "name/cos:InitiateMultipartUpload", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:UploadPart", + "name/cos:CompleteMultipartUpload" } + }; + services.AddSingleton(cosOptions); //注册缓存配置 + + #endregion + App.Services = services; + + services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All)); + + + + } + + /// + /// 加载模块应用 + /// + /// + private void LoadMoudleApps(IWebHostEnvironment env) + { + // 定位到插件应用目录 Apps + Microsoft.Extensions.FileProviders.IFileInfo apps = env.ContentRootFileProvider.GetFileInfo("Apps"); + if (!Directory.Exists(apps.PhysicalPath)) + { + return; + } + + // 把 Apps 下的动态库拷贝一份来运行, + // 使 Apps 中的动态库不会在运行时被占用(以便重新编译) + string shadows = targetPath = PrepareShadowCopies(); + // 从 Shadow Copy 目录加载 Assembly 并注册到 Mvc 中 + LoadFromShadowCopies(shadows); + + string PrepareShadowCopies() + { + // 准备 Shadow Copy 的目标目录 + string target = Path.Combine(env.ContentRootPath, "app_data", "apps-cache"); + Directory.CreateDirectory(target); + + // 找到插件目录下 bin 目录中的 .dll,拷贝 + Directory.EnumerateDirectories(apps.PhysicalPath) + .Select(path => Path.Combine(path, "bin")) + .Where(Directory.Exists) + .SelectMany(bin => Directory.EnumerateFiles(bin, "*.dll")) + .ForEach(dll => File.Copy(dll, Path.Combine(target, Path.GetFileName(dll)), true)); + + return target; + } + + void LoadFromShadowCopies(string targetPath) + { + foreach (string dll in Directory.GetFiles(targetPath, "*.dll")) + { + try + { + //解决插件还引用其他主程序没有引用的第三方dll问题System.IO.FileNotFoundException + AssemblyLoadContext.Default.LoadFromAssemblyPath(dll); + } + catch (Exception ex) + { + //非.net程序集类型的dll关联load时会报错,这里忽略就可以 + Log4NetHelper.Error(ex.Message); + } + } + + // 从 Shadow Copy 目录加载 Assembly 并注册到 Mvc 中 + System.Collections.Generic.IEnumerable groups = Directory.EnumerateFiles(targetPath, "Znyc.Cloudcar.Admin.*App.Api.dll") + .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath); + + // 直接加载到为 ApplicationPart + groups.ForEach(mvcBuilder.AddApplicationPart); + } + } + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/Znyc.Cloudcar.Admin.WebApi.csproj b/Znyc.Cloudcar.Admin.WebApi/Znyc.Cloudcar.Admin.WebApi.csproj new file mode 100644 index 0000000..b04ac4a --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/Znyc.Cloudcar.Admin.WebApi.csproj @@ -0,0 +1,71 @@ + + + + net6.0 + 4d454771-6ff7-43f2-a2b6-7c3bada83304 + Linux + + + + + bin\Release\Znyc.WebApi.xml + bin\Release\ + + + + bin\Debug\Znyc.WebApi.xml + bin\Debug\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/appsettings.Development.json b/Znyc.Cloudcar.Admin.WebApi/appsettings.Development.json new file mode 100644 index 0000000..9f0c387 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/appsettings.Development.json @@ -0,0 +1,128 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + }, + "AllowedHosts": "*", + "Jwt": { + "Secret": "Y2F0Y2yhciUyMHdvbmclMFWfsaZlJTIwLm5ldA==", //密钥,目前暂时没有用 + "Issuer": "ZnycTeach", //颁发者 + "Audience": "api", + "Expiration": 120, //过期时长,分钟, + "refreshJwtTime": 240 //有效刷新时间,分钟 + }, + "DbConnections": { + "DefaultDb": { + "MasterDB": { //必须配置 + //mysql数据库 + //外网 + "ConnectionString": "Server=81.71.148.57; Port=43306; Database=znyc_cloudcar; Uid=znyc; Pwd=bIQISVSO; Charset=utf8mb4;Allow User Variables=True;sslMode=None", + //"ConnectionString": "Server=49.234.103.173; Port=43306; Database=znyc_cloudcar; Uid=Znyc; Pwd=987654321; Charset=utf8mb4", //主库, + //mysql生产数据库 + // "ConnectionString": "server=81.71.15.59;database=znyc_cloudcar;user=Znyc;CharSet=utf8mb4;password=#%sN3E32pa2hX*wr;port=43306;Allow User Variables=True;sslMode=None", //主库, + "DatabaseType": "MySql" //数据库类型 + } + }, + "DispatchingDb": { + "MasterDB": { + //mysql数据库 + //"ConnectionString": "server=106.53.119.29;database=Znyc_dispatching;user=Znyc;CharSet=utf8;password=987654321;port=43306;Allow User Variables=True;sslMode=None;", //主库 + //mysql生产数据库 + //"ConnectionString": "server=81.71.15.59;database=Znyc_dispatching;user=Znyc;CharSet=utf8;password=#%sN3E32pa2hX*wr;port=43306;Allow User Variables=True;sslMode=None;", //主库 + "DatabaseType": "MySql" //MySql数据库类型 + } + } + }, + "AppSetting": { + "SoftName": "Znyc Framework", + "CertificatedCompany": "Znyc", + "ConStringEncrypt": "false", + "DefaultDataBase": "DefaultDb", + "IsDBReadWriteSeparate": false, //开启数据库读写分离 + "QueryDBStrategy": "Random", //定义多个从数据库的访问策略 + "LoginProvider": "Cookie", + "AppId": "system", + "AppSecret": "87135AB0160F706D8B47F06BDABA6FC6", + "AllowOrigins": "http://localhost,http://localhost:8080,http://localhost:9529,http://localhost:44304;http://localhost:9528;https://admin.znyunchecloudcar.cn", + "SessionTimeOut": "30", //session过期时长,分钟 + "IsMultiTenant": false //开启多租户模式 + }, + "CacheProvider": { + "UseRedis": true, + //Redis外网数据库 + "Redis_ConnectionString": "81.71.148.57:46379,password=dfeFEgeGH/,defaultdatabase=1", + //Redis数据库 + //"Redis_ConnectionString": "49.234.103.173:46379,password=123456789,defaultdatabase=0", + //Redis生产数据库 + // "Redis_ConnectionString": "81.71.15.59:46379,password=6zQ7j^gz,defaultdatabase=0", + "Redis_InstanceName": "", + "Cache_Memcached_Configuration": "" + }, + "SwaggerDoc": { + "ContactName": "Znyc", + "Description": "api接口采用token+签名验证,在使用swagger测试接口时须先获取Token;", + "Title": "Znyc Admin API 文档" + }, + "SenparcSetting": { + "IsDebug": true, + "DefaultCacheNamespace": "DefaultCache", + "SenparcUnionAgentKey": "#{SenparcUnionAgentKey}#" + }, + //微信小程序 + "SenparcWeixinSetting": { + "IsDebug": true, + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "bf868056d4e58f4b2831ff74308120ac", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM", + + //公众号 + "Token": "rzC0pRTuBznwd3", //说明:字符串内两侧#和{}符号为 Azure DevOps 默认的占位符格式,如果您有明文信息,请删除同占位符,修改整体字符串,不保留#和{},如:{"Token": "MyFullToken"} + "EncodingAESKey": "VtEIJLTcbrkGT18EkevZzKIBYgqpURtxyH6w2iWR5eD", + "WeixinAppId": "wx07c574aca93ae8d9", + "WeixinAppSecret": "466411f6865d130f50cc48ae1566de99" + }, + //微信公众号 + "WxOpen": { + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "bf868056d4e58f4b2831ff74308120ac", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM" + }, + "MongoConnection": { + "ConnectionString": "mongodb://81.71.15.59:21111", + "Database": "ZnycGPS", + "IsSSL": true + }, + "CosOptions": { + "secretId": "AKIDGMBk7D3cuvf8KFtGMBj00iALFsEJ7dsq", + "secretKey": "i9IBn8Bzav0pMcbJkunPjmY3HsCF2Zom", + "bucket": "znyc-images-1304677865", + "region": "ap-guangzhou", + "allowPrefix": "*", + "durationSeconds": 1800, + "allowActions": [ + "name/cos:PutObject", + "name/cos:PostObject", + "name/cos:InitiateMultipartUpload", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:UploadPart", + "name/cos:CompleteMultipartUpload" + ] + }, + "Hangfire": { + "Login": "znyc", + "Password": "znyc2021" + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/appsettings.Production.json b/Znyc.Cloudcar.Admin.WebApi/appsettings.Production.json new file mode 100644 index 0000000..e8d928c --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/appsettings.Production.json @@ -0,0 +1,119 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + }, + "AllowedHosts": "*", + "Jwt": { + "Secret": "Y2F0Y2yhciUyMHdvbmclMFWfsaZlJTIwLm5ldA==", //密钥,目前暂时没有用 + "Issuer": "ZnycTeach", //颁发者 + "Audience": "api", + "Expiration": 120, //过期时长,分钟, + "refreshJwtTime": 240 //有效刷新时间,分钟 + }, + "DbConnections": { + "DefaultDb": { + "MasterDB": { //必须配置 + //mysql数据库 + "ConnectionString": "server=172.16.0.8;database=znyc_cloudcar;user=znyc;CharSet=utf8mb4;password=PWgMtIHz;port=43306;Allow User Variables=True;sslMode=None", //主库, + //mysql生产数据库 + //"ConnectionString": "Server=172.16.0.6;Port=3306;Database=znyc_cloudcar;Uid=Znyc;Charset=utf8mb4;Pwd=UhcAoRR5A3hnt^%U;Allow User Variables=True;sslMode=None", //主库, + "DatabaseType": "MySql" //数据库类型 + } + }, + "DispatchingDb": { + "MasterDB": { + //mysql数据库 + //"ConnectionString": "server=106.53.119.29;database=Znyc_dispatching;user=Znyc;CharSet=utf8;password=987654321;port=43306;Allow User Variables=True;sslMode=None;", //主库 + //mysql生产数据库 + //"ConnectionString": "server=81.71.15.59;database=Znyc_dispatching;user=Znyc;CharSet=utf8;password=#%sN3E32pa2hX*wr;port=43306;Allow User Variables=True;sslMode=None;", //主库 + "DatabaseType": "MySql" //MySql数据库类型 + } + } + }, + "AppSetting": { + "SoftName": "Znyc Framework", + "CertificatedCompany": "Znyc", + "ConStringEncrypt": "false", + "DefaultDataBase": "DefaultDb", + "IsDBReadWriteSeparate": false, //开启数据库读写分离 + "QueryDBStrategy": "Random", //定义多个从数据库的访问策略 + "LoginProvider": "Cookie", + "AppId": "system", + "AppSecret": "87135AB0160F706D8B47F06BDABA6FC6", + "AllowOrigins": "http://localhost,http://localhost:8080,http://localhost:9529,http://localhost:44304;http://localhost:9528", + "SessionTimeOut": "30", //session过期时长,分钟 + "IsMultiTenant": false //开启多租户模式 + }, + "CacheProvider": { + "UseRedis": true, + //Redis数据库 + //"Redis_ConnectionString": "106.53.119.29:46379,password=123456789,defaultdatabase=0", + //Redis生产数据库 + "Redis_ConnectionString": "172.16.0.8:46379", + "Redis_InstanceName": "", + "Cache_Memcached_Configuration": "" + }, + "SwaggerDoc": { + "ContactName": "Znyc", + "Description": "api接口采用token+签名验证,在使用swagger测试接口时须先获取Token;", + "Title": "Znyc Admin API 文档" + }, + "SenparcSetting": { + "IsDebug": true, + "DefaultCacheNamespace": "DefaultCache", + "SenparcUnionAgentKey": "#{SenparcUnionAgentKey}#" + }, + //微信小程序 + "SenparcWeixinSetting": { + "IsDebug": true, + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "bf868056d4e58f4b2831ff74308120ac", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM" + }, + //微信公众号 + "WxOpen": { + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "bf868056d4e58f4b2831ff74308120ac", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM" + }, + "MongoConnection": { + "Database": "ZnycGPS", + "IsSSL": true + }, + "CosOptions": { + "secretId": "AKIDGMBk7D3cuvf8KFtGMBj00iALFsEJ7dsq", + "secretKey": "i9IBn8Bzav0pMcbJkunPjmY3HsCF2Zom", + "bucket": "znyc-images-1304677865", + "region": "ap-guangzhou", + "allowPrefix": "*", + "durationSeconds": 1800, + "allowActions": [ + "name/cos:PutObject", + // 表单上传、小程序上传 + "name/cos:PostObject", + // 分片上传 + "name/cos:InitiateMultipartUpload", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:UploadPart", + "name/cos:CompleteMultipartUpload" + ] + }, + "Hangfire": { + "Login": "znyc", + "Password": "znyc2021" + + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/appsettings.Staging.json b/Znyc.Cloudcar.Admin.WebApi/appsettings.Staging.json new file mode 100644 index 0000000..105e62b --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/appsettings.Staging.json @@ -0,0 +1,117 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + }, + "AllowedHosts": "*", + "Jwt": { + "Secret": "Y2F0Y2yhciUyMHdvbmclMFWfsaZlJTIwLm5ldA==", //密钥,目前暂时没有用 + "Issuer": "ZnycTeach", //颁发者 + "Audience": "api", + "Expiration": 120, //过期时长,分钟, + "refreshJwtTime": 240 //有效刷新时间,分钟 + }, + "DbConnections": { + "DefaultDb": { + "MasterDB": { //必须配置 + //mysql数据库 + "ConnectionString": "Server=10.0.8.16; Port=43306; Database=znyc_cloudcar; Uid=znyc; Pwd=bIQISVSO; Charset=utf8mb4", + //"ConnectionString": "Server=81.71.148.57; Port=43306; Database=znyc_cloudcar; Uid=Znyc; Pwd=bIQISVSO; Charset=utf8mb4", //主库, + //mysql生产数据库 + // "ConnectionString": "server=81.71.15.59;database=znyc_cloudcar;user=Znyc;CharSet=utf8;password=#%sN3E32pa2hX*wr;port=43306;Allow User Variables=True;sslMode=None", //主库, + "DatabaseType": "MySql" //数据库类型 + } + }, + "DispatchingDb": { + "MasterDB": { + //mysql数据库 + //"ConnectionString": "server=106.53.119.29;database=Znyc_dispatching;user=Znyc;CharSet=utf8;password=987654321;port=43306;Allow User Variables=True;sslMode=None;", //主库 + //mysql生产数据库 + //"ConnectionString": "server=81.71.15.59;database=Znyc_dispatching;user=Znyc;CharSet=utf8;password=#%sN3E32pa2hX*wr;port=43306;Allow User Variables=True;sslMode=None;", //主库 + "DatabaseType": "MySql" //MySql数据库类型 + } + } + }, + "AppSetting": { + "SoftName": "Znyc Framework", + "CertificatedCompany": "Znyc", + "ConStringEncrypt": "false", + "DefaultDataBase": "DefaultDb", + "IsDBReadWriteSeparate": false, //开启数据库读写分离 + "QueryDBStrategy": "Random", //定义多个从数据库的访问策略 + "LoginProvider": "Cookie", + "AppId": "system", + "AppSecret": "87135AB0160F706D8B47F06BDABA6FC6", + "AllowOrigins": "http://localhost,http://localhost:8080,http://localhost:9529,http://localhost:44304;http://localhost:9528", + "SessionTimeOut": "30", //session过期时长,分钟 + "IsMultiTenant": false //开启多租户模式 + }, + "CacheProvider": { + "UseRedis": true, + //Redis数据库 + //内网 + "Redis_ConnectionString": "10.0.8.16:46379,password=dfeFEgeGH/,defaultdatabase=0", + //"Redis_ConnectionString": "81.71.148.57:46379,password=dfeFEgeGH/,defaultdatabase=0", + + //Redis生产数据库 + // "Redis_ConnectionString": "81.71.15.59:46379,password=6zQ7j^gz,defaultdatabase=0", + "Redis_InstanceName": "", + "Cache_Memcached_Configuration": "" + }, + "SwaggerDoc": { + "ContactName": "Znyc", + "Description": "api接口采用token+签名验证,在使用swagger测试接口时须先获取Token;", + "Title": "Znyc Admin API 文档" + }, + "SenparcSetting": { + "IsDebug": true, + "DefaultCacheNamespace": "DefaultCache", + "SenparcUnionAgentKey": "#{SenparcUnionAgentKey}#" + }, + //微信小程序 + "SenparcWeixinSetting": { + "IsDebug": true, + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "bf868056d4e58f4b2831ff74308120ac", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM" + }, + //微信公众号 + "WxOpen": { + "WxOpenAppId": "wx71f2b227f8eaf00a", + "WxOpenAppSecret": "bf868056d4e58f4b2831ff74308120ac", + "WxOpenToken": "rzC0pRTuBznwd3", + "WxOpenEncodingAESKey": "Z9ifQKA8kvQjybOXuXl8I0r9cFHWJGwW2q5iE5e37AM" + }, + "MongoConnection": { + "ConnectionString": "mongodb://81.71.15.59:21111", + "Database": "ZnycGPS", + "IsSSL": true + }, + "CosOptions": { + "secretId": "AKIDGMBk7D3cuvf8KFtGMBj00iALFsEJ7dsq", + "secretKey": "i9IBn8Bzav0pMcbJkunPjmY3HsCF2Zom", + "bucket": "znyc-images-1304677865", + "region": "ap-guangzhou", + "allowPrefix": "*", + "durationSeconds": 1800, + "allowActions": [ + "name/cos:PutObject", + "name/cos:PostObject", + "name/cos:InitiateMultipartUpload", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:UploadPart", + "name/cos:CompleteMultipartUpload" + ] + } +} \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/index.html b/Znyc.Cloudcar.Admin.WebApi/index.html new file mode 100644 index 0000000..120c575 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/index.html @@ -0,0 +1,87 @@ + + + + + + + + %(DocumentTitle) + + + + + %(HeadContent) + + + +
+ + + + + + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/log4net.Production.config b/Znyc.Cloudcar.Admin.WebApi/log4net.Production.config new file mode 100644 index 0000000..95a0298 --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/log4net.Production.config @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/log4net.config b/Znyc.Cloudcar.Admin.WebApi/log4net.config new file mode 100644 index 0000000..9d6165e --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/log4net.config @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Znyc.Cloudcar.Admin.WebApi/logo.png b/Znyc.Cloudcar.Admin.WebApi/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..210599c1552b92a24dcdd104b7a82e11bda9da0e GIT binary patch literal 9168 zcmb7qcT`hP@b9InAgEtK>4;K9goso@iYQ8?O7BSTO{5cw2r3FlkX{9(NDsXvM3LTu z(n1JQ4J{}kln{8Ach39$_0DM20pJ<{ee}RED0>sf{L$0IYV|K(AW_(x>n$Cq&i%3ryNPMMy6#sDhe`*|of8a9$fs&BNR2kCs4v-6omf4Gh}Mg4S)nMj~& zT8q4C2Nh|es-1rER0SqIOlHRN#>mVxAYD&GW9dhYEE2(v<^3eT|DR7tujfn7ja0k; zBcnCK-HUohIeRKX2RR-hwa%7~xKS8R1!kUm?0(-d-dYjx2}qnY#=1+XN9?x1bKw+D zt17TVqDz34`Ip9>92<66tzCD6kvT5PtYUM`+K5HGb9xRp$5f*)&P-Uw1- ziYPY{VWYNCU2)%&Q^EgahiJ0<3XpmjUFce>q1y=?Rs$P`e2lp&2vfy0z>mvbFR~1v zI9EUU+&=C9E~ERpaAMNSl$@;~WRbJsl*r~Yc&ZS!uxL*s#Nh{wzj6BEX+LopZJOC& zcvUiq6Ke8vmV3xy#rhV3--Gc^tXR)Rw9M(YQ)SkA2<$zFcHAPIJPm=`jjQq7)kPAS z25BXxT=NU{V*Ud=xkMFLM@bnl;l&8A=)3O@4+!oGQnOddg%haVu`?13xViR9JFd=b z++?w=!g?jD$|cQfuP&p{IIa@IUrv=lM9_O_#5&x1Qv~WtKwd6c$}~pFp}{R zc9~_`ePT1CKt}TmO99qm;_<2}?P_pzk@_2P)+a2=ZOB5nG1D=*RaW6mAuqR)d3{WN z+&cNNBSeck$8qZl@H|uIZx=pHfl?AM<1pUcu^@^2yUP$>GQ1nUX&kVfYWA$D=_A@d zfcqgbqti4)&k(X?X0sel0~A}0-}Nbuz`pUM+Y%0`&UtF~vyRyTZ)lsMeSVFcdh6`m zp_g7$AWBw2v0;{OkMP-Fm+~^>)zvDj1?P*wAshkbI`e`D>l8DR>kTw@89oJ6xur!T zr5<3Pcp7X9w?4yg^YmB=QYM@;6Y$fc?&J5(wpV0_#0EFKE~Ygkmqxp*)~iIWlUJB@ zI;7V#5++|J2&}xJ=M#0%w!dcy)#GbS__VLp$%FjWliK(O{#xvgC5NPYPZx%E~WJil}%jPKd&3A+r<{j6hX~wRPzhUvq zU`f`Tey3MRVW;24X(Kxmn>jW3A$8^t-4-uzBMgLTR|? z0jsQu5lX;*j1sdjo;!*~&ks4IN-)prHmv`iEoorM>R9X))>h* zEK@Fd+tlxz?9ktY^9Kj1i}K_RqWHuK(Yi+VwyF%4jRoGr5NbBj7Qf`6UfQCa4T6L=?!k-CnIogBgzd4IB?#e3jB_19;f*Xn3G`Gl5NJ4zBqEv&&KH!QRg z5f4Zsnju+3thf|(^Vbw@-gW_uWTMv1SleR#@Voi9mMd5mSf_W5eVcXjvVV3AIePfD zb*X$GafbEoSzMs^B4uel=#_qcy3y8)*w7gS*-7bkj-E=m^-7DU2D$RQ^V3$0@tE}Z zgA)_GMKRsfOK*RzZ_fYhYnL|=b@mL6>bw*UPahXqe%5O*P|BY@z^44OPcG6T@h}QJ zn^=&RO(}JB0 zXCgPcMOV9sbX>nqzCyPpH7y6IihcQ~=EaoSE)eDWy4e~Nu{S%{^v}Uap;732vd87M zYGLKMi*k=FBV=6HmcHRf5IO=hQ%C4b`4g>d3JE&>>Q>>?mA%lJ^~lrK@6OoG2F~%jzo((uT@E8jBxiW8`}-WNw2J?%EB@^! zm*}iyL=MnfPlq&L+_}UBqgcL~`f^h4F7#0bt6U4&=b6mruB~bzD$RAwVXDm(+^^99 z@t@Ry$#;guNQq)2w610=ZfC!&5|*_TDhQj^IXDWNdFcN<)2@fGD{L_~TKz3xV*60z z^;#Np8x7&H2tKrGpDfBTH`>NwfU66-s3f-?C_}m1CK`>3-EX)7K-w5*aFbtv@Ps?$ zFG`dk0t+pg-oW}TTqxHcK_C~b=X%GSzhU3K4ZZJG4()!C!E56Z&`a<8B3s9dd{{j# z@NK%rHA^5vE6sCfG99S0qzBK`ps$LNp}x^l@=pCYn=>AHAT*ThlDmypq@PTnjD)ff8==TVgCKffG{9f? z^U(zsYxOUeD(Xi^G9=UDCS^E;5IqsT7*FMy)(yZ*^F+n<3YOI3gt({}W zL}5iJw@|rO3y*8%Ttk4u@{+4dahyF;ZJ?dMVR`w?5NqEO%fN1GOLKatRKz-vnLCuAv_g=t@UKiwGiReE7#x zVe3-Vqi~$;fmhY-hj-S#M3{CvHt5NU#onz8b6vZt@Ht;2WL8C^7x5Wo5EOWJ9sqiO zvZFIZ19jb|l$tx8GPd?`Q9~#hMKtG#LqqOu0>prCiGC+R>Gy&z;YC&}hr-as&P&qW zR~yOkt2{uYl|O^eo6Cd;s|zZctwKKhCdP_O=9U5kyj;-HZk22QE4ik!_tTk;IH8R1j?@R?u>hZ56f; zw0o6Gz3 z#LSvsj~Todnd!6P1Icp86*FD@A&5VWk4@Rfwq~M`-QW23JEcq zGqr)e@Pkv|KKlmY9Nf!oerkPdy^E_oV4GzwlSA;eLrU7y>=)dj9qWVl0l@Hcg4PrR zOG}+_5asD>YW?SbOLw%-{WM6%u=O|Y=9I&|x6vVY!0lL-aDLXF%crk8jU@6}aoReo z#T2u%c)rXx)BHoB7mBm_02e?TYFBYm@F|=Vu^@zsQ0d(UfYBF53_gi)(q*{yRHUd~ zUITK_&ILQu^x%S~^UW{jy$m|AEdyLD^5cdD>L93fy<=WcJJ8)uFPA;UHzzl^f?-{R z21w^}JmZt5aTp9$@px}uG~E8K!xXdmd2!Y{>)`l`GyX#cefNB^Y3=Lwm`ji)<#k)T z@aAW`XM}`5vUoN~QW4j1frk!Bt9|zaCl$5=%a^|29AMXCu_iTF4cHf-qa0BM>{)=) zM`kqH=VrsTG2`3;+|{Y1F%62_`iz`I*sE{p<2ufP(J}F?kQCQ*qS=!7BBeGNT9Mj4 zfCCga_ri7LDSIW)(O0NfLf?IO5uGg%J2Pro9s$?=TWoSkU^|Nj?PrP z6Q^Hrs+_gCW$!Fn>XN~CvLMt&cRNo_WPHq$7tEaAa-uV?MrH{i^P|#+=(*E0Tg5QP zGwtL`VuEz+Z@~ayIrG_jUY|?oFM?SG>sgNe=la8#axS82fYFPR#d^w*FccxGMzr@~ zmLS#W2Nj74&k-fCQR>2do>v{1ktySXN>kwxsnogzWN~*He7FXmr(9FD!NVP<(i;w; zIG13F{1SwXx2ubbsLVv-jR5rGA%d^%#p-vjD5j$8MSB*1fnkTWR-{qS;?SmX&&zwD zk(R2v0DGoT{>Br}uiQdNft9I|Hd3zmq-Wz~!NigLP}Mg@H@fc%KmL3+X=s&tu04#d zbT5=@S#wN{QFzw(*3w}yv*`hG!|RHeQ|HFN_i0O&q4Xc#lQQUlYcK(tS#|hvNs%9S zSRS#~K!m9M{I+C9S$=g2DHuvDbv@Z?Wa)En!56@*C zMCFS^$kekL1%LPqGv@2C7QSJ{R|Bi#MPJhb0DPGnZRMh(9^umIUD>CP10$~f7xA9I zx7)cAs9(4eI14@i{fw5iOGmqHl(;C- zb!!Do$oqdA{P-cgd^|3Cc1~Gyuu{riO;JF zuFTPCpZ}ONQ=8H1W80;vR_v=E{~r)3x&-EU4Mq{S31ciBY=KV?%VJYo19xk=nBu~; zF_rB6Qif(xI%CxC;r&lYe7kFDP>Wlg?y7sC-^~R>HT;4QlX-ILuDqYp8L7?GYpg)z z>lU5Q(nBqf+*jO(T+lq|a~`8R->_-go+(U;2Ti*XS1LIPoTU#dXurwujNxf-FWswW{&H zr`eNztk<&UYqJvl9`EoiEN-MTe}56nf00jOGnxiaEoWz$A2b};(@-e;eRZIH5NW9Y zGtuhuUJX1t+V|XwS)Wm_wetMh-J2Tp5>K^^#K-xJT-F zH%xGUAH;-O3*6_e1qtsAd=6|}HP@T^#&0Q4s-%%RxC3A?+U$kA3SF;DdI6E_2u5ZU zg0dCrZBMq}=|f4(3`zrlhE@_#Wgi+RgA<1zyEF5n`OEi%_GZZEh09+)?dl;fXVUnI zvq}<#=63h1AbWK}yBP!6`bno*ldKR-3>)3Md&|E>IL^D?2hHZGp##&hfsm3dlh^k= zkvp+pl^$W3#gtd1Hq$($h=ET-+KLp{kZkrXjCvLcG_!xoQl}5)CU*nZ>0m=~=B3wy z%yXMpM8wJ>3YL7ExdZssCLl5F5VOSA$0KYLf5^s4-S)K2_B2oC>c=O_=Xdr>H~u~w zr3duluG7pW>h^u{Hn%}=SPKvaxe`w_px!kGCN|;(I++AV`HsO)?tq+xDk-?nrit^v zv|0!w>Vs}umw>vs0?jIqe!JibsqY)CRoUIIjiyQWTHDw?W5UjgiL~RtGvLAmUBCk* zx!8p|XmXk3VG3%9QCn2r1Vizp+xNTNrlZX8Xo6Ra6wh35N!J_Bpgx&)bl?(SRzAK& zNJWib2z+{O9`Wj?GN(ZCGg{zdI`q^7@JR~E4K=J+`hXluCEa0oeQfN6e{gb7W;;KSC#`|z(oA^E-Zz-b| z(vi|6EH=PHVS94V{JRT?j+KB5Vla4VJ7hRoUYyT)Ajr&e@Z-nL`tgEE72i!_@)^tZTQsI3p?#zE&N z-Qp3eM(UC006;jM4XyN&2{Nxv7Go%`I9|TgV_U4CB%9M?0|nVAmqO*x~+7P7A#qt!1#oV$>qEn8({7VE; zu|WYqFa6U=A4oH2?{xjAjlCg$#h`hqfd#3I_o^#!QgEy;us_r~hvkn<_pqFFZI0%Y z+gthFX>qlvkyXO`PP$)Z_H=zD#3A!{#ipb2k1({fcCd8&mSU!lFBk`!7kYl#HL#nA zfC(=If$7vdqfMfwr|du27yiELLCWx3LZk&NRKip(N?lHnn(8bOA9MdF!)N{Njsuo}dA!(j?P1D{ipK{a{z5G`fUV$l$VsV5P5$ z*OfEi&(@PIX`AnjGTG#UA`(B z%LD4n;LGv&VcRy@o#q~Yx9gLX(MNtlO$A`Qds!<}E!dr|oU3@)F!v}TseAu66q18j zw>KAPe~e)l+Qd5_E;R%FGRa(ihfduU&VFLWciY-neZq{ZBP`Qy&wO)FG7`U!XbZT- zY-#ms^61#I$Dmb$G7F!S1tur6jnst!rX`GIEpZRiHI3%=G2uI-`&hO7Ccb2)y+8rs3< z>Re3Ng$VlSIEIXoa=AeMyt6(KC^ad=HC}p{cYR~fLA%=h!G#WI>Go>gQ*m4oFkDgF znl-?8+lf5HwjZP)zpBq(*G(jd%j<$2@@t?p*{NrFtE?JnCZe1q1(o@VM@*uND^Jpg#uC%3$aqXEE_;X42{s!ux7{*qQ@g z+x0vh$kT|{1e}jhMY=DD-3ol^Fe#QcJRb8kIrzT&sbpj_FXXW&Sh<%qzk5mv_klJ^Xj4|EWJ ze3YXp;{T4$_uE9p<2OF$v7quLO0irU!JN ztW1NblzFd0W5h?&b?DyC+1HMEFiDp{m}xsGUnA7LvwrXHcM=h{q);8Q9Nq7}X`YYp z+^m9Or4*MkQ$APisLvdJn^{BOT-|7W0OsqW^%wiz2qIruR0ke9ooaI0_}OOw0$fR` zRFAf}+vQU7F>WRE3gRZwkhJij!8#e`1Jzq9yMF20`65{X#-5KWhIcBR@zKTiIL;ws zH5>14yKSvH{04w{_Cokl+jT>0kGoRwBypO>2&B06tHJUc(hne-$M@unu25+!{xaH_ zKa3OP8K{&|aGO+%zw91j#miZ%FcO&FN?Y!FtKxSAOWkd3w$(smCgsj+fE5@uMX783 zvlb&*i03c{#TP*+9?eKuzgkc3$iXv0)ByP8bur7k`v{wQpFYgnYXwJXp_eTKLI>!C zema&&JO?^;sf~_)NHF6Zb>WPgE zCwu;KS|XvP`~P|ZS3GD^QAhacyUOh}!1DrA&;~9gMASlDb5bo26$PoWBe7u3uw*(G zC(^}ld?O>3CN0f6_%3s?@NS6tuu&ejEN`{THH5OmVd@4x`PQrEUpT~JDCe7&$o`K5 zbWx^BwfuEGn`cm(jXxsBWTFdczl=eKcXJ_eWw*A?`l&bz{ba5uw`Pyfh$s0%PpS~Q%XL?)7a&cYb>5BsWrrnKmk5AWc-k*d)f9K|ge^+cHs?>cxEe>8I1zYEEts&0Kg%K4$Tu z$}s?us*-W(=XV0(xq<|wL0B|cEEcQc_N*St79t$}R}D)}UtMg0qcXSCA0oU79M+sK z$_oC9uhNoI;xeI={-{y|^5=ntw-qMG&gyX)Jp35!$17k#Wabm+qge^U7q~>j_^pz@ zN!TO`3Z^f_Y{dHS{`T|K*D&QR?SN0V?s)xA{Gl?x?CZ+jA5=K9_f)NhJ!?89^>wx} zIFloIUsOHLaGYYC#0;%WV89Tl>~68%3d|I<=n>Oz^YP^j+w1~ZZdz#_1FH)cG(&vv zJ#?d&N+axT_|5;4tF}AX!1}KG8!q=cSI238<_2evKz^8Ek*ommy7#Ad0lJUS1GQNm z;$zPry!|J|;h#&~r$VM+BQqz%#JSEFrZ}Q^Y4!EC0&Jq7<4R&qr69 zs=&x?q<5;^Zu@7QqOg>+o`TRLRvIeis>gY2x_Wi;5Bcl!vtSmkg0t6F2;eDz=pzjtiM zkwxZMC*xzDMWIV&*$@x5^81Rd6$<4-vJeDT+ z(vxha#a(Ct)vm8h^M|OLgcNwVI!05F>Oog>`8ahovoaw^N8tv6G@F-moiI2%GDw>6 zi`{TGm7UKP7`GkadJ&=RIBMXhA{9l7_ES;x*I*w@-c+{g-j{)Pc+>4=y*aX8Gghi& zkA@@`TAx3&mviB|Wnxvm{@szmH2?V_!B%wc}8$2;ua|{_2)VFxEvVsMDkWWXY<--xNae+HjRnns9+cGDjcX~^7-LKH2YpwicA(GNJR>qosX03lCN_6t_tb_v>>$2c2$T6JYXC684GwJcoku% zHGRNM9gv$gYCKJcKu#Rs)y|7;21_C!=LsM;hwVk3%4;yt%(~bJQBHMV6QcJiL>gf> z%UHo&0Z^q}M6(2D6_p$CaDZea`FbSxmYg6=sVnMK(ghs()J%EHSWfS{0B7e}?@l)< z>U00^MO;L0?u|I$PZ>qv*eVF`(VmU;mIs;={>O6~cp{{e-s-g7 zJ}oJ2IRS*{%-_w1?R*$<$V9_7>fB&0IS{nci6Mu4CUj%hbm->Z@d0PnP;cFObB{rg z`LGCxE-fy=k~Vs6nK*KZ-4wDAv%wlb{bm9M%xn~}icr5}0~&11M!{PLQ16wkV?8EW z;p2k{TXP;PiGPsy@g-cxD+pheQw^m@fUyHH3QGd%k1p=Xd8TJJ_h?}D zu^N!Kl7TuZm|r{8^x-xofUj;BMD1+fh@CP93ITG9qp9EVk>V#+P0@wrv!<4B;0 zO$m-C&vqGBuIth;LyLNM88PQB=ae*;0K9QXa^5&(`|jBeg1j;z;+MwzIF$*+F(wh; zn7p?^ljJ&;YoJ@lJ?*U^e$JooE(7E$BcHeHG9+)E>*#llnVX>aCx{KnW89i#in>0D zsHX2J!R^!`R0}M>NtD~Iqnubjv#4)XGUBfCv^>-Yfc$c1hB}@@S0~?74U>rFnnKi* z>4?-nw*u7w%V!d1W4)?VO}2W<8DrT0REv^8EoIbYe$hB&C}LUIcZ6e2BKF-BV*94Y z>7gGAxG@2nBeO8tX$1ELTyN_}mRBc~w^wrWTq<@|tBPk%Q^a6}A|?^5;`#jg2{rv7 zr4~M&$yxtlj$A!5`{$i3oxHkp5?(YM0k1iewUqxCbA)jHF#P)g^g`@_!e9b$Fm@6P TSev`>kIefse8j-lTGaglBk)@N literal 0 HcmV?d00001 diff --git a/Znyc.Cloudcar.Admin.WebApi/xmlconfig/sys.config b/Znyc.Cloudcar.Admin.WebApi/xmlconfig/sys.config new file mode 100644 index 0000000..14a6f3d --- /dev/null +++ b/Znyc.Cloudcar.Admin.WebApi/xmlconfig/sys.config @@ -0,0 +1,23 @@ + + + 众能云车后台管理平台 + + vue.znyunche.com + https://Znyc-public-1304677865.cos.ap-guangzhou.myqcloud.com/znyclog.png + 众能云车后台管理平台 +
+ + + + + 0 + + + localhost + E:\Znyc\项目\人才招聘\Code\Cloudcaradmin.api\Znyc.Admin.WebApi\wwwroot + upload + 1 + gif,jpg,jpeg,png,bmp,rar,zip,doc,xls,txt,cer + 100 + 100 + \ No newline at end of file diff --git a/Znyc.Cloudcar.AdminNetCore.sln b/Znyc.Cloudcar.AdminNetCore.sln new file mode 100644 index 0000000..cc8b8d9 --- /dev/null +++ b/Znyc.Cloudcar.AdminNetCore.sln @@ -0,0 +1,67 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31815.197 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Znyc.Cloudcar.Admin.WeChat.Core", "Znyc.Cloudcar.Admin.WeChat.Core\Znyc.Cloudcar.Admin.WeChat.Core.csproj", "{CCF54E71-A953-4874-87C5-75478242C00D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Znyc.Cloudcar.Admin.WebApi", "Znyc.Cloudcar.Admin.WebApi\Znyc.Cloudcar.Admin.WebApi.csproj", "{64C6211F-C371-471F-A3B6-9F6258621AE4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docker", "docker", "{C9C1E969-626D-44F1-9363-2ABE2626DA3A}" + ProjectSection(SolutionItems) = preProject + .dockerignore = .dockerignore + Znyc.Cloudcar.Admin.WebApi\Dockerfile = Znyc.Cloudcar.Admin.WebApi\Dockerfile + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Znyc.Cloudcar.Admin.MongoDb.Core", "Znyc.Cloudcar.Admin.MongoDb\Znyc.Cloudcar.Admin.MongoDb.Core.csproj", "{40F0F101-CA80-4A5D-8E98-1047585C3A43}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Znyc.Cloudcar.Admin.Security.Core", "Znyc.Cloudcar.Admin.Security.Core\Znyc.Cloudcar.Admin.Security.Core.csproj", "{C2832070-4602-42BB-BE01-7420EF1B36B1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Znyc.Cloudcar.Admin.Commons", "Znyc.Cloudcar.Admin.Commons\Znyc.Cloudcar.Admin.Commons.csproj", "{596525C2-AA03-41E2-A285-68F90B22F9BD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Znyc.Cloudcar.Admin.AspNetCore", "Znyc.Cloudcar.Admin.AspNetCore\Znyc.Cloudcar.Admin.AspNetCore.csproj", "{79ED144C-4FC0-4BB1-8F5A-C71A49BAB353}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Znyc.Cloudcar.Admin.Hangfire", "Znyc.Cloudcar.Admin.Hangfire\Znyc.Cloudcar.Admin.Hangfire.csproj", "{2DBCC3AA-BF2C-417C-B13E-B38B29312770}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CCF54E71-A953-4874-87C5-75478242C00D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CCF54E71-A953-4874-87C5-75478242C00D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCF54E71-A953-4874-87C5-75478242C00D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CCF54E71-A953-4874-87C5-75478242C00D}.Release|Any CPU.Build.0 = Release|Any CPU + {64C6211F-C371-471F-A3B6-9F6258621AE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64C6211F-C371-471F-A3B6-9F6258621AE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64C6211F-C371-471F-A3B6-9F6258621AE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64C6211F-C371-471F-A3B6-9F6258621AE4}.Release|Any CPU.Build.0 = Release|Any CPU + {40F0F101-CA80-4A5D-8E98-1047585C3A43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40F0F101-CA80-4A5D-8E98-1047585C3A43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40F0F101-CA80-4A5D-8E98-1047585C3A43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40F0F101-CA80-4A5D-8E98-1047585C3A43}.Release|Any CPU.Build.0 = Release|Any CPU + {C2832070-4602-42BB-BE01-7420EF1B36B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2832070-4602-42BB-BE01-7420EF1B36B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2832070-4602-42BB-BE01-7420EF1B36B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2832070-4602-42BB-BE01-7420EF1B36B1}.Release|Any CPU.Build.0 = Release|Any CPU + {596525C2-AA03-41E2-A285-68F90B22F9BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {596525C2-AA03-41E2-A285-68F90B22F9BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {596525C2-AA03-41E2-A285-68F90B22F9BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {596525C2-AA03-41E2-A285-68F90B22F9BD}.Release|Any CPU.Build.0 = Release|Any CPU + {79ED144C-4FC0-4BB1-8F5A-C71A49BAB353}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79ED144C-4FC0-4BB1-8F5A-C71A49BAB353}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79ED144C-4FC0-4BB1-8F5A-C71A49BAB353}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79ED144C-4FC0-4BB1-8F5A-C71A49BAB353}.Release|Any CPU.Build.0 = Release|Any CPU + {2DBCC3AA-BF2C-417C-B13E-B38B29312770}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DBCC3AA-BF2C-417C-B13E-B38B29312770}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DBCC3AA-BF2C-417C-B13E-B38B29312770}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DBCC3AA-BF2C-417C-B13E-B38B29312770}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {34EF7E78-935D-4750-8AAF-26B4C5ED9807} + EndGlobalSection +EndGlobal diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..3ff2eba --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,11 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base +WORKDIR /app +EXPOSE 44304 +EXPOSE 443 + +FROM base AS final +WORKDIR . . +COPY . . +ENTRYPOINT ["dotnet", "ZNYC.Recruitment.Admin.WebApi.dll"] \ No newline at end of file diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..242384bf607e4236d16f171c3432be54055ce156 GIT binary patch literal 41421 zcmbTcbx>THjU003UjLQG6i(cI3-&e7cNCyBI}7|BluJ5vj569B+%IZMS=GZBO> zxB)UjQ5RjjtWCA{2au6h!VaQp<)bD541-Y7h5LfT;MFm)&@!dedIRR*rLw}db7`8* zL?Xg|M5^gtx z0z{lLV31LD5EC$n3#d`4H--l!0RYzSUZP}xawNd%t+e1Lz+zeADh^;V|4SJxAQ}RY zMk7f9DclAyQ1e%&hwSbFrkF+z7&LHKDkvPwewb$kN2#AwE$2pa(W(nRS;0VLdz z05KwrF({JnP`S+0U7Kb4KZBd4AOPJX$z!Rq(`=Z{$&>i5*O!~yq}x5#wW5YNUr|lr zcF8hRGsrQd4xqk|BLV>Uk5hl&xP{^l_IJ1TO%JRuZu|1ztS;@y1WB(p-rA!ep#iA! z6Bo<+dwcUxKL;RcoV%>bv;oWN0P~GUUA7gt+#m3h9*>dk+%LjJ*?EeC{DfcN5fIKO zjq*B}cOnJf*|zL9BYp0{zrL+_TmtOVh0}g_7X-fA8``>5DaRa)K#Q{2f)2>v27-NG zW4=ypv)Ag-V?|tPhBqsc$ql%-D93*z9ZKFtKk{Y0B2IaQOLRp7RE8*Y%Qt@hGh*HC za}EI+iL5#80uc7OVTi&%H2*6ls;SK=Meu%46nuPPc9~J=k zmg`SjBk~#XFJ@&oa^_#c_HGq5srC;pd{I zZ=p8)W#L9T*hJUyKlzCRV}P68gWDbg2Q4xPi(yF08-`{Svq&}$i<1@uO=c*?p5RwV zaukNCMAkRxPzYHjY8kI9MSjiTfXNfBBm5M%GDyN2@ervx<%=`7q*N{k=T zpX)f~#Ezotmy&Nah2KCV;MbU6G9`QH>;&+RhynUdu^^j9Eg9-Wg^C-5YvNN4U<3Cw zIn-l0fP|V{E?5NJ*@hRe6p)dA7^kp$L8v{}0daAXn%_0WN-0mt8_-)}HQ)k+SbC_* z5=#{tC_T_0d)<>5&w<5;B;q^+b@q!G#3>{^5B=M1!sP7>+x`xhPoZ3xgf7EjBD4ox zl*1~TmRqhgR+c>rTOP)n^F!Ju*F}*@CA18K-8r3dECX9?q>!OtZZh4%%mQT2bmY_u zw-!hwo;sO2ZFTth=-?>u))f&c1SxPp%7_Nf3eOX-1h)x~DeZglrR4dd_D)iL7izU?R6?e+uX0a>g z$_Ulk$~ddWm0gu%6(^MR3p({*1D=3Lbs@nLxgk;os=%gxyl7JFepZt!P0@J=b*K}1 zt6y?P+I5eo-(5aE6Sy#WepeB5EH|w*jW^BOw;zK*?yudv*RscQ=d#h6!x{G3$?}Es&n)3A`m8%%8(xqzTq|d*QfqMQiu1&=;0*A@ z{Rr-E_zwAKZA$Xa=COm!Y=w!`6uBWPM__r<7^ecfc$ir>)4f_0^^x3F)w^XpiWRk~^GRKtwZ z=;$E*YUN_(&}j_MT&7jFVdql&%1d-`k$7gGOeAOIK+1B8*T|<7xfD?4FLgn6clA5< zg-YppofG;Kn|TduMFNcs#0=hyk;c;B8NYj7GHf<5w=rYCPJg{qv0Y|4eL00cO+SS> zzn5%g*G2{UyeppN7&8clbpHulh}>R+ zG`H@^tAMzJBSqOGpVxYnQaDFdbKw@Mm!C81qDo=#*d%``voC$ zJaR%ii#y3S1Ukum=6%w9KEGr?^F58c#y)gyxnE;n$$v6{_zSTI(czEpUk_ykMGTz= zUG$mbQ}m}c7$!tPEKx)_BrRfxM7wUBYl250+o~CT`V`hMY!=oJf+yxts_#VeXfYuZ zup6j8cEyk1k476|!!{+Y!bM%**k&g=PP%$p3OR9u42og zTKHBh8y#HCDlM&*t%0W*&3?`0&Hiqo58_v;=uQ|EaA)DWy^Fm9;X96y2iECqnY-z# zDNewuz192{oc*Kmk!)9fEe@?XFYe%9=&5x=dx0dPicGi)dnLAVgc#RB8NmwTo%zxE zO0`YRGW-eqS?bC6+-rQ^Vo&BF3KGu!Y;X$7bnfwZ2`%I|a_Zma*DEKM?3WmLk}{Jr z3zU&8QX1$Mn44&t6in&p5|MV@_ics=5<`bUyX23KH!E1y!QZC}8kDOPk+HusmD0Is z<7&G#OLa*7m}T2AeLH?6M+m_7>WHgRY_6$aY!y8Y1t#4=1aR=coFozqtL zrNv3sul!kATJ=yP(Y(K{A+JB@b?0ugyu2>cG<6y?v&?Yc^5O*Fg82}#bL;CrajtNxpJMyS#a-><*PfQ{`$M3sdI^HdA@7S z)$;~9kPwS+{UYhK{STd+hE<2S_nqzZdB9pMz7aud*S^nMv!ts+Uv{i#k>}@o@rx5n zCp+ua>aMOjI2&coXd)@zpL-d8cFP%O>8^i%{-8zf5!w4oy;1DtxubZPH~w$+-`GZ) zZ_^#@iIh9tG;f!4B}0Ktu0USL#bH!I7NH)YWM|X6&jrg4(0PC(RwFw%i$>t;aW^1w zr^L7l9rXPr%}Q5Ex5G?qB3lT@>HK?>K4|D>{UBENvi;{R8OUgbvPt&0 zK$U=`&(GH_scLPz6BE$LnFfEA)2-YI-_*s7?~`Tsoa4g70;6t@d&fopDM6Dh)!LV4 z%GSFFm-{muSNQYqtGXVsZq+ZH%df|upHPl{8{TS7x@|Te47v>_{%N6HAj5@bza_oT zglV$mDH7BObq*|zq_9}Rvc`+Za>RTXud37B0NS; zbXB>R-8fuSlvVQ%kPi^IkGl(86~Fu*U-7nMK{wBo(>ZM5YLf&gr7Q;kcu)cWet`hM<2(3%1OPZQ0|3Vc008eV0074>LBCG| z07!X~{wAX8wtTAVs)Hd-;A4gX8AL`xQlf;GEGB+=iqyBRG*$09;X*rK?+J2moWby{ zE;Z9QT~onq%ch2nC>^v={q{}uTU6ZR+o0_teH$qp90m8pMN^!0`%OUz7?EL<%&E7_^{o~@kyA%)ASlK_yyn58a?04ZnyEG7UTg(!?=~LSv6?q7xiFU*khEVL|{ZgRQ_62Z|V%D851%QM7-(!gl?q}<& z!1Gb0&Wevwv0f1Z5NA@m6(o@%uc#;pqVY9f`%J;KMEi4i9vC}x--)TkV8mWKA!g?hUp zn|*pc!D7kS^Q~Yl7_qJG^LW*Iz1NCps0nh;L8A=9_;IDG=9OdElv~K6Mp?K zzUpu$p2Q78xP^fjiW0^KW>{V%1Rt_q>rWYscv?|XD$%J4uOJQpfQZLyO<4afEh?IJ z8+&xGBRbeVaese*WGaDZvZ4GgB`2SdCE!rApZ0Hy6hK1E>mqtss#KsZQ#4Hv)OkN& zD;*YUv~ph73C4=m?_|^^aV$E1WZ3Um0C_V9-Y44+kP>ci6}6}}KgJ34NoG_INUqQs zHG;+xax9}!rEsz6eQh8OzGLtd?s0FDdITU*)aZ*7QN|(Ven-{{R2EAijkS5rbK6)8 zGDZE>2RW25$^yuB*`Y#fVidpKqT}*3FnNEwo*PM+D}UVh3~+n6%yS*wgfI)P(w|zm z=pAA+TS-Gh(R!UP(tdTozIT8~jZ|lH>LM=D6$0(sG7tM!afMP?i7%rk3n>dNt`wYa zYcTtz6*=NIx0^~Y;VN>svSH}Z+ImdW;W{l*j2`l(*KNiNH`2)5%faE7Z zTH01tEpG3&NsT_OUw1zijc0z*TqfJy`^G!7F^#6Z-F2}spyk_Kp~?oQ=eTfCihSem zDm#6nh~u^V;lx~`coYY#=dvBV06ucTN z9vAz5vm?*>D!(V(kc zrFJe?Rs-KoVghZRT*JVV6e-A{!t6&)iiwFKUT(1Ro&NIl8}9j&NmMI`_dmD!F1ZYl)LQ$RGtZA2=_tnbFS#Mal-SM3mp~P*HJ_J8a?+3H?w- zS?>+{|HN-4unV^PWS!PITWNOP$%;|`9I2uk+N2ZGV7;ZGYCS9Xb;wUCHF^+s!`4iJ_q( zc^t-X>}s^hnBq#q?b!&x@3m@kA>Y+g$(cSeE2Da==_k{wMeKx>(Hz35WZcN9Iyss6 zb_Jk3D@~fO6pyuZ;d6yIyI+YC=LwF?FxCl~jb+ZYi{Ch=;93r1M&bfxTb&6=keI4@ z%Dv>|?`fzfz8Rl9h{z>1Lq{wPtl6Eiz@4mU{*WSpO-hZw?x?(kl@a`kqOR9VR{=}< zmE+&u3!(eW;J^@s)lOmvR1W}G8ju7JL=zA@)k2K_a^zsG*Ci<~u0b^0F(TMcHywxd zQ*RG79rMORkE1LsqRKjIQKvc~K}MdK>q%Hdh6cQ^h3;>+E^9T*Fq8D)4ac|lbekt^ zkkR2<*NmC;+G#9~j1@`=X`h}f!g8n;(m1l`@tkPsGHKH(XSCpEqpPxMYPij{)SvVqWgDZZkxIeR#wW(Tr^V=wVqTd{fd&3z>#LfoX@JGGa#n4Ea@aYP4Q zkvD3W$4#XA0zad8MWKgb9muNLDn7slq5cfdZi#DrK_!b~@p60rTU#ns+B~sX=#CH_ zCk#GTgoDaN6SgNx2T zY6bLRdSqR8(yoc?bKUaDyo>clh71@9y;fXdD+oj?pEF)3?&U_g4966a`(Fg!8(T@h z!H)7HUuT}U*C%y3K-{Iw6W~^(4?pk)PWsZR1zDRlTq}sF>;>bJgjQF!=fpKf_pS4$ z{itYQD0)FahDgR0Ivi%otm_gs*F(C*cl4W)5i=Spul{S+4eJ*k2X-0`p0Z-b1+3QC zN#g;o@MGG)?37=J71s6-_+{^}>7(in?uc-;v&JZie*gF*_)lQpx8C&CW&fueGhpyG zu5+ZPrw2we-DzU>mAm?+u%u+A{)`*}O7y<(i7Z!XCsJa^;L{U2HeJ>(^R;Q<=uFq> zSbL{AS%x&qTr}bg82@LjLhaz&BRgUvy;W zot3^EZ_ckZ&4vE4f?ibsKT3S>z*piO9q)#S(Ixs>rAJaP_p)y-2<5*sxRB=$TD_(j z@?KjrOHMjulWFe~Zh!uho{3}G8Muna5eA@~3tgtM2=4lQ4OjIU64rAmlb}ku=7~&= z-AbfrYilb(BIF}=`d8N{8}!7o0s4q zP-Y#jdw-T@o{<*#^~KmCdGd6FPN7&PF1WeyOiHYG7@!=HKLH}FqBqADDK|R}DUNLS z{oNitC$v!#tt9zxqi|_-a5E-7bH&+% zvd&i&qLkuT!V+pfM^ueQ2ZP+bOv4vlD$Rqr_4i%#}Q2R`bx z*(btsaW%1D!{E+W-|DjO4zTIyt5#}~zIB(?tJR=G<;QJmzHjeECa{3cAJ4&W2WsQ0 zw!+sGeDqH=(}sIBzsS`lGIezYHC(9_kLBNC99)7t_%rNJI-Rh#h zOkDTMz2x5~XE;=?nA+czJMk}p2hk6^%b$UIF371RFi`#INLP#n>Aktqhl`xF6wofs9dY|9$Zg_^|(Vmyf@p9H}a2Cu}3;|R4v7H3X7+@rqK zp$t5NvNv6_Ouf@p_bmw2w($`!$R%TRIxOePa~7D8vbtj!%IKoDccB0xA|jI5?<^Ob zE9)FgN6wZG%3}qRv7ekT)}y6Bu!slR!FrJ4V#N)hG?)3gkgCs!@FMvsIN>ucm5c)h zDa@bQKk<1T7>zpWR+^{;K(EW^$hKx$TwdL1WQ3J!+)>-Sn^irZ&M>uW=(sI{R8O-n z56T1p!U=TiC@WXOa<{l}5W}?-z!)^C66N1XBV8%%JU4_Dawa1 zhLbJ|HurK~-|QZXYy3AvzclrPFxKLZLAbcML`Wx6G1$zN$+{UXW6BgYYVDMK&p?56 z&kDwt(dMio7WE(y@gd<%4Onc@;!3C8f7IXKvv6EO7ZeN#L5me2+IY@L_0FCYtf~)= zqt%dVEis-lFQoDW;1T!+Fp+EcJ9DtY;Xzz63A(L^`KoZetdER`>b0Lh1JE~-ckyX8 zHc>ghWAG-CPl;v92WxGxtWB!MsMhF-a}^YGT;Eh<2eas9FYLOX949}O4M`J$6(V5` z?zZG+l{S%oBe0~=s1VO?G;awpE<33 zTsFJ?4ZnG7*B~IuUg4fEwSi)K?q^S@3Opa?#|Sq@{;GzlUVCCVgLl?dUkv;jeS&YJNLE=k)vW^knft--f1>4wS+NoNvDjZz)n{!dFR#nzDh6<6TgfT> zt-vnh1_`#gUchC8V=W-(NnJYx(d9csKu>Vd9-MQHs}xtL!=%ORi?HO1Mo^q}Uqasw z>=HQ*x-kksSf^;g=PTqOcORM8s&K#NL))^n7+g8KwGM}s-rsbV6K067L>ZqAC;|E0 zkmQZVu`MxS>p6GJgwwHqpr7x1wZuO6j%;|YyWKXPcmC24BJ#ef>foi9Ip0DJ0s#r{ z$pLxN2=#bA<1B*roc2V)ab(f{T{#=C(HWd5FBX?1o5jF7=p*?endI#tDju7K;lV*v zoRHd9&N4Ejw0OI(T&|)f7A%0VqIR2=1|HW+;LnE-@YvdT1&+>LgCiQpFznVp*Aifx zS^kM&_0}KZ-=@b205QuQs$Z3ZNOp{?3ByuW!OKVY&!x7_rqw>TUv&&>x4=6hlG}6} zA|!s?DR;n=oUjIml&zC)J-rykmQ|_uOiCW&yK;-VoQ@G^|89WwyZQ5GkpMh)yO z4YtyvNt{fP7P&->p7YIiurNj(QewVQAN&=2Ui=Zu<_M91$Egi{pnF#MA22$XWD26Z z{(vVB50dLgIn!s=x*b1!FZ5TQi;E~UCMJwoT!$i9dTBNuFx*8@v2>ZOAHtklVSbph z_M9$XX-u>aX1AcBi~YO0{G@!aViwj>O1l2`Sf=4f5@F=%{k1RI<2=;}F=yg_J+E;K zh{pEY#k2Lx0I4rNt(I+#vEcOp_We&DDzOJ#R_WR|D1eu@61t#nIf6@c6%<5o*TbPZ z)v?Kl4Jh$xL*`Kv12q9wW@$9&5CQJ-Z!=>RsbK-bss+b_*Y{mn68*jIjdf-|H=ciI9GJbWQ)iA+z~n?%%O^a>**NYjYVMm1+t2x{8Zrso*0^e>p%*B~Y%- z6rGKKK}Lze7c|OhxdWGu!2-w~zVGWtlm6bihs~L+Vkg8vM6m&RT#d%cgZlR6-u1tN z9bo!o zM|!k9pL4%%qFvVXbz|7Y4q(#ZJdVh=er_3}aK%Zzv_So5{Uixb5!dPlxybQ!rTs-% z$a^RyGty&@e_Kgrr|4=3C~}1bi2KG?OsIchhCfeV3=td~e|85CytCfyh>{R(r&aYD zEyUU`w-27BNr}?{Llsk-)dqKiRCz*OqJecQt6Y3pi&H^m)ws;e(_7lFWfT}@D0J@p ztrn8BjkgDX13wFftTKTSavkY`8aTP?WeokT-0;;XQJSeeGd@}PP1wKK<**_CP025L zSkwwfQ2MsUP>k!pV8wLTg}SaXJ$#;8#k`plY0F+mdp4eNXuHSVFKReA6HdETZa0O+ zVv$qMDbU)H&|!((J~phj^*Pg@#gYRbZNP(9;{tLeG#vUBs-R#Q5%G{1q_Qxl^r&nr zb>TP`iI-QgA??KKKase*UQ~Ue zd1Qdi6!Ojc%B4oI;fOD`_Zd*fX!D~N-(eeELR6TO)7aYDT7b6#tZo;(Q#fO}IKXcv z6d8Jhkk?xGkL4R^2>~)lF%Mn9<`SHmyXamFQnUYNq2S6qz~^tIfUZ3_UDw+;B6xT@ zw876qW?X7L@qN=0CG8Uw0If7GE)n>}{7cnXuLBOOT5DTs;qQ1GOYAr zQ|Jtl)C|K9LQst1;h+wC^Q6jt`^uLS-JGG($wl-2FNZQi#!QdH`3&#x| z>}h>jg!p_rVhLD_u>$My2_b`SznX0#%0I=(yZrUm8|wmVEzSn#HrneWCriykDmaI% z=Rac&mz#2#Ev5^Lu)JUMANwf?fuZSyP5JbDMcB``t4ua671Rcb=9f^UYE_MZfghab z?k%uH^U;?UnFI8VN#(D{o!5qH@x!Ulif>a^ePxpWUa=+Lc9@@62joM6F-*~N>CjqB z=-rxRxQJ+QH7>TR1W{uWtqY|A&*F~OP-0MY84-&6!3mUIo^SvMUC6I&AVKd#;hLg$ z3@keJFiF@UIVIQNIaAZ=iLZ>|GinZI$j)e3Sh_smWagl%>a?d(ogl+$wBBJ< zhW!d(*lL6e%}k}o#VI*r-4d3KmkN?llg|jH9Qqpn0ov)2fO1D!$I;s;{sE%{EKmT< zKOM5G?DyhqtgOAUL<0BoHuvLeC5V69T+0}hl%|qzu05wX-b+X;ymg1DJ!=>$FX^5{ z!Epf3a#vR~5+LgrCs4qc#|vN2n4h0dr|@Xflhevgziar9HnQ36s-o!62a{I5)+`OZ zVn3ww{JXN@`#5D*%1dWB!x?3hZKElom-of(-BFd#j}9A_&<6W3Qm$_iA)gsy<#Kop zSdGv`k+-0d_;Q#``(VGd)CWjyo>dWDu0;i>D8D!5wBPU%WzG7SZMS7#+0AsQ*$p0*`>)JZY7>|D!JFhT@*=kX=5^M}-q;)w zopio5Q*a7K^XbD4I?=ulGZEtB>d!AbHyLf6*BI`lgr%0xwietk@z-YVXBB%!d0r-7 z_pKT9**rZpLUTDTl1cH+qQqWqU1~KXTi{JyI#&Iw(<0jF*;?+HOj5Z$=Ypu+ zG19oEvTqFlJnWQl?&~a6ubZ?IwO-}hY%sWT<}KlL&MrHg%)h_63v#`kQR^p%vTsYN zMuxRY$#L`8F2ag{ru#sU{!@x)p~vrsZ5}>X*W%K$Uh{VGhqcn^uUcgpX`D7FPD6`l zchGcL_uVo|{n7T+G;3nK<&HdfEbPkp5Y#I$^|1_l7{e6^>{}zv%EaE@XOQaqJIS8U z(&-yhp3)+1Ih`j&IZs0w8|yJeZP>#=>#0pCJUnN%epJo%Ge|th=ulRZVL@Obgf7)= z4{Vpi_U_RB(<%;_^|EojO+MC*X~*vS!(-(pDJXtJfRWDQ4rzSaX zyGqfswk9y93C&df%e>Xpbjs!I#pvx+i|ucB?t$oqxR%0%ohgJrDlMj`P5(cwjZTA8 z+_VkGB`AQg2JKSgS}+w}D1pvjSc)*L#y}0q5nx+tBtZ1sk)snTva(jK6|n_)pT{qi zLzNTPJ#gauw`eE4r+lQ)HH~qBsAPVFAn|3#*8N9pX0vPVko@CxB$jmk=Ug*vsLVG4%l?9!D zzAu8KeH0dNY<1@k=i|E7)j^`BOc6ppVs@%{%;B<3{hkz!aZ}xRaB9W$Wg4D{MTcy(tj2sHdhKqgi)Kl6+m6=QvRKM1h(h zF8oS+XhXN_Kf)t%rc@ypJkmn6--hG(ssQprXeG22az6l_KE!^d^@@EBZj`RP>d z_=JERWv98ubi6mB5nOz35~k;)7V34NJ>5IbSQ6PbaF&~kEEz?0Hs!$7c@feOoR=U1 z08py;cgo0keD;vJ3krx}+bcPlf+wBro2=7X{i!oquB6j2yZwoAN!#a6Zm|2fkBi{M zL!G0Te%!~s%wBzZh(siuaAjN%&hKjqEjHY4y$NCUR<~god};yhJPEoM;BY701yJlf z?RIw_dGcqV%o)^6<+}0A|C_*T3`Ws&+@UuHmmOsP8BL-qS_^CZOI5FU*h8%p!|Ujp zEFXra0J#`A*0nTyQWQ~9AMulB^L!yfw3;{Pj%s(m>9-h3VSt+dK*@#tqDfc0o1xDXV zGL&jblpc@njdv$ph+(bI7bsx7=VY>a0SQtoF79-mqa5TQ{-E|B9CnKUc}^Cvq?FH1 zeiG44FrS>cjfP>NKFQqcwZ9(=?pzHl%|OZGCNC~FEIsd(oFNmFW*`sr{ON*9->luY zLvm(RFhz<+#PbSL(8prT*t9&i8;@#U-I`8QWe-LdMd=%3Gr82^vTPnwbDd@ zLH2Pj2aVB-UdzgGE$to`$E?CO6x{X}n+(o_D3FIG^r( zYPD!``P7`%eCrws2}y!(s7{6)@Sf!cH{gb9SOFb<_%b*+;=?#zOYVp^j^0nxV0EA| z)+m3)(hB3g6MUM2=-+_rXOqbllAk|N)AmsI>E+Eqn^oIA`&M z=o3x~bS&Sqy;0#$;QEzx(?ghkJoLE9MOoc~Bl*1t6@bqsoiXsMs1&w63mG#fRln<6 zf;hfK^mmS_DRhVe3{0_@19X1JjMbLCGK@v1m0LVEQ-YJH50*cp-pw87{0)UzkXvHy z6%?wiQ9Y|5Cx5+3t_c%I`k2`_GH|%00RSRW%KCt&!C_ENf5`c_Uw4-e5n&x|b$HGR ztYT7Fwqki(R1~6pZ(pSU2XCdv?b_J)0VD^Q^i${e@I&tRUi2hW9hDOkEs;;L+y9Ft z>DR%;;$CXI+9)}`d}3>OU7w)laF+3$OP z-wmWr)3QP0?XPi-$Y~n-bFkM|F!t9`qt5_9w+u9vEFWe1^QNZebn#1f?XLnok$=qn zsH|??OORB|NmX|iM$Vu{<(85O!euLpuXzpQUlB-SC> zi5tmQhTG2$FrKwm2%4(xfbb)=Lg&T1zv}Xa678KeU07qS%=s2Q)9!$-DpE>U^SWRx&n%z-u=BHGh*}=H6!I`UL#muif3KoY>GyK}tf^gM)+2 z<;+#WgX`I)4F(TMpMYKw3~Wcym0wtY6VMX`ip=ogI7$)ib2}K2+UexUl}SGdXW&$E zZl`A5Xr;MSdW$rOk6p`80kxC$UyZ)6IS`j{I6Smv_;#1dP+|vW{efgwH;>~TH5?O7 zOkP$;vk)4emdb7oEbW{J-8ZYFRxG{5ad^XhQs~x>eyx0`qC_i}>NAzG2qd*Bvy0;L z_5t2wnR_u+KI&MjrGDg+8t*M#D!KHAhMJk>yTd5~ufF2nQ2venbcoQSWRj zI}6p?e5cw}o*~6w>1e^~d^w)|l~FEBwS@!6`M{`k1`&?lIVALC|G?C4?d~^|mCSnD z6-UrQukPzCGM=?FBcB25iXO^dzK*&kQ9J6=$gb#oQQM@17jX>Q7ac^lEY;bn7tO}W&Pq-}r0yWWt!pYO}e>4(fHdrVVR$)ohT9No_Qxc<;*?8~d@? zfWFJ$tFLZeF35HjL6n6L< zKQoF!qeTikco9H{6Gu{5x>zpTRs)8JaERpR%b@U+mw0lO(z5sfFzX%(>SxP4Nv)9= z)Cvz5HWGMhL^^;m{>IAB-Tq~t1=7M^8w62=m84`#J*_~O-Qw6=LR-oW+`0-dgTO8$dE zvaJKfg5&d0HUq(D5z;b<6E1T%XRwsxKzPB_=5uDbmM?YhRO_tjpb$ch8_C#>+y@QD+4DOn~(HB0DjL`X#x%_yEv;(-G44VA7t z;ek}{D{<=L6ttYm(}2UEK^XCN{I&%)XQ(R8hV>UwwTC+t$0O@M!+dMM)z*(}r7Ga9 zX4vW}xOP;mh@-vN43B&-`bELXXR^hfV>K%>%sBSuOQ2QCnsH2@G2&dC(^+emXGu)x z23Uw*i#s_K+jMePoy7Ujcj|*gbi!7z+Id`06Kf9 z05NsF)HTqcrk0i-4%^$?3x=WuyLN&BS8mk>E+2DCi$`__{0GI|-<~Z!w0>>%m6Y}f zU)kx>o?kr<%VZC9b6kzGfTC1P{Xl|EEJ6mzl*3?`LD&L@5f%k6vJ^69P#*2LZ5u(i z^rVn9rZVy|UL72;O2ytldgeeop19p}8i}h2fkxzBSDBa~e!U#)7N4Y*E-<{yOIb9& zy8j?f9@hA(#HJgWdTvo@q%?bf)od|dbVsWp-)aA>@7>m5YyU%k=#!`vlQxse(#7M$ zLvNZRVJx_p$?33W>x3QK@=MzvjcUE*_Al;V4Zs|fmuy@}bOv{o$%wky!#VXsHt%8y z&P%J*ub=zL(BS$2lS~HQduJAs zA4H~2t}08#E~GarUFi3dAC4uyf*X!F5+ov(-0sIBi3Gq{lZ}BvMu$(b`~6Eh2!*4` z`=pcUxdETTulvr4W6X6J+ld}bL*Z~i8(_bBvjjs)GCE3xZObG)dI2!f_E5kHO_ z9FQBsu}u2V<-BviB}T2Do*Qhg=;L*4+R*66#DxzCB9QB1>K|h`p46B~-9Vun6x&_n zOka56503X|o8<<o_1l;MZ35+F(`=jU_9H(=dinz5nKSi zUOyB0S|#vDQhLf(7exir(?bX|OPDsbGZV?H)=F|aTkQk)1_qMn@YuPRIvk3GfSvV( zJih|dcItQv<^68UVE7=61_W^q;zmywR-UvWmv-_^`?jYpDJ!HpDa7c!o2p38Zw{w` z7as)PvE%p$fmcIaU+(j!Tq}HzZL*uNz_wHQrx}c z4_@mc;&Ka6Z z-ufgJ6fr65N_?g;ojYWI6~(h}7$}x0Q)a2=MO`@>CXz8)&e{E(Lx(ZaMFpSpyXEMN zZ|1X)T=+6QWRd`x=Ucaz-td&~5uF5R2hYFtI-bmQt5!a?_UT)f2|!WK(LJ57o{2X%Yg6*n2&n z)pq`V&KH{+{K!wp_sME83@th7Q#8Q6otQ3_5f6%9ZEwA+5kv^qwujpbe|~sMo|~`H z?qsFPW`%8ow{~QNC@Hd7E+bRu=e0G~{Yymhm!8yA!pf8lH3ZW_mJMK$C9%5EVw0U6 zNI;wO%~A^4DhTyK<9SQJp4wBOn&LuP;bnYYQIS+5$UxWXesto%lgN)AK%Y;SNGS8^ zVBEh#{&zo>^>C(}`?6F{c`bKuECc;^`A?n!Q)&hjG_`Cl!d@46S$90py25!CS%o;o zE&MBLqPGk^`$)KyLAP+y*464LMA1mnxW-SDAXM&_){V5gfq7Oki$k|amJ}3xcJq3c5ug*tdD%m(+}4c79jK>n0Vt;0 z`O0EUIj)$<JGVO}sdXnYptwrX|6;2$DewMk_S0ut*lT zU2oPR02u3B+usc*!?fzOIWE{fKZF(f-OAj9HV(pRxm;fdJ1U-X9`>4+ zy3(|H6f*gjGPMv7*a}k(g7y zFXiePb#ry}#}%YwK%16AuPDn@h9js!$}<(`NgYV?R)5F3NS0}FDp^UFo@o}-P>mY{wVH za^tepkQi#Z6ndi1yxgX6QE=BEEgyJUFnBjcOzXbRp}P~^G8{#hcQxTGp~%2JE{C~P z-}heu-$)Gk#0?^fruRIK>$(&(g@<&e2gn@odt;w-2m@o|iC8!49ehT7T>o@FoQ+wQ zx}CM{zp)a9d9P8Hutp3^p)fBUv;~{$e(Qwzrm%&^Hd(2U-)j6it*FNu&XOYJ^VrI6 z)g^tiJ8y|usUo_Y0@3QR&y&2?@0w z`7k#^`0whUf&jg$e+L#Yj`@-6jN`4cGPn`kI&50j8C#%W2< z4!RDH`$eCRS_Q271_adIoy;Rc$(!QbYxYUrYEICjoKN>rpz9PMEfaUq*xd8WU8Jz> z82D{-n$G!C%=I%W$~1qp7cCA|cpnjxTeS&vy&NRvdOUN4=oboqL>I$(PFY}t-8 z?H!eB{Dy#{j;kwLq#|YX9A09o4Um|V(QPV(nEJIq|2;r?ZbC>#AFg|6(X%s0(3@6t zeG_^=;zN81Nb&p2w0oVxV>9R%(-Wtj14?GG;`ZTpZ1;{HO7zp=YbVhi@9f=%fJhD-)|R=dfPZ6EFK{fcro zf6XmdckGE*L{pS|?!}1COgpACd9xNP*5DKaAZg;vce_obh;0H(;yD7dcmfH&;W@ zPf)Gotki&cm2vgKSyP+CuPB)$wV}R!f31!V^w94W@B%Kr-tBF~7!KlD7b$7)U$J%f zf;5z#iED0l9A@&a(1aL=W;k5wVFqP1d4|i6lRg<}(=M&T{9B3Lc>GJPu1Z)bb}fH{ zH$3;M8rWA6#e}tXlDq;1EkXR?ECMc5@M3lFHvR-v5#Zn)0O9KfN~aLXJYXR*4v!p> z1o_Bx3(=q@Y+O4|p1XQ`9a@R_UYoS)^#=C{n!TZb-<2?njD00xzY-FD5&ZcSmY_Y} zL*~7V?R z5(HButLKG>!P-5O&mL$ zQCH;Duc?Y<%7-9zzWX7n@;N_V3GdOWoiCKW{X5gAl1CH(E1Y3vBZ=|xr0006kHX*< zFS$;ZA=tR!@i!awv^taQKQ=S_tB*H0>1091tuS)?4QXD3lZI4sBNmu-P50+*hTY@Y zxiX>^aXeZ>V`t)6$+k{#Kt&QtT|IbV#o^S?M=FV|dBVfLLKR5lSW`g=(3f{t!%FHt zDhGiL#t|*EKo8Rt6Eeg!FjJm4= z39a|X9simv=YIX*uv%xVG??^#{ZoLFdWiSj!qQ*2QT$y`v0SyRGje|{t;*`vai!8^ zVDqPnIc1dmeTvXq_sH~EABIMO81G=h*HHM_WMX0sbqwy5TREC+J-x!%)Q4KNj^$wK zo^RhMQQ~QA<)2j09~Oii%Lc}9-U*;JzYd8TGq}hraitguvt2N=7U7v)n#E&wM9n`; z7w>WS2}Xq9Ki?iDQdAq?_PY^z$4p%88qsG^e^W9DJ0m&zr+Kh}Dw-?HtV^DvU|~+o z()gp^^mlrbf_~?Gw<FD?bq_jr6=S{0e>O6zdT?@_u_hStj`FvWd z{I%S@d|wGya1{NZbh0?XZ>{jr`%jJKxL@A(?t6w?0w`6|3+1S%KY!UC=v~{1KPL6I zzUO}3JDDNu=oJ*I&gVbg;0)#ca#QW4#VBFLGLFZ;S9pd*(1O*rtE7`IQ_QpTJ)sg# zifM=ltPUw0Krii3E6_eX<1L(vYrjngBxK_5{Mi46uyiU3m)*KeuBkJGkMj{^==B=R zAwj(E9XPnaTpF1&Ra!g(!RVbOks0IZ?F`7_zD=SMMdhlvb_%aoC}3j&*yG`6CFU}0E&gAj9i`aMfH(3TG^o@Od7$vz_Oo3&UfN|Ux7 z#U;)9zR@A;JaynjWrNT6PgoC3_QReJtXEq@)=6R|=MI85V2Kbc19Z?a_baf~TV%29 zDDVRm)pl_qnqz9Ag8mmz*BD$^+jdXV7>(W7R+GlIZQEAkG*)BVw%x|I-Pkt2bKYm> z%j}tRek3#5_r9^Nb*;5FP(niyJ(mVtVw*kA;`ZI5C7fN-GCEx#9tu8x^H%q`Bir}v zFYC!K&NYW{6R;FPSh#K2sLHSH;}L!(zng{->oXDCjCL&{bSBN-&GBi`qi{T&ZtMNV ze4V@O9(H;E2J8C$JtQRbUuREG=5lF>thRUwJmX25jEVv7+z@g(?6!*uK@eHJN=%k> zsbCo~%h!n6%*>DFxIVFkR9)mK?a66>##4g08q?UhmB6X49*K5#1_TDxZ?dCp1B-dGafT9N5mHh?yCytlN&FT3+L@NPVx9HItz0=}A1oSI|NB2)6R%$O_t8R1BVYR!W)5!<*ZnkEqflgZ z2Lu8vdER;66|Tx0mQ3+5!YZwUa!F$IwUD2`k6ySfv2On)4G#l+)-G_afG>@7 z-9Kx*wo6>ymF*AB07Va>2roZqGo^=+J3b!o+s0&*rvjA(Cm8f;nDk?67i!VJHu35 z(+d&CNX@bze0lh#w8YMEp?EW$Ye-tWP^JBN92!GdbulzJ%3iJ4cC?YPWc!Rc6hepI z`bwixre&bS>+fCes7_WGGiyLsX_TOsETm7CU$z(J!!;7Xgo zfM_nfS-xzuJry&y+4^XZBkuS4Vxo?;Ut!G#-#%%_?|bNevHyCYFb~BRm6sVPYvgLb zWKYvf5E?}dzoYj8to>ErFJNVBZCLszcyWLw%L=+u_OIkk2gDE9G$tetPR^ohdY)7_ zkho6Ps>~txvLgoh7m!Gh>2y5Yn(PZf^x3|=Ou+%t3qyu|A$+YE7#r2E{(q~$h-R=S zHNPEZfhV1S?FrYrf8M9S#a<_gzXj3tdP|>e{DVp0LiDGw)-2y4rJasS5+C|!%wk^3 z@BEDgg4e+{?g$n(8ymd*Sf1$FyLn5kBir2yy^zcOWJUZI%s8BjS4$D_PS8GpuX|WeWT!*`KxXI^ zUM^fcEfOMRunCq$_B&0DZ{xu?dTk9F;A8?!xuLa~rG#>;?D$rq+&_{uCYdsL8W8#P zGsHhvQkecXReDtY`Qs*kb>>gABd!d$4mgo4uaC{skVCyfwk4uG%n7%n!#`30>+pQz zK&Q~|BEdMyf%wVG3iCE6c|_tM?-Om??4KB_3B^DvQz%}LFR8k^P102qq*6nK_3(VO zQ`vX7*Mmph;2|RXVc3gmJVZx&A~x5pTr0tGz{F>fy z{d1ze%bqzWLQUYlA`kpvr4@$*+m%(F{O$hwf26*3HiJo<`18KXZ^apqjzw39|9`L@zQcc z*&a6-EI<#9fXsAn{FMjE<<8X%+W8XO=<>n5)Chxc*G5dK1VHxwHMSo=wu+Xh44w#2 zUDYC~#zg}&yO!4KW{|>ReJfa~7RJ`wP+P;$@W@MoFNd%dvSe&SR#QIIuG>c2g~wr` z@B0Rm1aq_S0=YmgYdX8F6M+h9i#G~iy0-;>AW%$#T0I6B9h`{70*CMT?RL3|mYL(^ za&of^CUggvb97D5aD*NE%V%bWITQgEo$lhp>oD{!o|*6NXy&~wvLjS+=ifcy-CS{R zDPG|4=Dj)20&$E7>yK`erRJbXLuGyw9AO|-;)OKPMTo6pB?^ZoqD5Np(_Z>ETarue zBL%iI#-1L1Yq09m#g*?IRSYa(^2$d%t>in${~Rtey!f$3caT zK;${{k7_LFn*;iEJlB1Dg!~qVf4z02ejh(^8t9*lH|IN7`D!?f4-oRWDm3bZcmTt} z*=0&aQjS4x7+-;e>W6u`b&JKCovLpQ(3A`&D2V?XU2Fr}q`{s2T3LExWXp-TY|(!0 zuz~ephw)Mu?2E}rjeoyAk^gtqs%$l1Cq+(6jiU0i`)-OElT$Q<0doNvGY$$`XxgP} zE&u*{ScnL_&2-TyG{GkmVB;)Q&@J91k6#00Qfz$ z26MUN0LB58ELE5!4?pv^STt_a%|(y9)p|Sn%n&XT;-P0`wDjR>(jy)`Cygeo6Z6ZFu z`91d(QV4k487EF#_x4O0f&R0%ov2%20jeez9=-sUo{VD>(IW3|Qo zxH$xlA7&{&eLXAKN^7Y~2MGka5J0N(X70~7mH;Jy1G~Y1HpcN-$a>j=|K^kfxlaX@ z^&yKt7`ozVNW}Vkex=o0=ZuExEe+e8>)C#ZG~E(I!oZEfh19)6tt?!n+D$pR1R6w6 ztk83NN^Cg|BS?&ki1!0A`)-V}4Aik=KOpN5ktfgL0BSF{PWk;lDrE#)HZC^2e%;0& z9ZxUb#9pHbO*Apy><3_km870>wR;+B_wH0U&YAfEt7EIN4WLJwQH!Q&V&{SpNFT{i zd9+rydhbh}SEyId>w^Ti`h;`tc^sBE^N_)UTrz14vN_g3I!3JjnHh*~)qsNC(OI{% z)R}@I(jXp0*z)n?$J%Y6SIGThb)zNsbfZ>E{v-2|*)rMq(oWa?&dEfVE?6;-#>fp! zV+G9g5`1_NR$vD~LhBn<8N7lUgTKx3#2`j&KSu1myT6DXz=(1p)l1{H!QdNTUNoa9 zo^gXXnpkF%aZie)=U#cG_>eYkh2G0WTMIrwT4hH@dem!-!i!FoA;bI2FV_j5kbvOb z)dg$UThgWxc{gZamudjy!1xBV;4k#+`w_}WGwgZVY5m=6+m}kX>Fsg2+x?vjM{a(RscHAk)c0ZZQkAk7+9cN786IQ$NOi3 zyC63Thb&MncFgLJr(AUa(xuQ750~8iLIT}vaFPc3!1n~Z6d?5P_PAEso*@n8&IHQI zG6~~{tiC)yQO_M{!(Gpa#}B>hDbNTj6W2QK!g$v8+PN33X~EI^v)gQJ_DE-7mf(c9 z5cgNrhPi`ETp3qe`^$)Ho^ui^*FNk%AWbK|+GwLlVX__s45w+715+rooyzGU(taE2 zRFxS{dPBCd!_33k6;58LR(>s3Z*#i&Rqoz3qBmb5!!N+Kaw>VzGg+xq5_R{Ryt6aj zvtZF&Pm7P@b)#TZ0L-Mv2Lh+W%-^R**WXrGWsh#Rs{9{|juTh(1h?uJDP2G!c5EXD zV9=j0MFFMX268(pG`(!T)kL;tGvSrB?=LdAg73%Cjid6r_1C~^;P@hvdLO50#+yMK zA1TnLI_pzh<)+n4FN6m__j_WiEiv-XuHS6?K0VDSZaIUD)VC#n1DkDt4g@0MCxn1z zWU639v3B)k2{}18F24_b9~NCZ)hOfX(GBXc}nJq-Tf+F^ay$HYp&P9*8Awf6(Td z*lC>!e04v#QPM&TWPp$#iX1QhdhgdTAsbN=a~JAGClvN$AtSOwT*+`b0tYV;3UL*IQ?Ctj(^t3M z4G}1Qhu2mrL3%h_!LvE3D+V=D5YA4s0o$;EY@7TP{TQd}v@e0Ip?!gmXDiwUCpul^ zUbK4Vzi024!wRQlL%!HFC#I;Yuy41^?!rd0GKR<*n)eR-{)Fzw(Aq6;t{rz_qy!w>;t*` zYda%Mi#y#L4kjiU-?k9i7#?THNdofRCWJO0=!P*TGFZDL6aL(S5RjSp1JQlt1>J|N zS<42%hyEC{*_Pe;VM#m%*L2K&!Tju%KSv)%sSZDEbiN2ksIWPQ<>1>+iKCGfK}`v8 z_7FozQI)KwB*Bi##|VC4d=+;6ZyjpA8ry>rg%7eC zC4XIwCl`>w5cz4qYTuyaKmDa(rjX@jTT#YkO`KVj(a%euU=Ryl2t0Yozha^sfHH@Q&&!rAGmIcE^%~V%@!(mg`owme3`2m#D>$g1@F(6t znXa#UXz=gwDklz8X>Xx{e-vxa-%z$HfjuPxkpbFYr5=#TZ7P6r57C7Ko$Sp~uze*k z5eB{Ts#YuohJ9yWcN%Dt!y5sNTktq*Q{*-%|KTb=BG@d5z%1P8s?mMrQx>bWvrK~t z9sBLd!ykCv`bxKi`=>`d3tqx*12+D5GO!wYZ_2jzI$y(~AbOsXwNzAoQ5`0+NBwCu zByhpMdj5uy`pIxX(4t)$7dX51xu;XVg88<*9Fy^s-D&j$i>4^z$fJ-c+9IRa%CCq zW1M90IL3C})ZsG4K?N(EpsuN3YH(HsZsEHA@$GnnrN zuL7JUr(f#t!I3e>M%pq4&>CXMf9}0!7g2=4NiJ+VjIOZ8U25ugjkzH5VfX=%<4bMt z=zP&l8u*eXHW_`3u#%{R%4UKnI7n7lV_0>?7^8KA~OcvmszOGO62ZCk>eay{NXY)^Fq9hTtF9HWu zwy{60@dViY$5`3}iY93&p|n*!Fo(TMD87v%VD$WPIl?59ov=Kcx>R}PD>`^WS?*HS zjS=$4$Ps*gfTiN6*h5aWnU)zFOg_r{rUVCotE*hJ?U2hu6VU_fbR$1bTZvC!yV(3y zvx3?*indF_L~{U#Qh>eGJc~*tG(3iRrX9)|r^gQK?ndj#?XrI|b8rwFmopN5tN9f$ z?ek}Q;vSE^bC!(hs*`$QUhC{?ukB`jC!hL#(G1V(cnShAU9ODPMcxbQZmZj@ayi^> ze`x;^kt1F;l00$d8^mU()8?smJ!LPE*)L;YzjgpzVQi20#RSmzxQEsDf2BOHvxG44 zA3x221~V(Gjf-$7`YpO$kN!o28w>ytMMFT$fgg9YQz%2%{J@8ajc*c~9K3Uf7>4?i zZzH&;hlBnYv%mLm!U)N&GK2Zpz*Z;ztep;@vTVk^rTH+!^Xl(giar0&azZ%6)!Swm z2j1k{(NTfRnJtWzVstj4-7__Cpqv_}0gVXk0KF5-n63tBcIrQCyDiRWI8h5@y5#n4 zPvWX&JAGF&A{SLmjDH4AbUoy$p(L7{0s6fRj>sJ&D*iMFIs;~6`=z`-Md9k1V%bw? zQ0==>YjX_|RX2`q>f-p=+GTk9@BtFk%?(BC70X+RPm)No@29}}5pcM)7Eoh~d&YI? z=a`Sr8mAhFeHl4ueGH^eIs*epc-i3+)9e%8TYjdR=I$Z$0VME4|5%Rl=1M(*FLTTl zGMax^`E_t@qks)Sh9ch!;>ZJh5rbh;1J75vyB=Gp0;uJxoz_1$4wf%0l8-bWr<$@y z4>CYnpA)n~+jm*@-26RN|s1Zqy|sQs-j447X;&Q93N;MnCdt^5#3iU}%+gt1 zFOTKI1@ryXas4IB48WrVUdd?CU6RKWlaR4pK)$A8G$7FJKwx&q|12}0p7E>134*?z zjq04!`2AqfWeiz0W6`;ptn0_toD(~}?>i}DKGx?+g89`9G&DdUA5OA&h=4xxbVfsS z$-1$tDk;Ad@fWsnsZN_y5-h7ZA{743xUaPZkkalHfqm?4o=HT)VfF1@=y)vGf}7cu z_%_bo0H@3Dnr({Z92>GbSTpgVp^Bvr<`=7Tn`&W*h50PUQ2;PELc_q-T7r!r(FnHM@^J z1R#oRtfnML#{R5(I^HWwH7QqFZtn8!%5g21UVrz)E+Vzjkt&p{Cqs{dGPn{o_erag z#0MZS^I2yr*Un~hiwTGw>_)n^Dr2C{Kjxq;sn${n6AUP1C~KY=q-%iv)}gYrJ#x)B z$J?{z@=6Sl_&yh*InM-*TecoVAV{KgXMcdNrlNj~ZH&$5y?lT~xXE3ukIN+}5qyQ{ zc|1BKpQ)jdz2pQOg+jqTKRvW>>ztiL;Ke7jl2mXSZB`2$8ckN2#AMB-i_v`hj7R2d zf2tL_ZFZCY4vrG8fif=GtmiE-F)`Tnz)Q*Fv<>*C)|YH?f?XlWW4 zKIB*<#+^3Q3SndO-Iiz^M$v_f{#h@H{O``mh0h<$J;c(IXsXh>uy7`~2BBJDl^pBM zR^ra%$$4Wmx=Uc_0!8Je>OFt&+Zudd&w;R0|3ZLt4`=j8ttPNda)$r{BUm+By!Aw9 zgV>=ELCEtq%N!)NmJRSp6)J7^)st9T?d^n$r4lH-QOvi2Q!35B7pnN@#&tR9fuNtFk+OXI+<7oY{FeR>FLQ! zr!d@Bs#R&V+|nq=5N!0d0R2m;c=MV$d~P7|*ha@A1fDWpF5${+dR0#X1zO8_1?q!H z5v2R0I~*fiV2JB3a|L-5bdXP5tBcKGnkwn_;SX{!uU`{P6GbihDXy z2Mi<_Kg7^O_rL&?P>|&G*;aG4TkNM?Uz!!Ro(GP#59HHUP;(GJdA#G|FGeQM4F8U4 zAYP;-45~Nr|5>?Q2O<0*rJY0S;B zB4MXQ6cbTtlbn1cA%$RSQ8PSw5}dJ&S4UNWzY*rN--!y0h7?KXB8vkiC$55A^Q_H| zpf+lupG=GSVB#AWj_td(_$5dSb3@+eJ&~h3P;K_IP8=Dwj8&TNpG=nb4T@Z>tOHULWUrV5x ztUNj}yS^FxmuN{r>J_=$4H%5qA^UBwWJV^QIpQrx-!cL;uhG$!W0cFh*X%8Mg>q5v zFhF|yI4~poNx6cdR7|E$+w1g(s;qGJn_6vRrd&rh-+T>gys`5n;7nqc(ut1ixMbAy z;XgK4-8ON1YwLtbZj0v~6!HJ`6sAem=<=1=h}*-U1p3Q>ktb6s@w|va!z7qSQrAYc z?q%`6cM|RMLs;huH5v2Y9R|5mY@Ro){9{pTp6#d5mQJQ1^xRm< zuAj;<&O!`|dzv+qIlN~zR9sMgB4A5@4@Y5mYHSJFj7do)v5ovXFmtiM9ZT?ECaeL~ ziZe_80h=^+nakdDU<};YWTl~-$fb0%Nb^Sy7M8xRMfK=@q!VlPFBr;Tmo7p~vtW%s zs%dpo!s-3?3c;uu)*c-wm)idY(gu!XH^t3e75T)ua6Fw+Swig+U6{6~^hIP4ZuPwH zmBTF$^%cO;*ilUi|0<<$f`QN^M$6KYJz=8ECOAb^Ga9JpV;hXs`|n?iC9F4hsrUc4 z(-0HwN$A-f{9W|p%H2k)Kq}*s$N!EI6+aC!lPz?eu>4uG3jnoUzB1enb)M|XzwPlx7CMr3jovss$ zCF*MR-zOjKZhe}DY(an9N9?rzsskKbj#+`c+cVv<5YKp?q4mf|-q2QF`rZR_#+ zaGox+X-lCjSGC$?m+as!@8;|*O?%{IYT}JaNk-=3BO~wbjg56!rS(dxK$E0WXEZPi zRLDOq?{deG{ZL=}J{u7%^1x#wS`$TyV+5%OMW>1S?pE27u=nq(y*fj(;V492zn;9R zFJE3y?qwR8DY^7~IcPQv44vqB?piD=2#J_0hlxH;1Y01k>L)$K_ZefGM<#!fN{z*y zU->w_-EVnHn>`%9jCk=jl6$p|KO)ZcPsOJ_aF0myu2Lo zu2HD(ckX6k-s+RjvQ}&=uldVN5?sx1yxBYQ1?q0ga=1-QzkPaXQH{b))1`|*-^qh9 zhvtzNG$h}&dj$Jv0RT4Z#m@6nZSqYOpX;*~=K%AmOiRa)`S4~-`>j?Xg79?|p&O?y z_3o`a=flABHFplR>P+))v_*Bg{c9cVY_lL_nVb%yDc?N%9%JK!H-5^;%PsqoqG)m) zoSXsmY8^|DgS%t3LwS7r*MGpwm_d!f!o!_n24R?y$hOvEmy<!cZ$=x z`Qm6TU-UNYtvOO3a;oGdN`7M1ou}UJ-LrrKays%%)g_*Xy?hVaQf4n6B}K2QE%mPL zx>~O26^*6@zXf$uy`t-M6Y(jXe&(unzu3_D)%*&ooxy-8QFxImxm=TeroeA1m-WOl zx+N4HMc2>5$ezAlv4HWk9#p`}K zm^m31ne4e&G?L;flV+Ec;?BJYrTo|9%S*PkRKECUNt7aHfG0#0Gg<$@DC&-pHp>=c zCdUgaD_C;P9^PDoeb4zI5jR3_A5wG9>*-w^0_U(Xsu_PE9WjGivyHFKnCb1IjQwKw zZrlv9aq@m>?Cd?!t`~IbC1`Yzv6ne|=jLvUs9&oYwH}Cqzav3@LPJLoBHkFSzMbbl={Jvxop#xt!E=&nG zi$;6Z7$4!ayL2x0mC3hE`>>VIx{Kg3-wQOM{hYyz=z!$>Ji}_P zL@q01%j^B&)V^VEv%72%U**Va6sub6$1i)-ebT%WC)_-4%dYO3$>ea^0? zvb5OWUsJ++#;1m#=qBy?r)OAMw!FMrs&(DTDJYW18NuF7cNlNEn=D=)pLfN57ZZ;5Nql8iwAgJuxhNdi2)T_5d-N}I^O4hUTRbj0nf9~&Mp(cwe zr>Ce*81A3PIDh&u!!HNKgE`5!uW}_3za!!};P;a_lB})>^$TB#sL1`Kh9laA|76Ym zc3srJN#SF;l`h)*+N{GV|J_El`&g=Y{xyop7dWUm{%e@4*}|pkLWd_WnJ~l$xb@uXq+X3*ZCtKz&HE%&jf{*& zs_}t>W#D=d*F&o#K;;AgR{mzK6}wn%U3l#HeI|{|^G}PhpaECG2k05f&Ro(#{`&{L z_K5hE>xqx8D82h#TADw3qYZbZ02ux7V=|i;%fe#oWWIajI*_|XRuE>y(~C>nT>fV$HyP z&P}i)qZwWc5#Z#BmN-rnw0+$7O5f3F?aacDn%^lgny0(=iY+BUhYz}Ed0aN{X!fKZ z@HaO}-tug=SdHysfnwZX0>7D)Z<~0nb8JLDH`nf~^o#95V>N#2BM2jkG*^rz1-RdcQrDrPJ=)@767{bt6E$X|AVw2C>gYURe#4FGG z%a8kB;Y;YJx!}!|SH!Cf;H>Sh~6=ZLhq!9uw(BeQ$P`Uj7;( z!8q~&q3=z*IN@wd2=q4=MK99nb5St!Rdddzw7#GCoM`ueCO-eq4pBA*2IFA)af0-iWM=cCy8Wp>{?0TP0 zyPa^U>+^p3uJ~ZA@LFKQib5cwUPD-GI$ZnD5E!P`NiyybwT%icks!48$h?+bjT z)l*%Ow~bd{m9_eB5tzSGX{;Z^_F2G9AC+uy$ns8KO?Ol-lVhb>I%S*mMTeD?RM^{N zEBnIR_?NQd4+*c=Vu9D_O%ulHz6YUzINpUlhBQx7%a8fc%LD!+mF9SP*tH;gqy2}e z(+6D!G6H{uU=i6$pw69sEmDnamX6Q}27i(>gkBg^5g338mxtzxzt?)AU5#Z? zlI`=!l3Y^LX80b0ND6<6F+xmZ+SQ2)_4V6TO81`M?jRyR{ipGTOELddDZ8n)dNpuc@k)h+v_q#k_zYY*y z-1{OHrB`I@U8>$PdG6_Yy3Xg-{Muc%JH+sh0hkKlxqcK^@s*H&Mhw{0hDFPmGSUs( z>`k)PhJ<#Pn|+A7KUsWMsjm=n001VS1z4$Fv$=3Ek)b;( z-}QjQ1Y;)uE~+rw?6!Y1^Ag`ht6t5%SAhgXeA}AcJis$tp=|5{2R8O>XyS}z16csc`-vPtwa$q3_37ZfczW*3u^x7Y{Ez>2wX-vfE#ALhW;F_QN@1ZeTMW;fwqLBwEh8+(s z&;$#e=>~&CY+D`f`af)!U~zb@AdR_)f7lTReDjj50U%4#t^*LrAl9u3dzX; z{W^Pf1?q)`g&YUwifUb+u2lLX>KazhR{=5Izj5&vfw_BKNPs_AiUrPHL*9CG!Ez5Y z9oqa*%%(4TRVaKS_~;re_hL$=yXC2mub0J87)e-9#%9eE$zzN!xdSaKWS0p--~d!M z!`@uWKDB97z91(F0^!x~Hdom4+G-i$-zD{^;mTT!NZ>L>(9zMrI3lRRd@?4D>VyQr z;&%SkdTwzqN3ce|`13hz`}d?bo;w8DGZ{#`h`oPzP}Uv=C%+Jf`g8|ia9KbHgF zP0zmDH%GRg$^R)54HeCBts7Hk7!eb*#Dx+ZY<6T!- zv$@{K(E71_4#nslo*M+E#|5tmE#`Pu`Pj}-yyL@J+nF?ETn%qtpC;C|sZGZ9RCRnLLYnk?8E6e@C0DynQN;=*e#G z?#8n}Ue^t=cP;YVPy0GldYY^kaYY_h$gG!#6+7Q$&OKa+bj-!06BE(Jxw47euSt+B z(6^(IwIkjxS%UQa@kc`Mpj@EHfs{ybyGcUg0(~ z`UdaDXIw&O`L*No`Njc+P!aPB1U=vt3Wp^2`$+(_ixik(8jiyR!cYC2L#>)+%~ERU zD)srfg-I|{(kj}pv?%B)VcS|a;;qSV0e#mVIf`{vszo20^+w@aaDu5n{66N57^>Zy zP(mKd?B5%MjSc5pgenG^mCeT|T(Brg2HWHzi8PkWblc_!?|I`zo( z;n%Mhne)KykZ|=yaycD?^d43;(V945`*pEOTeFUhMu()!^;{|opUv%JeI>F+j_dK{ z5sQ@b(0QJTmW=`MXIpB3T`-``DJ=>%Y6BBZ`K#piocc&iN%pxgtx?ZeSH|iHs@`(S zWp}Gx_gg)Zmg`~UREQs8rQemAid-j;+nJ!+v?XG`dEumgqr{a634odYFPbwba5W2R zMH&B;EdP&Y5a>$UJQG3Zn5EI?jsUlg0LMf51z)onXh!h;fN%^mmcnzlB2j0(Me=!L z3zgHs6&Oiw)K^RlAi|1w0F?ID1p(*vzz?7gK%1{g_x=T}0~+bWk~Gf{^2^{%-!iH& z6fjX1)kR^s!`=P|u{KQ*vWMquf0NA&2?@WcqqD0l9+S}>O*d@P->spq&^WkwSD~JW zd7kfpDq>HNkjCdMHP%$L?z2|d14c3kDhj)chF?w%tyo4g*VK`k+vh~3LI-}-ddZs4 z=jo65sgS|y9p|&pM?jz-7kFbywZhqeF1Pyw)82;R0YRBc`hwq6sj8M-LKcr}dlSRb zR$%_RZ;`L zgKJZq!PQF8Eg7e5>h~@DlLJC@<$ri0UG1)Rp)zTF>Jrfd2m+u2^$()s-%@+X$pl6n zpfg2r3-j9zcWw@cTVr6X3pg=Z&4X}L$1kN2TkTit1TqLncTR&SbDPcj0UW-Ousk%D zj?RJ1%tZ#B#!_^PI{GhwR)-y`%blS_h3@d{Nl%x~BI--W>zyKjVNwF422A?N{X+tf zJZ`*NpW$C5hcgY<3@pDxE_{a$j|g4+&s($0XeLZwCz^`~k+lw&v+2CaXAIx(_A5J4 z&3uDjW9foGAZ_*-itVLd*|8z zQZ%hLRQ_SZXRVAWlT)vVTIcaI;oEnc&jJjK>vP5;wRK^-JNi104*Gu8cD21cy1?|d4&ym$c-8am7!?ak0jg_aCKNn zIW;4Py8PVKCTzJLnZT=0CFc|j#kR2vgNoKG=XZ)N7RjgM5@NiHC8XsEg6~gJi7Pme z)w&(ov>q(nWPMRT;VJ#3^JvDwp6gb)y&iP7LFZ<$4Mzs>%n*^t?@NNYzRv;nBeH)C zvMyFBAO2>46$wJt>2@ir>xM`h(b+jZevYrBM=Mv4sGl*@5z;ZOf* zb3~)y%{1ceyzgWZ$OG;*_WoYJIWfgssARc#G%|O{%8X$?uDzVG@->V1llOc$FW|Q1 zcgw!AFw1NC5)zXZdnHBHs>Ol`Pqg3m?ZE^dW#FnpnN*-gi(D4BjVpUg&hZX{D~MtG z;}mAR*#^SnwByXf2CpI4{2ZYdUU%Krzg^0abwyCbUqWm5e$GXH~s-0+Fhqu;qN861k|Zwi%%OX`o4)TPi+BSqt` z+<%EmROnagVu7yjD=ZaWond4m4HkwGff1m{2Ym7Wl63oPO%X-}K!g!Kk5yZ&g4Iy; zxDqB(yFX)X7+wHO+|&hxOQ7)QE@XL*tpCqxk`6VU$=>nV3oI&%jj;&i2sgFOvql!=$}2M@V-8* z@tLm{E}oq>^mTpX@?ctCYJsak{Fjl4PHC1m0qaP9xzb>smrjBs^Kgo2bl z?}Z)ALuMLpUNcLJ;FHu1Ng@EIMq;5md!d4c)B*3$%pqMh`^IZ?X|+5s13N_xG5VO( z@a?j5ytG;>A7OM@JqJ9SroPLF-$X6MrD-K!q;K)7bD>3>SF&R!{rpOwM!6oJQaG|d z_I{}~m_-`H?0A7R@dQhLrjH)Uf}c2?ASPg0NrE1;8BI|D%)g0B9MM)f$6S{9PuMT| zn0O6Hwfc(*l6=l`oq_Z2CM#9C{Zt7HaQ~8$!?9r6rQh3fFFGtJ&1M5{(pZyIemUv! zw8;bj0cNbF4%($koM-y^v@&D0G^KhhG_+HELc+@~^QFn`Po1{;Fxhp^gf8!iMSP#J zq+4_qZr)bEp8Do?s)L<$BNmPVjT*t(qwje3xbV&+RQ*3l5d10aD7F($JJy1Uh9#UzzgtSV2g-(dsdna(ZTQe z!@_Go-yg2tPaaUS;&9UQC|H6z_lqMcoD{#0CkWLV3T{$#b2%s&7Ax@QXi)USQ@J(G z&q7Zs$^yuY;c#qdtmJdj(B-liaR5t1z9a#?Wqx>8qHAT7gy@@%C=At0h?XRIO(V{A{Kc`htP)plOjrpTiD}1R+T! z7p@?y0=;wXR`|_jf*^J&2(*X#Oaw@z3Uct!ZpF zuhDDSR5f1gC@9#4Ca??(nLju7Y&Z73_{+g~4`i=kDh=jzEdR&QG}()gchXWZbSND%RZs2i(me_lF4%U-9{j zWDR4&pW&dV*S3xsW5dwXqZMKuw~>+TcRV~uzNXE^>KrSmb;lB|t0Jr^tG)Lc6C7t> zqYha^5JM%;%aMWCHjml{Qtoi5)%KNXly!G#hv!y`KonJqY*V5LV$d!eDyfk;B$PJq z06*$c0}{y0o#RR$Fd9$;vM?as)X+Jk`VGuQ|GtEd)P5K`U3l)G%3&y~eY@D(VlMrC zhMwo%#(esy$(j|>v4MeG8q|50N{7>4JWnGOI};C$bDK7aSUF{e4qMRt%Cc|#+c0!# zyV(?o*=im3SHEJ_Y?Ky6*0~e3*@GF|%;%QD5S!}tzZmLdw(#8#J${S2McqXvLH3ek zx7~S~e%m`-@RBj3Z%qQOgc5sO?C1UU!ZxvT?Z50*Iz>`8hCMbsoHo&TWY~w@SVPrl zMi(0u<-i8S5+^diqDGT*%Lu_30mvf^@0U8h4@RHBI@Tq%xkbtiY+L||yH6{_7Wr;H z7jbKvTX+7$EjaRNMi@z?;4tjjDpJQH&o-NjMoCoH)|lU+N8X4c2^`@-S+QuS)IX1D z5(Q2H1)l3`Du@f0T4N*>$VqfaI}$h>YPd7tB?1GyY^bF6HEE0g$jJn#1pP_g1OhHH z5(qUT6pgtIksyQpz$H#wf995WHsKS1noOmZ6$-IuFX%l3>lTmg5|t5ct()&Y4`=o) z(opWR)D{a2`W}$FsClPFP52 zQLSQayT19*=kdVxex&E^#yo(nHJ+`ayvW;6PG(EvHG<_iI|lYOzMg4|@nUC=>=I`u zWf;d(9#LtKvkBD30@fJoSnUis1%qv@=Gx%$T77aGUKcE(!_d!q3(*yq?b!ViirXJJ z%fn}|b;HC$tBhmZ{;)yFBMoOzJ*G59lqg@q1{&wTTEq`2Ww8{>Ri@4KCdnzQ#eeAN z6q2|tCR!OwWOt>4mxU>zaM#g@WjDbDq~`yL0FINC>{TlL-KI2w(s;qB>bZKHv`(p~y_sLl+ma6dnCcEAK%b`udrPuHF_6UF_YQ2F(h(9aTzUQxg zj8qbt%rcRg)meT|A9~9bIPm6EEz7&7aq+G3eQ&YiRCPPr7IYPhj*6Pvsb!-TyP1#d zG#>gbK5n=^@)&8yn1|j_(Ki0Q`$#G#Wwcc~=`D^WF~%5@n?9pck;ciKT&>K8I&s(L z@0)R`jNw4v7Zh+x6mao4sdP#-VuyU>RdD1@V)TVRR9c)%vuwtpZSnTDO(L)6=^hwlfVHg$XpOc!&NSf9!TJj2MvZ^ zWTm(@N+oeiGwG2BiBJ>){(rOztyqAg;}1qgH>Djeq1yTRew+CTh9VDxyDDa{vk)(h z^;j+zmYuE9Ww#N=E(`86yV;F$CqW0qMe|RvXqai9{-TMFFkf;Cg!qX0T@Jii&3Z-9 zm5ho`daB{u-h#*t`KN%V@dHfw6e!bCbw;<8%$XD{)#JyVV;b=9l zYpMvZ#p+tpUR4pIkxK>}qg?{dda=@SzLtz$yD+DaO*a>Fdn4MM5r!%RxNAs_ zA?#Dr3NtCAse7IG)NDIQiqYnQC0|uwfIQCWi(PfKrR=I32d3lAvIAd@6Yxbamz!N1 zpqY^{6@mmXcq*Nt9XFk1f?IKpRY;@E@L4LJm^q{rBt-~kHxtgqz>Vi503Uv+U$`n% zmHZ^b4wQ+S*BJ{){#cnMlO6SxPm98ArmHuXCA6n676=C`B=NTqAQGgJ%#Vg)22&9b zQe=8x^vi8lFgv@QhZ^H)z$5m2CI~BEs&c=7yCz)-g6gf;(}NvU+H&gJTz*aUFC6^V z7)?wq03+zjYZ)#2J4;tb>7F_g#6N+$G!!zKtrm_JM`3#gX0a+_mLOI5*ohD^xs3n6K0` z25*M;CTe+kc@5oiGS;5n0Z%P2V4a+eyX#w{*A;K&H^20uBdwB#9%oQO_LC052RzPdT7RyitfEndRZfKm3K8L666W$DFZ zjRGF7vF~CiTLzP_A+mO=S@s(%oT@f&E>|;LW0uR!%i4Rs6nTI{U+7MzZI%6j?2kEN zAMSF}U^~0eFqPGJ=eoJE%LWM`iO*^_`DA>zcYG@tS$;EJeePpq`xV1O10oh=c(Dx98i-DAyh=Mm-LANwj0H(XOtp z==N6Y&CV6_k{vs0A!930Kf$p;oNrG%4D#`!XJTRD{!1!sRC{kc^oUeos!_O2oEhV1 zvPz3Y%&rLCFG|dPkBNFjpP!u;E3-W;BoKOc2UI`?ys&=2m_1}qQWU0;B&mNgy{@jn z;@8kBHlwyRN)ewLN%0>kk$_aU9pp%=+I#?ou3s|gNT1Y!?G*7(jRGO`u`i=Bn(G0970+`x}>{nK#`D=?rs>6M(Hkz0i*>al?D;+ z8Q=F^>wdUv-Sgq_VGgrq?|sfb&wl>D|9+@sf+Ow>0si8~RGv&8Ad0^jo$e3!eM`I< z0BBy1c(ua68}US;UFvfp^<~Yp$3bhsbJ=d=$4-LW373Ci*@Z;y&C@0EIej*KbF+ zVNV&|q4Vk4+=fESD4l&DNr4%CSoBCIW&HJxY=pH6P%-mi->l{ian+7F91yuwNHa-)QE0f$=vwr5pNkDTHA4&#E6sK2?=E#Yuy9ZG>1<~-} zfX!kN@(h@FAaQCsBwbNiMXHUs2Jv{HY@xY{MwcRy0yWZ73rg}r%0amC^DkX(^d4UZ zVqQOHX6|{hO?@OAJ1k#o$@zl?B$fOyV9^7R!?VJ^TEvmvPwlMYyMxbW$3>qd&LZ2;tq|Dyqd4sEmLEO-s%8aMQk->Kh>B zCo?a;I(DAG{F7{$jaHK_neWT`+> z1@iB!yd~{8QI-3?QB%-WkU$RknN13uSs(osfAa8y#CtraN(D*~m_B5fG&T58)3|vv zZDdKl8~JJPQZf??7>QVQ{BpVaEiONCGGk(MOVn10w`kcnfWgZa`dY&d@qWZeAr?<> zMxjia@_HpJ;HJcS+wDWVkq^E(Ua@A=XwcSrQAnqWUip zymvc*(tVnPj#@@7?%xgoB|?qMEWK50ccw^XB5TpWa4NNdNF-M+B_ExK;%)rZ1%*(| zAlZcPq(cea5Ydh(K`cn3jW(k;nHUFq1SwBP*>nx7!dl-Rg~kdeoJ`D;Fo>hz>af52 zGsTM)Sl<^j0sT0oZ|u_9OJEs5f%278`%?U-N4Ptdx=n_W!ua{?V0YZHd}A|cGkMM0 z>KMkdM>!Ld+*qjGu;yfW;ePP@H+W8G=j#eFu1`+px5jS2X>JROmKfq%8z#M8-$QNs z+Q+_3n=RAda&J21u&(>?0jLPW|4Nr0U^UvTElH&BfO)*Nq&M&qmF(+g?C1Hwo_4fE zHcs8Jank`utQh zFVjAaUMG?mzG=1Zx>`Q|y{9kWNcaW(n;_Z=SUJI;f4oNBC5DLa!7Syo#7nfM|L0Q7Ezjk9EoTDE8+p!Kn#p=XpH`2 znOyzpLoLJo12J0omd_#lEb?`;K!xiVP(gILRO^sHB?)Zy31C(rvzZF_(Nc`#LbZQN zXE(?B#VFGN_!Le_3M6kvu@&j#TV02E`?%#o*hp;Abq~>><8|RfcLa@a#HtrQ*Cyp5r{y4Tn}}> zntyP$xQa*O1^kHDQAua8iNPXbj)vwc0^IZ&M z|A@QFwTGr)irpaM5kOkFI;f#`#2`S5|Pbl44)_4*^{W{Dj389CXUGV7b_224>~9+(xfN-o_@OYF=U^Ia1F5XBLc8~5+II+uUKOyvPl z{o(lJ(0b(3hPzZii$76k{I%3@tD)gDuv-e2xBGJ5A@q2ms$*0YU=$wsteN9JM}v+Z zJ*}2S(2$T&w&l6F>w$r^)mt8IKu}-E@Hw5bn1ZGOP|E|qg(o~bH5-BcevOh|q*JNN z**fHwm*~9seODj%ALPEFT!{j72?-*FZAib;`qRM)_C))TwBFXYK!nF{6U=@}^KbyD zHuRHwx=Q(X1Iwv(9{`<_ST0~4d7Z>$3jI*ad7=tP`Arogzi=VgcpeUEl9p%bSKi7e z4WWrye9m*$pr7mdFaYR5udnXQEghn#4+{AS!43mbbo!n)tn_BPkpS0+sC@ zq?pNNQ$uxwNf`(`!`ox-u6GA%W;VbgKS#Mq68Kf7xV4hIFgwBWF7h7p?CAA+h4%Ft z&^`HhqxJ%%Q=&67Zu=ZYbBL5O{)J{4{?3z!ORe{yG-ybPzv|W2Gjsxq@L>KlFxKe^ z$mtgKE63fPtu)|C9qWBZEp`mk%3sjC3mK0UVg!|UCyb7gi}j)DeHv42M?~|_`BNJH zTY!$Z1SmxQN2ZV;&&G_}+-+Ny(0qW`>dC;2UGT`=$wi=&IStXvO1ik&jgP=n)#`D$ z|a>H4` z>cJZt!{XIuH(9(2ta)_=97zz9#?*bWtFQo{UiE!McdLn-&hX?d0Rz1&zs>tEW)UG}T^j zgi}4&DuM(51Spgu!XQs??{dul*!uPS~^d{>%_g-3c8u-=S+DnOfIm`g${iF)=@u>q~zAQ#-vERx^)*k5%l z1JhBJonZ?(h#{5h&(x_OpbooxphxNXkA%+=Ib90n)cyefoop}_>p@IREU144R~Otl z*rIH2DJW-Q$nTE}{soH|j$2Xe1__XB^;7aBuJdpdI@=wmjA;W%3EA8e0WWRJgc@>b zT@J$53ORLYPE1D*vV_E9yI*3^(vcn|WRu?axoNLgMf?Z+sTdnO+=jtdr{Y@xNVcGHSk)jtl^VQ{F@(pRZ z+`beBRF=L29uFuIz`Lg`3uw69_JFSeHGyIlsS3OEDr;TIwTW8JhR>@0xU+`B{)AuG z3Rs~RxV&`y%C@=Y{j$$s*1w#q${$$9{X8mhwz!=z+b2u~s>^-_((R?=KI=dN(BGuc zl8*+6X2!oQv-x@q!NoB=TU|#K6W>Y|6e3O5Rwp)yYh?0@rxL7tzX0h`DBNp2DM#?p zqs$Qepbz*#z&QkgDM|*9P_7{>fqFHZ1kjKHc~NWu(*`^)j*O28Ob#+kj;O>R!Drc8 z9bmg4C|nUUPLH(2JLyGoX6G20n)3tcsR2wr`IP6ecK3Gc8nqYcb;@RLgE_{ST#K#H zHO}l&&B%cMgda@61}S-%!~8)%<76b9)q#6C!?J3zc(zua=mYUeb37MB*3J)0oXD^b zKb8atz;_xtZgy<(b4q~)%D%>Z#s`7`%=-WWoo)0FRX_MWXxR|)@Q0Y$<~zyZirdi) zK}Q>U!0#6J7dL#fCr1NBLYDQ&jH_>XtQABLp4HMnHNQe|={KGUYKrdw;{DNNv_4Yg zZ2K6m#gUr)cl>USq{~fK8ws80Qf0PgV^g2hLb>WU@4Z!yt)CMRj^U;bbsWF0gB#V= z*%q(qsRu~~)nNK{6zzTM|+f7h@wy=c)OQv)WG8}ncm`^@AoAAR~z!e$4#Jy(j( zRCUeFyczgdR<;`f*y`UI(4D)Ru6l@z&1|~=QIM&JEz-o?075SfQcqy(L|Bl*mr!bq1PjhlMH_7>E5H|M1C#tI3mpZ{La_Lnq(sVdXv@ zM_UTJAN7Wikuiw+kB`&5>L~qpSO)-5sUvE7G=gf%%=V5_ZoyL}gWI?G6ZDPX5Gs2P z1ju&o5W|Xaos|$YLDDZ|{6rz9`6S_wfHe0O#a)>Qz8JH!g#}gzw+g*73mi+CBSNxv zt+J&qaMgDv27E|Gj?j^x<1+iN-I=O~mygVsPS8OiP`rAcVP{lw8UXz{>gb4czQ^%e zhoZB%NdJ)VmzY>I3L73_4ub||V%V{!eY6|7y1(B)yL-HH)HYvsu_IdN5OyFY1A~y zaJ4Ktt($pafJY`A$gZ6Mm{f}`xb)JG&yQPd?*#vKsi`dBRBY-aPzwtMyRy}I*R-{3 zsDMaw)M2TFd46Bqv`hz0S%+<_au~Je2~dA>>R_dAJ?_@e4nL5&37b@+@Q)B-q zRFTY?T`IdI)f`N&T?(T&{UCl7&)B;_)#brRSo;LmL)(*zMI?)BUD~!U{^L`*(ImIl z3fMHt&I(x;I_PD`p@(V71&(uEWWCCl*N!3f&-w-Qkkcnv@hzwUg zW*(EEwAueCB~ToMUdsI* z2}V5fM0BKVVtG};plC6j0dyO?UXrs!9b>;GA3^N%e;ktinbMvY zB2zjDhH;|cyaDBB%DW7-Sqi=x(T36oqu{9 znVPUFrA{D-Y1FARF7zoQbtGe}ZWwolZKBvSqx=8(KV{C2!bm=%1a9BLQjyTBeH~D& z6{)xcV^Q>8q&&OgefeEsHf?p|a98Ws_1TB=JZz(&a-MKF5F&ttBFPX|?a+cqYEg&G z3Oz05+ajrqoG;IwV}#YDuJAw~(_qa-=?eHXt)YM!S({Te3Zukj`stV~$pR3LHu+ie;LYaxG zZ@g}j+EFlh6~o4D#;24+%a(^=4x)gl$BA?^TG|~H<^+GQ)5jh?+`Gz8akYwCw&}M} zu`_gvYl}w2iv8DB&m-JsHE{2CB-P`#zg7&CNo8L&xK?ElpiSHRG&hbN^Ib*xpUYr7b!5<6qx$U~F6P zXLPNpTSL#&g|*^@Um%7F-RQC#)@xsL@jdBCkQ}&EtDMoJM~;%!x=Qa|O=>r4QZ5?e zkMI1YsF;9ZVqh|m7x%%2r1@7ikg0UP)1DBBeR+MfsAMvGG_l>PV52u{?UF?W_UmU_&c-Xd!l|q*l^VoqlS&9d$jG+BR#@`)aFa0zE zM~Hq#vt(0|vc`fMInU`lSX}F*8JLLge|((6&zTKaabgtyd*;pK+WEqE8(K>K6y6+r zO9160PTv@Nx@~AvjUmp3;mN9$67?OYu=BWz6S`%*OMeGL= zX_w7LjD{Kiwfk*fW`IUWpIiZ_Pe#H4F&Nsa%U2&K?jCEBjyJ)Ji;`v7llsE!>^nP6 zxxv;M6`aNKsocS6>HFcm_5(}UHswEU4Q7--1GjqKPWufc<~!xYO!aoL;D9hA&nQiN ze?K9C$O@ASngPc7IT}-UPU)N@o4GYMU?eOwT|d(3w0p|&F0aW2|Jz9QlL2}fLGr1x zs+JF8c0*G!SS!lfs<9UCcSM*)t2nJ7&a`Plz?Yr!3rqjHfck(rfNy%1z}C>vlzfb8 z{+>~l3>EPF$5fBK{1j!jZnyZmlkQx@$I+Efpc|}w0Hq3Mf+T7*=x1uaE2l)RUs38g`#jG|{BlC+#t-sgYAV7tKPh+qA$UjJW z)xu*+pn)Q&X(w1(_+5rA&ygoQ>}evR9K}DZ{8|ztzFAw+IO*jb0UN0I6dWB!>5`fL z+fJ$e%o?X-Yj1wgov|f9wqq!N9VSCy{qUYCUc7`G60@9i0usf~{*MmJ9;#mnTt9T0FR%B#v%$`}X#4;7zO A^Z)<= literal 0 HcmV?d00001